]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.99pre7-1 2.3.99pre7-1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:34:17 +0000 (15:34 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:34:17 +0000 (15:34 -0500)
127 files changed:
Documentation/Configure.help
Documentation/networking/8139too.txt
Makefile
arch/alpha/lib/copy_user.S
arch/i386/config.in
arch/i386/kernel/acpi.c
arch/mips/sgi/kernel/reset.c
arch/mips64/sgi-ip22/ip22-reset.c
drivers/acorn/block/fd1772.c
drivers/atm/ambassador.c
drivers/atm/fore200e.c
drivers/atm/horizon.c
drivers/atm/iphase.c
drivers/atm/nicstar.c
drivers/atm/zatm.c
drivers/char/applicom.c
drivers/char/bttv.c
drivers/char/buz.c
drivers/char/cyclades.c
drivers/char/dtlk.c
drivers/char/isicom.c
drivers/char/istallion.c
drivers/char/moxa.c
drivers/char/msp3400.c
drivers/char/pc110pad.c
drivers/char/radio-cadet.c
drivers/char/softdog.c
drivers/char/specialix.c
drivers/char/stallion.c
drivers/char/stradis.c
drivers/char/sx.c
drivers/char/zr36120.c
drivers/isdn/act2000/module.c
drivers/isdn/avmb1/t1pci.c
drivers/isdn/hisax/saphir.c
drivers/isdn/icn/icn.c
drivers/isdn/isdn_common.c
drivers/isdn/sc/timer.c
drivers/net/3c59x.c
drivers/net/8139too.c
drivers/net/82596.c
drivers/net/aironet4500_card.c
drivers/net/atp.c
drivers/net/dmfe.c
drivers/net/eepro100.c
drivers/net/epic100.c
drivers/net/ne2k-pci.c
drivers/net/pcmcia/xircom_tulip_cb.c
drivers/net/sis900.c
drivers/net/starfire.c
drivers/net/tokenring/abyss.c
drivers/net/tokenring/tmspci.c
drivers/net/tulip/tulip_core.c
drivers/net/via-rhine.c
drivers/net/wan/cycx_x25.c
drivers/net/yellowfin.c
drivers/pci/pci.c
drivers/scsi/NCR5380.c
drivers/scsi/aha152x.c
drivers/scsi/aic7xxx.c
drivers/sound/es1370.c
drivers/sound/es1371.c
drivers/sound/esssolo1.c
drivers/sound/i810_audio.c
drivers/sound/sonicvibes.c
drivers/sound/trident.c
drivers/usb/audio.c
drivers/usb/serial/usbserial.c
drivers/usb/serial/visor.c
drivers/usb/usb-ohci.c
drivers/usb/usb-uhci.c
drivers/video/vga.h
fs/autofs/dirhash.c
fs/autofs4/expire.c
fs/dcache.c
fs/namei.c
fs/nfsd/vfs.c
fs/proc/root.c
fs/super.c
include/asm-i386/string.h
include/asm-m68k/string.h
include/asm-sparc/string.h
include/asm-sparc64/string.h
include/linux/dcache.h
include/linux/file.h
include/linux/filter.h
include/linux/fs.h
include/linux/fs_struct.h
include/linux/input.h
include/linux/mm.h
include/linux/mount.h
include/linux/netfilter_ipv4/ip_conntrack.h
include/linux/netfilter_ipv4/ip_conntrack_core.h
include/linux/netfilter_ipv4/ip_tables.h
include/linux/sched.h
include/linux/string.h
include/linux/usb.h
kernel/ksyms.c
mm/filemap.c
mm/page_alloc.c
mm/vmscan.c
net/ipv4/ipmr.c
net/ipv4/netfilter/ip_conntrack_core.c
net/ipv4/netfilter/ip_conntrack_proto_tcp.c
net/ipv4/netfilter/ip_conntrack_standalone.c
net/ipv4/netfilter/ip_fw_compat.c
net/ipv4/netfilter/ip_fw_compat_masq.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/ipt_LOG.c
net/ipv4/netfilter/ipt_MARK.c
net/ipv4/netfilter/ipt_MASQUERADE.c
net/ipv4/netfilter/ipt_MIRROR.c
net/ipv4/netfilter/ipt_REDIRECT.c
net/ipv4/netfilter/ipt_REJECT.c
net/ipv4/netfilter/ipt_TOS.c
net/ipv4/netfilter/ipt_limit.c
net/ipv4/netfilter/ipt_mac.c
net/ipv4/netfilter/ipt_mark.c
net/ipv4/netfilter/ipt_multiport.c
net/ipv4/netfilter/ipt_owner.c
net/ipv4/netfilter/ipt_state.c
net/ipv4/netfilter/ipt_tos.c
net/ipv4/netfilter/ipt_unclean.c
net/ipv4/netfilter/iptable_filter.c
net/ipx/af_spx.c
net/sched/sch_tbf.c
net/sunrpc/svcauth.c

index e7dfc2b76cccdcb5fe47289098b5ad666f4a5241..1397a81024464d09375a63dd6966b40b978ca6c4 100644 (file)
@@ -1830,7 +1830,7 @@ limit match support
 CONFIG_IP_NF_MATCH_LIMIT
   limit matching allows you to control the rate at which a rule can be
   matched: mainly useful in combination with the LOG target ("LOG
-  target support", below).
+  target support", below) and to avoid some Denial of Service attacks.
 
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
index 6a75c7338801c94dfc169946ab3f0732e3802c57..92427b67957192cd34cd4b6ed7d1bb590f4b791b 100644 (file)
@@ -169,6 +169,33 @@ suggestions welcome)
 
 Change History
 --------------
+Version 0.9.4.1 - April 27, 2000 - third public beta release
+
+* Replace several "magic numbers" with symbolic constants
+* Differentiate between board-specific info and chip-specific info
+  (allows for easier support of specific boards or chips)
+* Move some of the transmit side outside of the spinlock
+  by using atomic variables.  Use spin_lock_irq instead of
+  spin_lock_irq{save,restore} in select places, for better performance.
+* New module option "media" for forcing media selection.  Functions the
+  same as "options" in other drivers, and will soon be renamed
+  'options' to be homogeneous.
+* New power management wake-up code
+* Slightly more verbose chip id messages in kernel log
+* Add/correct chip register constant list
+* New chipset wake up (open) logic
+* No longer locks CONFIGx updates
+* Do not set Interfame Gap (IFG) bits in TxConfig
+* Better Rx reset logic in case of Rx FIFO Overflow
+* For chips which support it, enable bit to automatically clear Rx
+  FIFO overflow
+* No longer enable and disable interrupts in interrupt handler
+  (technique borrowed from BSD driver, appears to have problems
+   with some chips)
+* H/W spinlock now protects ioctl
+* Chipset-dependent RxConfig settings
+
+
 Version 0.9.3.3.2 - Feb 22, 2000 - second public beta release
 
 * Begin integration of Daniel Kobras' MMIO flush patch (disabled for now)
@@ -187,8 +214,9 @@ Version 0.9.3.3.2 - Feb 22, 2000 - second public beta release
 * Reset NWay registers to sane defaults on rtl8139_open/hw_start
 * Miscellaneous code cleanup
 
-Version 0.7.0 - Feb 7, 2000 - first public beta release
 
+Version 0.7.0 - Feb 7, 2000 - first public beta release
+* Initial public version, derived from Donald Becker's rtl8139.c v1.08r
 
 [EOF]
 
index e2ad548213e34f199ceeb11f7538bb2b2ed4714f..f0dbc73d76d813059c91e7abced7b590ad8bc3a5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 3
 SUBLEVEL = 99
-EXTRAVERSION = -pre6
+EXTRAVERSION = -pre7
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
index 7cc7382ab314ff135e5c89351c9f64081ad7f805..d8f1a24cfeddcdb82959b8f69b7a64578b1ef2fb 100644 (file)
@@ -80,7 +80,7 @@ $50:
        extql $3,$7,$3
        extqh $2,$7,$1
        bis $3,$1,$1
-       stq $1,0($6)
+       EXO( stq $1,0($6) )
        addq $7,8,$7
        subq $0,8,$0
        addq $6,8,$6
index 589c347305eabdd437a5827aa8d5094abdf6af66..8f4782ca80f9c9be3fbde38f2663f212c37620cf 100644 (file)
@@ -22,7 +22,7 @@ choice 'Processor family' \
         486/Cx486              CONFIG_M486     \
         586/K5/5x86/6x86/6x86MX        CONFIG_M586     \
         Pentium/TSC            CONFIG_M586TSC  \
-        PPro                   CONFIG_M686 \
+        PPro/P-II/P-III        CONFIG_M686 \
         K6/II/III              CONFIG_MK6 \
         Athlon                 CONFIG_MK7" PPro
 #
index e63a45e665d915f4d6fff98cb65c4b11c71d452e..c505bd6c23e24f9cae4f833427009205ddd3e090 100644 (file)
@@ -144,14 +144,21 @@ static unsigned long acpi_opts = ACPI_ENABLED;
 
 struct acpi_errata_info
 {
-       const char *oem;
-       const char *oem_table;
-       u32 oem_rev;
-       unsigned long options;
+       const char *signature; // table signature (eg. "RSDT")
+       const char *oem;       // OEM name
+       const char *oem_table; // OEM table identifier (optional)
+       u32 oem_rev;           // OEM table revision (optional)
+       unsigned long options; // errata options
 };
 
+/*
+ * We must identify systems that need ACPI_TRUST_TABLES solely from the
+ * RSDP ("RSD PTR ").  All other options should be flagged from the
+ * RSDT ("RSDT") which can be better identified.
+ */
 struct acpi_errata_info acpi_errata[] =
 {
+       {"RSD PTR ", "AMI   ", NULL, 0, ACPI_TRUST_TABLES | ACPI_COPY_TABLES},
        {NULL, NULL, 0, 0},
 };
 
@@ -520,6 +527,51 @@ static void acpi_destroy_table(struct acpi_table_info *info)
        }
 }
 
+/*
+ * Match ACPI table and set options based on platform errata, if any
+ */
+static int __init acpi_find_errata(struct acpi_table *table)
+{
+       struct acpi_errata_info *info;
+       int size;
+
+       for (info = acpi_errata; info->signature && info->oem; info++) {
+               size = strlen(info->signature);
+               if (memcmp(&table->signature, info->signature, size))
+                       continue;
+               if (strcmp(info->signature, "RSD PTR ")) {
+                       // ordinary ACPI table
+                       size = strlen(info->oem);
+                       if (memcmp(table->oem, info->oem, size))
+                               continue;
+                       if (info->oem_table) {
+                               size = strlen(info->oem_table);
+                               if (memcmp(table->oem_table,
+                                          info->oem_table,
+                                          size))
+                                       continue;
+                       }
+                       if (info->oem_rev && table->oem_rev != info->oem_rev)
+                               continue;
+               }
+               else {
+                       // special handling for RSDP
+                       size = strlen(info->oem);
+                       if (memcmp(((struct acpi_rsdp*) table)->oem,
+                                  info->oem,
+                                  size))
+                               continue;
+               }
+
+               printk(KERN_INFO
+                      "ACPI: found platform errata 0x%08lx\n",
+                      info->options);
+               acpi_opts |= info->options;
+               return 0;
+       }
+       return -1;
+}
+
 /*
  * Locate and map ACPI tables
  */
@@ -556,6 +608,14 @@ static int __init acpi_find_tables(void)
        if (i >= ACPI_BIOS_ROM_END)
                return -ENODEV;
 
+       // find any errata based on the RSDP
+       if (!acpi_find_errata((struct acpi_table*) rsdp)) {
+               if (acpi_opts & ACPI_DISABLED)
+                       return -EINVAL;
+               else if (acpi_opts & ACPI_CHIPSET_ONLY)
+                       return -ENODEV;
+       }
+
        // fetch RSDT from RSDP
        rsdt = acpi_map_table(rsdp->rsdt);
        if (!rsdt) {
@@ -569,6 +629,15 @@ static int __init acpi_find_tables(void)
                acpi_unmap_table(rsdt);
                return -EINVAL;
        }
+
+       // find any errata based on the RSDT
+       if (!acpi_find_errata(rsdt)) {
+               if (acpi_opts & ACPI_DISABLED)
+                       return -EINVAL;
+               else if (acpi_opts & ACPI_CHIPSET_ONLY)
+                       return -ENODEV;
+       }
+
        // search RSDT for FACP
        acpi_facp.table = NULL;
        rsdt_entry = (u32 *) (rsdt + 1);
index 34016f2f1a2afc398a7185fa00b6c8144c92fec4..02789145b8f06422983cf6c926c71852e9025397 100644 (file)
@@ -88,9 +88,7 @@ static void blink_timeout(unsigned long data)
        sgi_hpc_write1 ^= (HPC3_WRITE1_LC0OFF|HPC3_WRITE1_LC1OFF);
        hpc3mregs->write1 = sgi_hpc_write1;
 
-       del_timer(&blink_timer);
-       blink_timer.expires = jiffies + data;
-       add_timer(&blink_timer);
+       mod_timer(&blink_timer, jiffies+data);
 }
 
 static void debounce(unsigned long data)
index 032391171b9777f206fd3078c9da7773e8117bb3..281967f92acee8055dab95beafcb8c213d35eda0 100644 (file)
@@ -87,9 +87,7 @@ static void blink_timeout(unsigned long data)
        sgi_hpc_write1 ^= (HPC3_WRITE1_LC0OFF|HPC3_WRITE1_LC1OFF);
        hpc3mregs->write1 = sgi_hpc_write1;
 
-       del_timer(&blink_timer);
-       blink_timer.expires = jiffies + data;
-       add_timer(&blink_timer);
+       mod_timer(&blink_timer, jiffies+data);
 }
 
 static void debounce(unsigned long data)
index 95836eb29544ef01cded04b9e955e67f5b533698..e2e7d96dfba20fa61ad5605013f34a38d35a60be 100644 (file)
@@ -303,11 +303,9 @@ static unsigned int changed_floppies = 0xff, fake_change = 0;
         timer_active |= (1 << FLOPPY_TIMER);                   \
        } while(0)
 
-#define        START_TIMEOUT()                                 \
-    do {                                               \
-        del_timer( &timeout_timer );                   \
-        timeout_timer.expires = jiffies + FLOPPY_TIMEOUT;      \
-        add_timer( &timeout_timer );                   \
+#define        START_TIMEOUT()                                      \
+    do {                                                    \
+        mod_timer(&timeout_timer, jiffies+FLOPPY_TIMEOUT); \
        } while(0)
 
 #define        STOP_TIMEOUT()                                  \
index 151704c95f2075ddde4f3145636a87cf9b0387c2..47530fa6f46e2c44e80dcb203145097261b41f4c 100644 (file)
@@ -2372,8 +2372,8 @@ static int __init amb_probe (void) {
     
     // read resources from PCI configuration space
     u8 irq = pci_dev->irq;
-    u32 * membase = bus_to_virt (pci_dev->resource[0].start);
-    u32 iobase = pci_dev->resource[1].start;
+    u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 0));
+    u32 iobase = pci_resource_start (pci_dev, 1);
     
     void setup_dev (void) {
       unsigned char pool;
@@ -2419,6 +2419,9 @@ static int __init amb_probe (void) {
     void setup_pci_dev (void) {
       unsigned char lat;
       
+      /* XXX check return value */
+      pci_enable_device (pci_dev);
+
       // enable bus master accesses
       pci_set_master (pci_dev);
       
index d9d5a66c548b053f261cb529cee9e77408941a64..6bee2f68d36e1141f8bbd0c70530e19ab730c493 100644 (file)
@@ -647,6 +647,9 @@ fore200e_pca_detect(const struct fore200e_bus* bus, int index)
        if (pci_dev == NULL)
            return NULL;
     } while (count--);
+
+    if (pci_enable_device(pci_dev))
+       return NULL;
     
     fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
     if (fore200e == NULL)
@@ -655,7 +658,7 @@ fore200e_pca_detect(const struct fore200e_bus* bus, int index)
     fore200e->bus       = bus;
     fore200e->bus_dev   = pci_dev;    
     fore200e->irq       = pci_dev->irq;
-    fore200e->phys_base = (pci_dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK);
+    fore200e->phys_base = pci_resource_start (pci_dev, 0);
 
 #if defined(__powerpc__)
     fore200e->phys_base += KERNELBASE;
@@ -663,7 +666,6 @@ fore200e_pca_detect(const struct fore200e_bus* bus, int index)
 
     sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
 
-    pci_enable_device(pci_dev);
     pci_set_master(pci_dev);
 
     return fore200e;
index f39845f853bfeb8141b70a1c1bf03b89103b7a09..dc39a1ce5c243f85828382af6785fca16cb54763 100644 (file)
@@ -2759,9 +2759,6 @@ static int __init hrz_probe (void) {
   
   PRINTD (DBG_FLOW, "hrz_probe");
   
-  if (!pci_present())
-    return 0;
-  
   devs = 0;
   pci_dev = NULL;
   while ((pci_dev = pci_find_device
@@ -2770,8 +2767,8 @@ static int __init hrz_probe (void) {
     hrz_dev * dev;
     
     // adapter slot free, read resources from PCI configuration space
-    u32 iobase = pci_dev->resource[0].start;
-    u32 * membase = bus_to_virt (pci_dev->resource[1].start);
+    u32 iobase = pci_resource_start (pci_dev, 0);
+    u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 1));
     u8 irq = pci_dev->irq;
     
     // check IO region
@@ -2779,7 +2776,10 @@ static int __init hrz_probe (void) {
       PRINTD (DBG_WARN, "IO range already in use");
       continue;
     }
-    
+
+    if (pci_enable_device (pci_dev))
+      continue;
+
     dev = kmalloc (sizeof(hrz_dev), GFP_KERNEL);
     if (!dev) {
       // perhaps we should be nice: deregister all adapters and abort?
index cd1714a53b09e6de684c88c5ded09cf32c6f5ca4..11a41ddc72d82c169abb3a328e38cd0b0b93e233 100644 (file)
@@ -3206,6 +3206,7 @@ __initfunc(int ia_detect(void))
                IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
                      iadev->pci->bus->number, PCI_SLOT(iadev->pci->devfn), 
                                                  PCI_FUNC(iadev->pci->devfn));)  
+               if (pci_enable_device(iadev->pci)) break;
                dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
                if (!dev) break;  
                IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", 
index 767fd75fb9d7efa424ba810281943c032faa87e4..20d7c0766c5048e663d0344dc95fec641fea72db 100644 (file)
@@ -452,6 +452,14 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
 
    error = 0;
 
+   if (pci_enable_device(pcidev))
+   {
+      printk("nicstar%d: can't enable PCI device\n", i);
+      error = 2;
+      ns_init_card_error(card, error);
+      return error;
+   }
+
    if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL)
    {
       printk("nicstar%d: can't allocate memory for device structure.\n", i);
index 1b68f552996927607b288bb86a357c974048a7ea..576f51aad257b868b900681d5bcfbd5aeb6d1639 100644 (file)
@@ -1811,6 +1811,7 @@ int __init zatm_detect(void)
                while ((pci_dev = pci_find_device(PCI_VENDOR_ID_ZEITNET,type ?
                    PCI_DEVICE_ID_ZEITNET_1225 : PCI_DEVICE_ID_ZEITNET_1221,
                    pci_dev))) {
+                       if (pci_enable_device(pci_dev)) break;
                        dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
                        if (!dev) break;
                        zatm_dev->pci_dev = pci_dev;
index 3d84dd0ad2284b6b2620af23d95e7b735c41cfd1..d5091ff4df4cea015ab0edb5cc0ae9f866f20d55 100644 (file)
@@ -205,6 +205,9 @@ int __init applicom_init(void)
                if (dev->device  > MAX_PCI_DEVICE_NUM || dev->device == 0)
                        continue;
                
+               if (pci_enable_device(dev))
+                       return -EIO;
+
                RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO);
 
                if (!RamIO) {
index a5ac48b23cccdf1ffb24da6caab5fddb595cda37..f55f992d8c20b2ba4e881501f56020bbbf119426 100644 (file)
@@ -3661,7 +3661,10 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
 
         btv->id=dev->device;
         btv->irq=dev->irq;
-        btv->bt848_adr=dev->resource[0].start;
+        btv->bt848_adr=pci_resource_start(dev, 0);
+
+       if (pci_enable_device(dev))
+               return -EIO;
        if (!request_mem_region(pci_resource_start(dev,0),
                                pci_resource_len(dev,0),
                                "bttv")) {
@@ -3672,7 +3675,6 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
         else
                 btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
 
-        btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
         pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
         printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ",
                bttv_num,btv->id, btv->revision);
index 4c4e44621722ee60f0bd865c24ee4630d7547245..cbf085e9e3bd7304c721c76f3d8792c7f86d29c9 100644 (file)
@@ -3324,7 +3324,10 @@ static int find_zr36057(void)
 
                spin_lock_init(&zr->lock);
 
-               zr->zr36057_adr = zr->pci_dev->resource[0].start;
+               if (pci_enable_device(dev))
+                       continue;
+
+               zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0);
                pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
                if (zr->revision < 2) {
                        printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
@@ -3332,8 +3335,8 @@ static int find_zr36057(void)
                } else {
                        unsigned short ss_vendor_id, ss_id;
 
-                       pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor_id);
-                       pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_ID, &ss_id);
+                       ss_vendor_id = zr->pci_dev->subsystem_vendor;
+                       ss_id = zr->pci_dev->subsystem_device;
                        printk(KERN_INFO "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
                               zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr);
                        printk(KERN_INFO "%s: subsystem vendor=0x%04x id=0x%04x\n",
@@ -3346,6 +3349,10 @@ static int find_zr36057(void)
                }
 
                zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000);
+               if (!zr->zr36057_mem) {
+                       printk(KERN_ERR "%s: ioremap failed\n", zr->name);
+                       /* XXX handle error */
+               }
 
                /* set PCI latency timer */
                pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency);
index d11de7b352780dd85aae333a7c6b547ecf560b97..814503728b2ca5f10c6e6c49936ad490a90c151b 100644 (file)
@@ -4859,9 +4859,6 @@ cy_detect_pci(void)
   uclong               Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
   unsigned char         Ze_irq[NR_CARDS];
 
-        if(pci_present() == 0) {    /* PCI bus not present */
-                return(0);
-        }
         for (i = 0; i < NR_CARDS; i++) {
                 /* look for a Cyclades card by vendor and device id */
                 while((device_id = cy_pci_dev_id[dev_index]) != 0) {
@@ -4876,11 +4873,14 @@ cy_detect_pci(void)
                if (device_id == 0)
                    break;
 
+               if (pci_enable_device(pdev))
+                   continue;
+
                 /* read PCI configuration area */
                cy_pci_irq = pdev->irq;
-               cy_pci_addr0 = pdev->resource[0].start;
-               cy_pci_addr1 = pdev->resource[1].start;
-               cy_pci_addr2 = pdev->resource[2].start;
+               cy_pci_addr0 = pci_resource_start(pdev, 0);
+               cy_pci_addr1 = pci_resource_start(pdev, 1);
+               cy_pci_addr2 = pci_resource_start(pdev, 2);
                 pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
 
                device_id &= ~PCI_DEVICE_ID_MASK;
index bd832b9b1a2d2ffffe66055ef84ad8f316ee4a0b..542ad99bf6ba69849d7a97fd627b68f5a2feb91e 100644 (file)
@@ -241,6 +241,8 @@ static ssize_t dtlk_write(struct file *file, const char *buf,
 static unsigned int dtlk_poll(struct file *file, poll_table * wait)
 {
        int mask = 0;
+       unsigned long expires;
+
        TRACE_TEXT(" dtlk_poll");
        /*
           static long int j;
@@ -261,9 +263,8 @@ static unsigned int dtlk_poll(struct file *file, poll_table * wait)
        /* there are no exception conditions */
 
        /* There won't be any interrupts, so we set a timer instead. */
-       del_timer(&dtlk_timer);
-       dtlk_timer.expires = jiffies + 3*HZ / 100;
-       add_timer(&dtlk_timer);
+       expires = jiffies + 3*HZ / 100;
+       mod_timer(&dtlk_timer, expires);
 
        return mask;
 }
index 77dc4625b5c898a5c5cf399985119781f3bb971f..5e04e5e6d1d839fcddb6a3888233514054882699 100644 (file)
@@ -1995,12 +1995,14 @@ int init_module(void)
                                if (card >= BOARD_COUNT)
                                        break;
                                        
+                               if (pci_enable_device(dev))
+                                       break;
+
                                /* found a PCI ISI card! */
-                               ioaddr = dev->resource[3].start; /* i.e at offset 0x1c in the
-                                                               * PCI configuration register
-                                                               * space.
-                                                               */
-                               ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
+                               ioaddr = pci_resource_start (dev, 3); /* i.e at offset 0x1c in the
+                                                                      * PCI configuration register
+                                                                      * space.
+                                                                      */
                                pciirq = dev->irq;
                                printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", device_id[idx]);
                                /*
index ad945239027b3c4cf3aa1ffa016bff40ea16db1d..6bdb340a7744e681600fd3ee4ee0e6feb587ac80 100644 (file)
@@ -4657,6 +4657,8 @@ static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp)
                dev->bus->number, dev->devfn);
 #endif
 
+       if (pci_enable_device(devp))
+               return(-EIO);
        if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
                return(-ENOMEM);
        if ((brdp->brdnr = stli_getbrdnr()) < 0) {
@@ -4667,17 +4669,19 @@ static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp)
        brdp->brdtype = brdtype;
 
 #if DEBUG
-       printk("%s(%d): BAR[]=%x,%x,%x,%x\n", __FILE__, __LINE__,
-               devp->resource[0].start, devp->resource[1].start,
-               devp->resource[2].start, devp->resource[3].start);
+       printk("%s(%d): BAR[]=%lx,%lx,%lx,%lx\n", __FILE__, __LINE__,
+               pci_resource_start(devp, 0),
+               pci_resource_start(devp, 1),
+               pci_resource_start(devp, 2),
+               pci_resource_start(devp, 3));
 #endif
 
 /*
  *     We have all resources from the board, so lets setup the actual
  *     board structure now.
  */
-       brdp->iobase = (devp->resource[3].start & PCI_BASE_ADDRESS_IO_MASK);
-       brdp->memaddr = (devp->resource[2].start & PCI_BASE_ADDRESS_MEM_MASK);
+       brdp->iobase = pci_resource_start(devp, 3);
+       brdp->memaddr = pci_resource_start(devp, 2);
        stli_brdinit(brdp);
 
        return(0);
index ca260fede4cd259e37dc6485498ba6eea479eb1f..5aaa09d0fd11c3ded0fafc319e788ada04d3f072 100644 (file)
@@ -482,13 +482,15 @@ int moxa_init(void)
 #endif
        /* Find PCI boards here */
 #ifdef CONFIG_PCI
-       if (pci_present()) {
+       {
                struct pci_dev *p = NULL;
                n = sizeof(moxa_pcibrds) / sizeof(moxa_pciinfo);
                i = 0;
                while (i < n) {
                        while((p = pci_find_device(moxa_pcibrds[i].vendor_id, moxa_pcibrds[i].device_id, p))!=NULL)
                        {
+                               if (pci_enable_device(p))
+                                       continue;
                                if (numBoards >= MAX_BOARDS) {
                                        if (verbose)
                                                printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS);
@@ -513,7 +515,7 @@ static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf
 {
        unsigned int val;
 
-       board->baseAddr = p->resource[2].start;
+       board->baseAddr = pci_resource_start (p, 2);
        board->boardType = board_type;
        switch (board_type) {
        case MOXA_BOARD_C218_ISA:
index bb6db3b6a0d26c71bf1f5bc3363bb3b40603d64e..630d6a94c22d4834f15db8fa37bd6dfe215f947e 100644 (file)
@@ -663,11 +663,8 @@ static void watch_stereo(struct i2c_client *client)
        }
        if (once)
                msp->watch_stereo = 0;
-       if (msp->watch_stereo) {
-               del_timer(&msp->wake_stereo);
-               msp->wake_stereo.expires = jiffies + 5*HZ;
-               add_timer(&msp->wake_stereo);
-       }
+       if (msp->watch_stereo)
+               mod_timer(&msp->wake_stereo, jiffies+5*HZ);
 }
 
 static int msp3400c_thread(void *data)
@@ -874,11 +871,8 @@ static int msp3400c_thread(void *data)
                /* unmute */
                msp3400c_setvolume(client, msp->left, msp->right);
 
-               if (msp->watch_stereo) {
-                       del_timer(&msp->wake_stereo);
-                       msp->wake_stereo.expires = jiffies + 5*HZ;
-                       add_timer(&msp->wake_stereo);
-               }
+               if (msp->watch_stereo) 
+                       mod_timer(&msp->wake_stereo, jiffies+5*HZ);
 
                if (debug)
                        msp3400c_print_mode(msp);
@@ -1092,11 +1086,8 @@ static int msp3410d_thread(void *data)
                msp3400c_settreble(client, msp->treble);
                msp3400c_setvolume(client, msp->left, msp->right);
 
-               if (msp->watch_stereo) {
-                       del_timer(&msp->wake_stereo);
-                       msp->wake_stereo.expires = jiffies + HZ;
-                       add_timer(&msp->wake_stereo);
-               }
+               if (msp->watch_stereo) 
+                       mod_timer(&msp->wake_stereo, jiffies+HZ);
 
                msp->active = 0;
        }
index 35098c7c48b7e40f6e9ab01f7aa73cbe04fdd49b..ed623c3a0cf6015f052ce029c0904ddea737f010 100644 (file)
@@ -70,20 +70,6 @@ static struct fasync_struct *asyncptr;
 static int active=0;   /* number of concurrent open()s */
 static struct semaphore reader_lock;
 
-/*
- *     set_timer_callback:
- *
- *     Utility to reset a timer to go off some time in the future.
- */
-
-static void set_timer_callback(struct timer_list *timer, int ticks)
-{
-       del_timer(timer);
-       timer->expires = jiffies+ticks;
-       add_timer(timer);
-}
-
-
 /**
  *     wake_readers:
  *
@@ -178,7 +164,7 @@ void notify_pad_up_down(void)
                transition_count=1;
                recent_transition=1;
        }
-       set_timer_callback(&tap_timer, current_params.tap_interval);
+       mod_timer(&tap_timer, jiffies + current_params.tap_interval);
 
        /* changes to transition_count can cause reported button to change */
        button_pending = 1;
@@ -369,8 +355,8 @@ static void pad_irq(int irq, void *ptr, struct pt_regs *regs)
                                else
                                {
                                        bounce=JUST_GONE_DOWN;
-                                       set_timer_callback(&bounce_timer,
-                                               current_params.bounce_interval);
+                                       mod_timer(&bounce_timer,
+                                               jiffies+current_params.bounce_interval);
                                        /* start new stroke/tap */
                                        debounced_down=new_down;
                                        notify_pad_up_down();
@@ -391,8 +377,8 @@ static void pad_irq(int irq, void *ptr, struct pt_regs *regs)
                                {
                                        /* don't trust it yet */
                                        bounce=JUST_GONE_UP;
-                                       set_timer_callback(&bounce_timer,
-                                               current_params.bounce_interval);
+                                       mod_timer(&bounce_timer,
+                                               jiffies+current_params.bounce_interval);
                                }
                        }
                }
index 685a08a0d5444812e6810dcccf4aa0fde59a5375..8f95d94dc8db2b5e9881b71c49dfa6ce4aace409 100644 (file)
@@ -572,12 +572,14 @@ int __init cadet_init(void)
 #ifdef MODULE        
                printk(KERN_ERR "You must set an I/O address with io=0x???\n");
 #endif
-               return EINVAL;
+               return -EINVAL;
        }
-       if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1)
+       if (!request_region(io,2,"cadet"))
+               return -EBUSY;
+       if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1) {
+               release_region(io,2);
                return -EINVAL;
-               
-       request_region(io,2,"cadet");
+       }
        printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io);
        return 0;
 }
index bdc61cca66f7376f89268912de3646fffa01eda8..a7620dda02ffa79864624305237699e3e070d43d 100644 (file)
@@ -83,9 +83,7 @@ static int softdog_open(struct inode *inode, struct file *file)
        /*
         *      Activate timer
         */
-       del_timer(&watchdog_ticktock);
-       watchdog_ticktock.expires=jiffies + (soft_margin * HZ);
-       add_timer(&watchdog_ticktock);
+       mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
        timer_alive=1;
        return 0;
 }
@@ -104,15 +102,6 @@ static int softdog_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static void softdog_ping(void)
-{
-       /*
-        *      Refresh the timer.
-        */
-
-       mod_timer(&watchdog_ticktock, jiffies + (soft_margin * HZ));
-}
-
 static ssize_t softdog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
 {
        /*  Can't seek (pwrite) on this device  */
@@ -122,9 +111,8 @@ static ssize_t softdog_write(struct file *file, const char *data, size_t len, lo
        /*
         *      Refresh the timer.
         */
-       if(len)
-       {
-               softdog_ping();
+       if(len) {
+               mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
                return 1;
        }
        return 0;
@@ -151,7 +139,7 @@ static int softdog_ioctl(struct inode *inode, struct file *file,
                case WDIOC_GETBOOTSTATUS:
                        return put_user(0,(int *)arg);
                case WDIOC_KEEPALIVE:
-                       softdog_ping();
+                       mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
                        return 0;
        }
 }
index fad27b0d5d6597af37380c9c73ce93ca5d6f2606..5c66649e85bcbc106eb1b7430a672bbd515a370f 100644 (file)
@@ -2351,11 +2351,14 @@ int specialix_init(void)
                                                pdev);
                        if (!pdev) break;
 
+                       if (pci_enable_device(pdev)) {
+                               i++;
+                               continue;
+                       }
+
                        sx_board[i].irq = pdev->irq;
 
-                       pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint);
-                       /* Mask out the fact that it's IO-space */
-                       sx_board[i].base = tint & PCI_BASE_ADDRESS_IO_MASK; 
+                       sx_board[i].base = pci_resource_start (pdev, 2);
 
                        sx_board[i].flags |= SX_BOARD_IS_PCI;
                        if (!sx_probe(&sx_board[i]))
index 18fa8c6452df5fa968c44236ad2df1a27ed2d51a..1898849d865ccb1ee8a72aba6e130de4f49b715e 100644 (file)
@@ -2778,6 +2778,8 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
                devp->bus->number, devp->devfn);
 #endif
 
+       if (pci_enable_device(devp))
+               return(-EIO);
        if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
                return(-ENOMEM);
        if ((brdp->brdnr = stl_getbrdnr()) < 0) {
index 6d98f932302510f034d1372d120cb584a50a15c9..f157d4e52c4786de52dcb47b7039a0cc1bf299b0 100644 (file)
@@ -2048,6 +2048,9 @@ static int configure_saa7146(struct pci_dev *dev, int num)
        init_waitqueue_head(&saa->debiq);
        init_waitqueue_head(&saa->vidq);
        spin_lock_init(&saa->lock);
+
+       if (pci_enable_device(dev))
+               return -EIO;
        
        saa->id = dev->device;
        saa->irq = dev->irq;
index a5c94927a4ebef13a100665e1a99df0d77ba0f2a..adfe3c69db743696afc1c1422a121f881f124694 100644 (file)
@@ -2472,6 +2472,8 @@ int sx_init(void)
                while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 
                                                PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, 
                                                      pdev))) {
+                       if (pci_enable_device(pdev))
+                               continue;
 #else
                        for (i=0;i< SX_NBOARDS;i++) {
                                if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, 
@@ -2503,14 +2505,16 @@ int sx_init(void)
 
                        /* CF boards use base address 3.... */
                        if (IS_CF_BOARD (board))
-                               pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3,
-                                                     &tint);
+                               board->hw_base = pci_resource_start (pdev, 3);
                        else
-                               pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2,
-                                                     &tint);
-                       board->hw_base = tint & PCI_BASE_ADDRESS_MEM_MASK;
+                               board->hw_base = pci_resource_start (pdev, 2);
                        board->base2 = 
                        board->base = (ulong) ioremap(board->hw_base, WINDOW_LEN (board));
+                       if (!board->base) {
+                               printk(KERN_ERR "ioremap failed\n");
+                               /* XXX handle error */
+                       }
+
                        /* Most of the stuff on the CF board is offset by
                           0x18000 ....  */
                        if (IS_CF_BOARD (board)) board->base += 0x18000;
index 692824133cb4e6c5d7bba13a1fcbd5bfebc89a69..a46c3d056210fbfc7e5b1ef9c67d84db6e8dd655 100644 (file)
@@ -1852,18 +1852,15 @@ int __init find_zoran(void)
        unsigned char revision;
        int zoran_num=0;
 
-       if (!pcibios_present())
-       {
-               printk(KERN_DEBUG "zoran: PCI-BIOS not present or not accessible!\n");
-               return 0;
-       }
-
        while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev)))
        {
                /* Ok, a ZR36120/ZR36125 found! */
                ztv = &zorans[zoran_num];
                ztv->dev = dev;
 
+               if (pci_enable_device(dev))
+                       return -EIO;
+
                pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision);
                printk(KERN_INFO "zoran: Zoran %x (rev %d) ",
                        dev->device, revision);
index f152792532ad88a274da22bc8ca3d514dc794c64..158d9463ed78359bfbf6c90904225fb9162ced01 100644 (file)
@@ -279,9 +279,7 @@ act2000_poll(unsigned long data)
        act2000_receive(card);
         save_flags(flags);
         cli();
-        del_timer(&card->ptimer);
-        card->ptimer.expires = jiffies + 3;
-        add_timer(&card->ptimer);
+        mod_timer(&card->ptimer, jiffies+3);
         restore_flags(flags);
 }
 
index 10304be3b065e650726bde71730ebeb282d21bea..70355abcaa3e47eea53a718b675f90f56fbecd7a 100644 (file)
@@ -305,9 +305,11 @@ int t1pci_init(void)
        while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, dev))) {
                struct capicardparams param;
 
-               param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK;
+               param.port = pci_resource_start (dev, 1);
                param.irq = dev->irq;
-               param.membase = dev->resource[ 0].start & PCI_BASE_ADDRESS_MEM_MASK;
+               param.membase = pci_resource_start (dev, 0);
+
+               pci_enable_device (dev); /* XXX check return */
 
                printk(KERN_INFO
                        "%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
index b642d759c54c5819c62c4b1df4c9382447bc9f01..5d659a0437c47c53b367b2f7ca442dbd1ef3f01f 100644 (file)
@@ -173,11 +173,9 @@ saphir_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                goto Start_ISAC;
        }
        /* Watchdog */
-       if (cs->hw.saphir.timer.function) {
-               del_timer(&cs->hw.saphir.timer);
-               cs->hw.saphir.timer.expires = jiffies + 1*HZ;
-               add_timer(&cs->hw.saphir.timer);
-       } else
+       if (cs->hw.saphir.timer.function) 
+               mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
+       else
                printk(KERN_WARNING "saphir: Spurious timer!\n");
        writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF);
        writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF);
@@ -192,9 +190,7 @@ SaphirWatchDog(struct IsdnCardState *cs)
 {
         /* 5 sec WatchDog, so read at least every 4 sec */
        cs->readisac(cs, ISAC_RBCH);
-       del_timer(&cs->hw.saphir.timer);
-       cs->hw.saphir.timer.expires = jiffies + 1*HZ;
-       add_timer(&cs->hw.saphir.timer);
+       mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
 }
 
 void
index 92ee95a2e47931b6cd248b9c8da980b28e121b0e..727165387ed7e5e6e46186c21505739cd506a33a 100644 (file)
@@ -602,9 +602,7 @@ icn_pollbchan(unsigned long data)
                /* schedule b-channel polling again */
                save_flags(flags);
                cli();
-               del_timer(&card->rb_timer);
-               card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
-               add_timer(&card->rb_timer);
+               mod_timer(&card->rb_timer, jiffies+ICN_TIMER_BCREAD);
                card->flags |= ICN_FLAGS_RBTIMER;
                restore_flags(flags);
        } else
@@ -905,9 +903,7 @@ icn_polldchan(unsigned long data)
        /* schedule again */
        save_flags(flags);
        cli();
-       del_timer(&card->st_timer);
-       card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
-       add_timer(&card->st_timer);
+       mod_timer(&card->st_timer, jiffies+ICN_TIMER_DCREAD);
        restore_flags(flags);
 }
 
index 6462a10bc5df350e84b0b9f0d46bb300257c6d1e..aca7161841ed22fa834b83c77fa06500813a75f8 100644 (file)
@@ -685,9 +685,7 @@ isdn_timer_funct(ulong dummy)
 
                save_flags(flags);
                cli();
-               del_timer(&dev->timer);
-               dev->timer.expires = jiffies + ISDN_TIMER_RES;
-               add_timer(&dev->timer);
+               mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);
                restore_flags(flags);
        }
 }
@@ -708,11 +706,8 @@ isdn_timer_ctrl(int tf, int onoff)
                dev->tflags |= tf;
        else
                dev->tflags &= ~tf;
-       if (dev->tflags) {
-               if (!del_timer(&dev->timer))    /* del_timer is 1, when active */
-                       dev->timer.expires = jiffies + ISDN_TIMER_RES;
-               add_timer(&dev->timer);
-       }
+       if (dev->tflags)
+               mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);
        restore_flags(flags);
 }
 
index 42abb3a422086d169fbb04818d0ee41ce79621b1..7cff7a727cac2c36775e2afecd354d062051ed99 100644 (file)
@@ -91,9 +91,7 @@ void check_reset(unsigned long data)
        else  {
                pr_debug("%s: No signature yet, waiting another %d jiffies.\n", 
                        adapter[card]->devicename, CHECKRESET_TIME);
-               del_timer(&adapter[card]->reset_timer);
-               adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
-               add_timer(&adapter[card]->reset_timer);
+               mod_timer(&adapter[card]->reset_timer, jiffies+CHECKRESET_TIME);
        }
        restore_flags(flags);
                
@@ -138,9 +136,7 @@ void check_phystat(unsigned long data)
        /* Reinitialize the timer */
        save_flags(flags);
        cli();
-       del_timer(&adapter[card]->stat_timer);
-       adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
-       add_timer(&adapter[card]->stat_timer);
+       mod_timer(&adapter[card]->stat_timer, jiffies+CHECKSTAT_TIME);
        restore_flags(flags);
 
        /* Send a new cePhyStatus message */
index 92da42e6d6b4917a3630570df21d24ef084347b1..6e7842c20383d50679e735ca9c833426977249ef 100644 (file)
@@ -1736,9 +1736,7 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
                        } while ((status = inw(ioaddr + EL3_CMD)) & IntLatch);
                        /* The timer will reenable interrupts. */
-                       del_timer(&vp->timer);
-                       vp->timer.expires = RUN_AT(1);
-                       add_timer(&vp->timer);
+                       mod_timer(&vp->timer, jiffies+1*HZ);
                        break;
                }
                /* Acknowledge the IRQ. */
@@ -1854,9 +1852,7 @@ static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
                        } while ((status = inw(ioaddr + EL3_CMD)) & IntLatch);
                        /* The timer will reenable interrupts. */
-                       del_timer(&vp->timer);
-                       vp->timer.expires = RUN_AT(1);
-                       add_timer(&vp->timer);
+                       mod_timer(&vp->timer, jiffies+1*HZ);
                        break;
                }
                /* Acknowledge the IRQ. */
index ce573e312b65577ffff2c758fb4c918f1ef9978e..9a5b25038f50f8854b22e524e424998986460d10 100644 (file)
@@ -84,10 +84,11 @@ an MMIO register read.
 #include <linux/ioport.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 
-#define RTL8139_VERSION "0.9.4"
+#define RTL8139_VERSION "0.9.4.1"
 #define RTL8139_MODULE_NAME "8139too"
 #define RTL8139_DRIVER_NAME   RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION
 #define PFX RTL8139_MODULE_NAME ": "
@@ -122,6 +123,9 @@ an MMIO register read.
 
 
 /* A few user-configurable values. */
+/* media options */
+static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
 
@@ -132,17 +136,24 @@ static int multicast_filter_limit = 32;
 /* Size of the in-memory receive ring. */
 #define RX_BUF_LEN_IDX 2       /* 0==8K, 1==16K, 2==32K, 3==64K */
 #define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+#define RX_BUF_PAD 16
+#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD)
+
+/* Number of Tx descriptor registers. */
+#define NUM_TX_DESC    4
+
 /* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
 #define TX_BUF_SIZE    1536
+#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
 
 /* PCI Tuning Parameters
    Threshold is bytes transferred to chip before transmission starts. */
 #define TX_FIFO_THRESH 256     /* In bytes, rounded down to 32 byte units. */
 
-/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024. */
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
 #define RX_FIFO_THRESH 4       /* Rx buffer level before first PCI xfer.  */
-#define RX_DMA_BURST   4       /* Maximum PCI burst, '4' is 256 bytes */
-#define TX_DMA_BURST   4       /* Calculate as 16<<val. */
+#define RX_DMA_BURST   4       /* Maximum PCI burst, '7' is unlimited */
+#define TX_DMA_BURST   4       /* Maximum PCI burst, '4' is 256 */
 
 
 /* Operational parameters that usually are not changed. */
@@ -156,7 +167,7 @@ enum {
 };
 
 #define RTL_MIN_IO_SIZE 0x80
-#define RTL8139B_IO_SIZE 0xFF
+#define RTL8139B_IO_SIZE 256
 
 #define RTL8139_CAPS   HAS_CHIP_XCVR|HAS_LNK_CHNG
 
@@ -167,13 +178,13 @@ typedef enum {
        /*MPX5030,*/
        DELTA8139,
        ADDTRON8139,
-} chip_t;
+} board_t;
 
 
-/* indexed by chip_t, above */
+/* indexed by board_t, above */
 static struct {
        const char *name;
-} chip_info[] __devinitdata = {
+} board_info[] __devinitdata = {
        { "RealTek RTL8139 Fast Ethernet" },
        { "RealTek RTL8139B PCI/CardBus" },
        { "SMC1211TX EZCard 10/100 (RealTek RTL8139)" },
@@ -196,7 +207,6 @@ MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
 
 
 /* The rest of these values should never change. */
-#define NUM_TX_DESC    4       /* Number of Tx descriptor registers. */
 
 /* Symbolic offsets to registers. */
 enum RTL8139_registers {
@@ -220,8 +230,8 @@ enum RTL8139_registers {
        Config0 = 0x51,
        Config1 = 0x52,
        FlashReg = 0x54,
-       GPPinData = 0x58,
-       GPPinDir = 0x59,
+       MediaStatus = 0x58,
+       Config3 = 0x59,
        Config4 = 0x5A,         /* absent on RTL-8139A */
        HltClk = 0x5B,
        MultiIntr = 0x5C,
@@ -236,6 +246,13 @@ enum RTL8139_registers {
        CSCR = 0x74,            /* Chip Status and Configuration Register. */
        PARA78 = 0x78,
        PARA7c = 0x7c,          /* Magic transceiver parameter register. */
+       Config5 = 0xD8,         /* absent on RTL-8139A */
+};
+
+enum ClearBitMasks {
+       MultiIntrClear = 0xF000,
+       ChipCmdClear = 0xE2,
+       Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
 };
 
 enum ChipCmdBits {
@@ -300,6 +317,19 @@ enum Config1Bits {
 };
 
 enum RxConfigBits {
+       /* Early Rx threshold, none or X/16 */
+       RxCfgEarlyRxNone = 0,
+       RxCfgEarlyRxShift = 24,
+       
+       /* rx fifo threshold */
+       RxCfgFIFOShift = 13,
+       RxCfgFIFONone = (7 << RxCfgFIFOShift),
+
+       /* Max DMA burst */
+       RxCfgDMAShift = 8,
+       RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
+
+       /* rx ring buffer length */
        RxCfgRcv8K = 0,
        RxCfgRcv16K = (1 << 11),
        RxCfgRcv32K = (1 << 12),
@@ -339,10 +369,33 @@ struct ring_info {
        dma_addr_t mapping;
 };
 
+typedef enum {
+       CH_8139 = 0,
+       CH_8139A,
+       CH_8139B,
+} chip_t;
+
+/* directly indexed by chip_t, above */
+const static struct {
+       const char *name;
+       u32 RxConfigMask; /* should clear the bits supported by this chip */
+} rtl_chip_info[] = {
+       { "RTL-8139",
+         0xf0fe0040, /* XXX copied from RTL8139A, verify */
+       },
+       
+       { "RTL-8139A",
+         0xf0fe0040,
+       },
+       
+       { "RTL-8139B(L)",
+         0xf0fc0040
+       },
+};
+
 
-#define PRIV_ALIGN     15      /* Required alignment mask */
 struct rtl8139_private {
-       chip_t chip;
+       board_t board;
        void *mmio_addr;
        int drv_flags;
        struct pci_dev *pci_dev;
@@ -350,7 +403,9 @@ struct rtl8139_private {
        struct timer_list timer;        /* Media selection timer. */
        unsigned char *rx_ring;
        unsigned int cur_rx;    /* Index into the Rx buffer of next Rx pkt. */
-       unsigned int cur_tx, dirty_tx, tx_flag;
+       unsigned int tx_flag;
+       atomic_t cur_tx;
+       atomic_t dirty_tx;
        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
        struct ring_info tx_info[NUM_TX_DESC];
        unsigned char *tx_buf[NUM_TX_DESC];     /* Tx bounce buffers */
@@ -365,8 +420,8 @@ struct rtl8139_private {
        unsigned int media2:4;  /* Secondary monitored media port. */
        unsigned int medialock:1;       /* Don't sense media type. */
        unsigned int mediasense:1;      /* Media sensing in progress. */
-       int extended_regs;              /* bool: supports regs > 0x80 ? */
        spinlock_t lock;
+       chip_t chipset;
 };
 
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
@@ -374,6 +429,7 @@ MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
 MODULE_PARM (multicast_filter_limit, "i");
 MODULE_PARM (max_interrupt_work, "i");
 MODULE_PARM (debug, "i");
+MODULE_PARM (media, "1-" __MODULE_STRING(8) "i");
 
 static int read_eeprom (void *ioaddr, int location, int addr_len);
 static int rtl8139_open (struct net_device *dev);
@@ -429,17 +485,21 @@ static const u16 rtl8139_intr_mask =
        TxErr | TxOK | RxErr | RxOK;
 
 static const unsigned int rtl8139_rx_config =
-           (RX_FIFO_THRESH << 13) | (RxCfgRcv32K) |
-           (RX_DMA_BURST << 8);
+         RxCfgEarlyRxNone | RxCfgFIFONone | RxCfgRcv32K | RxCfgDMAUnlimited;
 
 
-static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
+static int __devinit rtl8139_init_board (struct pci_dev *pdev,
+                                        struct net_device **dev_out,
+                                        void **ioaddr_out)
 {
        void *ioaddr = NULL;
+       struct net_device *dev;
+       struct rtl8139_private *tp;
        u8 tmp8;
-       int rc;
+       int rc, i;
        u32 pio_start, pio_end, pio_flags, pio_len;
        unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+       u32 tmp;
 
        DPRINTK ("ENTER\n");
 
@@ -447,6 +507,16 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
        assert (ioaddr_out != NULL);
 
        *ioaddr_out = NULL;
+       *dev_out = NULL;
+
+       /* dev zeroed in init_etherdev */
+       dev = init_etherdev (NULL, sizeof (*tp));
+       if (dev == NULL) {
+               printk (KERN_ERR PFX "unable to alloc new ethernet\n");
+               DPRINTK ("EXIT, returning -ENOMEM\n");
+               return -ENOMEM;
+       }
+       tp = dev->priv;
 
        pio_start = pci_resource_start (pdev, 0);
        pio_end = pci_resource_end (pdev, 0);
@@ -458,6 +528,13 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
        mmio_flags = pci_resource_flags (pdev, 1);
        mmio_len = pci_resource_len (pdev, 1);
 
+       /* set this immediately, we need to know before
+        * we talk to the chip directly */
+       DPRINTK("PIO region size == 0x%02X\n", pio_len);
+       DPRINTK("MMIO region size == 0x%02X\n", mmio_len);
+       if (pio_len == RTL8139B_IO_SIZE)
+               tp->chipset = CH_8139B;
+
        /* make sure PCI base addr 0 is PIO */
        if (!(pio_flags & IORESOURCE_IO)) {
                printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n");
@@ -482,14 +559,14 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
        }
 
        /* make sure our PIO region in PCI space is available */
-       if (!request_region (pio_start, pio_len, RTL8139_MODULE_NAME)) {
+       if (!request_region (pio_start, pio_len, dev->name)) {
                printk (KERN_ERR PFX "no I/O resource available, aborting\n");
                rc = -EBUSY;
                goto err_out;
        }
        
        /* make sure our MMIO region in PCI space is available */
-       if (!request_mem_region (mmio_start, mmio_len, RTL8139_MODULE_NAME)) {
+       if (!request_mem_region (mmio_start, mmio_len, dev->name)) {
                printk (KERN_ERR PFX "no mem resource available, aborting\n");
                rc = -EBUSY;
                goto err_out_free_pio;
@@ -514,9 +591,32 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
                goto err_out_free_mmio;
        }
 
+       /* Soft reset the chip. */
+       RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset);
+
+       /* Check that the chip has finished the reset. */
+       for (i = 1000; i > 0; i--)
+               if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
+                       break;
+               else
+                       udelay (10);
+
        /* Bring the chip out of low-power mode. */
-       RTL_W8 (Config1, 0x00);
+       if (tp->chipset == CH_8139B) {
+               RTL_W8 (Config1, RTL_R8 (Config1) & ~(1<<4));
+               RTL_W8 (Config4, RTL_R8 (Config4) & ~(1<<2));
+       } else {
+               /* handle RTL8139A and RTL8139 cases */
+               /* XXX from becker driver. is this right?? */
+               RTL_W8 (Config1, 0);
+       }
 
+       /* sanity checks -- ensure PIO and MMIO registers agree */
+       assert (inb (pio_start+Config0) == readb (ioaddr+Config0));
+       assert (inb (pio_start+Config1) == readb (ioaddr+Config1));
+       assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig));
+       assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig));
+       
        /* make sure chip thinks PIO and MMIO are enabled */
        tmp8 = RTL_R8 (Config1);
        if ((tmp8 & Cfg1_PIO) == 0) {
@@ -530,14 +630,26 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
                goto err_out_iounmap;
        }
        
-       /* sanity checks -- ensure PIO and MMIO registers agree */
-       assert (inb (pio_start+Config0) == RTL_R8 (Config0));
-       assert (inb (pio_start+Config1) == RTL_R8 (Config1));
-       assert (inb (pio_start+TxConfig) == RTL_R8 (TxConfig));
-       assert (inb (pio_start+RxConfig) == RTL_R8 (RxConfig));
-
+       /* identify chip attached to board */
+       tmp = RTL_R32 (TxConfig);
+       if (((tmp >> 28) & 7) == 7) {
+               if (pio_len == RTL8139B_IO_SIZE)
+                       tp->chipset = CH_8139B;
+               else
+                       tp->chipset = CH_8139A;
+       } else {
+               tp->chipset = CH_8139;
+       }
+       DPRINTK ("chipset id (%d/%d/%d) == %d, '%s'\n",
+               CH_8139,
+               CH_8139A,
+               CH_8139B,
+               tp->chipset,
+               rtl_chip_info[tp->chipset].name);
+       
        DPRINTK ("EXIT, returning 0\n");
        *ioaddr_out = ioaddr;
+       *dev_out = dev;
        return 0;       
 
 err_out_iounmap:
@@ -548,6 +660,8 @@ err_out_free_mmio:
 err_out_free_pio:
        release_region (pio_start, pio_len);
 err_out:
+       unregister_netdev (dev);
+       kfree (dev);
        DPRINTK ("EXIT, returning %d\n", rc);
        return rc;
 }
@@ -556,10 +670,12 @@ err_out:
 static int __devinit rtl8139_init_one (struct pci_dev *pdev,
                                       const struct pci_device_id *ent)
 {
-       struct net_device *dev;
+       struct net_device *dev = NULL;
        struct rtl8139_private *tp;
-       int i, addr_len, option = -1;
+       int i, addr_len, option;
        void *ioaddr = NULL;
+       static int board_idx = -1;
+       u8 tmp;
 
 #ifndef RTL8139_NDEBUG
        static int printed_version = 0;
@@ -570,29 +686,24 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
        assert (pdev != NULL);
        assert (ent != NULL);
 
-#ifndef RTL8139_NDEBUG
+       board_idx++;
+
        if (!printed_version) {
                printk (KERN_INFO RTL8139_DRIVER_NAME " loaded\n");
                printed_version = 1;
        }
-#endif /* RTL8139_NDEBUG */
 
-       i = rtl8139_init_pci (pdev, &ioaddr);
+       i = rtl8139_init_board (pdev, &dev, &ioaddr);
        if (i < 0) {
                DPRINTK ("EXIT, returning %d\n", i);
                return i;
        }
        
+       tp = dev->priv;
+       
        assert (ioaddr != NULL);
-
-       /* dev zeroed in init_etherdev */
-       dev = init_etherdev (NULL, sizeof (*tp) + PRIV_ALIGN);
-       if (dev == NULL) {
-               iounmap (ioaddr);
-               printk (KERN_ERR PFX "unable to alloc new ethernet\n");
-               DPRINTK ("EXIT, returning -ENOMEM\n");
-               return -ENOMEM;
-       }
+       assert (dev != NULL);
+       assert (tp != NULL);
 
        addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
        for (i = 0; i < 3; i++)
@@ -612,38 +723,47 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
        dev->irq = pdev->irq;
        dev->base_addr = pci_resource_start (pdev, 1);
 
-       /* dev->priv/tp zeroed in init_etherdev */
-       dev->priv = tp = (void *)
-               (((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN);
+       /* dev->priv/tp zeroed and aligned in init_etherdev */
+       tp = dev->priv;
 
+       /* note: tp->chipset set in rtl8139_init_board */
        tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
                        PCI_COMMAND_MASTER | RTL8139_CAPS;
        tp->pci_dev = pdev;
-       tp->chip = ent->driver_data;
+       tp->board = ent->driver_data;
        tp->mmio_addr = ioaddr;
-       tp->extended_regs =
-               (pci_resource_len (pdev, 0) == RTL8139B_IO_SIZE) ? 1 : 0;
        tp->lock = SPIN_LOCK_UNLOCKED;
 
        PCI_SET_DRIVER_DATA (pdev, dev);
 
        tp->phys[0] = 32;
 
-       printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d,%s "
+       printk (KERN_INFO "%s: '%s' board found at 0x%lx, IRQ %d\n",
+               dev->name, board_info[ent->driver_data].name,
+               dev->base_addr, dev->irq);
+
+       printk (KERN_INFO "%s:   Chip is '%s'\n",
+               dev->name,
+               rtl_chip_info[tp->chipset].name);
+
+       printk (KERN_INFO "%s:   MAC address "
                "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
-               dev->name, chip_info[ent->driver_data].name,
-               dev->base_addr, dev->irq,
-               tp->extended_regs ? " 8139B regs," : "",
+               dev->name,
                dev->dev_addr[0], dev->dev_addr[1],
                dev->dev_addr[2], dev->dev_addr[3],
                dev->dev_addr[4], dev->dev_addr[5]);
 
        /* Put the chip into low-power mode. */
-       RTL_W8 (Cfg9346, Cfg9346_Unlock);
-       RTL_W8 (Config1, 0x03); /* Enable PM & PCI VPD */
-       RTL_W8 (HltClk, 'H');   /* 'R' would leave the clock running. */
+       RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+
+       tmp = RTL_R8 (Config1) & Config1Clear;
+       tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */
+       RTL_W8_F (Config1, tmp);
+
+       RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */
 
        /* The lower four bits are the media type. */
+       option = (board_idx > 7) ? 0 : media[board_idx];
        if (option > 0) {
                tp->full_duplex = (option & 0x200) ? 1 : 0;
                tp->default_port = option & 15;
@@ -686,10 +806,9 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
 
 #ifndef RTL8139_NDEBUG
        /* poison memory before freeing */
-       memset (dev, 0xC0,
+       memset (dev, 0xBC,
                sizeof (struct net_device) +
-               sizeof (struct rtl8139_private) +
-               PRIV_ALIGN);
+               sizeof (struct rtl8139_private));
 #endif /* RTL8139_NDEBUG */
 
        kfree (dev);
@@ -911,18 +1030,18 @@ static int rtl8139_open (struct net_device *dev)
                return -EBUSY;
        }
 
-       tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+       tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
                                           &tp->tx_bufs_dma);
-       tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+       tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
                                           &tp->rx_ring_dma);
        if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
                free_irq(dev->irq, dev);
 
                if (tp->tx_bufs)
-                       pci_free_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+                       pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
                                            tp->tx_bufs, tp->tx_bufs_dma);
                if (tp->rx_ring)
-                       pci_free_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+                       pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
                                            tp->rx_ring, tp->rx_ring_dma);
 
                DPRINTK ("EXIT, returning -ENOMEM\n");
@@ -931,16 +1050,16 @@ static int rtl8139_open (struct net_device *dev)
                
        }
        
-       rtl8139_init_ring (dev);
        tp->full_duplex = tp->duplex_lock;
        tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
 
+       rtl8139_init_ring (dev);
        rtl8139_hw_start (dev);
 
        DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d"
                        " GP Pins %2.2x %s-duplex.\n",
                        dev->name, pci_resource_start (tp->pci_dev, 1),
-                       dev->irq, RTL_R8 (GPPinData),
+                       dev->irq, RTL_R8 (MediaStatus),
                        tp->full_duplex ? "full" : "half");
 
        /* Set the timer to switch to check for link beat and perhaps switch
@@ -961,15 +1080,14 @@ static void rtl8139_hw_start (struct net_device *dev)
 {
        struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
        void *ioaddr = tp->mmio_addr;
-       int i;
-       unsigned long flags;
+       u32 i;
+       u8 tmp;
 
        DPRINTK ("ENTER\n");
        
-       spin_lock_irqsave (&tp->lock, flags);
-
        /* Soft reset the chip. */
-       RTL_W8 (ChipCmd, CmdReset);
+       RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset);
+       udelay (100);
 
        /* Check that the chip has finished the reset. */
        for (i = 1000; i > 0; i--)
@@ -981,53 +1099,100 @@ static void rtl8139_hw_start (struct net_device *dev)
        RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
 
        /* unlock Config[01234] and BMCR register writes */
-       RTL_W8 (Cfg9346, Cfg9346_Unlock);
+       RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+       udelay (100);
 
        tp->cur_rx = 0;
 
+       /* init Rx ring buffer DMA address */
+       RTL_W32_F (RxBuf, tp->rx_ring_dma);
+
+       /* init Tx buffer DMA addresses */
+       for (i = 0; i < NUM_TX_DESC; i++)
+               RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs));
+
        /* Must enable Tx/Rx before setting transfer thresholds! */
-       RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
-       RTL_W32 (RxConfig, rtl8139_rx_config);
-       /* Check this value: the documentation contradicts ifself.  Is the
-          IFG correct with bit 28:27 zero, or with |0x03000000 ? */
-       RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000);
-
-       /* Reset N-Way to chipset defaults */
-       RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9));
-       for (i = 1000; i > 0; i--)
-               if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0)
-                       break;
+       RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) |
+                          CmdRxEnb | CmdTxEnb);
+
+       i = rtl8139_rx_config |
+           (RTL_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+       RTL_W32_F (RxConfig, i);
+
+       /* Check this value: the documentation for IFG contradicts ifself. */
+       RTL_W32 (TxConfig, (TX_DMA_BURST << 8));
+
+       /* if link status not ok... */
+       if ((RTL_R16 (BasicModeStatus) & (1<<2)) == 0) {
+               printk (KERN_INFO "%s: no link, starting NWay\n", dev->name);
+
+               /* Reset N-Way to chipset defaults */
+               RTL_W16 (BasicModeCtrl, RTL_R16 (BasicModeCtrl) | (1<<15));
+               for (i = 1000; i > 0; i--)
+                       if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0)
+                               break;
        
-       /* Set N-Way to sane defaults */
-       RTL_W16 (FIFOTMS, 0x0000);
-       RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1);
-       RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8));
+               /* Set N-Way to sane defaults */
+               RTL_W16_F (FIFOTMS, RTL_R16 (FIFOTMS) & ~(1<<7));
+               RTL_W16_F (NWayAdvert, RTL_R16 (NWayAdvert) |
+                         (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<0));
+               RTL_W16_F (BasicModeCtrl, RTL_R16 (BasicModeCtrl) |
+                       (1<<13)|(1<<12)|(1<<9)|(1<<8));
+               RTL_W8_F (MediaStatus, RTL_R8 (MediaStatus) | (1<<7) | (1<<6));
        
-       /* check_duplex() here. */
-       RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+               /* check_duplex() here. */
+               /* XXX writing Config1 here is flat out wrong */
+               /* RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); */
+       }
 
-       /* lock Config[01234] and BMCR register writes */
-       RTL_W8 (Cfg9346, Cfg9346_Lock);
+       tmp = RTL_R8 (Config1) & Config1Clear;
+       tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */
+       RTL_W8_F (Config1, tmp);
 
-       RTL_W32 (RxBuf, tp->rx_ring_dma);
+       if (tp->chipset == CH_8139B) {
+               tmp = RTL_R8 (Config4) & ~(1<<2);
+               /* chip will clear Rx FIFO overflow automatically */
+               tmp |= (1<<7);  
+               RTL_W8 (Config4, tmp);
+       }
+       
+       /* disable magic packet scanning, which is enabled
+        * when PM is enabled above (Config1) */
+       RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5));
 
-       /* Start the chip's Tx and Rx process. */
-       RTL_W32 (RxMissed, 0);
+       RTL_W32_F (RxMissed, 0);
 
-       /* release lock cuz set_rx_mode wants it */
-       spin_unlock_irqrestore (&tp->lock, flags);
        rtl8139_set_rx_mode (dev);
-       spin_lock_irqsave (&tp->lock, flags);
 
-       RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+       /* no early-rx interrupts */
+       RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear);
 
        /* Enable all known interrupts by setting the interrupt mask. */
-       RTL_W16 (IntrMask, rtl8139_intr_mask);
+       RTL_W16_F (IntrMask, rtl8139_intr_mask);
 
-       if (netif_queue_stopped (dev))
-               netif_start_queue (dev);
+       netif_start_queue (dev);
 
-       spin_unlock_irqrestore (&tp->lock, flags);
+       DPRINTK ("EXIT\n");
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void rtl8139_init_ring (struct net_device *dev)
+{
+       struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+       int i;
+
+       DPRINTK ("ENTER\n");
+
+       tp->cur_rx = 0;
+       atomic_set (&tp->cur_tx, 0);
+       atomic_set (&tp->dirty_tx, 0);
+
+       for (i = 0; i < NUM_TX_DESC; i++) {
+               tp->tx_info[i].skb = NULL;
+               tp->tx_info[i].mapping = 0;
+               tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
+       }
 
        DPRINTK ("EXIT\n");
 }
@@ -1134,11 +1299,8 @@ static void rtl8139_timer (unsigned long data)
        void *ioaddr = tp->mmio_addr;
        int next_tick = 60 * HZ;
        int mii_reg5;
-       unsigned long flags;
 
-       DPRINTK ("ENTER\n");
-       
-       spin_lock_irqsave (&tp->lock, flags);
+       spin_lock_irq (&tp->lock);
 
        mii_reg5 = mdio_read (dev, tp->phys[0], 5);
 
@@ -1154,7 +1316,6 @@ static void rtl8139_timer (unsigned long data)
                                tp->phys[0], mii_reg5);
                        RTL_W8 (Cfg9346, Cfg9346_Unlock);
                        RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
-                       RTL_W8 (Cfg9346, Cfg9346_Lock);
                }
        }
 
@@ -1171,12 +1332,10 @@ static void rtl8139_timer (unsigned long data)
                 dev->name, RTL_R8 (Config0),
                 RTL_R8 (Config1));
 
-       spin_unlock_irqrestore (&tp->lock, flags);
+       spin_unlock_irq (&tp->lock);
 
        tp->timer.expires = jiffies + next_tick;
        add_timer (&tp->timer);
-
-       DPRINTK ("EXIT\n");
 }
 
 
@@ -1184,38 +1343,37 @@ static void rtl8139_tx_timeout (struct net_device *dev)
 {
        struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
        void *ioaddr = tp->mmio_addr;
-       int mii_reg, i;
-       unsigned long flags;
-
-       DPRINTK ("ENTER\n");
-
-       spin_lock_irqsave (&tp->lock, flags);
+       int i;
 
        DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x "
                 "media %2.2x.\n", dev->name,
                 RTL_R8 (ChipCmd),
                 RTL_R16 (IntrStatus),
-                RTL_R8 (GPPinData));
+                RTL_R8 (MediaStatus));
+
+       spin_lock_irq (&tp->lock);
 
        /* Disable interrupts by clearing the interrupt mask. */
        RTL_W16 (IntrMask, 0x0000);
+
+       spin_unlock_irq (&tp->lock);
+       
        /* Emit info to figure out what went wrong. */
        printk (KERN_DEBUG
                "%s: Tx queue start entry %d  dirty entry %d.\n",
-               dev->name, tp->cur_tx, tp->dirty_tx);
+               dev->name, atomic_read (&tp->cur_tx),
+               atomic_read (&tp->dirty_tx));
        for (i = 0; i < NUM_TX_DESC; i++)
                printk (KERN_DEBUG "%s:  Tx descriptor %d is %8.8x.%s\n",
                        dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
                        i ==
-                     tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
-       printk (KERN_DEBUG "%s: MII #%d registers are:", dev->name,
-               tp->phys[0]);
-       for (mii_reg = 0; mii_reg < 8; mii_reg++)
-               printk (" %4.4x", mdio_read (dev, tp->phys[0], mii_reg));
-       printk (".\n");
+                     atomic_read (&tp->dirty_tx) % NUM_TX_DESC ? " (queue head)" : "");
+
+       spin_lock_irq (&tp->lock);
 
        /* Stop a shared interrupt from scavenging while we are. */
-       tp->dirty_tx = tp->cur_tx = 0;
+       atomic_set (&tp->cur_tx, 0);
+       atomic_set (&tp->dirty_tx, 0);
 
        /* Dump the unsent Tx packets. */
        for (i = 0; i < NUM_TX_DESC; i++) {
@@ -1230,79 +1388,43 @@ static void rtl8139_tx_timeout (struct net_device *dev)
                        rp->mapping = 0;
                }
        }
-
-       spin_unlock_irqrestore (&tp->lock, flags);
+       
+       spin_unlock_irq (&tp->lock);
 
        rtl8139_hw_start (dev);
-
-       DPRINTK ("EXIT\n");
 }
 
 
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void rtl8139_init_ring (struct net_device *dev)
-{
-       struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
-       int i;
-
-       DPRINTK ("ENTER\n");
-
-       tp->cur_rx = 0;
-       tp->dirty_tx = tp->cur_tx = 0;
-
-       for (i = 0; i < NUM_TX_DESC; i++) {
-               tp->tx_info[i].skb = NULL;
-               tp->tx_info[i].mapping = 0;
-               tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
-       }
-
-       DPRINTK ("EXIT\n");
-}
-
 
 static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
        struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
        void *ioaddr = tp->mmio_addr;
        int entry;
-       unsigned long flags;
-
-       DPRINTK ("ENTER\n");
-       
-       spin_lock_irqsave (&tp->lock, flags);
 
        /* Calculate the next Tx descriptor entry. */
-       entry = tp->cur_tx % NUM_TX_DESC;
+       entry = atomic_read (&tp->cur_tx) % NUM_TX_DESC;
 
        tp->tx_info[entry].skb = skb;
-       if ((long) skb->data & 3) {     /* Must use alignment buffer. */
-               tp->tx_info[entry].mapping = 0;
-               memcpy (tp->tx_buf[entry], skb->data, skb->len);
+       tp->tx_info[entry].mapping = 0;
+       memcpy (tp->tx_buf[entry], skb->data, skb->len);
 
-               assert (tp->tx_bufs_dma > 0);
-               RTL_W32 (TxAddr0 + entry * 4, tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs));
-       } else {
-               tp->tx_info[entry].mapping =
-                       pci_map_single(tp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+       spin_lock_irq (&tp->lock);
 
-               assert (tp->tx_info[entry].mapping > 0);
-               RTL_W32 (TxAddr0 + entry * 4, tp->tx_info[entry].mapping);
-       }
-       
        /* Note: the chip doesn't have auto-pad! */
-       RTL_W32 (TxStatus0 + entry * 4,
+       RTL_W32 (TxStatus0 + (entry * sizeof(u32)),
                 tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
+       spin_unlock_irq (&tp->lock);
+
        dev->trans_start = jiffies;
-       if (++tp->cur_tx - tp->dirty_tx >= NUM_TX_DESC)
+       atomic_inc (&tp->cur_tx);
+       if ((atomic_read (&tp->cur_tx) - atomic_read (&tp->dirty_tx)) >= NUM_TX_DESC)
                netif_stop_queue (dev);
 
-       spin_unlock_irqrestore (&tp->lock, flags);
-
        DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
                 dev->name, skb->data, skb->len, entry);
 
-       DPRINTK ("EXIT\n");
        return 0;
 }
 
@@ -1317,12 +1439,19 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev,
        assert (tp != NULL);
        assert (ioaddr != NULL);
        
-       dirty_tx = tp->dirty_tx;
+       /* drop lock held in rtl8139_interrupt */
+       spin_unlock (&tp->lock);
+       
+       dirty_tx = atomic_read (&tp->dirty_tx);
 
-       while (tp->cur_tx - dirty_tx > 0) {
+       while ((atomic_read (&tp->cur_tx) - dirty_tx) > 0) {
                int entry = dirty_tx % NUM_TX_DESC;
-               int txstatus = RTL_R32 (TxStatus0 + (entry * 4));
+               int txstatus;
 
+               spin_lock (&tp->lock);
+               txstatus = RTL_R32 (TxStatus0 + (entry * 4));
+               spin_unlock (&tp->lock);
+               
                if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
                        break;  /* It still hasn't been Txed */
 
@@ -1334,7 +1463,9 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev,
                        tp->stats.tx_errors++;
                        if (txstatus & TxAborted) {
                                tp->stats.tx_aborted_errors++;
-                               RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x03000001);
+                               spin_lock (&tp->lock);
+                               RTL_W32 (TxConfig, (TX_DMA_BURST << 8));
+                               spin_unlock (&tp->lock);
                        }
                        if (txstatus & TxCarrierLost)
                                tp->stats.tx_carrier_errors++;
@@ -1356,39 +1487,36 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev,
                        tp->stats.tx_packets++;
                }
 
-               if (tp->tx_info[entry].mapping != 0) {
-                       pci_unmap_single (tp->pci_dev,
-                                         tp->tx_info[entry].mapping,
-                                         tp->tx_info[entry].skb->len,
-                                         PCI_DMA_TODEVICE);
-                       tp->tx_info[entry].mapping = 0;
-               }
                /* Free the original skb. */
                dev_kfree_skb_irq (tp->tx_info[entry].skb);
                tp->tx_info[entry].skb = NULL;
                dirty_tx++;
-               if (tp->cur_tx - dirty_tx < NUM_TX_DESC)
+               if (netif_queue_stopped (dev) &&
+                   (atomic_read (&tp->cur_tx) - dirty_tx < NUM_TX_DESC))
                        netif_wake_queue (dev);
        }
 
 #ifndef RTL8139_NDEBUG
-       if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
+       if (atomic_read (&tp->cur_tx) - dirty_tx > NUM_TX_DESC) {
                printk (KERN_ERR
                  "%s: Out-of-sync dirty pointer, %d vs. %d.\n",
-                    dev->name, dirty_tx, tp->cur_tx);
+                    dev->name, dirty_tx, atomic_read (&tp->cur_tx));
                dirty_tx += NUM_TX_DESC;
        }
 #endif /* RTL8139_NDEBUG */
 
-       tp->dirty_tx = dirty_tx;
+       atomic_set (&tp->dirty_tx, dirty_tx);
+       
+       /* obtain lock need for rtl8139_interrupt */
+       spin_lock (&tp->lock);
 }
 
 
 /* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
    field alignments and semantics. */
-static inline void rtl8139_rx_interrupt (struct net_device *dev,
-                                        struct rtl8139_private *tp,
-                                        void *ioaddr)
+static void rtl8139_rx_interrupt (struct net_device *dev,
+                                 struct rtl8139_private *tp,
+                                 void *ioaddr)
 {
        unsigned char *rx_ring;
        u16 cur_rx;
@@ -1440,6 +1568,9 @@ static inline void rtl8139_rx_interrupt (struct net_device *dev,
                if (rx_status &
                    (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr |
                     RxBadAlign)) {
+                       u8 tmp8;
+                       int tmp_work = 1000;
+
                        DPRINTK ("%s: Ethernet frame had errors,"
                                        " status %8.8x.\n", dev->name,
                                        rx_status);
@@ -1457,10 +1588,23 @@ static inline void rtl8139_rx_interrupt (struct net_device *dev,
                                tp->stats.rx_crc_errors++;
                        /* Reset the receiver, based on RealTek recommendation. (Bug?) */
                        tp->cur_rx = 0;
-                       RTL_W8 (ChipCmd, CmdTxEnb);
+
+                       /* disable receive */
+                       tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear;
+                       RTL_W8_F (ChipCmd, tmp8 | CmdTxEnb);
+
                        /* A.C.: Reset the multicast list. */
                        rtl8139_set_rx_mode (dev);
-                       RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+                       while (--tmp_work > 0) {
+                               tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear;
+                               if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
+                                       break;
+                               RTL_W8_F (ChipCmd, tmp8 | CmdRxEnb | CmdTxEnb);
+                       }
+
+                       if (tmp_work <= 0)                      
+                               printk (KERN_WARNING PFX "tx/rx enable wait too long\n");
                } else {
                        /* Malloc up new buffer, compatible with net-2e. */
                        /* Omit the four octet CRC from the length. */
@@ -1478,6 +1622,7 @@ static inline void rtl8139_rx_interrupt (struct net_device *dev,
                        }
                        skb->dev = dev;
                        skb_reserve (skb, 2);   /* 16 byte align the IP fields. */
+
                        if (ring_offset + rx_size + 4 > RX_BUF_LEN) {
                                int semi_count =
                                    RX_BUF_LEN - ring_offset - 4;
@@ -1485,27 +1630,24 @@ static inline void rtl8139_rx_interrupt (struct net_device *dev,
                                memcpy (skb_put (skb, semi_count),
                                        &rx_ring[ring_offset + 4],
                                        semi_count);
-                               memcpy (skb_put
-                                       (skb, rx_size - semi_count),
+                               memcpy (skb_put (skb, rx_size - semi_count),
                                        rx_ring, rx_size - semi_count);
 #ifdef RTL8139_DEBUG
                                {
                                int i;
-                               printk (KERN_DEBUG
-                                       "%s:  Frame wrap @%d",
+                               printk (KERN_DEBUG "%s:  Frame wrap @%d",
                                        dev->name, semi_count);
                                for (i = 0; i < 16; i++)
-                                       printk (" %2.2x",
-                                               rx_ring[i]);
-                               printk (".\n");
+                                       printk (" %2.2x", rx_ring[i]);
+                               printk ("\n");
                                memset (rx_ring, 0xcc, 16);
                                }
 #endif /* RTL8139_DEBUG */
 
                        } else {
                                eth_copy_and_sum (skb,
-                                                 &rx_ring[ring_offset +
-                                                          4], rx_size, 0);
+                                                 &rx_ring[ring_offset + 4],
+                                                 rx_size, 0);
                                skb_put (skb, rx_size);
                        }
                        skb->protocol = eth_type_trans (skb, dev);
@@ -1526,10 +1668,10 @@ static inline void rtl8139_rx_interrupt (struct net_device *dev,
 }
 
 
-static inline int rtl8139_weird_interrupt (struct net_device *dev,
-                                          struct rtl8139_private *tp,
-                                          void *ioaddr,
-                                          int status, int link_changed)
+static int rtl8139_weird_interrupt (struct net_device *dev,
+                                   struct rtl8139_private *tp,
+                                   void *ioaddr,
+                                   int status, int link_changed)
 {
        DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
                 dev->name, status);
@@ -1552,7 +1694,6 @@ static inline int rtl8139_weird_interrupt (struct net_device *dev,
                        tp->full_duplex = duplex;
                        RTL_W8 (Cfg9346, Cfg9346_Unlock);
                        RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
-                       RTL_W8 (Cfg9346, Cfg9346_Lock);
                }
                status &= ~RxUnderrun;
        }
@@ -1594,9 +1735,6 @@ static void rtl8139_interrupt (int irq, void *dev_instance,
 
        spin_lock (&tp->lock);
        
-       /* disable interrupt generation while handling this interrupt */
-       RTL_W16 (IntrMask, 0x0000);
-
        do {
                status = RTL_R16 (IntrStatus);
 
@@ -1628,7 +1766,7 @@ static void rtl8139_interrupt (int irq, void *dev_instance,
                   CPU speed, lower CPU speed --> more errors).
                   After clearing the RxOverflow bit the transfer of the
                   packet was repeated and all data are error free transfered */
-               RTL_W16 (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status);
+               RTL_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status);
 
                DPRINTK ("%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",
                                dev->name, status,
@@ -1664,14 +1802,10 @@ static void rtl8139_interrupt (int irq, void *dev_instance,
                RTL_W16 (IntrStatus, 0xffff);
        }
 
-       /* Enable all known interrupts by setting the interrupt mask. */
-       RTL_W16 (IntrMask, rtl8139_intr_mask);
-
        spin_unlock (&tp->lock);
        
        DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
                 dev->name, RTL_R16 (IntrStatus));
-
 }
 
 
@@ -1695,7 +1829,7 @@ static int rtl8139_close (struct net_device *dev)
        RTL_W16 (IntrMask, 0x0000);
 
        /* Stop the chip's Tx and Rx DMA processes. */
-       RTL_W8 (ChipCmd, 0x00);
+       RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear));
 
        /* Update the error counts. */
        tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
@@ -1724,9 +1858,9 @@ static int rtl8139_close (struct net_device *dev)
                tp->tx_info[i].mapping = 0;
        }
 
-       pci_free_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+       pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
                            tp->rx_ring, tp->rx_ring_dma);
-       pci_free_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+       pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
                            tp->tx_bufs, tp->tx_bufs_dma);
        tp->rx_ring = NULL;
        tp->tx_bufs = NULL;
@@ -1838,6 +1972,7 @@ static void rtl8139_set_rx_mode (struct net_device *dev)
        void *ioaddr = tp->mmio_addr;
        u32 mc_filter[2];       /* Multicast hash filter */
        int i, rx_mode;
+       u32 tmp;
        unsigned long flags=0;
 
        DPRINTK ("ENTER\n");
@@ -1863,13 +1998,10 @@ static void rtl8139_set_rx_mode (struct net_device *dev)
                struct dev_mc_list *mclist;
                rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0;
-               for (i = 0, mclist = dev->mc_list;
-                    mclist && i < dev->mc_count;
-                    i++, mclist =
-                    mclist->next) set_bit (ether_crc (ETH_ALEN,
-                                                      mclist->
-                                                      dmi_addr) >> 26,
-                                           mc_filter);
+               for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+                    i++, mclist = mclist->next)
+                       set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26,
+                                mc_filter);
        }
        
        /* if called from irq handler, lock already acquired */
@@ -1877,7 +2009,9 @@ static void rtl8139_set_rx_mode (struct net_device *dev)
                spin_lock_irqsave (&tp->lock, flags);
 
        /* We can safely update without stopping the chip. */
-       RTL_W32 (RxConfig, rtl8139_rx_config | rx_mode);
+       tmp = rtl8139_rx_config | rx_mode |
+               (RTL_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+       RTL_W32_F (RxConfig, tmp);
        RTL_W32_F (MAR0 + 0, mc_filter[0]);
        RTL_W32_F (MAR0 + 4, mc_filter[1]);
 
@@ -1901,7 +2035,7 @@ static void rtl8139_suspend (struct pci_dev *pdev)
 
        /* Disable interrupts, stop Tx and Rx. */
        RTL_W16 (IntrMask, 0x0000);
-       RTL_W8 (ChipCmd, 0x00);
+       RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear));
 
        /* Update the error counts. */
        tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
index 673da178d233da622b9cab47b66beff3cf2efa76..44c6726a8d95c7433cf81efb4ebcc616ceff4f9c 100644 (file)
@@ -1152,7 +1152,8 @@ int __init i82596_probe(struct net_device *dev)
                if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)
                        return -ENODEV;
 
-               request_region(ioaddr, I596_TOTAL_SIZE, "i596");
+               if (!request_region(ioaddr, I596_TOTAL_SIZE, "i596"))
+                       return -ENODEV;
 
                dev->base_addr = ioaddr;
                dev->irq = 10;
index 04108ad73ad96cb7870a9aebf9e683d778bae09e..5bbef8a553d4a05d6620ef43a1492c433d9d2282 100644 (file)
@@ -121,7 +121,8 @@ int awc4500_pci_probe(struct net_device *dev)
 //                             printk(KERN_ERR "aironet4X00 mem addrs not available for maping \n");
 //                             continue;
 //             }
-               request_region(pci_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr");
+               if (!request_region(pci_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr"))
+                       continue;
 //             request_region(pci_cisaddr, AIRONET4X00_CIS_SIZE, "aironet4x00 cis");
 //             request_region(pci_memaddr, AIRONET4X00_MEM_SIZE, "aironet4x00 mem");
 
@@ -998,4 +999,4 @@ void cleanup_module(void)
 #endif
 
 }
-#endif
\ No newline at end of file
+#endif
index 1f58b30c47fcf66dea770b01e6cca5b90b5f3df7..3ebfe9bcc21e087da3a0166d77ed6ef23204d8aa 100644 (file)
@@ -571,9 +571,7 @@ net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                for (i = 0; i < 6; i++)
                        write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);
 #ifdef TIMED_CHECKER
-               del_timer(&atp_timer);
-               atp_timer.expires = jiffies + TIMED_CHECKER;
-               add_timer(&atp_timer);
+               mod_timer(&atp_timer, jiffies+TIMED_CHECKER);
 #endif
        }
 
@@ -605,9 +603,7 @@ static void atp_timed_checker(unsigned long ignored)
        for (i = 0; i < 6; i++)
                write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
        spin_unlock(&lp->lock);
-       del_timer(&atp_timer);
-       atp_timer.expires = jiffies + TIMED_CHECKER;
-       add_timer(&atp_timer);
+       mod_timer(&atp_timer, jiffies+TIMED_CHECKER);
 }
 #endif
 
index 87e5ccd7f1aff41222873d0f407cee5a5e8340c2..6d44ab654ef7c63f3cfd3bc33db882a23b4f41f5 100644 (file)
@@ -367,7 +367,7 @@ static int __init dmfe_probe(void)
                                
                /* Enable Master/IO access, Disable memory access */
                
-               pci_enable_device (net_dev);
+               pci_enable_device (net_dev); /* XXX check return val */
                pci_set_master(net_dev);
                
                /* Set Latency Timer 80h */
index b8e5acd667702ab55211c59d9c6fb19f1c5d3b2a..afb6cbfeb04bfe4ec55142d4cf21968b4343c7f9 100644 (file)
@@ -651,10 +651,8 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
                acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
        }
 
-       if (pci_enable_device(pdev)) {
-               printk(KERN_ERR "eepro100: Could not enable PCI device\n");
+       if (pci_enable_device(pdev))
                goto err_out_free_mmio_region;
-       }
 
        pci_set_master(pdev);
 
index 2832775ae601c5f62b2ee284c903a4bc073cd4f0..4fa665f1c9d2d3b762a4413e3ff955d002e9406d 100644 (file)
@@ -1120,7 +1120,11 @@ static int __devinit epic100_init_one (struct pci_dev *pdev,
        if (!request_region(ioaddr, EPIC_TOTAL_SIZE, EPIC100_MODULE_NAME))
                return -EBUSY;
 
-       pci_enable_device (pdev);
+       i = pci_enable_device (pdev);
+       if (i) {
+               release_region(ioaddr, EPIC_TOTAL_SIZE);
+               return i;
+       }
 
        /* EPIC-specific code: Soft-reset the chip ere setting as master. */
        outl(0x0001, ioaddr + GENCTL);
index 2ecbdee2d3d5de5e57761a526fc4e3fc0480a545..c36c76dff99ccbef243a57863f1d1aecc8620aac 100644 (file)
@@ -189,10 +189,8 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
        }
        
        i = pci_enable_device (pdev);
-       if (i) {
-               printk (KERN_ERR "ne2k-pci: cannot enable device\n");
+       if (i)
                return i;
-       }
        
        if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) {
                printk (KERN_ERR "ne2k-pci: I/O resource 0x%x @ 0x%lx busy\n",
@@ -567,7 +565,6 @@ static int __init ne2k_pci_init(void)
 {
        int rc;
        
-       MOD_INC_USE_COUNT;
        lock_8390_module();
        
        rc = pci_module_init (&ne2k_driver);
@@ -576,8 +573,6 @@ static int __init ne2k_pci_init(void)
        if (rc <= 0)
                unlock_8390_module();
 
-       MOD_DEC_USE_COUNT;
-       
        return rc;
 }
 
index bf71f29fd37485b4fedeb410258489cc8a2d7568..f8075373e5b78983b59c619f8355ad3f59797271 100644 (file)
@@ -3078,7 +3078,8 @@ static int __devinit tulip_pci_probe(struct pci_dev *pdev, const struct pci_devi
 
        printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name);
 
-       pci_enable_device (pdev);
+       if (pci_enable_device (pdev))
+               return -ENODEV;
        pci_set_master (pdev);
        dev = tulip_probe1(pdev, NULL,
                           pci_resource_start (pdev, 0), pdev->irq,
index ddbb4bf7a647e3ec225ff1e5c8930822d6ed31ee..b48b726f646b97878c8958ecb0f664d2f1977291 100644 (file)
@@ -182,7 +182,8 @@ static int __init sis900_probe (struct pci_dev *pci_dev, const struct pci_device
        }
 
        /* setup various bits in PCI command register */
-       pci_enable_device (pci_dev);
+       if (pci_enable_device (pci_dev))
+               return -ENODEV;
        pci_set_master(pci_dev);
 
        /* do the real low level jobs */
index 43b093a121d5b83e377c48144196c03008536878..9e2da8e7053caf764c8aafd5e515a30c5f28fc65 100644 (file)
@@ -1,31 +1,35 @@
 /* starfire.c: Linux device driver for the Adaptec Starfire network adapter. */
 /*
-       Written 1998-1999 by Donald Becker.
-
-       This software may be used and distributed according to the terms
-       of the GNU Public License (GPL), incorporated herein by reference.
-
-       The author may be reached as becker@usra.edu, or
-       Donald Becker
-       312 Severn Ave. #W302
+       Written 1998-2000 by Donald Becker.
+
+       This software may be used and distributed according to the terms of
+       the GNU General Public License (GPL), incorporated herein by reference.
+       Drivers based on or derived from this code fall under the GPL and must
+       retain the authorship, copyright and license notice.  This file is not
+       a complete program and may only be used when the entire operating
+       system is licensed under the GPL.
+
+       The author may be reached as becker@scyld.com, or C/O
+       Scyld Computing Corporation
+       410 Severn Ave., Suite 210
        Annapolis MD 21403
 
        Support and updates available at
-       http://cesdis.gsfc.nasa.gov/linux/drivers/starfire.html
+       http://www.scyld.com/network/starfire.html
+
+       Linux kernel-specific changes:
        
        LK1.1.1 (jgarzik):
        - Use PCI driver interface
        - Fix MOD_xxx races
        - softnet fixups
 
+       LK1.1.2 (jgarzik):
+       - Merge Becker version 0.15
 */
 
-static const char *versionA =
-"starfire.c:v0.12+LK1.1.1  3/19/2000  Written by Donald Becker and others\n",
-*versionB =" Undates and info at http://www.beowulf.org/linux/drivers.html\n";
-
-/* A few user-configurable values.   These may be modified when a driver
-   module is loaded.*/
+/* The user-configurable values.
+   These may be modified when a driver module is loaded.*/
 
 /* Used for tuning interrupt latency vs. overhead. */
 static int interrupt_mitigation = 0x0;
@@ -69,16 +73,16 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 
 #define PFX "starfire: "
 
-
-#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#if !defined(__OPTIMIZE__)
 #warning  You must compile this file with the correct options!
 #warning  See the last lines of the source file.
 #error You must compile this driver with "-O".
 #endif
 
+/* Include files, designed to support most kernel versions 2.0.0 and later. */
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/errno.h>
@@ -94,12 +98,13 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 #include <asm/bitops.h>
 #include <asm/io.h>
 
-/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
-   This is only in the support-all-kernels source code. */
-
-#define RUN_AT(x) (jiffies + (x))
+/* These identify the driver base version and may not be removed. */
+static const char version1[] __devinitdata =
+"starfire.c:v0.15+LK1.1.2 4/28/2000  Written by Donald Becker <becker@scyld.com>\n";
+static const char version2[] __devinitdata =
+" Undates and info at http://www.scyld.com/network/starfire.html\n";
 
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(mtu, "i");
@@ -113,16 +118,10 @@ MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 
 I. Board Compatibility
 
-State the chips and boards this driver is known to work with.
-Note any similar chips or boards that will not work.
-
-This driver skeleton demonstrates the driver for an idealized
-descriptor-based bus-master PCI chip.
+This driver is for the Adaptec 6915 "Starfire" 64 bit PCI Ethernet adapter.
 
 II. Board-specific settings
 
-No jumpers exist on most PCI boards, so this section is usually empty.
-
 III. Driver operation
 
 IIIa. Ring buffers
@@ -194,21 +193,16 @@ IVc. Errata
 
 */
 
-\f
 
-/* This table drives the PCI probe routines.  It's mostly boilerplate in all
-   PCI drivers, and will likely be provided by some future kernel.
-*/
-enum pci_flags_bit {
-       PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-       PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
-};
+enum chip_capability_flags {CanHaveMII=1, };
+
+#define MEM_ADDR_SZ 0x80000            /* And maps in 0.5MB(!).  */
 
 #if 0
 #define ADDR_64BITS 1                  /* This chip uses 64 bit addresses. */
 #endif
-#define MEM_ADDR_SZ 0x80000            /* And maps in 0.5MB(!).  */
 
+#define HAS_IP_COPYSUM 1
 
 enum chipset {
        CH_6915 = 0,
@@ -223,13 +217,12 @@ MODULE_DEVICE_TABLE(pci, starfire_pci_tbl);
 
 
 /* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */
-enum chip_capability_flags {CanHaveMII=1, };
 static struct chip_info {
-       char *chip_name;
+       const char *name;
        int io_size;
-       int flags;
-} netdrv_tbl[] = {
-       { "Adaptec Starfire 6915", 128, CanHaveMII },
+       int drv_flags;
+} netdrv_tbl[] __devinitdata = {
+       { "Adaptec Starfire 6915", MEM_ADDR_SZ, CanHaveMII },
 };
 
 
@@ -337,9 +330,9 @@ struct netdev_private {
        dma_addr_t tx_done_q_dma;
        struct net_device_stats stats;
        struct timer_list timer;        /* Media monitoring timer. */
+       int chip_id, drv_flags;
+       struct pci_dev *pci_dev;
        /* Frequently used values: keep some adjacent for cache effect. */
-       int chip_id;
-       struct pci_dev *pdev;
        unsigned int cur_rx, dirty_rx;          /* Producer/consumer ring indices */
        unsigned int cur_tx, dirty_tx;
        unsigned int rx_buf_sz;                         /* Based on MTU+slack. */
@@ -357,7 +350,6 @@ struct netdev_private {
        int mii_cnt;                                            /* MII device addresses. */
        u16 advertising;                                        /* NWay media advertisement */
        unsigned char phys[2];                          /* MII device addresses. */
-       u32 pad[4];                                                     /* Used for 32-byte alignment */
 };
 
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
@@ -377,62 +369,61 @@ static struct net_device_stats *get_stats(struct net_device *dev);
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  netdev_close(struct net_device *dev);
 
+\f
 
 static int __devinit starfire_init_one (struct pci_dev *pdev,
                                        const struct pci_device_id *ent)
 {
        struct netdev_private *np;
-       int i, irq, option, chip_id = ent->driver_data;
+       int i, irq, option, chip_idx = ent->driver_data;
        struct net_device *dev;
-       static int card_idx = 0;
+       static int card_idx = -1;
        static int printed_version = 0;
        long ioaddr;
-       int io_size = netdrv_tbl[chip_id].io_size;
+       int io_size = netdrv_tbl[chip_idx].io_size;
+
+       card_idx++;
+       option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+       
+       if (!printed_version++)
+               printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
 
        ioaddr = pci_resource_start (pdev, 0);
        if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) {
-               printk (KERN_ERR PFX "no PCI MEM resources, aborting\n");
+               printk (KERN_ERR PFX "card %d: no PCI MEM resources, aborting\n", card_idx);
                return -ENODEV;
        }
        
        dev = init_etherdev(NULL, sizeof(*np));
        if (!dev) {
-               printk (KERN_ERR PFX "cannot alloc etherdev, aborting\n");
+               printk (KERN_ERR PFX "card %d: cannot alloc etherdev, aborting\n", card_idx);
                return -ENOMEM;
        }
        
        irq = pdev->irq; 
-       
+
        if (request_mem_region (ioaddr, io_size, dev->name) == NULL) {
-               printk (KERN_ERR PFX "resource 0x%x @ 0x%lx busy, aborting\n",
-                       io_size, ioaddr);
+               printk (KERN_ERR PFX "card %d: resource 0x%x @ 0x%lx busy, aborting\n",
+                       card_idx, io_size, ioaddr);
                goto err_out_free_netdev;
        }
        
        if (pci_enable_device (pdev)) {
-               printk (KERN_ERR PFX "cannot enable PCI device, aborting\n");
+               printk (KERN_ERR PFX "card %d: cannot enable PCI device, aborting\n", card_idx);
                goto err_out_free_res;
        }
        
        ioaddr = (long) ioremap (ioaddr, io_size);
        if (!ioaddr) {
-               printk (KERN_ERR PFX "cannot remap 0x%x @ 0x%lx, aborting\n",
-                       io_size, ioaddr);
+               printk (KERN_ERR PFX "card %d: cannot remap 0x%x @ 0x%lx, aborting\n",
+                       card_idx, io_size, ioaddr);
                goto err_out_free_res;
        }
 
        pci_set_master (pdev);
        
-       option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-       card_idx++;
-       
-       if (!printed_version) {
-               printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-               printed_version = 1;
-       }
-
-       printk (KERN_INFO "%s: %s at 0x%lx, ",
-               dev->name, netdrv_tbl[chip_id].chip_name, ioaddr);
+       printk(KERN_INFO "%s: %s at 0x%lx, ",
+                  dev->name, netdrv_tbl[chip_idx].name, ioaddr);
 
        /* Serial EEPROM reads are hidden by the hardware. */
        for (i = 0; i < 6; i++)
@@ -454,13 +445,16 @@ static int __devinit starfire_init_one (struct pci_dev *pdev,
        dev->base_addr = ioaddr;
        dev->irq = irq;
 
+       pdev->driver_data = dev;
+
        /* private struct aligned and zeroed by init_etherdev */
        np = dev->priv;
 
-       np->pdev = pdev;
-       np->chip_id = chip_id;
+       np->pci_dev = pdev;
+       np->chip_id = chip_idx;
        
-       pdev->driver_data = dev;
+       /* save useful data, netdrv_tbl is __devinitdata and might be dropped */
+       np->drv_flags = netdrv_tbl[chip_idx].drv_flags;
 
        if (dev->mem_start)
                option = dev->mem_start;
@@ -492,7 +486,7 @@ static int __devinit starfire_init_one (struct pci_dev *pdev,
        if (mtu)
                dev->mtu = mtu;
 
-       if (netdrv_tbl[np->chip_id].flags & CanHaveMII) {
+       if (np->drv_flags & CanHaveMII) {
                int phy, phy_idx = 0;
                for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
                        int mii_status = mdio_read(dev, phy, 1);
@@ -524,7 +518,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
        long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
        int result, boguscnt=1000;
-       /* ??? Must add a busy-wait here. */
+       /* ??? Should we add a busy-wait here? */
        do
                result = readl(mdio_addr);
        while ((result & 0xC0000000) != 0x80000000 && --boguscnt >= 0);
@@ -546,12 +540,13 @@ static int netdev_open(struct net_device *dev)
        long ioaddr = dev->base_addr;
        int i;
 
+       /* Do we ever need to reset the chip??? */
+
        MOD_INC_USE_COUNT;
-       /* Do we need to reset the chip??? */
 
        if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
                MOD_DEC_USE_COUNT;
-               return -EBUSY;
+               return -EAGAIN;
        }
 
        /* Disable the Rx and Tx, and reset the chip. */
@@ -562,26 +557,26 @@ static int netdev_open(struct net_device *dev)
                           dev->name, dev->irq);
        /* Allocate the various queues, failing gracefully. */
        if (np->tx_done_q == 0)
-               np->tx_done_q = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->tx_done_q_dma);
+               np->tx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_done_q_dma);
        if (np->rx_done_q == 0)
-               np->rx_done_q = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->rx_done_q_dma);
+               np->rx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->rx_done_q_dma);
        if (np->tx_ring == 0)
-               np->tx_ring = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->tx_ring_dma);
+               np->tx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_ring_dma);
        if (np->rx_ring == 0)
-               np->rx_ring = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->rx_ring_dma);
+               np->rx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->rx_ring_dma);
        if (np->tx_done_q == 0  ||  np->rx_done_q == 0
                || np->rx_ring == 0 ||  np->tx_ring == 0) {
                if (np->tx_done_q)
-                       pci_free_consistent(np->pdev, PAGE_SIZE,
+                       pci_free_consistent(np->pci_dev, PAGE_SIZE,
                                                                np->tx_done_q, np->tx_done_q_dma);
                if (np->rx_done_q)
-                       pci_free_consistent(np->pdev, PAGE_SIZE,
+                       pci_free_consistent(np->pci_dev, PAGE_SIZE,
                                                                np->rx_done_q, np->rx_done_q_dma);
                if (np->tx_ring)
-                       pci_free_consistent(np->pdev, PAGE_SIZE,
+                       pci_free_consistent(np->pci_dev, PAGE_SIZE,
                                                                np->tx_ring, np->tx_ring_dma);
                if (np->rx_ring)
-                       pci_free_consistent(np->pdev, PAGE_SIZE,
+                       pci_free_consistent(np->pci_dev, PAGE_SIZE,
                                                                np->rx_ring, np->rx_ring_dma);
                MOD_DEC_USE_COUNT;
                return -ENOMEM;
@@ -632,6 +627,8 @@ static int netdev_open(struct net_device *dev)
        if (dev->if_port == 0)
                dev->if_port = np->default_port;
 
+       netif_start_queue(dev);
+
        if (debug > 1)
                printk(KERN_DEBUG "%s:  Setting the Rx and Tx modes.\n", dev->name);
        set_rx_mode(dev);
@@ -649,15 +646,13 @@ static int netdev_open(struct net_device *dev)
        /* Enable the Rx and Tx units. */
        writel(0x000F, ioaddr + GenCtrl);
 
-       netif_start_queue(dev);
-
        if (debug > 2)
                printk(KERN_DEBUG "%s: Done netdev_open().\n",
                           dev->name);
 
        /* Set the timer to check for link beat. */
        init_timer(&np->timer);
-       np->timer.expires = RUN_AT(3*HZ);
+       np->timer.expires = jiffies + 3*HZ;
        np->timer.data = (unsigned long)dev;
        np->timer.function = &netdev_timer;                             /* timer handler */
        add_timer(&np->timer);
@@ -670,21 +665,22 @@ static void check_duplex(struct net_device *dev, int startup)
        struct netdev_private *np = (struct netdev_private *)dev->priv;
        long ioaddr = dev->base_addr;
        int mii_reg5 = mdio_read(dev, np->phys[0], 5);
+       int negotiated =  mii_reg5 & np->advertising;
        int duplex, new_tx_mode ;
 
        new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) | (np->rx_flowctrl ? 0x0400:0);
        if (np->duplex_lock)
                duplex = 1;
        else
-               duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
+               duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
        if (duplex)
                new_tx_mode |= 2;
        if (np->full_duplex != duplex) {
                np->full_duplex = duplex;
                if (debug)
-                       printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
-                                  " partner capability of %4.4x.\n", dev->name,
-                                  duplex ? "full" : "half", np->phys[0], mii_reg5);
+                       printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d"
+                                  " negotiated capability %4.4x.\n", dev->name,
+                                  duplex ? "full" : "half", np->phys[0], negotiated);
        }
        if (new_tx_mode != np->tx_mode) {
                np->tx_mode = new_tx_mode;
@@ -718,11 +714,10 @@ static void netdev_timer(unsigned long data)
        }
 #endif
 
-       np->timer.expires = RUN_AT(next_tick);
+       np->timer.expires = jiffies + next_tick;
        add_timer(&np->timer);
 }
 
-
 static void tx_timeout(struct net_device *dev)
 {
        struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -753,6 +748,7 @@ static void tx_timeout(struct net_device *dev)
        /* Trigger an immediate transmit demand. */
        /* XXX todo */
 
+       dev->trans_start = jiffies;
        np->stats.tx_errors++;
 }
 
@@ -775,12 +771,12 @@ static void init_ring(struct net_device *dev)
                np->rx_info[i].skb = skb;
                if (skb == NULL)
                        break;
-               np->rx_info[i].mapping = pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+               np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
                skb->dev = dev;                 /* Mark as being used by this device. */
                /* Grrr, we cannot offset to correctly align the IP header. */
                np->rx_ring[i].rxaddr = cpu_to_le32(np->rx_info[i].mapping | RxDescValid);
        }
-       writew(i-1, dev->base_addr + RxDescQIdx);
+       writew(i - 1, dev->base_addr + RxDescQIdx);
        np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 
        /* Clear the remainder of the Rx buffer ring. */
@@ -819,10 +815,10 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 
        np->tx_info[entry].skb = skb;
        np->tx_info[entry].mapping =
-               pci_map_single(np->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+               pci_map_single(np->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
 
        np->tx_ring[entry].addr = cpu_to_le32(np->tx_info[entry].mapping);
-       /* Add  |TxDescIntr to generate Tx-done interrupts. */
+       /* Add  "| TxDescIntr" to generate Tx-done interrupts. */
        np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID);
        if (debug > 5) {
                printk(KERN_DEBUG "%s: Tx #%d slot %d  %8.8x %8.8x.\n",
@@ -862,7 +858,8 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
 {
        struct net_device *dev = (struct net_device *)dev_instance;
        struct netdev_private *np;
-       long ioaddr, boguscnt = max_interrupt_work;
+       long ioaddr;
+       int boguscnt = max_interrupt_work;
 
 #ifndef final_version                  /* Can never occur. */
        if (dev == NULL) {
@@ -889,8 +886,8 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
                        netdev_rx(dev);
 
                /* Scavenge the skbuff list based on the Tx-done queue.
-                  There are redundant checks here that may be cleaned up when
-                  after the driver has proven reliable. */
+                  There are redundant checks here that may be cleaned up
+                  after the driver has proven to be reliable. */
                {
                        int consumer = readl(ioaddr + TxConsumerIdx);
                        int tx_status;
@@ -905,7 +902,8 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
                                           (np->tx_done+1) & (DONE_Q_SIZE-1),
                                           le32_to_cpu(np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status));
 #endif
-                       while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status)) != 0) {
+                       while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status))
+                                  != 0) {
                                if (debug > 4)
                                        printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n",
                                                   dev->name, np->tx_done, tx_status);
@@ -917,9 +915,9 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
                                        entry >>= 3;
 
                                        skb = np->tx_info[entry].skb;
-                                       pci_unmap_single(np->pdev,
-                                                                        np->tx_info[entry].mapping,
-                                                                        skb->len, PCI_DMA_TODEVICE);
+                                       pci_unmap_single(np->pci_dev,
+                                                        np->tx_info[entry].mapping,
+                                                        skb->len, PCI_DMA_TODEVICE);
 
                                        /* Scavenge the descriptor. */
                                        dev_kfree_skb_irq(skb);
@@ -954,16 +952,27 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
                printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
                           dev->name, readl(ioaddr + IntrStatus));
 
-       return;
+#ifndef final_version
+       /* Code that should never be run!  Remove after testing.. */
+       {
+               static int stopit = 10;
+               if (!netif_running(dev)  &&  --stopit < 0) {
+                       printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
+                                  dev->name);
+                       free_irq(irq, dev);
+               }
+       }
+#endif
 }
 
-/* This routine is logically part of the interrupt handler, but seperated
+/* This routine is logically part of the interrupt handler, but separated
    for clarity and better register allocation. */
 static int netdev_rx(struct net_device *dev)
 {
        struct netdev_private *np = (struct netdev_private *)dev->priv;
        int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
        u32 desc_status;
+
        if (np->rx_done_q == 0) {
                printk(KERN_ERR "%s:  rx_done_q is NULL!  rx_done is %d. %p.\n",
                           dev->name, np->rx_done, np->tx_done_q);
@@ -977,7 +986,7 @@ static int netdev_rx(struct net_device *dev)
                                   np->rx_done, desc_status);
                if (--boguscnt < 0)
                        break;
-               if (! (desc_status & RxOK)) {
+               if ( ! (desc_status & RxOK)) {
                        /* There was a error. */
                        if (debug > 2)
                                printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
@@ -1002,9 +1011,9 @@ static int netdev_rx(struct net_device *dev)
                                && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
                                skb->dev = dev;
                                skb_reserve(skb, 2);    /* 16 byte align the IP header */
-                               pci_dma_sync_single(np->pdev,
-                                                                       np->rx_info[entry].mapping,
-                                                                       pkt_len, PCI_DMA_FROMDEVICE);
+                               pci_dma_sync_single(np->pci_dev,
+                                                   np->rx_info[entry].mapping,
+                                                   pkt_len, PCI_DMA_FROMDEVICE);
 #if HAS_IP_COPYSUM                     /* Call copy + cksum if available. */
                                eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
                                skb_put(skb, pkt_len);
@@ -1015,11 +1024,19 @@ static int netdev_rx(struct net_device *dev)
                        } else {
                                char *temp;
 
-                               pci_unmap_single(np->pdev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                               pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
                                skb = np->rx_info[entry].skb;
                                temp = skb_put(skb, pkt_len);
                                np->rx_info[entry].skb = NULL;
                                np->rx_info[entry].mapping = 0;
+#ifndef final_version                          /* Remove after testing. */
+                               if (le32_to_cpu(np->rx_ring[entry].rxaddr & ~3) != ((unsigned long) temp))
+                                       printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
+                                                  "do not match in netdev_rx: %d vs. %p / %p.\n",
+                                                  dev->name,
+                                                  le32_to_cpu(np->rx_ring[entry].rxaddr),
+                                                  skb->head, temp);
+#endif
                        }
 #ifndef final_version                          /* Remove after testing. */
                        /* You will want this info for the initial debug. */
@@ -1059,7 +1076,7 @@ static int netdev_rx(struct net_device *dev)
                        if (skb == NULL)
                                break;                  /* Better luck next round. */
                        np->rx_info[entry].mapping =
-                               pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                               pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
                        skb->dev = dev;                 /* Mark as being used by this device. */
                        np->rx_ring[entry].rxaddr =
                                cpu_to_le32(np->rx_info[entry].mapping | RxDescValid);
@@ -1108,7 +1125,7 @@ static void netdev_error(struct net_device *dev, int intr_status)
                np->stats.rx_fifo_errors++;
 }
 
-static struct enet_statistics *get_stats(struct net_device *dev)
+static struct net_device_stats *get_stats(struct net_device *dev)
 {
        long ioaddr = dev->base_addr;
        struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -1263,7 +1280,7 @@ static int netdev_close(struct net_device *dev)
        if (debug > 2) {
                printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
                           np->tx_ring_dma);
-               for (i = 0; i < 8 /* TX_RING_SIZE */; i++)
+               for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++)
                        printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n",
                                   i, le32_to_cpu(np->tx_ring[i].status),
                                   le32_to_cpu(np->tx_ring[i].addr),
@@ -1284,7 +1301,7 @@ static int netdev_close(struct net_device *dev)
        for (i = 0; i < RX_RING_SIZE; i++) {
                np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
                if (np->rx_info[i].skb != NULL) {
-                       pci_unmap_single(np->pdev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                       pci_unmap_single(np->pci_dev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
                        dev_kfree_skb(np->rx_info[i].skb);
                }
                np->rx_info[i].skb = NULL;
@@ -1293,9 +1310,9 @@ static int netdev_close(struct net_device *dev)
        for (i = 0; i < TX_RING_SIZE; i++) {
                struct sk_buff *skb = np->tx_info[i].skb;
                if (skb != NULL) {
-                       pci_unmap_single(np->pdev,
-                                                        np->tx_info[i].mapping,
-                                                        skb->len, PCI_DMA_TODEVICE);
+                       pci_unmap_single(np->pci_dev,
+                                        np->tx_info[i].mapping,
+                                        skb->len, PCI_DMA_TODEVICE);
                        dev_kfree_skb(skb);
                }
                np->tx_info[i].skb = NULL;
@@ -1313,10 +1330,8 @@ static void __devexit starfire_remove_one (struct pci_dev *pdev)
        struct net_device *dev = pdev->driver_data;
        struct netdev_private *np;
        
-       if (!dev) {
-               printk (KERN_WARNING "bug: removing starfire pci dev without driver\n");
-               return;
-       }
+       if (!dev)
+               BUG();
 
        np = dev->priv;
 
@@ -1324,16 +1339,16 @@ static void __devexit starfire_remove_one (struct pci_dev *pdev)
        iounmap((char *)dev->base_addr);
 
        if (np->tx_done_q)
-               pci_free_consistent(np->pdev, PAGE_SIZE,
+               pci_free_consistent(np->pci_dev, PAGE_SIZE,
                                    np->tx_done_q, np->tx_done_q_dma);
        if (np->rx_done_q)
-               pci_free_consistent(np->pdev, PAGE_SIZE,
+               pci_free_consistent(np->pci_dev, PAGE_SIZE,
                                    np->rx_done_q, np->rx_done_q_dma);
        if (np->tx_ring)
-               pci_free_consistent(np->pdev, PAGE_SIZE,
+               pci_free_consistent(np->pci_dev, PAGE_SIZE,
                                    np->tx_ring, np->tx_ring_dma);
        if (np->rx_ring)
-               pci_free_consistent(np->pdev, PAGE_SIZE,
+               pci_free_consistent(np->pci_dev, PAGE_SIZE,
                                    np->rx_ring, np->rx_ring_dma);
 
        kfree(dev);
@@ -1350,15 +1365,7 @@ static struct pci_driver starfire_driver = {
 
 static int __init starfire_init (void)
 {
-       int rc;
-       
-       MOD_INC_USE_COUNT;
-       
-       rc = pci_module_init (&starfire_driver);
-       
-       MOD_DEC_USE_COUNT;
-       
-       return rc;
+       return pci_module_init (&starfire_driver);
 }
 
 
@@ -1374,8 +1381,8 @@ module_exit(starfire_cleanup);
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  simple-compile-command: "gcc -DMODULE -D__KERNEL__ -O6 -c starfire.c"
+ *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c starfire.c"
+ *  simple-compile-command: "gcc -DMODULE -O6 -c starfire.c"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
index 724847af239278b25b1d324cbdd6b188c14c4755..3db04bdee4f1efbb930096f09682075f4e45de53 100644 (file)
@@ -114,23 +114,28 @@ int __init abyss_probe(void)
                if (versionprinted++ == 0)
                        printk("%s", version);
 
-               pci_enable_device(pdev);
+               if (pci_enable_device(pdev))
+                       continue;
 
                /* Remove I/O space marker in bit 0. */
                pci_irq_line = pdev->irq;
-               pci_ioaddr = pdev->resource[0].start ; 
+               pci_ioaddr = pci_resource_start (pdev, 0);
                
-               if(check_region(pci_ioaddr, ABYSS_IO_EXTENT))
+               if(!request_region(pci_ioaddr, ABYSS_IO_EXTENT, "abyss"))
                        continue;
                
                /* At this point we have found a valid card. */
                
                dev = init_trdev(NULL, 0);
+               if (!dev) {
+                       release_region(pci_ioaddr, ABYSS_IO_EXTENT);
+                       continue;
+               }
                
-               request_region(pci_ioaddr, ABYSS_IO_EXTENT, "abyss");
                if(request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ,
                               "abyss", dev)) { 
                        release_region(pci_ioaddr, ABYSS_IO_EXTENT) ; 
+                       /* XXX free trdev */
                        continue; /*return (-ENODEV);*/ /* continue; ?? */
                }
                
@@ -140,7 +145,6 @@ int __init abyss_probe(void)
                  }
                */
 
-               pci_ioaddr &= ~3 ; 
                dev->base_addr  = pci_ioaddr;
                dev->irq                = pci_irq_line;
                dev->dma                = 0;
index ffcfab93152deeea5fc91e7976b26c59f82733b8..029e0cdfa8132a355a116ed1842d21a677b5bf80 100644 (file)
@@ -137,11 +137,12 @@ int __init tms_pci_probe(void)
                if (versionprinted++ == 0)
                        printk("%s", version);
 
-               pci_enable_device(pdev);
+               if (pci_enable_device(pdev))
+                       continue;
 
                /* Remove I/O space marker in bit 0. */
                pci_irq_line = pdev->irq;
-               pci_ioaddr = pdev->resource[0].start ; 
+               pci_ioaddr = pci_resource_start (pdev, 0);
                
                if(check_region(pci_ioaddr, TMS_PCI_IO_EXTENT))
                        continue;
@@ -149,11 +150,15 @@ int __init tms_pci_probe(void)
                /* At this point we have found a valid card. */
     
                dev = init_trdev(NULL, 0);
+               if (!dev) {
+                       continue; /*return (-ENOMEM);*/ /* continue; ?? */
+               }
                
-               request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, cardinfo->name);
+               request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, cardinfo->name); /* XXX check return */
                if(request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ,
                               cardinfo->name, dev)) { 
                        release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); 
+                       /* XXX free trdev */
                        continue; /*return (-ENODEV);*/ /* continue; ?? */
                }
 
index ca99883281d3acfb3866bd9672b0a2eaf186f27c..6e7cd9a63c25c939572f762369e2620462afe834 100644 (file)
@@ -1348,6 +1348,7 @@ static void tulip_suspend (struct pci_dev *pdev)
                netif_device_detach (dev);
                tulip_down (dev);
        }
+       pci_set_power_state(pdev, 3);
 }
 
 
@@ -1355,6 +1356,7 @@ static void tulip_resume (struct pci_dev *pdev)
 {
        struct net_device *dev = pdev->driver_data;
 
+       pci_enable_device(pdev);
        if (dev && !netif_device_present (dev)) {
                tulip_up (dev);
                netif_device_attach (dev);
index ae451a43e17e031c4fd1beeb9fdeb9f4a949006f..3934071e78be8f4f479fade89b765438bcb9bdee 100644 (file)
@@ -454,11 +454,8 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
 
        ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1);
 
-       if (pci_enable_device (pdev)) {
-               printk (KERN_ERR "unable to init PCI device (card #%d)\n",
-                       card_idx);
+       if (pci_enable_device (pdev))
                goto err_out_free_dma;
-       }
        
        if (pci_flags & PCI_USES_MASTER)
                pci_set_master (pdev);
@@ -1294,15 +1291,7 @@ static struct pci_driver via_rhine_driver = {
 
 static int __init via_rhine_init (void)
 {
-       int rc;
-       
-       MOD_INC_USE_COUNT;
-       
-       rc = pci_module_init (&via_rhine_driver);
-       
-       MOD_DEC_USE_COUNT;
-       
-       return rc;
+       return pci_module_init (&via_rhine_driver);
 }
 
 
index f3669aaf9370f2a165235a85f20e571cd2042ef4..6a68bd5e790104e5c3160ff5dff1eb854f330427 100644 (file)
@@ -1513,11 +1513,8 @@ static void reset_timer(struct net_device *dev)
 {
        x25_channel_t *chan = dev->priv;
 
-       if (chan->svc) {
-               del_timer(&chan->timer);
-               chan->timer.expires = jiffies + chan->idle_tmout * HZ;
-               add_timer(&chan->timer);
-       }
+       if (chan->svc)
+               mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ);
 }
 #ifdef CYCLOMX_X25_DEBUG
 static void x25_dump_config(TX25Config *conf)
index 17207612dd0d5bf02b731627ba2dff9dff9df76b..2be7d5823e1c435c8de0782afbf740d777a49a45 100644 (file)
@@ -1255,6 +1255,7 @@ 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);
        pci_set_master (pdev);
 
@@ -1263,6 +1264,7 @@ 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 */
 #endif
        irq = pdev->irq;
 
index ee901ab5d3cb5aba7d7907046921e6f9fa764b3d..8866a4b56dd382639a09c33954c30aa76b5eb405 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/ioport.h>
+#include <linux/pm.h>
 
 #include <asm/page.h>
 #include <asm/dma.h>   /* isa_dma_bridge_buggy */
@@ -1020,6 +1021,106 @@ struct pci_bus * __init pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata
        return b;
 }
 
+#ifdef CONFIG_PM
+
+/*
+ * PCI Power management..
+ *
+ * This needs to be done centralized, so that we power manage PCI
+ * devices in the right order: we should not shut down PCI bridges
+ * before we've shut down the devices behind them, and we should
+ * not wake up devices before we've woken up the bridge to the
+ * device.. Eh?
+ *
+ * We do not touch devices that don't have a driver that exports
+ * a suspend/resume function. That is just too dangerous. If the default
+ * PCI suspend/resume functions work for a device, the driver can
+ * easily implement them (ie just have a suspend function that calls
+ * the pci_set_power_state() function).
+ */
+static int pci_pm_suspend_device(struct pci_dev *dev)
+{
+       if (dev) {
+               struct pci_driver *driver = dev->driver;
+               if (driver && driver->suspend)
+                       driver->suspend(dev);
+       }
+       return 0;
+}
+
+static int pci_pm_resume_device(struct pci_dev *dev)
+{
+       if (dev) {
+               struct pci_driver *driver = dev->driver;
+               if (driver && driver->resume)
+                       driver->resume(dev);
+       }
+       return 0;
+}
+
+static int pci_pm_suspend_bus(struct pci_bus *bus)
+{
+       struct list_head *list;
+
+       /* Walk the bus children list */
+       list_for_each(list, &bus->children) 
+               pci_pm_suspend_bus(pci_bus_b(list));
+
+       /* Walk the device children list */
+       list_for_each(list, &bus->devices)
+               pci_pm_suspend_device(pci_dev_b(list));
+
+       /* Suspend the bus controller.. */
+       pci_pm_suspend_device(bus->self);
+       return 0;
+}
+
+static int pci_pm_resume_bus(struct pci_bus *bus)
+{
+       struct list_head *list;
+
+       pci_pm_resume_device(bus->self);
+
+       /* Walk the device children list */
+       list_for_each(list, &bus->devices)
+               pci_pm_resume_device(pci_dev_b(list));
+
+       /* And then walk the bus children */
+       list_for_each(list, &bus->children)
+               pci_pm_resume_bus(pci_bus_b(list));
+       return 0;
+}
+
+static int pci_pm_suspend(void)
+{
+       struct list_head *list;
+
+       list_for_each(list, &pci_root_buses)
+               pci_pm_suspend_bus(pci_bus_b(list));
+       return 0;
+}
+
+static int pci_pm_resume(void)
+{
+       struct list_head *list;
+
+       list_for_each(list, &pci_root_buses)
+               pci_pm_resume_bus(pci_bus_b(list));
+       return 0;
+}
+
+static int pci_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+       switch (rqst) {
+       case PM_SUSPEND:
+               return pci_pm_suspend();
+       case PM_RESUME:
+               return pci_pm_resume();
+       }       
+       return 0;
+}
+#endif
+
 void __init pci_init(void)
 {
        struct pci_dev *dev;
@@ -1029,6 +1130,10 @@ void __init pci_init(void)
        pci_for_each_dev(dev) {
                pci_fixup_device(PCI_FIXUP_FINAL, dev);
        }
+
+#ifdef CONFIG_PM
+       pm_register(PM_PCI_DEV, 0, pci_pm_callback);
+#endif
 }
 
 static int __init pci_setup(char *str)
index df412e35bba17d3d4927ab45be2507126e6d24d6..c48445d65b0bf022a057465536e204daaff32222 100644 (file)
@@ -667,9 +667,7 @@ static int NCR5380_set_timer(struct Scsi_Host *instance)
        ((struct NCR5380_hostdata *) instance->hostdata)->next_timer = tmp;
        *prev = instance;
    
-       del_timer(&usleep_timer);
-       usleep_timer.expires = ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires;
-       add_timer(&usleep_timer);
+       mod_timer(&usleep_timer, ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires);
        restore_flags(flags);
        return 0;
 }
index 30faaa9ad9be8e674c204baee1dcb9d5ba3dde9e..b11872c421739293120e6140081c02796aa379bf 100644 (file)
@@ -676,8 +676,10 @@ static struct signature {
 {
        { "Adaptec AHA-1520 BIOS",      0x102e, 21 },
                /* Adaptec 152x */
-       { "Adaptec AHA-1520B",          0x000b, 19 },
+       { "Adaptec AHA-1520B",          0x000b, 17 },
                /* Adaptec 152x rev B */
+       { "Adaptec AHA-1520B",          0x0026, 17 },
+               /* Iomega Jaz Jet ISA (AIC6370Q) */
        { "Adaptec ASW-B626 BIOS",      0x1029, 21 },
                /* on-board controller */
        { "Adaptec BIOS: ASW-B626",     0x000f, 22 },
index 40ccb2fa8b03c2c5bbbf6318c398dc7cfc25c318..8d041639b000dfce379fa701d7249d2554114314 100644 (file)
@@ -3585,9 +3585,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
       if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
             time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
       {
-        del_timer(&p->dev_timer);
-        p->dev_timer.expires = p->dev_expires[i];
-        add_timer(&p->dev_timer);
+        mod_timer(&p->dev_timer, p->dev_expires[i]);
         p->dev_timer_active |= (0x01 << MAX_TARGETS);
       }
     }
@@ -5045,11 +5043,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                 }
                 else if ( time_after_eq(p->dev_timer.expires,
                                         p->dev_expires[tindex]) )
-                {
-                  del_timer(&p->dev_timer);
-                  p->dev_timer.expires = p->dev_expires[tindex];
-                  add_timer(&p->dev_timer);
-                }
+                  mod_timer(&p->dev_timer, p->dev_expires[tindex]);
               }
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
               if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ||
@@ -12058,9 +12052,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
             time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
       {
-        del_timer(&p->dev_timer);
-        p->dev_timer.expires = p->dev_expires[p->scsi_id];
-        add_timer(&p->dev_timer);
+        mod_timer(&p->dev_timer, p->dev_expires[p->scsi_id]);
         p->dev_timer_active |= (0x01 << MAX_TARGETS);
       }
       aic7xxx_reset_channel(p, cmd->channel, TRUE);
index 0003a4b1d3d8e0de16ad1b85df09ad0a70c1a47f..f457347713776642a3cc5134a3ae4d4ee2adc0b7 100644 (file)
@@ -2494,11 +2494,12 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
                printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1);
                goto err_region;
        }
+       if (pci_enable_device(pcidev))
+               goto err_irq;
        if (request_irq(s->irq, es1370_interrupt, SA_SHIRQ, "es1370", s)) {
                printk(KERN_ERR "es1370: irq %u in use\n", s->irq);
                goto err_irq;
        }
-       pci_enable_device(pcidev);
        /* initialize codec registers */
        /* note: setting CTRL_SERR_DIS is reported to break
         * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
index 73333a73d2f92f8da5dc59f7174a0ed000b9049a..8ae10a074f80b67d8243748ba994f99518bfebfb 100644 (file)
@@ -2664,11 +2664,12 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
                printk(KERN_ERR PFX "io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
                goto err_region;
        }
+       if (pci_enable_device(pcidev))
+               goto err_irq;
        if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) {
                printk(KERN_ERR PFX "irq %u in use\n", s->irq);
                goto err_irq;
        }
-       pci_enable_device(pcidev);
        printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n"
               KERN_INFO PFX "features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]);
        /* register devices */
index f62f01414dd5a88d8b783160c17c8da28a49d1c1..aa1fc77d19edcb9c6b7db523385af0264c691f1c 100644 (file)
@@ -2252,11 +2252,12 @@ static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device
                printk(KERN_ERR "solo1: io ports in use\n");
                goto err_region4;
        }
+       if (pci_enable_device(pcidev))
+               goto err_irq;
        if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
                printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
                goto err_irq;
        }
-       pci_enable_device(pcidev);
        printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase);
        printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1);
        /* register devices */
index 10438f115db38da89c53365b69dc824b13b0caef..c96397ab2e0fd05b623432a0358c6cebf29660c8 100644 (file)
@@ -1735,14 +1735,16 @@ static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id
                return -ENODEV;
        }
 
+       if (pci_enable_device(pci_dev))
+               return -EIO;
        if ((card = kmalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) {
                printk(KERN_ERR "i810_audio: out of memory\n");
                return -ENOMEM;
        }
        memset(card, 0, sizeof(*card));
 
-       card->iobase = pci_dev->resource[1].start;
-       card->ac97base = pci_dev->resource[0].start;
+       card->iobase = pci_resource_start (pci_dev, 1);
+       card->ac97base = pci_resource_start (pci_dev, 0);
        card->pci_dev = pci_dev;
        card->pci_id = pci_id->device;
        card->irq = pci_dev->irq;
@@ -1752,7 +1754,6 @@ static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id
        devs = card;
 
        pci_set_master(pci_dev);
-       pci_enable_device(pci_dev);
 
        printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, IRQ %d\n",
               card_names[pci_id->driver_data], card->iobase, card->ac97base, 
index a5fb3a1ef3516c04f80d59cc25a51b9e9ad2ce09..6588f3b3f6e1f05db72db84df827aea84043502b 100644 (file)
@@ -2520,7 +2520,8 @@ static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id
                printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1);
                goto err_region1;
        }
-       pci_enable_device(pcidev);
+       if (pci_enable_device(pcidev))
+               goto err_irq;
        /* initialize codec registers */
        outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */
        udelay(50);
index 575a6561693217517147ca25490036de3c3e2673..6f5a383cd3382fe62de8eb0116afbd1595be9c7c 100644 (file)
@@ -2343,13 +2343,16 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device
        }
        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
 
-       iobase = pci_dev->resource[0].start;
+       iobase = pci_resource_start (pci_dev, 0);
        if (check_region(iobase, 256)) {
                printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n",
                       iobase);
                return -ENODEV;
        }
 
+       if (pci_enable_device(pci_dev))
+               return -ENODEV;
+
        if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) {
                printk(KERN_ERR "trident: out of memory\n");
                return -ENOMEM;
@@ -2371,7 +2374,6 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device
        devs = card;
 
        pci_set_master(pci_dev);
-       pci_enable_device(pci_dev);
 
        printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
               card_names[pci_id->driver_data], card->iobase, card->irq);
index c8f187280ce6c8db26671c3f6a022c9e232313e2..354c1d6cf924badf3e5b666feab41c6aa943e286 100644 (file)
@@ -2159,10 +2159,10 @@ static int usb_audio_mmap(struct file *file, struct vm_area_struct *vma)
                db = &as->usbin.dma;
        } else
                return -EINVAL;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,22)
+
        if (vma->vm_pgoff != 0)
                return -EINVAL;
-#endif
+
        return dmabuf_mmap(db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
 }
 
index 588fed5d192df1774d7450274c008949d976d08f..7b2bfb9d3ee235095e03ad95f67429eb636fcff9 100644 (file)
@@ -14,6 +14,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (04/27/2000) Ryan VanderBijl
+ *     Put calls to *_paranoia_checks into one function.
+ * 
  * (04/23/2000) gkh
  *     Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
  *     Moved when the startup code printed out the devices that are supported.
@@ -318,6 +321,20 @@ static struct termios *            serial_termios_locked[SERIAL_TTY_MINORS];
 static struct usb_serial       *serial_table[SERIAL_TTY_MINORS] = {NULL, };
 
 
+static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function) 
+{ 
+       /* if no port was specified, or it fails a paranoia check */
+       if (!port || 
+               port_paranoia_check (port, function) ||
+               serial_paranoia_check (port->serial, function)) {
+               /* then say that we dont have a valid usb_serial thing, which will
+                * end up genrating -ENODEV return values */ 
+               return NULL;
+       }
+
+       return port->serial;
+}
+
 
 static struct usb_serial *get_serial_by_minor (int minor)
 {
@@ -357,7 +374,7 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
                for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
                        serial_table[i] = serial;
                return serial;
-               }
+       }
        return NULL;
 }
 
@@ -454,16 +471,9 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
 static void serial_close(struct tty_struct *tty, struct file * filp)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial;
+       struct usb_serial *serial = get_usb_serial (port, "serial_close");
 
-       dbg("serial_close");
-
-       if (port_paranoia_check (port, "serial_close")) {
-               return;
-       }
-
-       serial = port->serial;
-       if (serial_paranoia_check (serial, "serial_close")) {
+       if (!serial) {
                return;
        }
 
@@ -486,16 +496,9 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
 static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial;
-       
-       dbg("serial_write");
-       
-       if (port_paranoia_check (port, "serial_write")) {
-               return -ENODEV;
-       }
+       struct usb_serial *serial = get_usb_serial (port, "serial_write");
        
-       serial = port->serial;
-       if (serial_paranoia_check (serial, "serial_write")) {
+       if (!serial) {
                return -ENODEV;
        }
        
@@ -518,26 +521,19 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
 static int serial_write_room (struct tty_struct *tty) 
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial;
-       
-       dbg("serial_write_room");
-       
-       if (port_paranoia_check (port, "serial_write")) {
-               return -ENODEV;
-       }
-       
-       serial = port->serial;
-       if (serial_paranoia_check (serial, "serial_write")) {
+       struct usb_serial *serial = get_usb_serial (port, "serial_write_room");
+
+       if (!serial) {
                return -ENODEV;
        }
-       
+
        dbg("serial_write_room port %d", port->number);
        
        if (!port->active) {
                dbg ("port not open");
                return -EINVAL;
        }
-       
+
        /* pass on to the driver specific version of this function if it is available */
        if (serial->type->write_room) {
                return (serial->type->write_room(port));
@@ -550,24 +546,17 @@ static int serial_write_room (struct tty_struct *tty)
 static int serial_chars_in_buffer (struct tty_struct *tty) 
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial;
-       
-       dbg("serial_chars_in_buffer");
-       
-       if (port_paranoia_check (port, "serial_chars_in_buffer")) {
-               return -ENODEV;
-       }
-       
-       serial = port->serial;
-       if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
+       struct usb_serial *serial = get_usb_serial (port, "serial_chars_in_buffer");
+
+       if (!serial) {
                return -ENODEV;
        }
-       
+
        if (!port->active) {
                dbg ("port not open");
                return -EINVAL;
        }
-       
+
        /* pass on to the driver specific version of this function if it is available */
        if (serial->type->chars_in_buffer) {
                return (serial->type->chars_in_buffer(port));
@@ -580,21 +569,14 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
 static void serial_throttle (struct tty_struct * tty)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial;
-       
-       dbg("serial_throttle");
-       
-       if (port_paranoia_check (port, "serial_throttle")) {
-               return;
-       }
-       
-       serial = port->serial;
-       if (serial_paranoia_check (serial, "serial_throttle")) {
+       struct usb_serial *serial = get_usb_serial (port, "serial_throttle");
+
+       if (!serial) {
                return;
        }
-       
+
        dbg("serial_throttle port %d", port->number);
-       
+
        if (!port->active) {
                dbg ("port not open");
                return;
@@ -612,21 +594,14 @@ static void serial_throttle (struct tty_struct * tty)
 static void serial_unthrottle (struct tty_struct * tty)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial;
-       
-       dbg("serial_unthrottle");
-       
-       if (port_paranoia_check (port, "serial_unthrottle")) {
-               return;
-       }
-       
-       serial = port->serial;
-       if (serial_paranoia_check (serial, "serial_unthrottle")) {
+       struct usb_serial *serial = get_usb_serial (port, "serial_unthrottle");
+
+       if (!serial) {
                return;
        }
-       
+
        dbg("serial_unthrottle port %d", port->number);
-       
+
        if (!port->active) {
                dbg ("port not open");
                return;
@@ -644,21 +619,14 @@ static void serial_unthrottle (struct tty_struct * tty)
 static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial;
-       
-       dbg("serial_ioctl");
-       
-       if (port_paranoia_check (port, "serial_ioctl")) {
-               return -ENODEV;
-       }
+       struct usb_serial *serial = get_usb_serial (port, "serial_ioctl");
 
-       serial = port->serial;
-       if (serial_paranoia_check (serial, "serial_ioctl")) {
+       if (!serial) {
                return -ENODEV;
        }
-       
+
        dbg("serial_ioctl port %d", port->number);
-       
+
        if (!port->active) {
                dbg ("port not open");
                return -ENODEV;
@@ -676,16 +644,9 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
 static void serial_set_termios (struct tty_struct *tty, struct termios * old)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial;
-       
-       dbg("serial_set_termios");
-       
-       if (port_paranoia_check (port, "serial_set_termios")) {
-               return;
-       }
+       struct usb_serial *serial = get_usb_serial (port, "serial_set_termios");
 
-       serial = port->serial;
-       if (serial_paranoia_check (serial, "serial_set_termios")) {
+       if (!serial) {
                return;
        }
 
@@ -708,16 +669,9 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
 static void serial_break (struct tty_struct *tty, int break_state)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial;
-       
-       dbg("serial_break");
-       
-       if (port_paranoia_check (port, "serial_break")) {
-               return;
-       }
+       struct usb_serial *serial = get_usb_serial (port, "serial_break");
 
-       serial = port->serial;
-       if (serial_paranoia_check (serial, "serial_break")) {
+       if (!serial) {
                return;
        }
 
@@ -861,22 +815,15 @@ static int generic_chars_in_buffer (struct usb_serial_port *port)
 static void generic_read_bulk_callback (struct urb *urb)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-       struct usb_serial *serial;
-               struct tty_struct *tty;
-               unsigned char *data = urb->transfer_buffer;
+       struct usb_serial *serial = get_usb_serial (port, "generic_read_bulk_callback");
+       struct tty_struct *tty;
+       unsigned char *data = urb->transfer_buffer;
        int i;
 
-       dbg("generic_read_bulk_callback");
-
-       if (port_paranoia_check (port, "generic_read_bulk_callback")) {
+       if (!serial) {
                return;
        }
 
-       serial = port->serial;
-       if (serial_paranoia_check (serial, "generic_read_bulk_callback")) {
-               return;
-       }
-       
        if (urb->status) {
                dbg("nonzero read bulk status received: %d", urb->status);
                return;
@@ -911,20 +858,13 @@ static void generic_read_bulk_callback (struct urb *urb)
 static void generic_write_bulk_callback (struct urb *urb)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-       struct usb_serial *serial;
-               struct tty_struct *tty;
-
-       dbg("generic_write_bulk_callback");
+       struct usb_serial *serial = get_usb_serial (port, "generic_write_bulk_callback");
+       struct tty_struct *tty;
 
-       if (port_paranoia_check (port, "generic_write_bulk_callback")) {
+       if (!serial) {
                return;
        }
 
-       serial = port->serial;
-       if (serial_paranoia_check (serial, "generic_write_bulk_callback")) {
-               return;
-       }
-       
        if (urb->status) {
                dbg("nonzero write bulk status received: %d", urb->status);
                return;
index 6832814da8115a33f2db0cec06d1d4b2c84d4895..77f1199eb5ec4c2bc5fc36cb6735b4670be767a3 100644 (file)
@@ -11,6 +11,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (04/27/2000) Ryan VanderBijl
+ *     Fixed memory leak in visor_close
+ *
  * (03/26/2000) gkh
  *     Split driver up into device specific pieces.
  * 
@@ -110,6 +113,7 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
                /* send a shutdown message to the device */
                usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
                                0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+               kfree (transfer_buffer);
        }
 
        /* shutdown our bulk reads and writes */
index 9c9b3816741543899244c0e71062b4714670194b..e6f3a55c789d9c30ca0897dcf980569ec86ba8e9 100644 (file)
@@ -81,12 +81,9 @@ static void urb_rm_priv (urb_t * urb)
 {
        urb_priv_t * urb_priv = urb->hcpriv;
        int i;
-       void * wait;
        
        if (!urb_priv) return;
        
-       wait = urb_priv->wait;
-       
        for (i = 0; i < urb_priv->length; i++) {
                if (urb_priv->td [i]) {
                        OHCI_FREE (urb_priv->td [i]);
@@ -94,11 +91,8 @@ static void urb_rm_priv (urb_t * urb)
        }
        kfree (urb->hcpriv);
        urb->hcpriv = NULL;
-       
-       if (wait) {
-               add_wait_queue (&op_wakeup, wait); 
-               wake_up (&op_wakeup);
-       }
+
+       wake_up (&op_wakeup);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -476,7 +470,6 @@ static int sohci_submit_urb (urb_t * urb)
        urb_priv->td_cnt = 0;
        urb_priv->state = 0;
        urb_priv->ed = ed;      
-       urb_priv->wait = NULL;
        
        /* allocate the TDs */
        for (i = 0; i < size; i++) { 
@@ -540,20 +533,20 @@ static int sohci_unlink_urb (urb_t * urb)
                if (urb->status == USB_ST_URB_PENDING) { /* URB active? */
                        urb_priv_t  * urb_priv = urb->hcpriv;
                        urb_priv->state = URB_DEL; 
+
                        /* we want to delete the TDs of an URB from an ed 
                         * request the deletion, it will be handled at the next USB-frame */
-                       urb_priv->wait = &wait;
                        
                        spin_lock_irqsave (&usb_ed_lock, flags);
                        ep_rm_ed (urb->dev, urb_priv->ed);
                        urb_priv->ed->state |= ED_URB_DEL;
                        spin_unlock_irqrestore (&usb_ed_lock, flags);
 
+                       add_wait_queue (&op_wakeup, &wait);
                        current->state = TASK_UNINTERRUPTIBLE;
-                       if(schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
-                               remove_wait_queue (&op_wakeup, &wait); 
-                       else
+                       if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
                                err("unlink URB timeout!");
+                       remove_wait_queue (&op_wakeup, &wait); 
                } else 
                        urb_rm_priv (urb);
                usb_dec_dev_use (urb->dev);             
@@ -611,7 +604,7 @@ static int sohci_free_dev (struct usb_device * usb_dev)
                spin_unlock_irqrestore (&usb_ed_lock, flags);
                
                if (cnt > 0) {
-                       dev->wait = &wait;
+                       add_wait_queue (&op_wakeup, &wait);
                        current->state = TASK_UNINTERRUPTIBLE;
                        schedule_timeout (HZ / 10);
                        remove_wait_queue (&op_wakeup, &wait);
@@ -1160,10 +1153,8 @@ static void dl_del_list (ohci_t  * ohci, unsigned int frame)
                        ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 
                        ed->state = ED_NEW; 
                        /* if all eds are removed wake up sohci_free_dev */
-                       if ((! --dev->ed_cnt) && dev->wait) {
-                               add_wait_queue (&op_wakeup, dev->wait); 
+                       if (!--dev->ed_cnt)
                                wake_up (&op_wakeup);
-                       }
                }
                else {
                        ed->state &= ~ED_URB_DEL;
@@ -1924,21 +1915,9 @@ static int hc_start_ohci (struct pci_dev * dev)
 {
        unsigned long mem_base;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
        mem_base = dev->resource[0].start;
        if (pci_enable_device(dev) < 0)
                return -ENODEV;
-#else
-       u16 cmd;
-
-       mem_base = dev->base_address[0];
-       if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV;
-       mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
-
-       /* Some Mac firmware will switch memory response off */
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
-#endif
        
        pci_set_master (dev);
        mem_base = (unsigned long) ioremap_nocache (mem_base, 4096);
@@ -1998,15 +1977,15 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
        if (ohci) {
                switch (rqst) {
                case PM_SUSPEND:
-                       dbg("USB-Bus suspend: %p", ohci->regs);
-                       if (ohci->bus->root_hub)
-                               usb_disconnect (&ohci->bus->root_hub);
-                       hc_reset (ohci);
+                       dbg("USB-Bus suspend: %p", ohci);
+                       writel (ohci->hc_control = 0xFF, &ohci->regs->control);
+                       wait_ms (10);
                        break;
                case PM_RESUME:
-                       dbg("USB-Bus resume: %p", ohci->regs);
-                       if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0)
-                               err ("can't restart controller, %d", temp);
+                       dbg("USB-Bus resume: %p", ohci);
+                       writel (ohci->hc_control = 0x7F, &ohci->regs->control);
+                       wait_ms (20);
+                       writel (ohci->hc_control = 0xBF, &ohci->regs->control);
                        break;
                }
        }
index b9c09f0d8cd10ecaad767e4f60fb25f85a13b405..8a33186128fca0e517decaba366afa67e37d34f0 100644 (file)
@@ -29,9 +29,7 @@
 #include <linux/interrupt.h>   /* for in_interrupt() */
 #include <linux/init.h>
 #include <linux/version.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,44)
 #include <linux/pm.h>
-#endif
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -2634,7 +2632,6 @@ _static int __init uhci_start_usb (uhci_t *s)
        return 0;
 }
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,44)
 _static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
 {
        uhci_t *s = (uhci_t*) dev->data;
@@ -2651,7 +2648,6 @@ _static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
        }
        return 0;
 }
-#endif
 
 _static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
 {
@@ -2754,11 +2750,11 @@ _static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_add
 
        //chain new uhci device into global list
        devs = s;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,44)
+
        pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(dev), handle_pm_event);
        if (pmdev)
                pmdev->data = s;
-#endif
+
        return 0;
 }
 
@@ -2768,19 +2764,12 @@ _static int __init start_uhci (struct pci_dev *dev)
 
        /* Search for the IO base address.. */
        for (i = 0; i < 6; i++) {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
+
                unsigned int io_addr = dev->resource[i].start;
                unsigned int io_size =
                dev->resource[i].end - dev->resource[i].start + 1;
                if (!(dev->resource[i].flags & 1))
                        continue;
-#else
-               unsigned int io_addr = dev->base_address[i];
-               unsigned int io_size = 0x14;
-               if (!(io_addr & 1))
-                       continue;
-               io_addr &= ~1;
-#endif
 
                /* Is it already in use? */
                if (check_region (io_addr, io_size))
@@ -2835,10 +2824,10 @@ int __init uhci_init (void)
                if (type != 0)
                        continue;
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
+
                if (pci_enable_device (dev) < 0)
                        continue;
-#endif
+
                if(!dev->irq)
                {
                        err("Found UHCI device with no IRQ assigned. Check BIOS settings!");
@@ -2879,9 +2868,7 @@ int init_module (void)
 
 void cleanup_module (void)
 {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,44)
        pm_unregister_all (handle_pm_event);
-#endif
        uhci_cleanup ();
 }
 
index cfadced52c39d662eefbcd1f43c7509245670fed..ce33bef82fc25e826c7ef5feade0590cdd95630f 100644 (file)
  * generic VGA port read/write
  */
  
-extern inline unsigned char vga_io_r (unsigned short port)
+static inline unsigned char vga_io_r (unsigned short port)
 {
        return inb (port);
 }
 
-extern inline void vga_io_w (unsigned short port, unsigned char val)
+static inline void vga_io_w (unsigned short port, unsigned char val)
 {
        outb (val, port);
 }
 
-extern inline void vga_io_w_fast (unsigned short port, unsigned char reg,
+static inline void vga_io_w_fast (unsigned short port, unsigned char reg,
                                  unsigned char val)
 {
        outw (VGA_OUT16VAL (val, reg), port);
 }
 
-extern inline unsigned char vga_mm_r (caddr_t regbase, unsigned short port)
+static inline unsigned char vga_mm_r (caddr_t regbase, unsigned short port)
 {
        return readb (regbase + port);
 }
 
-extern inline void vga_mm_w (caddr_t regbase, unsigned short port, unsigned char val)
+static inline void vga_mm_w (caddr_t regbase, unsigned short port, unsigned char val)
 {
        writeb (val, regbase + port);
 }
 
-extern inline void vga_mm_w_fast (caddr_t regbase, unsigned short port,
+static inline void vga_mm_w_fast (caddr_t regbase, unsigned short port,
                                  unsigned char reg, unsigned char val)
 {
        writew (VGA_OUT16VAL (val, reg), regbase + port);
 }
 
-extern inline unsigned char vga_r (caddr_t regbase, unsigned short port)
+static inline unsigned char vga_r (caddr_t regbase, unsigned short port)
 {
        if (regbase)
                return vga_mm_r (regbase, port);
@@ -219,7 +219,7 @@ extern inline unsigned char vga_r (caddr_t regbase, unsigned short port)
                return vga_io_r (port);
 }
 
-extern inline void vga_w (caddr_t regbase, unsigned short port, unsigned char val)
+static inline void vga_w (caddr_t regbase, unsigned short port, unsigned char val)
 {
        if (regbase)
                vga_mm_w (regbase, port, val);
@@ -228,7 +228,7 @@ extern inline void vga_w (caddr_t regbase, unsigned short port, unsigned char va
 }
 
 
-extern inline void vga_w_fast (caddr_t regbase, unsigned short port,
+static inline void vga_w_fast (caddr_t regbase, unsigned short port,
                               unsigned char reg, unsigned char val)
 {
        if (regbase)
@@ -242,13 +242,13 @@ extern inline void vga_w_fast (caddr_t regbase, unsigned short port,
  * VGA CRTC register read/write
  */
  
-extern inline unsigned char vga_rcrt (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_rcrt (caddr_t regbase, unsigned char reg)
 {
         vga_w (regbase, VGA_CRT_IC, reg);
         return vga_r (regbase, VGA_CRT_DC);
 }
 
-extern inline void vga_wcrt (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_wcrt (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
        vga_w_fast (regbase, VGA_CRT_IC, reg, val);
@@ -258,13 +258,13 @@ extern inline void vga_wcrt (caddr_t regbase, unsigned char reg, unsigned char v
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_io_rcrt (unsigned char reg)
+static inline unsigned char vga_io_rcrt (unsigned char reg)
 {
         vga_io_w (VGA_CRT_IC, reg);
         return vga_io_r (VGA_CRT_DC);
 }
 
-extern inline void vga_io_wcrt (unsigned char reg, unsigned char val)
+static inline void vga_io_wcrt (unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
        vga_io_w_fast (VGA_CRT_IC, reg, val);
@@ -274,13 +274,13 @@ extern inline void vga_io_wcrt (unsigned char reg, unsigned char val)
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_mm_rcrt (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_mm_rcrt (caddr_t regbase, unsigned char reg)
 {
         vga_mm_w (regbase, VGA_CRT_IC, reg);
         return vga_mm_r (regbase, VGA_CRT_DC);
 }
 
-extern inline void vga_mm_wcrt (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_mm_wcrt (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
        vga_mm_w_fast (regbase, VGA_CRT_IC, reg, val);
@@ -295,13 +295,13 @@ extern inline void vga_mm_wcrt (caddr_t regbase, unsigned char reg, unsigned cha
  * VGA sequencer register read/write
  */
  
-extern inline unsigned char vga_rseq (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_rseq (caddr_t regbase, unsigned char reg)
 {
         vga_w (regbase, VGA_SEQ_I, reg);
         return vga_r (regbase, VGA_SEQ_D);
 }
 
-extern inline void vga_wseq (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_wseq (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
        vga_w_fast (regbase, VGA_SEQ_I, reg, val);
@@ -311,13 +311,13 @@ extern inline void vga_wseq (caddr_t regbase, unsigned char reg, unsigned char v
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_io_rseq (unsigned char reg)
+static inline unsigned char vga_io_rseq (unsigned char reg)
 {
         vga_io_w (VGA_SEQ_I, reg);
         return vga_io_r (VGA_SEQ_D);
 }
 
-extern inline void vga_io_wseq (unsigned char reg, unsigned char val)
+static inline void vga_io_wseq (unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
        vga_io_w_fast (VGA_SEQ_I, reg, val);
@@ -327,13 +327,13 @@ extern inline void vga_io_wseq (unsigned char reg, unsigned char val)
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_mm_rseq (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_mm_rseq (caddr_t regbase, unsigned char reg)
 {
         vga_mm_w (regbase, VGA_SEQ_I, reg);
         return vga_mm_r (regbase, VGA_SEQ_D);
 }
 
-extern inline void vga_mm_wseq (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_mm_wseq (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
        vga_mm_w_fast (regbase, VGA_SEQ_I, reg, val);
@@ -349,13 +349,13 @@ extern inline void vga_mm_wseq (caddr_t regbase, unsigned char reg, unsigned cha
  * VGA graphics controller register read/write
  */
  
-extern inline unsigned char vga_rgfx (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_rgfx (caddr_t regbase, unsigned char reg)
 {
         vga_w (regbase, VGA_GFX_I, reg);
         return vga_r (regbase, VGA_GFX_D);
 }
 
-extern inline void vga_wgfx (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_wgfx (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
        vga_w_fast (regbase, VGA_GFX_I, reg, val);
@@ -365,13 +365,13 @@ extern inline void vga_wgfx (caddr_t regbase, unsigned char reg, unsigned char v
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_io_rgfx (unsigned char reg)
+static inline unsigned char vga_io_rgfx (unsigned char reg)
 {
         vga_io_w (VGA_GFX_I, reg);
         return vga_io_r (VGA_GFX_D);
 }
 
-extern inline void vga_io_wgfx (unsigned char reg, unsigned char val)
+static inline void vga_io_wgfx (unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
        vga_io_w_fast (VGA_GFX_I, reg, val);
@@ -381,13 +381,13 @@ extern inline void vga_io_wgfx (unsigned char reg, unsigned char val)
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_mm_rgfx (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_mm_rgfx (caddr_t regbase, unsigned char reg)
 {
         vga_mm_w (regbase, VGA_GFX_I, reg);
         return vga_mm_r (regbase, VGA_GFX_D);
 }
 
-extern inline void vga_mm_wgfx (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_mm_wgfx (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
        vga_mm_w_fast (regbase, VGA_GFX_I, reg, val);
@@ -402,37 +402,37 @@ extern inline void vga_mm_wgfx (caddr_t regbase, unsigned char reg, unsigned cha
  * VGA attribute controller register read/write
  */
  
-extern inline unsigned char vga_rattr (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_rattr (caddr_t regbase, unsigned char reg)
 {
         vga_w (regbase, VGA_ATT_IW, reg);
         return vga_r (regbase, VGA_ATT_R);
 }
 
-extern inline void vga_wattr (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_wattr (caddr_t regbase, unsigned char reg, unsigned char val)
 {
         vga_w (regbase, VGA_ATT_IW, reg);
         vga_w (regbase, VGA_ATT_W, val);
 }
 
-extern inline unsigned char vga_io_rattr (unsigned char reg)
+static inline unsigned char vga_io_rattr (unsigned char reg)
 {
         vga_io_w (VGA_ATT_IW, reg);
         return vga_io_r (VGA_ATT_R);
 }
 
-extern inline void vga_io_wattr (unsigned char reg, unsigned char val)
+static inline void vga_io_wattr (unsigned char reg, unsigned char val)
 {
         vga_io_w (VGA_ATT_IW, reg);
         vga_io_w (VGA_ATT_W, val);
 }
 
-extern inline unsigned char vga_mm_rattr (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_mm_rattr (caddr_t regbase, unsigned char reg)
 {
         vga_mm_w (regbase, VGA_ATT_IW, reg);
         return vga_mm_r (regbase, VGA_ATT_R);
 }
 
-extern inline void vga_mm_wattr (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_mm_wattr (caddr_t regbase, unsigned char reg, unsigned char val)
 {
         vga_mm_w (regbase, VGA_ATT_IW, reg);
         vga_mm_w (regbase, VGA_ATT_W, val);
index 6dc3e4f60dd0948bf0e4d748727ed29595e8a022..44c761901a1057ef7f3a501983cc86daaae9e9bd 100644 (file)
@@ -80,11 +80,11 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
                        continue;
                }
 
-               if ( !is_root_busy(dentry->d_mounts) ) {
+               if ( may_umount(dentry->d_mounts->d_sb) == 0 ) {
                        DPRINTK(("autofs: signaling expire on %s\n", ent->name));
                        return ent; /* Expirable! */
                }
-               DPRINTK(("autofs: didn't expire due to is_root_busy: %s\n", ent->name));
+               DPRINTK(("autofs: didn't expire due to may_umount: %s\n", ent->name));
        }
        return NULL;            /* No expirable entries */
 }
index e93557db8193a9942dd835b778622d423e9646bd..8a8767faa4a1d3cb1d0aaa782aa1dc6460f025ca 100644 (file)
@@ -76,14 +76,20 @@ resume:
                /* Decrement count for unused children */
                count += (dentry->d_count - 1);
 
-               /* Mountpoints don't count (either mountee or mounter) */
-               if (d_mountpoint(dentry) ||
-                   dentry != dentry->d_covers) {
+               /* Mountpoints don't count */
+               if (d_mountpoint(dentry)) {
                        DPRINTK(("is_tree_busy: mountpoint dentry=%p covers=%p mounts=%p\n",
                                 dentry, dentry->d_covers, dentry->d_mounts));
                        adj++;
                }
 
+               /* ... and roots - twice as much... */
+               if (dentry != dentry->d_covers) {
+                       DPRINTK(("is_tree_busy: mountpoint dentry=%p covers=%p mounts=%p\n",
+                                dentry, dentry->d_covers, dentry->d_mounts));
+                       adj+=2;
+               }
+
                /* Ignore autofs's extra reference */
                if (is_autofs4_dentry(dentry)) {
                        DPRINTK(("is_tree_busy: autofs\n"));
index 3caf950eb63c287efd98b410953f9aa508aa503a..001b1024d2b57021bf9f1289f226cf059f351dd9 100644 (file)
@@ -337,25 +337,27 @@ repeat:
        }
 }
 
+/*
+ * Search for at least 1 mount point in the dentry's subdirs.
+ * We descend to the next level whenever the d_subdirs
+ * list is non-empty and continue searching.
+ */
 /**
- * is_root_busy - check if a root dentry could be freed
- * @root: Dentry to work down from
- *
- * Check whether a root dentry would be in use if all of its
- * child dentries were freed. This allows a non-destructive
- * test for unmounting a device.
+ * have_submounts - check for mounts over a dentry
+ * @parent: dentry to check.
  *
- * Return non zero if the root is still busy.
+ * Return true if the parent or its subdirectories contain
+ * a mount point
  */
  
-int is_root_busy(struct dentry *root)
+int have_submounts(struct dentry *parent)
 {
-       struct dentry *this_parent = root;
+       struct dentry *this_parent = parent;
        struct list_head *next;
-       int count = root->d_count;
-
-       check_lock();
 
+       if (d_mountpoint(parent))
+               return 1;
 repeat:
        next = this_parent->d_subdirs.next;
 resume:
@@ -363,48 +365,31 @@ resume:
                struct list_head *tmp = next;
                struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
                next = tmp->next;
-               /* Decrement count for unused children */
-               count += (dentry->d_count - 1);
+               /* Have we found a mount point ? */
+               if (d_mountpoint(dentry))
+                       return 1;
                if (!list_empty(&dentry->d_subdirs)) {
                        this_parent = dentry;
                        goto repeat;
                }
-               /* root is busy if any leaf is busy */
-               if (dentry->d_count)
-                       return 1;
        }
        /*
         * All done at this level ... ascend and resume the search.
         */
-       if (this_parent != root) {
+       if (this_parent != parent) {
                next = this_parent->d_child.next; 
                this_parent = this_parent->d_parent;
                goto resume;
        }
-       return (count > 1); /* remaining users? */
+       return 0; /* No mount points found in tree */
 }
 
-/*
- * Search for at least 1 mount point in the dentry's subdirs.
- * We descend to the next level whenever the d_subdirs
- * list is non-empty and continue searching.
- */
-/**
- * have_submounts - check for mounts over a dentry
- * @parent: dentry to check.
- *
- * Return true if the parent or its subdirectories contain
- * a mount point
- */
-int have_submounts(struct dentry *parent)
+int d_active_refs(struct dentry *root)
 {
-       struct dentry *this_parent = parent;
+       struct dentry *this_parent = root;
        struct list_head *next;
+       int count = root->d_count;
 
-       if (d_mountpoint(parent))
-               return 1;
 repeat:
        next = this_parent->d_subdirs.next;
 resume:
@@ -412,9 +397,8 @@ resume:
                struct list_head *tmp = next;
                struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
                next = tmp->next;
-               /* Have we found a mount point ? */
-               if (d_mountpoint(dentry))
-                       return 1;
+               /* Decrement count for unused children */
+               count += (dentry->d_count - 1);
                if (!list_empty(&dentry->d_subdirs)) {
                        this_parent = dentry;
                        goto repeat;
@@ -423,12 +407,12 @@ resume:
        /*
         * All done at this level ... ascend and resume the search.
         */
-       if (this_parent != parent) {
+       if (this_parent != root) {
                next = this_parent->d_child.next; 
                this_parent = this_parent->d_parent;
                goto resume;
        }
-       return 0; /* No mount points found in tree */
+       return count;
 }
 
 /*
@@ -576,6 +560,7 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
                
        dentry->d_mounts = dentry;
        dentry->d_covers = dentry;
+       INIT_LIST_HEAD(&dentry->d_vfsmnt);
        INIT_LIST_HEAD(&dentry->d_hash);
        INIT_LIST_HEAD(&dentry->d_lru);
        INIT_LIST_HEAD(&dentry->d_subdirs);
@@ -895,6 +880,7 @@ char * __d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
 {
        char * end = buffer+buflen;
        char * retval;
+       int namelen;
 
        *--end = '\0';
        buflen--;
@@ -910,14 +896,18 @@ char * __d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
 
        for (;;) {
                struct dentry * parent;
-               int namelen;
 
-               if (dentry == root)
+               if (dentry == root && vfsmnt == rootmnt)
                        break;
-               dentry = dentry->d_covers;
+               if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
+                       /* Global root? */
+                       if (vfsmnt->mnt_parent == vfsmnt)
+                               goto global_root;
+                       dentry = vfsmnt->mnt_mountpoint;
+                       vfsmnt = vfsmnt->mnt_parent;
+                       continue;
+               }
                parent = dentry->d_parent;
-               if (dentry == parent)
-                       break;
                namelen = dentry->d_name.len;
                buflen -= namelen + 1;
                if (buflen < 0)
@@ -929,6 +919,14 @@ char * __d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
                dentry = parent;
        }
        return retval;
+global_root:
+       namelen = dentry->d_name.len;
+       buflen -= namelen;
+       if (buflen >= 0) {
+               end -= namelen;
+               memcpy(end, dentry->d_name.name, namelen);
+       }
+       return end;
 }
 
 /*
index 7a94b38ddec0ecb69957d31d4c052a551008f55f..57302fa7bc698a8455db3008a7f385e427e87647 100644 (file)
@@ -11,6 +11,8 @@
 /* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname
  * lookup logic.
  */
+/* [Feb-Apr 2000, AV] Rewrite to the new namespace architecture.
+ */
 
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 
 #include <asm/namei.h>
 
-/* This can be removed after the beta phase. */
-#define CACHE_SUPERVISE        /* debug the correctness of dcache entries */
-#undef DEBUG           /* some other debugging */
-
-
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
 /* [Feb-1997 T. Schoebel-Theuer]
  * [10-Sep-98 Alan Modra] Another symlink change.
  */
 
+/* [Feb-Apr 2000 AV] Complete rewrite. Rules for symlinks:
+ *     inside the path - always follow.
+ *     in the last component in creation/removal/renaming - never follow.
+ *     if LOOKUP_FOLLOW passed - follow.
+ *     if the pathname has trailing slashes - follow.
+ *     otherwise - don't follow.
+ * (applied in that order).
+ */
+
 /* In order to reduce some races, while at the same time doing additional
  * checking and hopefully speeding things up, we copy filenames to the
  * kernel data space before using them..
@@ -270,14 +276,45 @@ loop:
        return -ELOOP;
 }
 
-static inline int follow_down(struct dentry ** dentry, struct vfsmount **mnt)
+static inline int follow_up(struct vfsmount **mnt, struct dentry **base)
 {
-       struct dentry * parent = dget((*dentry)->d_mounts);
-       dput(*dentry);
-       *dentry = parent;
+       struct vfsmount *parent=(*mnt)->mnt_parent;
+       struct dentry *dentry;
+       if (parent == *mnt)
+               return 0;
+       dentry=dget((*mnt)->mnt_mountpoint);
+       mntget(parent);
+       mntput(*mnt);
+       *mnt = parent;
+       dput(*base);
+       *base = dentry;
        return 1;
 }
 
+static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry)
+{
+       struct list_head *p = (*dentry)->d_vfsmnt.next;
+       while (p != &(*dentry)->d_vfsmnt) {
+               struct vfsmount *tmp;
+               tmp = list_entry(p, struct vfsmount, mnt_clash);
+               if (tmp->mnt_parent == *mnt) {
+                       *mnt = mntget(tmp);
+                       mntput(tmp->mnt_parent);
+                       /* tmp holds the mountpoint, so... */
+                       dput(*dentry);
+                       *dentry = dget(tmp->mnt_root);
+                       return 1;
+               }
+               p = p->next;
+       }
+       return 0;
+}
+
+int follow_down(struct vfsmount **mnt, struct dentry **dentry)
+{
+       return __follow_down(mnt,dentry);
+}
+
 /*
  * Name resolution.
  *
@@ -343,12 +380,20 @@ int walk_name(const char * name, struct nameidata *nd)
                        case 2: 
                                if (this.name[1] != '.')
                                        break;
-                               if (nd->dentry != current->fs->root) {
-                                       dentry = dget(nd->dentry->d_covers->d_parent);
-                                       dput(nd->dentry);
-                                       nd->dentry = dentry;
-                                       inode = dentry->d_inode;
+                               while (1) {
+                                       if (nd->dentry == current->fs->root &&
+                                           nd->mnt == current->fs->rootmnt)
+                                               break;
+                                       if (nd->dentry != nd->mnt->mnt_root) {
+                                               dentry = dget(nd->dentry->d_parent);
+                                               dput(nd->dentry);
+                                               nd->dentry = dentry;
+                                               break;
+                                       }
+                                       if (!follow_up(&nd->mnt, &nd->dentry))
+                                               break;
                                }
+                               inode = nd->dentry->d_inode;
                                /* fallthrough */
                        case 1:
                                continue;
@@ -371,7 +416,7 @@ int walk_name(const char * name, struct nameidata *nd)
                                break;
                }
                /* Check mountpoints.. */
-               while (d_mountpoint(dentry) && follow_down(&dentry, &nd->mnt))
+               while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
                        ;
 
                err = -ENOENT;
@@ -415,12 +460,20 @@ last_component:
                        case 2: 
                                if (this.name[1] != '.')
                                        break;
-                               if (nd->dentry != current->fs->root) {
-                                       dentry = dget(nd->dentry->d_covers->d_parent);
-                                       dput(nd->dentry);
-                                       nd->dentry = dentry;
-                                       inode = dentry->d_inode;
+                               while (1) {
+                                       if (nd->dentry == current->fs->root &&
+                                           nd->mnt == current->fs->rootmnt)
+                                               break;
+                                       if (nd->dentry != nd->mnt->mnt_root) {
+                                               dentry = dget(nd->dentry->d_parent);
+                                               dput(nd->dentry);
+                                               nd->dentry = dentry;
+                                               break;
+                                       }
+                                       if (!follow_up(&nd->mnt, &nd->dentry))
+                                               break;
                                }
+                               inode = nd->dentry->d_inode;
                                /* fallthrough */
                        case 1:
                                goto return_base;
@@ -437,7 +490,7 @@ last_component:
                        if (IS_ERR(dentry))
                                break;
                }
-               while (d_mountpoint(dentry) && follow_down(&dentry, &nd->mnt))
+               while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
                        ;
                inode = dentry->d_inode;
                if ((lookup_flags & LOOKUP_FOLLOW)
index cb6134ca1ff00e20c014b720aff06ca5cf5350ce..a664046a435dc930248d9b07d32c2161da4be055 100644 (file)
@@ -92,7 +92,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
 {
        struct svc_export       *exp;
        struct dentry           *dparent;
-       struct nameidata nd;
+       struct dentry           *dentry;
        int                     err;
 
        dprintk("nfsd: nfsd_lookup(fh %s, %s)\n", SVCFH_fmt(fhp), name);
@@ -113,59 +113,50 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
        err = nfserr_acces;
 
        /* Lookup the name, but don't follow links */
-       if (strcmp(name, "..")==0) {
+       if (strcmp(name, ".")==0) {
+               dentry = dget(dparent);
+       } else if (strcmp(name, "..")==0) {
                /* checking mountpoint crossing is very different when stepping up */
                if (dparent == exp->ex_dentry) {
                        if (!EX_CROSSMNT(exp))
-                               nd.dentry = dget(dparent); /* .. == . just like at / */
+                               dentry = dget(dparent); /* .. == . just like at / */
                        else
                        {
                                struct svc_export *exp2 = NULL;
                                struct dentry *dp;
-                               nd.dentry = dparent->d_covers->d_parent;
-                               for (dp=nd.dentry;
-                                    exp2 == NULL && dp->d_covers->d_parent != dp;
-                                    dp=dp->d_covers->d_parent)
+                               dentry = dparent->d_covers->d_parent;
+                               for (dp=dentry;
+                                    exp2 == NULL && dp->d_parent != dp;
+                                    dp=dp->d_parent)
                                        exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
-                               if (exp2==NULL || nd.dentry->d_sb != exp2->ex_dentry->d_sb) {
-                                       nd.dentry = dget(dparent);
+                               if (exp2==NULL || dentry->d_sb != exp2->ex_dentry->d_sb) {
+                                       dentry = dget(dparent);
                                } else {
-                                       dget(nd.dentry);
+                                       dget(dentry);
                                        exp = exp2;
                                }
                        }
                } else
-                       nd.dentry = dget(dparent->d_parent);
+                       dentry = dget(dparent->d_parent);
        } else {
-               nd.mnt = NULL;
-               nd.dentry = dget(dparent);
-               nd.flags = 0;
-               err = walk_name(name, &nd);
+               dentry = lookup_one(name, dparent);
+               err = PTR_ERR(dentry);
                if (err)
                        goto out_nfserr;
                /*
                 * check if we have crossed a mount point ...
                 */
-               if (nd.dentry->d_sb != dparent->d_sb) {
+               if (d_mountpoint(dentry)) {
                        struct svc_export *exp2 = NULL;
+                       struct dentry *mounts = dget(dentry->d_mounts);
                        exp2 = exp_get(rqstp->rq_client,
-                                      nd.dentry->d_inode->i_dev,
-                                      nd.dentry->d_inode->i_ino);
-                       if (exp2 && EX_CROSSMNT(exp2))
+                                      mounts->d_inode->i_dev,
+                                      mounts->d_inode->i_ino);
+                       if (exp2 && EX_CROSSMNT(exp2)) {
                                /* successfully crossed mount point */
                                exp = exp2;
-                       else if (nd.dentry->d_covers->d_sb == dparent->d_sb) {
-                               /* stay in the original filesystem */
-                               struct dentry *tdentry = dget(nd.dentry->d_covers);
-                               dput(nd.dentry);
-                               nd.dentry = tdentry;
-                       } else {
-                               /* This cannot possibly happen */
-                               printk("nfsd_lookup: %s/%s impossible mount point!\n", dparent->d_name.name, nd.dentry->d_name.name);
-                               dput(nd.dentry);
-                               err = nfserr_acces;
-                               goto out;
-
+                               dput(dentry);
+                               dentry = mounts;
                        }
                }
        }
@@ -173,8 +164,8 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
         * Note: we compose the file handle now, but as the
         * dentry may be negative, it may need to be updated.
         */
-       err = fh_compose(resfh, exp, nd.dentry);
-       if (!err && !nd.dentry->d_inode)
+       err = fh_compose(resfh, exp, dentry);
+       if (!err && !dentry->d_inode)
                err = nfserr_noent;
 out:
        return err;
index af01f02813321c1947f3697ff139d3f9acd84b25..8088d064d9038840059c02439583b10c16ef5126 100644 (file)
@@ -76,32 +76,12 @@ void __init proc_root_init(void)
 
 static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry)
 {
-       struct task_struct *p;
-
        if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
-               extern unsigned long total_forks;
-               static int last_timestamp = 0;
-
-               /*
-                * this one can be a serious 'ps' performance problem if
-                * there are many threads running - thus we do 'lazy'
-                * link-recalculation - we change it only if the number
-                * of threads has increased.
-                */
-               if (total_forks != last_timestamp) {
-                       int nlink = proc_root.nlink;
-
-                       read_lock(&tasklist_lock);
-                       last_timestamp = total_forks;
-                       for_each_task(p)
-                               nlink++;
-                       read_unlock(&tasklist_lock);
-                       /*
-                        * subtract the # of idle threads which
-                        * do not show up in /proc:
-                        */
-                       dir->i_nlink = nlink - smp_num_cpus;
-               }
+               int nlink = proc_root.nlink;
+
+               nlink += nr_threads;
+
+               dir->i_nlink = nlink;
        }
 
        if (!proc_lookup(dir, dentry))
index 141bde7d8e0094ed6ca281fd8c5897cf284c0314..7c8596822dff6c1b6ec18629bb6bf14819dd5217 100644 (file)
@@ -279,7 +279,11 @@ static struct file_system_type *get_fs_type(const char *name)
 static LIST_HEAD(vfsmntlist);
 
 static struct vfsmount *add_vfsmnt(struct super_block *sb,
-                       const char *dev_name, const char *dir_name)
+                               struct dentry *mountpoint,
+                               struct dentry *root,
+                               struct vfsmount *parent,
+                               const char *dev_name,
+                               const char *dir_name)
 {
        struct vfsmount *mnt;
        char *name;
@@ -289,8 +293,12 @@ static struct vfsmount *add_vfsmnt(struct super_block *sb,
                goto out;
        memset(mnt, 0, sizeof(struct vfsmount));
 
+       atomic_set(&mnt->mnt_count,1);
        mnt->mnt_sb = sb;
        mnt->mnt_dev = sb->s_dev;
+       mnt->mnt_mountpoint = dget(mountpoint);
+       mnt->mnt_root = dget(root);
+       mnt->mnt_parent = parent ? mntget(parent) : mnt;
 
        /* N.B. Is it really OK to have a vfsmount without names? */
        if (dev_name) {
@@ -308,26 +316,81 @@ static struct vfsmount *add_vfsmnt(struct super_block *sb,
                }
        }
 
+       list_add(&mnt->mnt_instances, &sb->s_mounts);
+       list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt);
        list_add(&mnt->mnt_list, vfsmntlist.prev);
+       mountpoint->d_mounts = root;
+       root->d_covers = mountpoint;
 out:
        return mnt;
 }
 
-void remove_vfsmnt(kdev_t dev)
+static void move_vfsmnt(struct vfsmount *mnt,
+                       struct dentry *mountpoint,
+                       struct vfsmount *parent,
+                       const char *dev_name,
+                       const char *dir_name)
 {
-       struct list_head *p, *next;
+       struct dentry *old_mountpoint = mnt->mnt_mountpoint;
+       struct vfsmount *old_parent = mnt->mnt_parent;
+       char *new_devname = NULL, *new_dirname = NULL;
 
-       for (p = vfsmntlist.next; p != &vfsmntlist; p = next) {
-               struct vfsmount *mnt = list_entry(p, struct vfsmount, mnt_list);
+       if (dev_name) {
+               new_devname = (char *) kmalloc(strlen(dev_name)+1, GFP_KERNEL);
+               if (new_devname)
+                       strcpy(new_devname, dev_name);
+       }
+       if (dir_name) {
+               new_dirname = (char *) kmalloc(strlen(dir_name)+1, GFP_KERNEL);
+               if (new_dirname)
+                       strcpy(new_dirname, dir_name);
+       }
 
-               next = p->next;
-               if (mnt->mnt_dev != dev)
-                       continue;
-               list_del(&mnt->mnt_list);
-               kfree(mnt->mnt_devname);
+       /* flip names */
+       if (new_dirname) {
                kfree(mnt->mnt_dirname);
-               kfree(mnt);
+               mnt->mnt_dirname = new_dirname;
        }
+       if (new_devname) {
+               kfree(mnt->mnt_devname);
+               mnt->mnt_devname = new_devname;
+       }
+
+       /* flip the linkage */
+       mnt->mnt_mountpoint = dget(mountpoint);
+       mnt->mnt_parent = parent ? mntget(parent) : mnt;
+       list_del(&mnt->mnt_clash);
+       list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt);
+
+       /* put the old stuff */
+       old_mountpoint->d_mounts = old_mountpoint;
+       mountpoint->d_mounts = mnt->mnt_sb->s_root;
+       mnt->mnt_sb->s_root->d_covers = mountpoint;
+       dput(old_mountpoint);
+       if (old_parent != mnt)
+               mntput(old_parent);
+}
+
+static void remove_vfsmnt(struct vfsmount *mnt)
+{
+       struct dentry * root = mnt->mnt_sb->s_root;
+       struct dentry * covered = mnt->mnt_mountpoint;
+       /* First of all, remove it from all lists */
+       list_del(&mnt->mnt_instances);
+       list_del(&mnt->mnt_clash);
+       list_del(&mnt->mnt_list);
+       /* Now we can work safely */
+       if (mnt->mnt_parent != mnt)
+               mntput(mnt->mnt_parent);
+
+       root->d_covers = root;
+       covered->d_mounts = covered;
+
+       dput(mnt->mnt_mountpoint);
+       dput(mnt->mnt_root);
+       kfree(mnt->mnt_devname);
+       kfree(mnt->mnt_dirname);
+       kfree(mnt);
 }
 
 static struct proc_fs_info {
@@ -375,9 +438,7 @@ int get_filesystem_info( char *buf )
        for (p = vfsmntlist.next; p!=&vfsmntlist && len < PAGE_SIZE - 160;
            p = p->next) {
                struct vfsmount *tmp = list_entry(p, struct vfsmount, mnt_list);
-               if (!tmp->mnt_sb || !tmp->mnt_sb->s_root)
-                       continue;
-               path = d_path(tmp->mnt_sb->s_root, tmp, buffer, PAGE_SIZE);
+               path = d_path(tmp->mnt_root, tmp, buffer, PAGE_SIZE);
                if (!path)
                        continue;
                len += sprintf( buf + len, "%s %s %s %s",
@@ -576,6 +637,7 @@ struct super_block *get_empty_super(void)
                list_add (&s->s_list, super_blocks.prev);
                init_waitqueue_head(&s->s_wait);
                INIT_LIST_HEAD(&s->s_files);
+               INIT_LIST_HEAD(&s->s_mounts);
        }
        return s;
 }
@@ -734,6 +796,8 @@ static struct block_device *kill_super(struct super_block *sb, int umount_root)
 {
        struct block_device *bdev;
        kdev_t dev;
+       dput(sb->s_root);
+       sb->s_root = NULL;
        lock_super(sb);
        if (sb->s_op) {
                if (sb->s_op->write_super && sb->s_dirt)
@@ -803,48 +867,55 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data)
        return 0;
 }
 
-static int d_umount(struct super_block * sb)
+/*
+ * Doesn't take quota and stuff into account. IOW, in some cases it will
+ * give false negatives. The main reason why it's here is that we need
+ * a non-destructive way to look for easily umountable filesystems.
+ */
+ /* MOUNT_REWRITE: it should take vfsmount, not superblock */
+int may_umount(struct super_block *sb)
 {
-       struct dentry * root = sb->s_root;
-       struct dentry * covered = root->d_covers;
+       struct dentry * root;
+       int count;
 
-       if (root->d_count != 1)
-               return -EBUSY;
+       root = sb->s_root;
 
-       if (root->d_inode->i_state)
+       count = d_active_refs(root);
+       if (root->d_covers == root)
+               count--;
+       if (count != 2)
                return -EBUSY;
 
-       sb->s_root = NULL;
-
-       if (covered != root) {
-               root->d_covers = root;
-               covered->d_mounts = covered;
-               dput(covered);
-       }
-       dput(root);
        return 0;
 }
 
-static void d_mount(struct dentry *covered, struct dentry *dentry)
+static int do_umount(struct vfsmount *mnt, int umount_root, int flags)
 {
-       if (covered->d_mounts != covered) {
-               printk("VFS: mount - already mounted\n");
-               return;
+       struct super_block * sb = mnt->mnt_sb;
+       int count;
+
+       if (mnt == current->fs->rootmnt && !umount_root) {
+               int retval = 0;
+               /*
+                * Special case for "unmounting" root ...
+                * we just try to remount it readonly.
+                */
+               mntput(mnt);
+               if (!(sb->s_flags & MS_RDONLY))
+                       retval = do_remount_sb(sb, MS_RDONLY, 0);
+               return retval;
        }
-       covered->d_mounts = dentry;
-       dentry->d_covers = covered;
-}
 
-static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags)
-{
-       struct super_block * sb;
-       struct block_device *bdev;
-       int retval;
-       
-       retval = -ENOENT;
-       sb = get_super(dev);
-       if (!sb || !sb->s_root)
-               goto out;
+       if (atomic_read(&mnt->mnt_count) > 2) {
+               mntput(mnt);
+               return -EBUSY;
+       }
+
+       if (mnt->mnt_instances.next != mnt->mnt_instances.prev) {
+               mntput(mnt);
+               remove_vfsmnt(mnt);
+               return 0;
+       }
 
        /*
         * Before checking whether the filesystem is still busy,
@@ -853,7 +924,7 @@ static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags)
         * are no quotas running any more. Just turn them on again.
         */
        DQUOT_OFF(sb);
-       acct_auto_close(dev);
+       acct_auto_close(sb->s_dev);
 
        /*
         * If we may have to abort operations to get out of this
@@ -864,7 +935,7 @@ static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags)
         * must return, and the like. Thats for the mount program to worry
         * about for the moment.
         */
-        
+
        if( (flags&MNT_FORCE) && sb->s_op->umount_begin)
                sb->s_op->umount_begin(sb);
 
@@ -875,52 +946,38 @@ static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags)
         * clean.
         */
        shrink_dcache_sb(sb);
-       fsync_dev(dev);
+       fsync_dev(sb->s_dev);
 
-       if (sb == current->fs->root->d_sb && !unmount_root) {
-               /*
-                * Special case for "unmounting" root ...
-                * we just try to remount it readonly.
-                */
-               retval = 0;
-               if (!(sb->s_flags & MS_RDONLY))
-                       retval = do_remount_sb(sb, MS_RDONLY, 0);
-               return ERR_PTR(retval);
-       }
+       /* Something might grab it again - redo checks */
 
-       retval = d_umount(sb);
-       if (retval)
-               goto out;
-       remove_vfsmnt(dev);
-       bdev = kill_super(sb, unmount_root);
-
-       return bdev;
-
-out:
-       return ERR_PTR(retval);
-}
-
-static int umount_dev(kdev_t dev, int flags)
-{
-       int retval;
-       struct block_device *bdev;
+       if (atomic_read(&mnt->mnt_count) > 2) {
+               mntput(mnt);
+               return -EBUSY;
+       }
+       /*
+        * OK, at that point we have only one instance. We should have
+        * one active reference from ->s_root, one active reference
+        * from ->mnt_root (which may be different) and possibly one
+        * active reference from ->mnt_mountpoint (if mnt->mnt_parent == mnt).
+        * Anything above that means that tree is busy.
+        */
 
-       retval = -ENXIO;
-       if (MAJOR(dev) >= MAX_BLKDEV)
-               goto out;
+       count = d_active_refs(sb->s_root);
+       if (mnt->mnt_parent == mnt)
+               count--;
+       if (count != 2)
+               return -EBUSY;
 
-       fsync_dev(dev);
+       if (sb->s_root->d_inode->i_state)
+               return -EBUSY;
 
-       down(&mount_sem);
+       /* OK, that's the point of no return */
+       mntput(mnt);
+       remove_vfsmnt(mnt);
 
-       bdev = do_umount(dev, 0, flags);
-       if (IS_ERR(bdev))
-               retval = PTR_ERR(bdev);
-       else
-               retval = 0;
-       up(&mount_sem);
-out:
-       return retval;
+       kill_super(sb, umount_root);
+       return 0;
 }
 
 /*
@@ -933,36 +990,39 @@ out:
 
 asmlinkage long sys_umount(char * name, int flags)
 {
-       struct dentry * dentry;
+       struct nameidata nd;
+       char *kname;
        int retval;
+       struct super_block *sb;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        lock_kernel();
-       dentry = namei(name);
-       retval = PTR_ERR(dentry);
-       if (!IS_ERR(dentry)) {
-               struct inode * inode = dentry->d_inode;
-               kdev_t dev = inode->i_rdev;
-
-               retval = 0;             
-               if (S_ISBLK(inode->i_mode)) {
-                       if (IS_NODEV(inode))
-                               retval = -EACCES;
-               } else {
-                       struct super_block *sb = inode->i_sb;
-                       retval = -EINVAL;
-                       if (sb && inode == sb->s_root->d_inode) {
-                               dev = sb->s_dev;
-                               retval = 0;
-                       }
-               }
-               dput(dentry);
-
-               if (!retval)
-                       retval = umount_dev(dev, flags);
-       }
+       kname = getname(name);
+       retval = PTR_ERR(kname);
+       if (IS_ERR(kname))
+               goto out;
+       retval = 0;
+       if (walk_init(kname, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd))
+               retval = walk_name(kname, &nd);
+       putname(kname);
+       if (retval)
+               goto out;
+       sb = nd.dentry->d_inode->i_sb;
+       retval = -EINVAL;
+       if (nd.dentry!=nd.mnt->mnt_root)
+               goto dput_and_out;
+       dput(nd.dentry);
+       /* puts nd.mnt */
+       down(&mount_sem);
+       retval = do_umount(nd.mnt, 0, flags);
+       up(&mount_sem);
+       goto out;
+dput_and_out:
+       dput(nd.dentry);
+       mntput(nd.mnt);
+out:
        unlock_kernel();
        return retval;
 }
@@ -976,19 +1036,6 @@ asmlinkage long sys_oldumount(char * name)
        return sys_umount(name,0);
 }
 
-/*
- * Check whether we can mount the specified device.
- */
-int fs_may_mount(kdev_t dev)
-{
-       struct super_block * sb = get_super(dev);
-       int busy;
-
-       busy = sb && sb->s_root &&
-              (sb->s_root->d_count != 1 || sb->s_root->d_covers != sb->s_root);
-       return !busy;
-}
-
 /*
  * change filesystem flags. dir should be a physical root of filesystem.
  * If you've mounted a non-root directory somewhere and want to do remount
@@ -1073,10 +1120,10 @@ long do_sys_mount(char * dev_name, char * dir_name, char *type_page,
                  unsigned long new_flags, void *data_page)
 {
        struct file_system_type * fstype;
-       struct dentry * dir_d;
+       struct nameidata nd;
        struct vfsmount *mnt;
        struct super_block *sb;
-       int retval;
+       int retval = 0;
        unsigned long flags = 0;
  
        /* Basic sanity checks */
@@ -1111,9 +1158,9 @@ long do_sys_mount(char * dev_name, char * dir_name, char *type_page,
                return -ENODEV;
 
        /* ... and mountpoint. Do the lookup first to force automounting. */
-       dir_d = lookup_dentry(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
-       retval = PTR_ERR(dir_d);
-       if (IS_ERR(dir_d))
+       if (walk_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))
+               retval = walk_name(dir_name, &nd);
+       if (retval)
                goto fs_out;
 
        /* get superblock, locks mount_sem on success */
@@ -1127,44 +1174,30 @@ long do_sys_mount(char * dev_name, char * dir_name, char *type_page,
                goto dput_out;
 
        retval = -ENOENT;
-       if (d_unhashed(dir_d))
+       if (d_unhashed(nd.dentry))
                goto fail;
 
-       retval = -ENOTDIR;
-       if (!S_ISDIR(dir_d->d_inode->i_mode))
-               goto fail;
-
-       retval = -EBUSY;
-       if (dir_d->d_covers != dir_d)
-               goto fail;
-
-       /*
-        * We may have slept while reading the super block, 
-        * so we check afterwards whether it's safe to mount.
-        */
-       retval = -EBUSY;
-       if (!fs_may_mount(sb->s_dev))
-               goto fail;
+       /* Something was mounted here while we slept */
+       while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry))
+               ;
 
        retval = -ENOMEM;
-       mnt = add_vfsmnt(sb, dev_name, dir_name);
+       mnt = add_vfsmnt(sb, nd.dentry, sb->s_root, nd.mnt, dev_name, dir_name);
        if (!mnt)
                goto fail;
-       d_mount(dget(dir_d), sb->s_root);
-
        retval = 0;
 unlock_out:
        up(&mount_sem);
 dput_out:
-       dput(dir_d);
+       dput(nd.dentry);
+       mntput(nd.mnt);
 fs_out:
        put_filesystem(fstype);
        return retval;
 
 fail:
-       dput(sb->s_root);
-       sb->s_root = NULL;
-       kill_super(sb, 0);
+       if (list_empty(&sb->s_mounts))
+               kill_super(sb, 0);
        goto unlock_out;
 }
 
@@ -1220,7 +1253,7 @@ void __init mount_root(void)
 {
        struct file_system_type * fs_type;
        struct super_block * sb;
-       struct vfsmount *vfsmnt = NULL;
+       struct vfsmount *vfsmnt;
        struct block_device *bdev = NULL;
        mode_t mode;
        int retval;
@@ -1330,6 +1363,11 @@ skip_nfs:
        }
 
        check_disk_change(ROOT_DEV);
+       sb = get_super(ROOT_DEV);
+       if (sb) {
+               fs_type = sb->s_type;
+               goto mount_it;
+       }
 
        spin_lock(&file_systems_lock);
        for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
@@ -1338,12 +1376,6 @@ skip_nfs:
                if (!try_inc_mod_count(fs_type->owner))
                        continue;
                spin_unlock(&file_systems_lock);
-               sb = get_super(ROOT_DEV);
-               if (sb) {
-                       /* Shouldn't we fail here? Oh, well... */
-                       sb->s_bdev = bdev;
-                       goto mount_it;
-               }
                sb = read_super(ROOT_DEV,bdev,fs_type,root_mountflags,NULL,1);
                if (sb) 
                        goto mount_it;
@@ -1355,8 +1387,6 @@ skip_nfs:
                kdevname(ROOT_DEV));
 
 mount_it:
-       set_fs_root(current->fs, vfsmnt, sb->s_root);
-       set_fs_pwd(current->fs, vfsmnt, sb->s_root);
        printk ("VFS: Mounted root (%s filesystem)%s.\n",
                fs_type->name,
                (sb->s_flags & MS_RDONLY) ? " readonly" : "");
@@ -1366,11 +1396,15 @@ mount_it:
                                  path + 5 + path_start, 0,
                                  NULL, NULL);
                memcpy (path + path_start, "/dev/", 5);
-               vfsmnt = add_vfsmnt (sb, path + path_start,
-                                    "/");
+               vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL,
+                                       path + path_start, "/");
        }
-       else vfsmnt = add_vfsmnt (sb, "/dev/root", "/");
+       else
+               vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL,
+                                       "/dev/root", "/");
        if (vfsmnt) {
+               set_fs_root(current->fs, vfsmnt, sb->s_root);
+               set_fs_pwd(current->fs, vfsmnt, sb->s_root);
                if (bdev)
                        bdput(bdev); /* sb holds a reference */
                return;
@@ -1420,68 +1454,79 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
 {
        struct dentry *root = current->fs->root;
        struct vfsmount *root_mnt = current->fs->rootmnt;
-       struct dentry *d_new_root, *d_put_old, *covered;
-       struct dentry *root_dev_root, *new_root_dev_root;
-       struct dentry *walk, *next;
-       struct vfsmount *new_root_mnt = NULL;
+       struct vfsmount *tmp;
+       struct nameidata new_nd, old_nd;
+       char *name;
        int error;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        lock_kernel();
-       d_new_root = namei(new_root);
-       if (IS_ERR(d_new_root)) {
-               error = PTR_ERR(d_new_root);
+
+       name = getname(new_root);
+       error = PTR_ERR(name);
+       if (IS_ERR(name))
                goto out0;
-       }
-       d_put_old = namei(put_old);
-       if (IS_ERR(d_put_old)) {
-               error = PTR_ERR(d_put_old);
+       error = 0;
+       if (walk_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd))
+               error = walk_name(name, &new_nd);
+       putname(name);
+       if (error)
+               goto out0;
+
+       name = getname(put_old);
+       error = PTR_ERR(name);
+       if (IS_ERR(name))
+               goto out0;
+       error = 0;
+       if (walk_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd))
+               error = walk_name(name, &old_nd);
+       putname(name);
+       if (error)
                goto out1;
-       }
+
        down(&mount_sem);
-       if (!d_new_root->d_inode || !d_put_old->d_inode) {
-               error = -ENOENT;
+       error = -ENOENT;
+       if (d_unhashed(new_nd.dentry) || d_unhashed(old_nd.dentry))
                goto out2;
-       }
-       if (!S_ISDIR(d_new_root->d_inode->i_mode) ||
-           !S_ISDIR(d_put_old->d_inode->i_mode)) {
-               error = -ENOTDIR;
-               goto out2;
-       }
        error = -EBUSY;
-       if (d_new_root->d_sb == root->d_sb || d_put_old->d_sb == root->d_sb)
+       if (new_nd.mnt == root_mnt || old_nd.mnt == root_mnt)
                goto out2; /* loop */
-       if (d_put_old != d_put_old->d_covers)
-               goto out2; /* mount point is busy */
        error = -EINVAL;
-       walk = d_put_old; /* make sure we can reach put_old from new_root */
-       for (;;) {
-               next = walk->d_covers->d_parent;
-               if (next == walk)
+       tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */
+       if (tmp != new_nd.mnt) {
+               for (;;) {
+                       if (tmp->mnt_parent == tmp)
+                               goto out2;
+                       if (tmp->mnt_parent == new_nd.mnt)
+                               break;
+                       tmp = tmp->mnt_parent;
+               }
+               if (!is_subdir(tmp->mnt_root, new_nd.dentry))
                        goto out2;
-               if (next == d_new_root)
-                       break;
-               walk = next;
-       }
+       } else if (!is_subdir(old_nd.dentry, new_nd.dentry))
+               goto out2;
 
-       new_root_dev_root = d_new_root->d_sb->s_root;
-       covered = new_root_dev_root->d_covers;
-       new_root_dev_root->d_covers = new_root_dev_root;
-       dput(covered);
-       covered->d_mounts = covered;
+       error = -ENOMEM;
+       name = __getname();
+       if (!name)
+               goto out2;
 
-       root_dev_root = root->d_sb->s_root;
-       root_dev_root->d_covers = dget(d_put_old);
-       d_put_old->d_mounts = root_dev_root;
-       chroot_fs_refs(root,root_mnt,d_new_root,new_root_mnt);
+       move_vfsmnt(new_nd.mnt, new_nd.dentry, NULL, NULL, "/");
+       move_vfsmnt(root_mnt, old_nd.dentry, old_nd.mnt, NULL,
+                       __d_path(old_nd.dentry, old_nd.mnt, new_nd.dentry,
+                               new_nd.mnt, name, PAGE_SIZE));
+       putname(name);
+       chroot_fs_refs(root,root_mnt,new_nd.dentry,new_nd.mnt);
        error = 0;
 out2:
        up(&mount_sem);
-       dput(d_put_old);
+       dput(old_nd.dentry);
+       mntput(old_nd.mnt);
 out1:
-       dput(d_new_root);
+       dput(new_nd.dentry);
+       mntput(new_nd.mnt);
 out0:
        unlock_kernel();
        return error;
@@ -1492,34 +1537,31 @@ out0:
 
 int __init change_root(kdev_t new_root_dev,const char *put_old)
 {
-       kdev_t old_root_dev;
-       struct vfsmount *vfsmnt;
-       struct dentry *old_root,*old_pwd,*dir_d = NULL;
-       int error;
+       kdev_t old_root_dev = ROOT_DEV;
+       struct vfsmount *old_rootmnt = mntget(current->fs->rootmnt);
+       struct nameidata devfs_nd, nd;
+       int error = 0;
 
-       old_root = current->fs->root;
-       old_pwd = current->fs->pwd;
-       old_root_dev = ROOT_DEV;
-       if (!fs_may_mount(new_root_dev)) {
-               printk(KERN_CRIT "New root is busy. Staying in initrd.\n");
-               return -EBUSY;
-       }
        /*  First unmount devfs if mounted  */
-       dir_d = lookup_dentry ("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE);
-       if (!IS_ERR(dir_d)) {
-               struct super_block *sb = dir_d->d_inode->i_sb;
-
-               if (sb && (dir_d->d_inode == sb->s_root->d_inode) &&
-                   (sb->s_magic == DEVFS_SUPER_MAGIC)) {
-                       dput (dir_d);
-                       do_umount (sb->s_dev, 0, 0);
+       if (walk_init("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd))
+               error = walk_name("/dev", &devfs_nd);
+       if (!error) {
+               struct super_block *sb = devfs_nd.dentry->d_inode->i_sb;
+
+               if (devfs_nd.mnt->mnt_sb->s_magic == DEVFS_SUPER_MAGIC &&
+                   devfs_nd.dentry == devfs_nd.mnt->mnt_root) {
+                       dput(devfs_nd.dentry);
+                       down(&mount_sem);
+                       /* puts devfs_nd.mnt */
+                       do_umount(devfs_nd.mnt, 0, 0);
+                       up(&mount_sem);
+               } else {
+                       dput(devfs_nd.dentry);
+                       mntput(devfs_nd.mnt);
                }
-               else dput (dir_d);
        }
        ROOT_DEV = new_root_dev;
        mount_root();
-       dput(old_root);
-       dput(old_pwd);
 #if 1
        shrink_dcache();
        printk("change_root: old root has d_count=%d\n", old_root->d_count);
@@ -1528,40 +1570,26 @@ int __init change_root(kdev_t new_root_dev,const char *put_old)
        /*
         * Get the new mount directory
         */
-       dir_d = lookup_dentry(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
-       if (IS_ERR(dir_d)) {
-               error = PTR_ERR(dir_d);
-       } else {
-               error = 0;
-       }
-       if (!error && dir_d->d_covers != dir_d) {
-               dput(dir_d);
-               error = -EBUSY;
-       }
-       if (!error && !S_ISDIR(dir_d->d_inode->i_mode)) {
-               dput(dir_d);
-               error = -ENOTDIR;
-       }
+       error = 0;
+       if (walk_init(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))
+               error = walk_name(put_old, &nd);
        if (error) {
-               struct block_device *bdev;
+               int blivet;
 
                printk(KERN_NOTICE "Trying to unmount old root ... ");
-               bdev = do_umount(old_root_dev,1, 0);
-               if (!IS_ERR(bdev)) {
+               blivet = do_umount(old_rootmnt, 1, 0);
+               if (!blivet) {
                        printk("okay\n");
                        return 0;
                }
-               printk(KERN_ERR "error %ld\n",PTR_ERR(bdev));
+               printk(KERN_ERR "error %ld\n",blivet);
                return error;
        }
-       remove_vfsmnt(old_root_dev);
-       vfsmnt = add_vfsmnt(old_root->d_sb, "/dev/root.old", put_old);
-       if (vfsmnt) {
-               d_mount(dir_d,old_root);
-               return 0;
-       }
-       printk(KERN_CRIT "Trouble: add_vfsmnt failed\n");
-       return -ENOMEM;
+       move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old", put_old);
+       mntput(old_rootmnt);
+       dput(nd.dentry);
+       mntput(nd.mnt);
+       return 0;
 }
 
 #endif
index 5db9768d0d8e110c202b19211b18e832ac4f975f..62bf7916c1e64b5ce651beb5ec2f4c0ddc4b2071 100644 (file)
@@ -30,7 +30,7 @@
  */
 
 #define __HAVE_ARCH_STRCPY
-extern inline char * strcpy(char * dest,const char *src)
+static inline char * strcpy(char * dest,const char *src)
 {
 int d0, d1, d2;
 __asm__ __volatile__(
@@ -44,7 +44,7 @@ return dest;
 }
 
 #define __HAVE_ARCH_STRNCPY
-extern inline char * strncpy(char * dest,const char *src,size_t count)
+static inline char * strncpy(char * dest,const char *src,size_t count)
 {
 int d0, d1, d2, d3;
 __asm__ __volatile__(
@@ -63,7 +63,7 @@ return dest;
 }
 
 #define __HAVE_ARCH_STRCAT
-extern inline char * strcat(char * dest,const char * src)
+static inline char * strcat(char * dest,const char * src)
 {
 int d0, d1, d2, d3;
 __asm__ __volatile__(
@@ -80,7 +80,7 @@ return dest;
 }
 
 #define __HAVE_ARCH_STRNCAT
-extern inline char * strncat(char * dest,const char * src,size_t count)
+static inline char * strncat(char * dest,const char * src,size_t count)
 {
 int d0, d1, d2, d3;
 __asm__ __volatile__(
@@ -103,7 +103,7 @@ return dest;
 }
 
 #define __HAVE_ARCH_STRCMP
-extern inline int strcmp(const char * cs,const char * ct)
+static inline int strcmp(const char * cs,const char * ct)
 {
 int d0, d1;
 register int __res;
@@ -124,7 +124,7 @@ return __res;
 }
 
 #define __HAVE_ARCH_STRNCMP
-extern inline int strncmp(const char * cs,const char * ct,size_t count)
+static inline int strncmp(const char * cs,const char * ct,size_t count)
 {
 register int __res;
 int d0, d1, d2;
@@ -147,7 +147,7 @@ return __res;
 }
 
 #define __HAVE_ARCH_STRCHR
-extern inline char * strchr(const char * s, int c)
+static inline char * strchr(const char * s, int c)
 {
 int d0;
 register char * __res;
@@ -166,7 +166,7 @@ return __res;
 }
 
 #define __HAVE_ARCH_STRRCHR
-extern inline char * strrchr(const char * s, int c)
+static inline char * strrchr(const char * s, int c)
 {
 int d0, d1;
 register char * __res;
@@ -183,7 +183,7 @@ return __res;
 }
 
 #define __HAVE_ARCH_STRLEN
-extern inline size_t strlen(const char * s)
+static inline size_t strlen(const char * s)
 {
 int d0;
 register int __res;
@@ -196,7 +196,7 @@ __asm__ __volatile__(
 return __res;
 }
 
-extern inline void * __memcpy(void * to, const void * from, size_t n)
+static inline void * __memcpy(void * to, const void * from, size_t n)
 {
 int d0, d1, d2;
 __asm__ __volatile__(
@@ -218,7 +218,7 @@ return (to);
  * This looks horribly ugly, but the compiler can optimize it totally,
  * as the count is constant.
  */
-extern inline void * __constant_memcpy(void * to, const void * from, size_t n)
+static inline void * __constant_memcpy(void * to, const void * from, size_t n)
 {
        switch (n) {
                case 0:
@@ -300,7 +300,7 @@ __asm__ __volatile__( \
  *     This CPU favours 3DNow strongly (eg AMD Athlon)
  */
 
-extern inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
+static inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
 {
        if(len<512 || in_interrupt())
                return __constant_memcpy(to, from, len);
@@ -349,7 +349,7 @@ extern void __struct_cpy_bug (void);
 })
 
 #define __HAVE_ARCH_MEMMOVE
-extern inline void * memmove(void * dest,const void * src, size_t n)
+static inline void * memmove(void * dest,const void * src, size_t n)
 {
 int d0, d1, d2;
 if (dest<src)
@@ -376,7 +376,7 @@ return dest;
 #define memcmp __builtin_memcmp
 
 #define __HAVE_ARCH_MEMCHR
-extern inline void * memchr(const void * cs,int c,size_t count)
+static inline void * memchr(const void * cs,int c,size_t count)
 {
 int d0;
 register void * __res;
@@ -392,7 +392,7 @@ __asm__ __volatile__(
 return __res;
 }
 
-extern inline void * __memset_generic(void * s, char c,size_t count)
+static inline void * __memset_generic(void * s, char c,size_t count)
 {
 int d0, d1;
 __asm__ __volatile__(
@@ -412,7 +412,7 @@ return s;
  * things 32 bits at a time even when we don't know the size of the
  * area at compile-time..
  */
-extern inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
+static inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
 {
 int d0, d1;
 __asm__ __volatile__(
@@ -432,7 +432,7 @@ return (s);
 
 /* Added by Gertjan van Wingerde to make minix and sysv module work */
 #define __HAVE_ARCH_STRNLEN
-extern inline size_t strnlen(const char * s, size_t count)
+static inline size_t strnlen(const char * s, size_t count)
 {
 int d0;
 register int __res;
@@ -453,7 +453,7 @@ return __res;
 /* end of additional stuff */
 
 #define __HAVE_ARCH_STRSTR
-extern inline char * strstr(const char * cs,const char * ct)
+static inline char * strstr(const char * cs,const char * ct)
 {
 int    d0, d1;
 register char * __res;
@@ -486,7 +486,7 @@ return __res;
  * This looks horribly ugly, but the compiler can optimize it totally,
  * as we by now know that both pattern and count is constant..
  */
-extern inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
+static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
 {
        switch (count) {
                case 0:
@@ -545,7 +545,7 @@ __asm__  __volatile__( \
  * find the first occurrence of byte 'c', or 1 past the area if none
  */
 #define __HAVE_ARCH_MEMSCAN
-extern inline void * memscan(void * addr, int c, size_t size)
+static inline void * memscan(void * addr, int c, size_t size)
 {
        if (!size)
                return addr;
index 710288a1a12a846b73ef8e0efc04c8eb31f3d856..7e144e03e9a25b8d8d4cf97058a5d070acd6c795 100644 (file)
@@ -5,7 +5,7 @@
 #include <asm/page.h>
 
 #define __HAVE_ARCH_STRCPY
-extern inline char * strcpy(char * dest,const char *src)
+static inline char * strcpy(char * dest,const char *src)
 {
   char *xdest = dest;
 
@@ -18,7 +18,7 @@ extern inline char * strcpy(char * dest,const char *src)
 }
 
 #define __HAVE_ARCH_STRNCPY
-extern inline char * strncpy(char *dest, const char *src, size_t n)
+static inline char * strncpy(char *dest, const char *src, size_t n)
 {
   char *xdest = dest;
 
@@ -38,7 +38,7 @@ extern inline char * strncpy(char *dest, const char *src, size_t n)
 }
 
 #define __HAVE_ARCH_STRCAT
-extern inline char * strcat(char * dest, const char * src)
+static inline char * strcat(char * dest, const char * src)
 {
        char *tmp = dest;
 
@@ -51,7 +51,7 @@ extern inline char * strcat(char * dest, const char * src)
 }
 
 #define __HAVE_ARCH_STRNCAT
-extern inline char * strncat(char *dest, const char *src, size_t count)
+static inline char * strncat(char *dest, const char *src, size_t count)
 {
        char *tmp = dest;
 
@@ -70,7 +70,7 @@ extern inline char * strncat(char *dest, const char *src, size_t count)
 }
 
 #define __HAVE_ARCH_STRCHR
-extern inline char * strchr(const char * s, int c)
+static inline char * strchr(const char * s, int c)
 {
   const char ch = c;
   
@@ -81,7 +81,7 @@ extern inline char * strchr(const char * s, int c)
 }
 
 #define __HAVE_ARCH_STRPBRK
-extern inline char * strpbrk(const char * cs,const char * ct)
+static inline char * strpbrk(const char * cs,const char * ct)
 {
   const char *sc1,*sc2;
   
@@ -93,7 +93,7 @@ extern inline char * strpbrk(const char * cs,const char * ct)
 }
 
 #define __HAVE_ARCH_STRSPN
-extern inline size_t strspn(const char *s, const char *accept)
+static inline size_t strspn(const char *s, const char *accept)
 {
   const char *p;
   const char *a;
@@ -114,7 +114,7 @@ extern inline size_t strspn(const char *s, const char *accept)
 }
 
 #define __HAVE_ARCH_STRTOK
-extern inline char * strtok(char * s,const char * ct)
+static inline char * strtok(char * s,const char * ct)
 {
   char *sbegin, *send;
   
@@ -137,7 +137,7 @@ extern inline char * strtok(char * s,const char * ct)
 /* strstr !! */
 
 #define __HAVE_ARCH_STRLEN
-extern inline size_t strlen(const char * s)
+static inline size_t strlen(const char * s)
 {
   const char *sc;
   for (sc = s; *sc != '\0'; ++sc) ;
@@ -147,7 +147,7 @@ extern inline size_t strlen(const char * s)
 /* strnlen !! */
 
 #define __HAVE_ARCH_STRCMP
-extern inline int strcmp(const char * cs,const char * ct)
+static inline int strcmp(const char * cs,const char * ct)
 {
   char __res;
 
@@ -166,7 +166,7 @@ extern inline int strcmp(const char * cs,const char * ct)
 }
 
 #define __HAVE_ARCH_STRNCMP
-extern inline int strncmp(const char * cs,const char * ct,size_t count)
+static inline int strncmp(const char * cs,const char * ct,size_t count)
 {
   char __res;
 
@@ -199,7 +199,7 @@ extern inline int strncmp(const char * cs,const char * ct,size_t count)
  * 680[46]0 doesn't really care due to their copy-back caches.
  *                                             10/09/96 - Jes Sorensen
  */
-extern inline void * __memset_g(void * s, int c, size_t count)
+static inline void * __memset_g(void * s, int c, size_t count)
 {
   void *xs = s;
   size_t temp;
@@ -304,7 +304,7 @@ extern inline void * __memset_g(void * s, int c, size_t count)
  * caveat is that the destination address must be 16-byte aligned.
  *                                            01/09/96 - Jes Sorensen
  */
-extern inline void * __memset_page(void * s,int c,size_t count)
+static inline void * __memset_page(void * s,int c,size_t count)
 {
   unsigned long data, tmp;
   void *xs, *sp;
@@ -381,7 +381,7 @@ extern inline void * __memset_page(void * s,int c,size_t count)
  * both source and destination must be 16-byte aligned, if not we fall
  * back to the generic memcpy function.  - Jes
  */
-extern inline void * __memcpy_page(void * to, const void * from, size_t count)
+static inline void * __memcpy_page(void * to, const void * from, size_t count)
 {
   unsigned long tmp;
   void *xto = to;
@@ -429,7 +429,7 @@ extern inline void * __memcpy_page(void * to, const void * from, size_t count)
  memcpy((to),(from),(n)))
 
 #define __HAVE_ARCH_MEMMOVE
-extern inline void * memmove(void * dest,const void * src, size_t n)
+static inline void * memmove(void * dest,const void * src, size_t n)
 {
   void *xdest = dest;
   size_t temp;
index 7f8d06587c67ce196bb1a76ad0157e2dcd98cef0..f103f4a2badc105f493d76783c2ab418d5beefb6 100644 (file)
@@ -34,7 +34,7 @@ extern __kernel_size_t __memset(void *,int,__kernel_size_t);
 
 #define __HAVE_ARCH_MEMCPY
 
-extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
+static inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
        extern void __copy_1page(void *, const void *);
 
@@ -53,7 +53,7 @@ extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_
        return to;
 }
 
-extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n)
+static inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
        __memcpy(to, from, n);
        return to;
@@ -67,7 +67,7 @@ extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_si
 
 #define __HAVE_ARCH_MEMSET
 
-extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count)
+static inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count)
 {
        extern void bzero_1page(void *);
        extern __kernel_size_t __bzero(void *, __kernel_size_t);
@@ -83,7 +83,7 @@ extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size
        return s;
 }
 
-extern inline void *__constant_c_memset(void *s, char c, __kernel_size_t count)
+static inline void *__constant_c_memset(void *s, char c, __kernel_size_t count)
 {
        extern __kernel_size_t __bzero(void *, __kernel_size_t);
 
@@ -94,7 +94,7 @@ extern inline void *__constant_c_memset(void *s, char c, __kernel_size_t count)
        return s;
 }
 
-extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count)
+static inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count)
 {
        __memset(s, c, count);
        return s;
@@ -134,7 +134,7 @@ extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count)
 
 extern int __strncmp(const char *, const char *, __kernel_size_t);
 
-extern inline int __constant_strncmp(const char *src, const char *dest, __kernel_size_t count)
+static inline int __constant_strncmp(const char *src, const char *dest, __kernel_size_t count)
 {
        register int retval;
        switch(count) {
index f6b69aa53cfd3fc5af9118556cd151d029fd5d34..1ac4c5f773cddbb4ae6703b86a41e9c43da06ae2 100644 (file)
@@ -41,7 +41,7 @@ extern void *__builtin_memset(void *,int,__kernel_size_t);
 
 #define __HAVE_ARCH_MEMCPY
 
-extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
+static inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
        if(n) {
                if(n <= 32) {
@@ -53,7 +53,7 @@ extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_
        return to;
 }
 
-extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n)
+static inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
        __memcpy(to, from, n);
        return to;
@@ -67,7 +67,7 @@ extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_si
 
 #define __HAVE_ARCH_MEMSET
 
-extern inline void *__constant_memset(void *s, int c, __kernel_size_t count)
+static inline void *__constant_memset(void *s, int c, __kernel_size_t count)
 {
        extern __kernel_size_t __bzero(void *, __kernel_size_t);
 
@@ -127,7 +127,7 @@ extern __kernel_size_t strlen(const char *);
 
 extern int __strncmp(const char *, const char *, __kernel_size_t);
 
-extern inline int __constant_strncmp(const char *src, const char *dest, __kernel_size_t count)
+static inline int __constant_strncmp(const char *src, const char *dest, __kernel_size_t count)
 {
        register int retval;
        switch(count) {
index 9ed7e072610ed00d6b9996f2dfea6d0ddbe7880f..09735190064fdeff1c4c07765c45b0595e61d984 100644 (file)
@@ -63,6 +63,7 @@ struct dentry {
        struct dentry * d_parent;       /* parent directory */
        struct dentry * d_mounts;       /* mount information */
        struct dentry * d_covers;
+       struct list_head d_vfsmnt;
        struct list_head d_hash;        /* lookup hash list */
        struct list_head d_lru;         /* d_count = 0 LRU list */
        struct list_head d_child;       /* child of parent list */
@@ -162,7 +163,7 @@ extern void prune_icache(int);
 extern struct dentry * d_alloc_root(struct inode *);
 
 /* test whether root is busy without destroying dcache */
-extern int is_root_busy(struct dentry *);
+extern int d_active_refs(struct dentry *);
 
 /* test whether we have any submounts in a subdir tree */
 extern int have_submounts(struct dentry *);
@@ -235,10 +236,9 @@ static __inline__ int d_unhashed(struct dentry *dentry)
 
 extern void dput(struct dentry *);
 
-/* MOUNT_REWRITE: replace with the check for d_vfsmnt */
 static __inline__ int d_mountpoint(struct dentry *dentry)
 {
-       return dentry != dentry->d_mounts;
+       return !list_empty(&dentry->d_vfsmnt);
 }
 
 
index a6998496caab29591718fc32a080eeb91b9205d1..062a6ca6fdfc1b40ad3329f60a4db89187638ddb 100644 (file)
@@ -11,7 +11,7 @@ extern void _fput(struct file *);
  * Check whether the specified task has the fd open. Since the task
  * may not have a files_struct, we must test for p->files != NULL.
  */
-extern inline struct file * fcheck_task(struct task_struct *p, unsigned int fd)
+static inline struct file * fcheck_task(struct task_struct *p, unsigned int fd)
 {
        struct file * file = NULL;
 
@@ -23,7 +23,7 @@ extern inline struct file * fcheck_task(struct task_struct *p, unsigned int fd)
 /*
  * Check whether the specified fd has an open file.
  */
-extern inline struct file * fcheck(unsigned int fd)
+static inline struct file * fcheck(unsigned int fd)
 {
        struct file * file = NULL;
        struct files_struct *files = current->files;
@@ -33,7 +33,7 @@ extern inline struct file * fcheck(unsigned int fd)
        return file;
 }
 
-extern inline struct file * frip(struct files_struct *files, unsigned int fd)
+static inline struct file * frip(struct files_struct *files, unsigned int fd)
 {
        struct file * file = NULL;
 
@@ -42,7 +42,7 @@ extern inline struct file * frip(struct files_struct *files, unsigned int fd)
        return file;
 }
 
-extern inline struct file * fget(unsigned int fd)
+static inline struct file * fget(unsigned int fd)
 {
        struct file * file = NULL;
        struct files_struct *files = current->files;
@@ -58,8 +58,8 @@ extern inline struct file * fget(unsigned int fd)
 /*
  * 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>: 
  * 
- * Since those functions where calling other functions, it was compleatly 
- * bogous to make them all "extern inline".
+ * Since those functions where calling other functions, it was completely 
+ * bogos to make them all "static inline".
  *
  * The removal of this pseudo optimization saved me scandaleous:
  *
@@ -71,7 +71,7 @@ extern inline struct file * fget(unsigned int fd)
  * I suspect there are many other similar "optimizations" across the
  * kernel...
  */
-extern inline void fput(struct file * file)
+static inline void fput(struct file * file)
 {
        if (atomic_dec_and_test(&file->f_count))
                _fput(file);
@@ -88,7 +88,7 @@ extern void put_filp(struct file *);
  * fput() the struct file we are about to overwrite in this case.
  */
 
-extern inline void fd_install(unsigned int fd, struct file * file)
+static inline void fd_install(unsigned int fd, struct file * file)
 {
        struct files_struct *files = current->files;
        struct file * result;
index 58ad8b1bc0ac394b8ce99f0667387719d1995b66..ae1a1ebed4260f82176318169a43f304532f6011 100644 (file)
@@ -38,7 +38,7 @@ struct sk_filter
         struct sock_filter             insns[0];
 };
 
-extern __inline__ unsigned int sk_filter_len(struct sk_filter *fp)
+static inline unsigned int sk_filter_len(struct sk_filter *fp)
 {
        return fp->len*sizeof(struct sock_filter) + sizeof(*fp);
 }
index 3f135fa011d78054cdee460d800680106fd0b6b2..46d8c0fbced1037c3e74b5601f2e135a9ac675fb 100644 (file)
@@ -625,6 +625,7 @@ struct super_block {
        struct list_head        s_files;
 
        struct block_device     *s_bdev;
+       struct list_head        s_mounts;       /* vfsmount(s) of this one */
        struct quota_mount_options s_dquot;     /* Diskquota specific options */
 
        union {
@@ -785,6 +786,7 @@ struct file_system_type var = { \
 
 extern int register_filesystem(struct file_system_type *);
 extern int unregister_filesystem(struct file_system_type *);
+extern int may_umount(struct super_block *);
 
 static inline int vfs_statfs(struct super_block *sb, struct statfs *buf)
 {
@@ -821,7 +823,7 @@ static inline int locks_verify_locked(struct inode *inode)
        return 0;
 }
 
-extern inline int locks_verify_area(int read_write, struct inode *inode,
+static inline int locks_verify_area(int read_write, struct inode *inode,
                                    struct file *filp, loff_t offset,
                                    size_t count)
 {
@@ -830,7 +832,7 @@ extern inline int locks_verify_area(int read_write, struct inode *inode,
        return 0;
 }
 
-extern inline int locks_verify_truncate(struct inode *inode,
+static inline int locks_verify_truncate(struct inode *inode,
                                    struct file *filp,
                                    loff_t size)
 {
@@ -898,7 +900,6 @@ extern struct file_operations write_pipe_fops;
 extern struct file_operations rdwr_pipe_fops;
 
 extern int fs_may_remount_ro(struct super_block *);
-extern int fs_may_mount(kdev_t);
 
 extern int try_to_free_buffers(struct page *);
 extern void refile_buffer(struct buffer_head * buf);
@@ -912,7 +913,7 @@ extern void refile_buffer(struct buffer_head * buf);
 /*
  * This is called by bh->b_end_io() handlers when I/O has completed.
  */
-extern inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
+static inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
 {
        if (on)
                set_bit(BH_Uptodate, &bh->b_state);
@@ -922,12 +923,12 @@ extern inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
 
 #define atomic_set_buffer_clean(bh) test_and_clear_bit(BH_Dirty, &(bh)->b_state)
 
-extern inline void __mark_buffer_clean(struct buffer_head *bh)
+static inline void __mark_buffer_clean(struct buffer_head *bh)
 {
        refile_buffer(bh);
 }
 
-extern inline void mark_buffer_clean(struct buffer_head * bh)
+static inline void mark_buffer_clean(struct buffer_head * bh)
 {
        if (atomic_set_buffer_clean(bh))
                __mark_buffer_clean(bh);
@@ -935,12 +936,12 @@ extern inline void mark_buffer_clean(struct buffer_head * bh)
 
 #define atomic_set_buffer_protected(bh) test_and_set_bit(BH_Protected, &(bh)->b_state)
 
-extern inline void __mark_buffer_protected(struct buffer_head *bh)
+static inline void __mark_buffer_protected(struct buffer_head *bh)
 {
        refile_buffer(bh);
 }
 
-extern inline void mark_buffer_protected(struct buffer_head * bh)
+static inline void mark_buffer_protected(struct buffer_head * bh)
 {
        if (!atomic_set_buffer_protected(bh))
                __mark_buffer_protected(bh);
@@ -1034,6 +1035,7 @@ extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
 extern struct dentry * lookup_dentry(const char *, unsigned int);
 extern int walk_init(const char *, unsigned, struct nameidata *);
 extern int walk_name(const char *, struct nameidata *);
+extern int follow_down(struct vfsmount **, struct dentry **);
 extern struct dentry * lookup_one(const char *, struct dentry *);
 extern struct dentry * __namei(const char *, unsigned int);
 
@@ -1064,13 +1066,13 @@ extern struct buffer_head * getblk(kdev_t, int, int);
 extern void ll_rw_block(int, int, struct buffer_head * bh[]);
 extern int is_read_only(kdev_t);
 extern void __brelse(struct buffer_head *);
-extern inline void brelse(struct buffer_head *buf)
+static inline void brelse(struct buffer_head *buf)
 {
        if (buf)
                __brelse(buf);
 }
 extern void __bforget(struct buffer_head *);
-extern inline void bforget(struct buffer_head *buf)
+static inline void bforget(struct buffer_head *buf)
 {
        if (buf)
                __bforget(buf);
@@ -1119,7 +1121,6 @@ extern int vfs_readdir(struct file *, filldir_t, void *);
 
 extern struct super_block *get_super(kdev_t);
 struct super_block *get_empty_super(void);
-void remove_vfsmnt(kdev_t dev);
 extern void put_super(kdev_t);
 unsigned long generate_cluster(kdev_t, int b[], int);
 unsigned long generate_cluster_swab32(kdev_t, int b[], int);
index e9c32f386edcbf12948af43860ae8f9d6e459462..53f9c44f71b40d0bb5576ad1a0ae11d0e54062f3 100644 (file)
@@ -31,8 +31,10 @@ static inline void set_fs_root(struct fs_struct *fs,
        struct vfsmount *old_rootmnt = fs->rootmnt;
        fs->rootmnt = mntget(mnt);
        fs->root = dget(dentry);
-       dput(old_root);
-       mntput(old_rootmnt);
+       if (old_root) {
+               dput(old_root);
+               mntput(old_rootmnt);
+       }
 }
 
 /*
@@ -48,8 +50,10 @@ static inline void set_fs_pwd(struct fs_struct *fs,
        struct vfsmount *old_pwdmnt = fs->pwdmnt;
        fs->pwdmnt = mntget(mnt);
        fs->pwd = dget(dentry);
-       dput(old_pwd);
-       mntput(old_pwdmnt);
+       if (old_pwd) {
+               dput(old_pwd);
+               mntput(old_pwdmnt);
+       }
 }
 
 struct fs_struct *copy_fs_struct(struct fs_struct *old);
index 17f6c046f8dcd98274c8e00690cc81a7079337a1..d43d1e5a7ab01e5461091f5fa4fb25524d7f5237 100644 (file)
@@ -416,7 +416,7 @@ struct input_id {
 #include <linux/devfs_fs_kernel.h>
 
 #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
-#define BIT(x) (1<<((x)%BITS_PER_LONG))
+#define BIT(x) (1UL<<((x)%BITS_PER_LONG))
 #define LONG(x) ((x)/BITS_PER_LONG)
 
 struct input_dev {
index bab73696fc9fc7262e4c344111880dc57cb38717..ff34ee99f971e4735fb7869c11106907085651c9 100644 (file)
@@ -312,7 +312,7 @@ extern struct page * FASTCALL(__alloc_pages(zonelist_t *zonelist, unsigned long
 extern struct page * alloc_pages_node(int nid, int gfp_mask, unsigned long order);
 
 #ifndef CONFIG_DISCONTIGMEM
-extern inline struct page * alloc_pages(int gfp_mask, unsigned long order)
+static inline struct page * alloc_pages(int gfp_mask, unsigned long order)
 {
        /*  temporary check. */
        if (contig_page_data.node_zonelists[gfp_mask].gfp_mask != (gfp_mask))
@@ -331,7 +331,7 @@ extern struct page * alloc_pages(int gfp_mask, unsigned long order);
 #define alloc_page(gfp_mask) \
                alloc_pages(gfp_mask, 0)
 
-extern inline unsigned long __get_free_pages (int gfp_mask, unsigned long order)
+static inline unsigned long __get_free_pages (int gfp_mask, unsigned long order)
 {
        struct page * page;
 
@@ -347,7 +347,7 @@ extern inline unsigned long __get_free_pages (int gfp_mask, unsigned long order)
 #define __get_dma_pages(gfp_mask, order) \
                __get_free_pages((gfp_mask) | GFP_DMA,(order))
 
-extern inline unsigned long get_zeroed_page(int gfp_mask)
+static inline unsigned long get_zeroed_page(int gfp_mask)
 {
        unsigned long page;
 
@@ -367,7 +367,7 @@ extern inline unsigned long get_zeroed_page(int gfp_mask)
  */
 extern void FASTCALL(__free_pages_ok(struct page * page, unsigned long order));
 
-extern inline void __free_pages(struct page *page, unsigned long order)
+static inline void __free_pages(struct page *page, unsigned long order)
 {
        if (!put_page_testzero(page))
                return;
@@ -376,7 +376,7 @@ extern inline void __free_pages(struct page *page, unsigned long order)
 
 #define __free_page(page) __free_pages(page, 0)
 
-extern inline void free_pages(unsigned long addr, unsigned long order)
+static inline void free_pages(unsigned long addr, unsigned long order)
 {
        unsigned long map_nr;
 
@@ -433,7 +433,7 @@ extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
        unsigned long len, unsigned long prot,
        unsigned long flag, unsigned long pgoff);
 
-extern inline unsigned long do_mmap(struct file *file, unsigned long addr,
+static inline unsigned long do_mmap(struct file *file, unsigned long addr,
        unsigned long len, unsigned long prot,
        unsigned long flag, unsigned long offset)
 {
index ddd2cad4d37eaa6d1c76c7a61884149c6a9c2341..40b2ea67ae3ea501fc4deec39d933fad7f4472a8 100644 (file)
  */
 #ifndef _LINUX_MOUNT_H
 #define _LINUX_MOUNT_H
+#ifdef __KERNEL__
 
 struct vfsmount
 {
+       struct dentry *mnt_mountpoint;  /* dentry of mountpoint */
+       struct dentry *mnt_root;        /* root of the mounted tree */
+       struct vfsmount *mnt_parent;    /* fs we are mounted on */
+       struct list_head mnt_instances; /* other vfsmounts of the same fs */
+       struct list_head mnt_clash;     /* those who are mounted on (other */
+                                       /* instances) of the same dentry */
+       struct super_block *mnt_sb;     /* pointer to superblock */
+       atomic_t mnt_count;
+
   kdev_t mnt_dev;                      /* Device this applies to */
   char *mnt_devname;                   /* Name of device e.g. /dev/dsk/hda1 */
   char *mnt_dirname;                   /* Name of directory mounted on */
-  struct super_block *mnt_sb;          /* pointer to superblock */
        struct list_head mnt_list;
 };
 
-/* MOUNT_REWRITE: fill these */
 static inline struct vfsmount *mntget(struct vfsmount *mnt)
 {
+       atomic_inc(&mnt->mnt_count);
        return mnt;
 }
 
 static inline void mntput(struct vfsmount *mnt)
 {
+       if (atomic_dec_and_test(&mnt->mnt_count))
+               BUG();
 }
 
+#endif
 #endif /* _LINUX_MOUNT_H */
index 178eb4c06cd34b6d6c83bfc4b9a8a829ed5ab69c..1836dda4875ed679a33c3fafd5a6131729b9e07c 100644 (file)
@@ -51,7 +51,10 @@ enum ip_conntrack_status {
        IPS_EXPECTED = 0x01,
 
        /* We've seen packets both ways: bit 1 set.  Can be set, not unset. */
-       IPS_SEEN_REPLY = 0x02
+       IPS_SEEN_REPLY = 0x02,
+
+       /* Packet seen leaving box: bit 2 set.  Can be set, not unset. */
+       IPS_CONFIRMED = 0x04
 };
 
 struct ip_conntrack_expect
@@ -88,7 +91,7 @@ struct ip_conntrack
        struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
 
        /* Have we seen traffic both ways yet? (bitset) */
-       unsigned int status;
+       volatile unsigned int status;
 
        /* Timer function; drops refcnt when it goes off. */
        struct timer_list timeout;
index 9cb49afaff884adc416dd0fbfec9b8640447ec25..4631db1eef14f5663f24244260a7e99f444ee0a5 100644 (file)
@@ -20,8 +20,9 @@ extern struct ip_conntrack_protocol *find_proto(u_int8_t protocol);
 extern struct ip_conntrack_protocol *__find_proto(u_int8_t protocol);
 extern struct list_head protocol_list;
 
-/* Returns TRUE if it dealt with ICMP, and filled in skb->nfct */
-int icmp_error_track(struct sk_buff *skb);
+/* Returns conntrack if it dealt with ICMP, and filled in skb->nfct */
+extern struct ip_conntrack *icmp_error_track(struct sk_buff *skb,
+                                            enum ip_conntrack_info *ctinfo);
 extern int get_tuple(const struct iphdr *iph, size_t len,
                     struct ip_conntrack_tuple *tuple,
                     struct ip_conntrack_protocol *protocol);
@@ -31,6 +32,9 @@ struct ip_conntrack_tuple_hash *
 ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
                      const struct ip_conntrack *ignored_conntrack);
 
+/* Confirm a connection */
+void ip_conntrack_confirm(struct ip_conntrack *ct);
+
 extern unsigned int ip_conntrack_htable_size;
 extern struct list_head *ip_conntrack_hash;
 extern struct list_head expect_list;
index 20361b06470cea242aebca8c80f8a9aa4c0b6ef3..a2431cd7224246faefd367166f77822673bd2a6b 100644 (file)
@@ -346,6 +346,9 @@ struct ipt_match
                          unsigned int matchinfosize,
                          unsigned int hook_mask);
 
+       /* Called when entry of this type deleted. */
+       void (*destroy)(void *matchinfo, unsigned int matchinfosize);
+
        /* Set this to THIS_MODULE if you are a module, otherwise NULL */
        struct module *me;
 };
@@ -375,6 +378,9 @@ struct ipt_target
                          unsigned int targinfosize,
                          unsigned int hook_mask);
 
+       /* Called when entry of this type deleted. */
+       void (*destroy)(void *targinfo, unsigned int targinfosize);
+
        /* Set this to THIS_MODULE if you are a module, otherwise NULL */
        struct module *me;
 };
index eb5909de8647ec72e5440733f9df74ccfcdc28e5..d6b4813127a329431d4264484e2c6a2e3f9a4231 100644 (file)
@@ -442,7 +442,7 @@ extern struct task_struct *pidhash[PIDHASH_SZ];
 
 #define pid_hashfn(x)  ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
 
-extern __inline__ void hash_pid(struct task_struct *p)
+static inline void hash_pid(struct task_struct *p)
 {
        struct task_struct **htable = &pidhash[pid_hashfn(p->pid)];
 
@@ -452,14 +452,14 @@ extern __inline__ void hash_pid(struct task_struct *p)
        p->pidhash_pprev = htable;
 }
 
-extern __inline__ void unhash_pid(struct task_struct *p)
+static inline void unhash_pid(struct task_struct *p)
 {
        if(p->pidhash_next)
                p->pidhash_next->pidhash_pprev = p->pidhash_pprev;
        *p->pidhash_pprev = p->pidhash_next;
 }
 
-extern __inline__ struct task_struct *find_task_by_pid(int pid)
+static inline struct task_struct *find_task_by_pid(int pid)
 {
        struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];
 
@@ -525,7 +525,7 @@ extern int kill_proc(pid_t, int, int);
 extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
 extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long);
 
-extern inline int signal_pending(struct task_struct *p)
+static inline int signal_pending(struct task_struct *p)
 {
        return (p->sigpending != 0);
 }
@@ -593,7 +593,7 @@ extern void free_irq(unsigned int, void *);
  * These will be removed, but in the mean time, when the SECURE_NOROOT 
  * flag is set, uids don't grant privilege.
  */
-extern inline int suser(void)
+static inline int suser(void)
 {
        if (!issecure(SECURE_NOROOT) && current->euid == 0) { 
                current->flags |= PF_SUPERPRIV;
@@ -602,7 +602,7 @@ extern inline int suser(void)
        return 0;
 }
 
-extern inline int fsuser(void)
+static inline int fsuser(void)
 {
        if (!issecure(SECURE_NOROOT) && current->fsuid == 0) {
                current->flags |= PF_SUPERPRIV;
@@ -617,7 +617,7 @@ extern inline int fsuser(void)
  * fsuser(). See include/linux/capability.h for defined capabilities.
  */
 
-extern inline int capable(int cap)
+static inline int capable(int cap)
 {
 #if 1 /* ok now */
        if (cap_raised(current->cap_effective, cap))
@@ -707,7 +707,7 @@ extern void daemonize(void);
 extern int do_execve(char *, char **, char **, struct pt_regs *);
 extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
 
-extern inline void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
+static inline void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
        unsigned long flags;
 
@@ -716,7 +716,7 @@ extern inline void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
        wq_write_unlock_irqrestore(&q->lock, flags);
 }
 
-extern inline void add_wait_queue_exclusive(wait_queue_head_t *q,
+static inline void add_wait_queue_exclusive(wait_queue_head_t *q,
                                                        wait_queue_t * wait)
 {
        unsigned long flags;
@@ -726,7 +726,7 @@ extern inline void add_wait_queue_exclusive(wait_queue_head_t *q,
        wq_write_unlock_irqrestore(&q->lock, flags);
 }
 
-extern inline void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
+static inline void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
        unsigned long flags;
 
@@ -820,12 +820,12 @@ static inline void del_from_runqueue(struct task_struct * p)
        p->run_list.next = NULL;
 }
 
-extern inline int task_on_runqueue(struct task_struct *p)
+static inline int task_on_runqueue(struct task_struct *p)
 {
        return (p->run_list.next != NULL);
 }
 
-extern inline void unhash_process(struct task_struct *p)
+static inline void unhash_process(struct task_struct *p)
 {
        if (task_on_runqueue(p)) BUG();
        write_lock_irq(&tasklist_lock);
index 88eb21c28f4b5d0dff799085b3b07985d0d5355a..e23d4989e008a17df0e58ff3e5a7e5f671deccf0 100644 (file)
@@ -9,34 +9,72 @@ extern "C" {
 #endif
 
 extern char * ___strtok;
+extern char * strpbrk(const char *,const char *);
+extern char * strtok(char *,const char *);
+extern char * strsep(char **,const char *);
+extern __kernel_size_t strspn(const char *,const char *);
+
+
+/*
+ * Include machine specific inline routines
+ */
+#include <asm/string.h>
+
+#ifndef __HAVE_ARCH_STRCPY
 extern char * strcpy(char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCPY
 extern char * strncpy(char *,const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCAT
 extern char * strcat(char *, const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCAT
 extern char * strncat(char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCMP
+extern int strcmp(const char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCMP
+extern int strncmp(const char *,const char *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRNICMP
+extern int strnicmp(const char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCHR
 extern char * strchr(const char *,int);
+#endif
+#ifndef __HAVE_ARCH_STRRCHR
 extern char * strrchr(const char *,int);
-extern char * strpbrk(const char *,const char *);
-extern char * strtok(char *,const char *);
-extern char * strsep(char **,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRSTR
 extern char * strstr(const char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRLEN
 extern __kernel_size_t strlen(const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNLEN
 extern __kernel_size_t strnlen(const char *,__kernel_size_t);
-extern __kernel_size_t strspn(const char *,const char *);
-extern int strcmp(const char *,const char *);
-extern int strncmp(const char *,const char *,__kernel_size_t);
-extern int strnicmp(const char *, const char *, __kernel_size_t);
+#endif
 
+#ifndef __HAVE_ARCH_MEMSET
 extern void * memset(void *,int,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCPY
 extern void * memcpy(void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMMOVE
 extern void * memmove(void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMSCAN
 extern void * memscan(void *,int,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCMP
 extern int memcmp(const void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCHR
 extern void * memchr(const void *,int,__kernel_size_t);
-
-/*
- * Include machine specific inline routines
- */
-#include <asm/string.h>
+#endif
 
 #ifdef __cplusplus
 }
index e67e96bdce20e1103dc8595c57581b5096035bf5..df5f5b434b321033802f184ed2e905968a22077b 100644 (file)
 #define USB_PID_OUT                            0xe1
 #define USB_PID_ACK                            0xd2
 #define USB_PID_DATA0                          0xc3
-#define USB_PID_UNDEF_4                        0xb4
+#define USB_PID_PING                           0xb4    /* USB 2.0 */
 #define USB_PID_SOF                            0xa5
-#define USB_PID_UNDEF_6                        0x96
-#define USB_PID_UNDEF_7                        0x87
-#define USB_PID_UNDEF_8                        0x78
+#define USB_PID_NYET                           0x96    /* USB 2.0 */
+#define USB_PID_DATA2                          0x87    /* USB 2.0 */
+#define USB_PID_SPLIT                          0x78    /* USB 2.0 */
 #define USB_PID_IN                             0x69
 #define USB_PID_NAK                            0x5a
 #define USB_PID_DATA1                          0x4b
-#define USB_PID_PREAMBLE                       0x3c
+#define USB_PID_PREAMBLE                       0x3c    /* Token mode */
+#define USB_PID_ERR                            0x3c    /* USB 2.0: handshake mode */
 #define USB_PID_SETUP                          0x2d
 #define USB_PID_STALL                          0x1e
-#define USB_PID_UNDEF_F                        0x0f
+#define USB_PID_MDATA                          0x0f    /* USB 2.0 */
 
 /*
  * Standard requests
 
 #define USB_MAJOR 180
 
-/* for 2.2-kernels */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-
-static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
-{
-       __list_add(new, head->prev, head);
-}
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-typedef struct wait_queue wait_queue_t;
-
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAITQUEUE(wait, current) \
-       struct wait_queue wait = { current, NULL }
-#define DECLARE_WAIT_QUEUE_HEAD(wait)\
-       wait_queue_head_t wait
-
-#define init_waitqueue_head(x) *x=NULL
-#define init_MUTEX(x) *(x)=MUTEX
-#define DECLARE_MUTEX(name) struct semaphore name=MUTEX
-#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED
-
-
-#define __set_current_state(state_value)                        \
-       do { current->state = state_value; } while (0)
-#ifdef CONFIG_SMP
-#define set_current_state(state_value)          \
-       set_mb(current->state, state_value)
-#else
-#define set_current_state(state_value)          \
-       __set_current_state(state_value)
-#endif
-
-#endif // 2.2.x
-
-
 static __inline__ void wait_ms(unsigned int ms)
 {
        if(!in_interrupt()) {
index 27b9cde9d0d544a2837b41fc899f821185ce1a9b..dd67f9748c95f5a12eb0a8bd929a25fdf35d87cc 100644 (file)
@@ -137,7 +137,6 @@ EXPORT_SYMBOL(in_group_p);
 EXPORT_SYMBOL(update_atime);
 EXPORT_SYMBOL(get_super);
 EXPORT_SYMBOL(get_empty_super);
-EXPORT_SYMBOL(remove_vfsmnt);
 EXPORT_SYMBOL(getname);
 EXPORT_SYMBOL(_fput);
 EXPORT_SYMBOL(igrab);
@@ -145,6 +144,7 @@ EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget4);
 EXPORT_SYMBOL(iput);
 EXPORT_SYMBOL(__namei);
+EXPORT_SYMBOL(follow_down);
 EXPORT_SYMBOL(lookup_dentry);
 EXPORT_SYMBOL(walk_init);
 EXPORT_SYMBOL(walk_name);
@@ -214,7 +214,6 @@ EXPORT_SYMBOL(posix_block_lock);
 EXPORT_SYMBOL(posix_unblock_lock);
 EXPORT_SYMBOL(locks_mandatory_area);
 EXPORT_SYMBOL(dput);
-EXPORT_SYMBOL(is_root_busy);
 EXPORT_SYMBOL(have_submounts);
 EXPORT_SYMBOL(prune_dcache);
 EXPORT_SYMBOL(shrink_dcache_sb);
@@ -309,6 +308,7 @@ EXPORT_SYMBOL(console_loglevel);
 /* filesystem registration */
 EXPORT_SYMBOL(register_filesystem);
 EXPORT_SYMBOL(unregister_filesystem);
+EXPORT_SYMBOL(may_umount);
 
 /* executable format registration */
 EXPORT_SYMBOL(register_binfmt);
index d0df8bd2c3480112de8d40ccc5ed062e45f62a27..5d507d6654b0c9cd4c814fe17b91666ae8c86286 100644 (file)
@@ -97,9 +97,6 @@ void remove_inode_page(struct page *page)
        if (!PageLocked(page))
                PAGE_BUG(page);
 
-       /* Initiate completion of any async operations */
-       sync_page(page);
-
        spin_lock(&pagecache_lock);
        remove_page_from_inode_queue(page);
        remove_page_from_hash_queue(page);
@@ -238,14 +235,13 @@ repeat:
 
 int shrink_mmap(int priority, int gfp_mask, zone_t *zone)
 {
-       int ret = 0, loop = 0, count;
+       int ret = 0, count;
        LIST_HEAD(young);
        LIST_HEAD(old);
        LIST_HEAD(forget);
        struct list_head * page_lru, * dispose;
        struct page * page = NULL;
        struct zone_struct * p_zone;
-       int maxloop = 256 >> priority;
        
        if (!zone)
                BUG();
@@ -262,30 +258,26 @@ again:
                list_del(page_lru);
                p_zone = page->zone;
 
-               /*
-                * These two tests are there to make sure we don't free too
-                * many pages from the "wrong" zone. We free some anyway,
-                * they are the least recently used pages in the system.
-                * When we don't free them, leave them in &old.
-                */
-               dispose = &old;
-               if (p_zone != zone && (loop > (maxloop / 4) ||
-                               p_zone->free_pages > p_zone->pages_high))
-                       goto dispose_continue;
+               /* This LRU list only contains a few pages from the system,
+                * so we must fail and let swap_out() refill the list if
+                * there aren't enough freeable pages on the list */
 
                /* The page is in use, or was used very recently, put it in
                 * &young to make sure that we won't try to free it the next
                 * time */
                dispose = &young;
-
                if (test_and_clear_bit(PG_referenced, &page->flags))
                        goto dispose_continue;
 
-               count--;
+               if (p_zone->free_pages > p_zone->pages_high)
+                       goto dispose_continue;
+
                if (!page->buffers && page_count(page) > 1)
                        goto dispose_continue;
 
-               /* Page not used -> free it; if that fails -> &old */
+               count--;
+               /* Page not used -> free it or put it on the old list
+                * so it gets freed first the next time */
                dispose = &old;
                if (TryLockPage(page))
                        goto dispose_continue;
@@ -375,9 +367,8 @@ made_buffer_progress:
        /* nr_lru_pages needs the spinlock */
        nr_lru_pages--;
 
-       loop++;
        /* wrong zone?  not looped too often?    roll again... */
-       if (page->zone != zone && loop < maxloop)
+       if (page->zone != zone && count)
                goto again;
 
 out:
index ba5ba30137646acf548c7a970dcb8da4c1ca15a6..d4e830a1714bd9674fb2d8cf4b44b5dd6a65a8bd 100644 (file)
@@ -285,9 +285,11 @@ struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order)
                goto allocate_ok;
 
        /* If we're a memory hog, unmap some pages */
-       if (current->hog && low_on_memory &&
-                       (gfp_mask & __GFP_WAIT))
-               swap_out(4, gfp_mask);
+       if (current->hog && low_on_memory && (gfp_mask & __GFP_WAIT)) {
+       //      swap_out(6, gfp_mask);
+       //      shm_swap(6, gfp_mask, (zone_t *)(zone));
+               try_to_free_pages(gfp_mask, (zone_t *)(zone));
+       }
 
        /*
         * (If anyone calls gfp from interrupts nonatomically then it
index 691d47f18e4790aa611567a5dfa4b6a8b6b80bdc..644ff1cdec26ff522bf60a379239ce56c3ce8fd1 100644 (file)
@@ -387,8 +387,8 @@ int swap_out(unsigned int priority, int gfp_mask)
                                if (!p->swappable || !mm || mm->rss <= 0)
                                        continue;
                                /* small processes are swapped out less */
-                               while ((mm->swap_cnt << 2 * (i + 1) < max_cnt))
-                                       i++;
+                               while ((mm->swap_cnt << 2 * (i + 1) < max_cnt)
+                                               && i++ < 10)
                                mm->swap_cnt >>= i;
                                mm->swap_cnt += i; /* if swap_cnt reaches 0 */
                                /* we're big -> hog treatment */
@@ -437,14 +437,13 @@ static int do_try_to_free_pages(unsigned int gfp_mask, zone_t *zone)
 {
        int priority;
        int count = SWAP_CLUSTER_MAX;
-       int ret;
 
        /* Always trim SLAB caches when memory gets low. */
        kmem_cache_reap(gfp_mask);
 
        priority = 6;
        do {
-               while ((ret = shrink_mmap(priority, gfp_mask, zone))) {
+               while (shrink_mmap(priority, gfp_mask, zone)) {
                        if (!--count)
                                goto done;
                }
@@ -467,9 +466,7 @@ static int do_try_to_free_pages(unsigned int gfp_mask, zone_t *zone)
                        }
                }
 
-               /* Then, try to page stuff out..
-                * We use swapcount here because this doesn't actually
-                * free pages */
+               /* Then, try to page stuff out.. */
                while (swap_out(priority, gfp_mask)) {
                        if (!--count)
                                goto done;
@@ -530,12 +527,16 @@ int kswapd(void *unused)
                pgdat = pgdat_list;
                while (pgdat) {
                        for (i = 0; i < MAX_NR_ZONES; i++) {
-                               zone = pgdat->node_zones + i;
+                           int count = SWAP_CLUSTER_MAX;
+                           zone = pgdat->node_zones + i;
+                           do {
                                if (tsk->need_resched)
                                        schedule();
                                if ((!zone->size) || (!zone->zone_wake_kswapd))
                                        continue;
                                do_try_to_free_pages(GFP_KSWAPD, zone);
+                          } while (zone->free_pages < zone->pages_low &&
+                                          --count);
                        }
                        pgdat = pgdat->node_next;
                }
index 1e33ec4ca1a246f1472612f729933f73681259bb..37d3027d8f8afb406380110afe2d304cfed7d938 100644 (file)
@@ -321,7 +321,7 @@ void ipmr_expire_process(unsigned long dummy)
        struct mfc_cache *c, **cp;
 
        if (!spin_trylock(&mfc_unres_lock)) {
-               mod_timer(&ipmr_expire_timer, jiffies + HZ/10);
+               mod_timer(&ipmr_expire_timer, jiffies+HZ/10);
                return;
        }
 
@@ -661,9 +661,7 @@ ipmr_cache_unresolved(vifi_t vifi, struct sk_buff *skb)
                c->next = mfc_unres_queue;
                mfc_unres_queue = c;
 
-               if (!del_timer(&ipmr_expire_timer))
-                       ipmr_expire_timer.expires = c->mfc_un.unres.expires;
-               add_timer(&ipmr_expire_timer);
+               mod_timer(&ipmr_expire_timer, c->mfc_un.unres.expires);
        }
 
        /*
index fdfd747e2ea17858b0b330a917c6abd7ea36a516..e5f35dcd132d5ff71b6c38d0471cdbdf7282738b 100644 (file)
@@ -156,11 +156,48 @@ invert_tuple(struct ip_conntrack_tuple *inverse,
        return protocol->invert_tuple(inverse, orig);
 }
 
+static void
+clean_from_lists(struct ip_conntrack *ct)
+{
+       MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
+       /* Remove from both hash lists */
+       LIST_DELETE(&ip_conntrack_hash
+                   [hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)],
+                   &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
+       LIST_DELETE(&ip_conntrack_hash
+                   [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)],
+                   &ct->tuplehash[IP_CT_DIR_REPLY]);
+       /* If our expected is in the list, take it out. */
+       if (ct->expected.expectant) {
+               IP_NF_ASSERT(list_inlist(&expect_list, &ct->expected));
+               IP_NF_ASSERT(ct->expected.expectant == ct);
+               LIST_DELETE(&expect_list, &ct->expected);
+       }
+}
+
 static void
 destroy_conntrack(struct nf_conntrack *nfct)
 {
        struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
 
+       /* Unconfirmed connections haven't been cleaned up by the
+          timer: hence they cannot be simply deleted here. */
+       if (!(ct->status & IPS_CONFIRMED)) {
+               WRITE_LOCK(&ip_conntrack_lock);
+               /* Race check: they can't get a reference if noone has
+                   one and we have the write lock. */
+               if (atomic_read(&ct->ct_general.use) == 0) {
+                       clean_from_lists(ct);
+                       WRITE_UNLOCK(&ip_conntrack_lock);
+               } else {
+                       /* Either a last-minute confirmation (ie. ct
+                          now has timer attached), or a last-minute
+                          new skb has reference (still unconfirmed). */
+                       WRITE_UNLOCK(&ip_conntrack_lock);
+                       return;
+               }
+       }
+
        IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
        IP_NF_ASSERT(!timer_pending(&ct->timeout));
 
@@ -178,19 +215,7 @@ static void death_by_timeout(unsigned long ul_conntrack)
        struct ip_conntrack *ct = (void *)ul_conntrack;
 
        WRITE_LOCK(&ip_conntrack_lock);
-       /* Remove from both hash lists */
-       LIST_DELETE(&ip_conntrack_hash
-                   [hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)],
-                   &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
-       LIST_DELETE(&ip_conntrack_hash
-                   [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)],
-                   &ct->tuplehash[IP_CT_DIR_REPLY]);
-       /* If our expected is in the list, take it out. */
-       if (ct->expected.expectant) {
-               IP_NF_ASSERT(list_inlist(&expect_list, &ct->expected));
-               IP_NF_ASSERT(ct->expected.expectant == ct);
-               LIST_DELETE(&expect_list, &ct->expected);
-       }
+       clean_from_lists(ct);
        WRITE_UNLOCK(&ip_conntrack_lock);
        ip_conntrack_put(ct);
 }
@@ -235,6 +260,26 @@ ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
        return h;
 }
 
+/* Confirm a connection */
+void
+ip_conntrack_confirm(struct ip_conntrack *ct)
+{
+       DEBUGP("Confirming conntrack %p\n", ct);
+       WRITE_LOCK(&ip_conntrack_lock);
+       /* Race check */
+       if (!(ct->status & IPS_CONFIRMED)) {
+               IP_NF_ASSERT(!timer_pending(&ct->timeout));
+               ct->status |= IPS_CONFIRMED;
+               /* Timer relative to confirmation time, not original
+                  setting time, otherwise we'd get timer wrap in
+                  wierd delay cases. */
+               ct->timeout.expires += jiffies;
+               add_timer(&ct->timeout);
+               atomic_inc(&ct->ct_general.use);
+       }
+       WRITE_UNLOCK(&ip_conntrack_lock);
+}
+
 /* Returns true if a connection correspondings to the tuple (required
    for NAT). */
 int
@@ -250,24 +295,28 @@ ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
        return h != NULL;
 }
 
-/* Returns TRUE if it dealt with ICMP, and filled in skb fields */
-int icmp_error_track(struct sk_buff *skb)
+/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
+struct ip_conntrack *
+icmp_error_track(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
 {
-       const struct iphdr *iph = skb->nh.iph;
-       struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
+       const struct iphdr *iph;
+       struct icmphdr *hdr;
        struct ip_conntrack_tuple innertuple, origtuple;
-       struct iphdr *inner = (struct iphdr *)(hdr + 1);
-       size_t datalen = skb->len - iph->ihl*4 - sizeof(*hdr);
+       struct iphdr *inner;
+       size_t datalen;
        struct ip_conntrack_protocol *innerproto;
        struct ip_conntrack_tuple_hash *h;
-       enum ip_conntrack_info ctinfo;
 
-       if (iph->protocol != IPPROTO_ICMP)
-               return 0;
+       IP_NF_ASSERT(iph->protocol == IPPROTO_ICMP);
+
+       iph = skb->nh.iph;
+       hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
+       inner = (struct iphdr *)(hdr + 1);
+       datalen = skb->len - iph->ihl*4 - sizeof(*hdr);
 
        if (skb->len < iph->ihl * 4 + sizeof(struct icmphdr)) {
                DEBUGP("icmp_error_track: too short\n");
-               return 1;
+               return NULL;
        }
 
        if (hdr->type != ICMP_DEST_UNREACH
@@ -275,12 +324,12 @@ int icmp_error_track(struct sk_buff *skb)
            && hdr->type != ICMP_TIME_EXCEEDED
            && hdr->type != ICMP_PARAMETERPROB
            && hdr->type != ICMP_REDIRECT)
-               return 0;
+               return NULL;
 
        /* Ignore it if the checksum's bogus. */
        if (ip_compute_csum((unsigned char *)hdr, sizeof(*hdr) + datalen)) {
                DEBUGP("icmp_error_track: bad csum\n");
-               return 1;
+               return NULL;
        }
 
        innerproto = find_proto(inner->protocol);
@@ -290,28 +339,68 @@ int icmp_error_track(struct sk_buff *skb)
                DEBUGP("icmp_error: ! get_tuple p=%u (%u*4+%u dlen=%u)\n",
                       inner->protocol, inner->ihl, 8,
                       datalen);
-               return 1;
+               return NULL;
        }
 
        /* Ordinarily, we'd expect the inverted tupleproto, but it's
           been preserved inside the ICMP. */
        if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
                DEBUGP("icmp_error_track: Can't invert tuple\n");
-               return 1;
+               return NULL;
        }
        h = ip_conntrack_find_get(&innertuple, NULL);
        if (!h) {
                DEBUGP("icmp_error_track: no match\n");
-               return 1;
+               return NULL;
+       }
+       if (!(h->ctrack->status & IPS_CONFIRMED)) {
+               DEBUGP("icmp_error_track: unconfirmed\n");
+               ip_conntrack_put(h->ctrack);
+               return NULL;
        }
 
-       ctinfo = IP_CT_RELATED;
+       *ctinfo = IP_CT_RELATED;
        if (DIRECTION(h) == IP_CT_DIR_REPLY)
-               ctinfo += IP_CT_IS_REPLY;
+               *ctinfo += IP_CT_IS_REPLY;
 
        /* Update skb to refer to this connection */
-       skb->nfct = &h->ctrack->infos[ctinfo];
-       return 1;
+       skb->nfct = &h->ctrack->infos[*ctinfo];
+       return h->ctrack;
+}
+
+/* There's a small race here where we may free a just-replied to
+   connection.  Too bad: we're in trouble anyway. */
+static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
+{
+       /* Unconfirmed connections either really fresh or transitory
+           anyway */
+       if (!(i->ctrack->status & IPS_SEEN_REPLY)
+           && (i->ctrack->status & IPS_CONFIRMED))
+               return 1;
+       return 0;
+}
+
+static int early_drop(struct list_head *chain)
+{
+       /* Traverse backwards: gives us oldest, which is roughly LRU */
+       struct ip_conntrack_tuple_hash *h;
+       int dropped = 0;
+
+       READ_LOCK(&ip_conntrack_lock);
+       h = LIST_FIND(chain, unreplied, struct ip_conntrack_tuple_hash *);
+       if (h)
+               atomic_inc(&h->ctrack->ct_general.use);
+       READ_UNLOCK(&ip_conntrack_lock);
+
+       if (!h)
+               return dropped;
+
+       if (del_timer(&h->ctrack->timeout)) {
+               death_by_timeout((unsigned long)h->ctrack);
+               dropped = 1;
+       }
+       ip_conntrack_put(h->ctrack);
+       return dropped;
 }
 
 static inline int helper_cmp(const struct ip_conntrack_helper *i,
@@ -345,29 +434,38 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
        enum ip_conntrack_info ctinfo;
        unsigned long extra_jiffies;
        int i;
+       static unsigned int drop_next = 0;
 
-       if (!invert_tuple(&repl_tuple, tuple, protocol)) {
-               DEBUGP("Can't invert tuple.\n");
-               return 1;
-       }
+       hash = hash_conntrack(tuple);
 
-       if(ip_conntrack_max &&
-           (atomic_read(&ip_conntrack_count) >= ip_conntrack_max)) {
+       if (ip_conntrack_max &&
+           atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
                if (net_ratelimit())
-                       printk(KERN_WARNING "ip_conntrack: maximum limit of %d entries exceeded\n", ip_conntrack_max);
+                       printk(KERN_WARNING "ip_conntrack: maximum limit of"
+                              " %d entries exceeded\n", ip_conntrack_max);
+
+               /* Try dropping from random chain, or else from the
+                   chain about to put into (in case they're trying to
+                   bomb one hash chain). */
+               if (!early_drop(&ip_conntrack_hash[drop_next++])
+                   && !early_drop(&ip_conntrack_hash[hash]))
+                       return 1;
+       }
+
+       if (!invert_tuple(&repl_tuple, tuple, protocol)) {
+               DEBUGP("Can't invert tuple.\n");
                return 1;
        }
+       repl_hash = hash_conntrack(&repl_tuple);
 
        conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
        if (!conntrack) {
                DEBUGP("Can't allocate conntrack.\n");
                return 1;
        }
-       hash = hash_conntrack(tuple);
-       repl_hash = hash_conntrack(&repl_tuple);
 
        memset(conntrack, 0, sizeof(struct ip_conntrack));
-       atomic_set(&conntrack->ct_general.use, 2);
+       atomic_set(&conntrack->ct_general.use, 1);
        conntrack->ct_general.destroy = destroy_conntrack;
        conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
        conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
@@ -381,17 +479,17 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
                kmem_cache_free(ip_conntrack_cachep, conntrack);
                return 1;
        }
+       /* Don't set timer yet: wait for confirmation */
+       init_timer(&conntrack->timeout);
        conntrack->timeout.data = (unsigned long)conntrack;
        conntrack->timeout.function = death_by_timeout;
-       conntrack->timeout.expires = jiffies + extra_jiffies;
-       add_timer(&conntrack->timeout);
+       conntrack->timeout.expires = extra_jiffies;
 
        /* Sew in at head of hash list. */
        WRITE_LOCK(&ip_conntrack_lock);
        /* Check noone else beat us in the race... */
        if (__ip_conntrack_find(tuple, NULL)) {
                WRITE_UNLOCK(&ip_conntrack_lock);
-               printk("ip_conntrack: Wow someone raced us!\n");
                kmem_cache_free(ip_conntrack_cachep, conntrack);
                return 0;
        }
@@ -417,70 +515,70 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
                     &conntrack->tuplehash[IP_CT_DIR_ORIGINAL]);
        list_prepend(&ip_conntrack_hash[repl_hash],
                     &conntrack->tuplehash[IP_CT_DIR_REPLY]);
+       atomic_inc(&ip_conntrack_count);
        WRITE_UNLOCK(&ip_conntrack_lock);
 
        /* Update skb to refer to this connection */
        skb->nfct = &conntrack->infos[ctinfo];
 
-       atomic_inc(&ip_conntrack_count);
        return 1;
 }
 
-static void
-resolve_normal_ct(struct sk_buff *skb, int create)
+/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
+static inline struct ip_conntrack *
+resolve_normal_ct(struct sk_buff *skb,
+                 struct ip_conntrack_protocol *proto,
+                 enum ip_conntrack_info *ctinfo)
 {
        struct ip_conntrack_tuple tuple;
        struct ip_conntrack_tuple_hash *h;
-       struct ip_conntrack_protocol *proto;
-       enum ip_conntrack_info ctinfo;
 
-       proto = find_proto(skb->nh.iph->protocol);
        if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto))
-               return;
+               return NULL;
 
        /* Loop around search/insert race */
        do {
                /* look for tuple match */
                h = ip_conntrack_find_get(&tuple, NULL);
-               if (!h && (!create || init_conntrack(&tuple, proto, skb)))
-                       return;
+               if (!h && init_conntrack(&tuple, proto, skb))
+                       return NULL;
        } while (!h);
 
        /* It exists; we have (non-exclusive) reference. */
        if (DIRECTION(h) == IP_CT_DIR_REPLY) {
-               ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
+               /* Reply on unconfirmed connection => unclassifiable */
+               if (!(h->ctrack->status & IPS_CONFIRMED)) {
+                       DEBUGP("Reply on unconfirmed connection\n");
+                       ip_conntrack_put(h->ctrack);
+                       return NULL;
+               }
+
+               *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
                h->ctrack->status |= IPS_SEEN_REPLY;
        } else {
                /* Once we've had two way comms, always ESTABLISHED. */
                if (h->ctrack->status & IPS_SEEN_REPLY) {
                        DEBUGP("ip_conntrack_in: normal packet for %p\n",
                               h->ctrack);
-                       ctinfo = IP_CT_ESTABLISHED;
+                       *ctinfo = IP_CT_ESTABLISHED;
                } else if (h->ctrack->status & IPS_EXPECTED) {
                        DEBUGP("ip_conntrack_in: related packet for %p\n",
                               h->ctrack);
-                       ctinfo = IP_CT_RELATED;
+                       *ctinfo = IP_CT_RELATED;
                } else {
                        DEBUGP("ip_conntrack_in: new packet for %p\n",
                               h->ctrack);
-                       ctinfo = IP_CT_NEW;
+                       *ctinfo = IP_CT_NEW;
                }
        }
-       skb->nfct = &h->ctrack->infos[ctinfo];
+       skb->nfct = &h->ctrack->infos[*ctinfo];
+       return h->ctrack;
 }
 
 /* Return conntrack and conntrack_info a given skb */
-static struct ip_conntrack *
-__ip_conntrack_get(struct sk_buff *skb,
-                  enum ip_conntrack_info *ctinfo,
-                  int create)
+inline struct ip_conntrack *
+ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
 {
-       if (!skb->nfct) {
-               /* It may be an icmp error... */
-               if (!icmp_error_track(skb))
-                       resolve_normal_ct(skb, create);
-       }
-
        if (skb->nfct) {
                struct ip_conntrack *ct
                        = (struct ip_conntrack *)skb->nfct->master;
@@ -493,11 +591,6 @@ __ip_conntrack_get(struct sk_buff *skb,
        return NULL;
 }
 
-struct ip_conntrack *
-ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
-{
-       return __ip_conntrack_get(skb, ctinfo, 0);
-}
 
 /* Netfilter hook itself. */
 unsigned int ip_conntrack_in(unsigned int hooknum,
@@ -526,15 +619,19 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
                        return NF_STOLEN;
        }
 
-       ct = __ip_conntrack_get(*pskb, &ctinfo, 1);
-       if (!ct) {
-               /* Not valid part of a connection */
-               return NF_ACCEPT;
+       proto = find_proto((*pskb)->nh.iph->protocol);
+
+       /* It may be an icmp error... */
+       if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP 
+           || !(ct = icmp_error_track(*pskb, &ctinfo))) {
+               if (!(ct = resolve_normal_ct(*pskb, proto, &ctinfo))) {
+                       /* Not valid part of a connection */
+                       return NF_ACCEPT;
+               }
        }
+       IP_NF_ASSERT((*pskb)->nfct);
 
-       proto = find_proto((*pskb)->nh.iph->protocol);
        ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo);
-
        if (ret == -1) {
                /* Invalid */
                nf_conntrack_put((*pskb)->nfct);
@@ -665,10 +762,15 @@ void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
        IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
 
        WRITE_LOCK(&ip_conntrack_lock);
-       /* Need del_timer for race avoidance (may already be dying). */
-       if (del_timer(&ct->timeout)) {
-               ct->timeout.expires = jiffies + extra_jiffies;
-               add_timer(&ct->timeout);
+       /* Timer may not be active yet */
+       if (!(ct->status & IPS_CONFIRMED))
+               ct->timeout.expires = extra_jiffies;
+       else {
+               /* Need del_timer for race avoidance (may already be dying). */
+               if (del_timer(&ct->timeout)) {
+                       ct->timeout.expires = jiffies + extra_jiffies;
+                       add_timer(&ct->timeout);
+               }
        }
        WRITE_UNLOCK(&ip_conntrack_lock);
 }
@@ -740,6 +842,17 @@ ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
                /* Time to push up daises... */
                if (del_timer(&h->ctrack->timeout))
                        death_by_timeout((unsigned long)h->ctrack);
+               else if (!(h->ctrack->status & IPS_CONFIRMED)) {
+                       /* Unconfirmed connection.  Clean from lists,
+                          mark confirmed so it gets cleaned as soon
+                          as packet comes back. */
+                       WRITE_LOCK(&ip_conntrack_lock);
+                       if (!(h->ctrack->status & IPS_CONFIRMED)) {
+                               clean_from_lists(h->ctrack);
+                               h->ctrack->status |= IPS_CONFIRMED;
+                       }
+                       WRITE_UNLOCK(&ip_conntrack_lock);
+               }
                /* ... else the timer will get him soon. */
 
                ip_conntrack_put(h->ctrack);
@@ -836,7 +949,14 @@ void ip_conntrack_cleanup(void)
 #ifdef CONFIG_SYSCTL
        unregister_sysctl_table(ip_conntrack_sysctl_header);
 #endif
+ i_see_dead_people:
        ip_ct_selective_cleanup(kill_all, NULL);
+       if (atomic_read(&ip_conntrack_count) != 0) {
+               schedule();
+               goto i_see_dead_people;
+       }
+
        kmem_cache_destroy(ip_conntrack_cachep);
        vfree(ip_conntrack_hash);
        nf_unregister_sockopt(&so_getorigdst);
index 997a917bcb60327aeaa50591c913b14a479aaffe..c4056ff8e875d7f984b180eb77ebd7fe12c71d17 100644 (file)
@@ -23,6 +23,10 @@ static DECLARE_RWLOCK(tcp_lock);
 /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
    closely.  They're more complex. --RR */
 
+/* We steal a bit to indicate no reply yet (can't use status, because
+   it's set before we get into packet handling). */
+#define TCP_REPLY_BIT 0x1000
+
 /* Actually, I believe that neither ipmasq (where this code is stolen
    from) nor ipfilter do it exactly right.  A new conntrack machine taking
    into account packet loss (which creates uncertainty as to exactly
@@ -141,7 +145,7 @@ static unsigned int tcp_print_conntrack(char *buffer,
        enum tcp_conntrack state;
 
        READ_LOCK(&tcp_lock);
-       state = conntrack->proto.tcp_state;
+       state = (conntrack->proto.tcp_state & ~TCP_REPLY_BIT);
        READ_UNLOCK(&tcp_lock);
 
        return sprintf(buffer, "%s ", tcp_conntrack_names[state]);
@@ -161,7 +165,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
                      struct iphdr *iph, size_t len,
                      enum ip_conntrack_info ctinfo)
 {
-       enum tcp_conntrack newconntrack;
+       enum tcp_conntrack newconntrack, oldtcpstate;
        struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
 
        /* We're guaranteed to have the base header, but maybe not the
@@ -172,10 +176,11 @@ static int tcp_packet(struct ip_conntrack *conntrack,
        }
 
        WRITE_LOCK(&tcp_lock);
+       oldtcpstate = conntrack->proto.tcp_state;
        newconntrack
                = tcp_conntracks
                [CTINFO2DIR(ctinfo)]
-               [get_conntrack_index(tcph)][conntrack->proto.tcp_state];
+               [get_conntrack_index(tcph)][oldtcpstate & ~TCP_REPLY_BIT];
 
        /* Invalid */
        if (newconntrack == TCP_CONNTRACK_MAX) {
@@ -187,9 +192,22 @@ static int tcp_packet(struct ip_conntrack *conntrack,
        }
 
        conntrack->proto.tcp_state = newconntrack;
+       if ((oldtcpstate & TCP_REPLY_BIT)
+           || ctinfo >= IP_CT_IS_REPLY)
+               conntrack->proto.tcp_state |= TCP_REPLY_BIT;
+
        WRITE_UNLOCK(&tcp_lock);
 
-       ip_ct_refresh(conntrack, tcp_timeouts[conntrack->proto.tcp_state]);
+       /* If only reply is a RST, we can consider ourselves not to
+          have an established connection: this is a fairly common
+          problem case, so we can delete the conntrack
+          immediately.  --RR */
+       if (!(oldtcpstate & TCP_REPLY_BIT) && tcph->rst) {
+               if (del_timer(&conntrack->timeout))
+                       conntrack->timeout.function((unsigned long)conntrack);
+       } else 
+               ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
+
        return NF_ACCEPT;
 }
 
index 3219f4c8564e240317a3a2e08ae312a7823b371c..77db6572fd6e3c3c2024f16338683d77ce0377a4 100644 (file)
@@ -86,6 +86,12 @@ print_conntrack(char *buffer, const struct ip_conntrack *conntrack)
        len += print_tuple(buffer + len,
                           &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
                           proto);
+#if 0
+       if (!(conntrack->status & IPS_CONFIRMED))
+               len += sprintf(buffer + len, "[UNCONFIRMED] ");
+       len += sprintf(buffer + len, "use=%u ",
+                      atomic_read(&conntrack->ct_general.use));
+#endif
        len += sprintf(buffer + len, "\n");
 
        return len;
@@ -157,6 +163,22 @@ list_conntracks(char *buffer, char **start, off_t offset, int length)
        return len;
 }
 
+static unsigned int ip_confirm(unsigned int hooknum,
+                              struct sk_buff **pskb,
+                              const struct net_device *in,
+                              const struct net_device *out,
+                              int (*okfn)(struct sk_buff *))
+{
+       /* We've seen it coming out the other side: confirm */
+       if ((*pskb)->nfct) {
+               struct ip_conntrack *ct
+                       = (struct ip_conntrack *)(*pskb)->nfct->master;
+               if (!(ct->status & IPS_CONFIRMED))
+                       ip_conntrack_confirm(ct);
+       }
+       return NF_ACCEPT;
+}
+
 static unsigned int ip_refrag(unsigned int hooknum,
                              struct sk_buff **pskb,
                              const struct net_device *in,
@@ -165,6 +187,14 @@ static unsigned int ip_refrag(unsigned int hooknum,
 {
        struct rtable *rt = (struct rtable *)(*pskb)->dst;
 
+       /* We've seen it coming out the other side: confirm */
+       if ((*pskb)->nfct) {
+               struct ip_conntrack *ct
+                       = (struct ip_conntrack *)(*pskb)->nfct->master;
+               if (!(ct->status & IPS_CONFIRMED))
+                       ip_conntrack_confirm(ct);
+       }
+
        /* Local packets are never produced too large for their
           interface.  We degfragment them at LOCAL_OUT, however,
           so we have to refragment them here. */
@@ -203,6 +233,8 @@ static struct nf_hook_ops ip_conntrack_local_out_ops
 /* Refragmenter; last chance. */
 static struct nf_hook_ops ip_conntrack_out_ops
 = { { NULL, NULL }, ip_refrag, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_LAST };
+static struct nf_hook_ops ip_conntrack_local_in_ops
+= { { NULL, NULL }, ip_confirm, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_LAST-1 };
 
 static int init_or_cleanup(int init)
 {
@@ -230,10 +262,17 @@ static int init_or_cleanup(int init)
                printk("ip_conntrack: can't register post-routing hook.\n");
                goto cleanup_inandlocalops;
        }
+       ret = nf_register_hook(&ip_conntrack_local_in_ops);
+       if (ret < 0) {
+               printk("ip_conntrack: can't register local in hook.\n");
+               goto cleanup_inoutandlocalops;
+       }
 
        return ret;
 
  cleanup:
+       nf_unregister_hook(&ip_conntrack_local_in_ops);
+ cleanup_inoutandlocalops:
        nf_unregister_hook(&ip_conntrack_out_ops);
  cleanup_inandlocalops:
        nf_unregister_hook(&ip_conntrack_local_out_ops);
index 2a08ee89c00121f9559ba2076781e85fd5204eb1..9aa50a1c821bc7c3e9434dbe1dc6855ea4dfdf85 100644 (file)
@@ -13,6 +13,7 @@ struct notifier_block;
 #include <net/route.h>
 #include <linux/netfilter_ipv4/compat_firewall.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
 
 static struct firewall_ops *fwops;
 
@@ -60,6 +61,18 @@ int unregister_firewall(int pf, struct firewall_ops *fw)
        return 0;
 }
 
+static inline void
+confirm_connection(struct sk_buff *skb)
+{
+       if (skb->nfct) {
+               struct ip_conntrack *ct
+                       = (struct ip_conntrack *)skb->nfct->master;
+
+               if (!(ct->status & IPS_CONFIRMED))
+                       ip_conntrack_confirm(ct);
+       }
+}
+
 static unsigned int
 fw_in(unsigned int hooknum,
       struct sk_buff **pskb,
@@ -105,10 +118,14 @@ fw_in(unsigned int hooknum,
                ret = fwops->fw_output(fwops, PF_INET,
                                       (struct net_device *)out,
                                       (*pskb)->nh.raw, &redirpt, pskb);
-               if (fwops->fw_acct_out && (ret == FW_ACCEPT || ret == FW_SKIP))
-                       fwops->fw_acct_out(fwops, PF_INET,
-                                          (struct net_device *)in,
-                                          (*pskb)->nh.raw, &redirpt, pskb);
+               if (ret == FW_ACCEPT || ret == FW_SKIP) {
+                       if (fwops->fw_acct_out)
+                               fwops->fw_acct_out(fwops, PF_INET,
+                                                  (struct net_device *)in,
+                                                  (*pskb)->nh.raw, &redirpt,
+                                                  pskb);
+                       confirm_connection(*pskb);
+               }
                break;
        }
 
@@ -155,6 +172,16 @@ fw_in(unsigned int hooknum,
        }
 }
 
+static unsigned int fw_confirm(unsigned int hooknum,
+                              struct sk_buff **pskb,
+                              const struct net_device *in,
+                              const struct net_device *out,
+                              int (*okfn)(struct sk_buff *))
+{
+       confirm_connection(*pskb);
+       return NF_ACCEPT;
+}
+
 extern int ip_fw_ctl(int optval, void *user, unsigned int len);
 
 static int sock_fn(struct sock *sk, int optval, void *user, unsigned int len)
@@ -174,6 +201,9 @@ static struct nf_hook_ops postroute_ops
 static struct nf_hook_ops forward_ops
 = { { NULL, NULL }, fw_in, PF_INET, NF_IP_FORWARD, NF_IP_PRI_FILTER };
 
+static struct nf_hook_ops local_in_ops
+= { { NULL, NULL }, fw_confirm, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_LAST - 1 };
+
 static struct nf_sockopt_ops sock_ops
 = { { NULL, NULL }, PF_INET, 64, 64 + 1024 + 1, &sock_fn, 0, 0, NULL,
     0, NULL };
@@ -202,6 +232,7 @@ static int init_or_cleanup(int init)
        nf_register_hook(&preroute_ops);
        nf_register_hook(&postroute_ops);
        nf_register_hook(&forward_ops);
+       nf_register_hook(&local_in_ops);
 
        return ret;
 
@@ -209,6 +240,7 @@ static int init_or_cleanup(int init)
        nf_unregister_hook(&preroute_ops);
        nf_unregister_hook(&postroute_ops);
        nf_unregister_hook(&forward_ops);
+       nf_unregister_hook(&local_in_ops);
 
        masq_cleanup();
 
index 96bdc9d8d675b17945a554d79c2d06c3fa98b0bf..755206b25715f81800132f547f3f01099247de7e 100644 (file)
@@ -103,6 +103,7 @@ check_for_demasq(struct sk_buff **pskb)
        struct ip_conntrack_protocol *protocol;
        struct ip_conntrack_tuple_hash *h;
        enum ip_conntrack_info ctinfo;
+       struct ip_conntrack *ct;
        int ret;
 
        protocol = find_proto(iph->protocol);
@@ -113,31 +114,18 @@ check_for_demasq(struct sk_buff **pskb)
        switch (iph->protocol) {
        case IPPROTO_ICMP:
                /* ICMP errors. */
-               if (icmp_error_track(*pskb)) {
-                       /* If it is valid, tranlsate it */
-                       if ((*pskb)->nfct) {
-                               struct ip_conntrack *ct
-                                       = (struct ip_conntrack *)
-                                       (*pskb)->nfct->master;
-                               enum ip_conntrack_dir dir;
-
-                               if ((*pskb)->nfct-ct->infos >= IP_CT_IS_REPLY)
-                                       dir = IP_CT_DIR_REPLY;
-                               else
-                                       dir = IP_CT_DIR_ORIGINAL;
-
-                               icmp_reply_translation(*pskb,
-                                                      ct,
-                                                      NF_IP_PRE_ROUTING,
-                                                      dir);
-                       }
+               if ((ct = icmp_error_track(*pskb, &ctinfo))) {
+                       icmp_reply_translation(*pskb, ct,
+                                              NF_IP_PRE_ROUTING,
+                                              CTINFO2DIR(ctinfo));
                        return NF_ACCEPT;
                }
                /* Fall thru... */
        case IPPROTO_TCP:
        case IPPROTO_UDP:
                if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
-                       printk("ip_fw_compat_masq: Couldn't get tuple\n");
+                       if (net_ratelimit())
+                               printk("ip_fw_compat_masq: Can't get tuple\n");
                        return NF_ACCEPT;
                }
                break;
@@ -166,8 +154,9 @@ check_for_demasq(struct sk_buff **pskb)
                                            NF_IP_PRE_ROUTING,
                                            pskb);
                        } else
-                               printk("ip_fw_compat_masq: conntrack"
-                                      " didn't like\n");
+                               if (net_ratelimit()) 
+                                       printk("ip_fw_compat_masq: conntrack"
+                                              " didn't like\n");
                }
        } else {
                if (h)
index 73424cef80d9d0967529d63a1967ae3d70724b71..2700d29899e59b6223ff14fd1ff41b754cb43775 100644 (file)
@@ -589,6 +589,9 @@ cleanup_match(struct ipt_entry_match *m, unsigned int *i)
        if (i && (*i)-- == 0)
                return 1;
 
+       if (m->u.match->destroy)
+               m->u.match->destroy(m->data, m->match_size - sizeof(*m));
+
        if (m->u.match->me)
                __MOD_DEC_USE_COUNT(m->u.match->me);
 
@@ -769,6 +772,8 @@ cleanup_entry(struct ipt_entry *e, unsigned int *i)
        /* Cleanup all matches */
        IPT_MATCH_ITERATE(e, cleanup_match, NULL);
        t = ipt_get_target(e);
+       if (t->u.target->destroy)
+               t->u.target->destroy(t->data, t->target_size - sizeof(*t));
        if (t->u.target->me)
                __MOD_DEC_USE_COUNT(t->u.target->me);
 
@@ -1094,7 +1099,7 @@ do_replace(void *user, unsigned int len)
        /* Silent error: too late now. */
        copy_to_user(tmp.counters, counters,
                     sizeof(struct ipt_counters) * tmp.num_counters);
-
+       vfree(counters);
        up(&ipt_mutex);
        return 0;
 
index 395b1b301edad748897989c93d8ada27ad4248e3..a04a5a8019dc8d02412190d7bcf6c23c435f60bb 100644 (file)
@@ -334,7 +334,8 @@ static int ipt_log_checkentry(const char *tablename,
 }
 
 static struct ipt_target ipt_log_reg
-= { { NULL, NULL }, "LOG", ipt_log_target, ipt_log_checkentry, THIS_MODULE };
+= { { NULL, NULL }, "LOG", ipt_log_target, ipt_log_checkentry, NULL, 
+    THIS_MODULE };
 
 static int __init init(void)
 {
index 924e00e5c9b6857b299a3ded8593d5d5941382d4..dd8bb322691c39c2cc1263de1901dba2a68a1d53 100644 (file)
@@ -47,7 +47,7 @@ checkentry(const char *tablename,
 }
 
 static struct ipt_target ipt_mark_reg
-= { { NULL, NULL }, "MARK", target, checkentry, THIS_MODULE };
+= { { NULL, NULL }, "MARK", target, checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
index 071e2c3cd5d720acd88d2b973404c90561f57799..5800f024e2b9f93f7f77824f745814ecdebedce1 100644 (file)
@@ -60,7 +60,7 @@ masquerade_target(struct sk_buff **pskb,
 {
        struct ip_conntrack *ct;
        enum ip_conntrack_info ctinfo;
-       const struct ip_nat_range *r;
+       const struct ip_nat_multi_range *mr;
        struct ip_nat_multi_range newrange;
        u_int32_t newsrc;
        struct rtable *rt;
@@ -76,7 +76,7 @@ masquerade_target(struct sk_buff **pskb,
        IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW
                                  || ctinfo == IP_CT_RELATED));
 
-       r = targinfo;
+       mr = targinfo;
 
        if (ip_route_output(&rt, (*pskb)->nh.iph->daddr,
                            0,
@@ -97,9 +97,9 @@ masquerade_target(struct sk_buff **pskb,
 
        /* Transfer from original range. */
        newrange = ((struct ip_nat_multi_range)
-               { 1, { { r->flags | IP_NAT_RANGE_MAP_IPS,
+               { 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
                         newsrc, newsrc,
-                        r->min, r->max } } });
+                        mr->range[0].min, mr->range[0].max } } });
 
        /* Hand modified range to generic setup. */
        return ip_nat_setup_info(ct, &newrange, hooknum);
@@ -142,7 +142,7 @@ static struct notifier_block masq_dev_notifier = {
 };
 
 static struct ipt_target masquerade
-= { { NULL, NULL }, "MASQUERADE", masquerade_target, masquerade_check,
+= { { NULL, NULL }, "MASQUERADE", masquerade_target, masquerade_check, NULL,
     THIS_MODULE };
 
 static int __init init(void)
index dba913387ccc32e100c3f3ae26fc8072703e462d..54e62c0008cf654470162c6dd3bc61542a1bfdd6 100644 (file)
@@ -113,7 +113,7 @@ static int ipt_mirror_checkentry(const char *tablename,
 }
 
 static struct ipt_target ipt_mirror_reg
-= { { NULL, NULL }, "MIRROR", ipt_mirror_target, ipt_mirror_checkentry,
+= { { NULL, NULL }, "MIRROR", ipt_mirror_target, ipt_mirror_checkentry, NULL,
     THIS_MODULE };
 
 static int __init init(void)
index aa7ac5e5d71a88d3277b8ea215d3a260009f204d..877e77ed4a235c79794c1dd9f9c6326e4cddadf8 100644 (file)
@@ -58,7 +58,7 @@ redirect_target(struct sk_buff **pskb,
        struct ip_conntrack *ct;
        enum ip_conntrack_info ctinfo;
        u_int32_t newdst;
-       const struct ip_nat_range *r = targinfo;
+       const struct ip_nat_multi_range *mr = targinfo;
        struct ip_nat_multi_range newrange;
 
        IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
@@ -77,16 +77,17 @@ redirect_target(struct sk_buff **pskb,
 
        /* Transfer from original range. */
        newrange = ((struct ip_nat_multi_range)
-               { 1, { { r->flags | IP_NAT_RANGE_MAP_IPS,
+               { 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
                         newdst, newdst,
-                        r->min, r->max } } });
+                        mr->range[0].min, mr->range[0].max } } });
 
        /* Hand modified range to generic setup. */
        return ip_nat_setup_info(ct, &newrange, hooknum);
 }
 
 static struct ipt_target redirect_reg
-= { { NULL, NULL }, "REDIRECT", redirect_target, redirect_check, THIS_MODULE };
+= { { NULL, NULL }, "REDIRECT", redirect_target, redirect_check, NULL,
+    THIS_MODULE };
 
 static int __init init(void)
 {
index 7e82c908c58402704033aea32ff437fca28f5ae2..dde271102a1fcd8eed2a5e207111ff515e095822 100644 (file)
@@ -120,7 +120,7 @@ static int check(const char *tablename,
 }
 
 static struct ipt_target ipt_reject_reg
-= { { NULL, NULL }, "REJECT", reject, check, THIS_MODULE };
+= { { NULL, NULL }, "REJECT", reject, check, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
index f0c293868d27424cb2c49687d7df95445ff0db59..e834d5103343dcbfe837b4a04e1b5fc543016f66 100644 (file)
@@ -66,7 +66,7 @@ checkentry(const char *tablename,
 }
 
 static struct ipt_target ipt_tos_reg
-= { { NULL, NULL }, "TOS", target, checkentry, THIS_MODULE };
+= { { NULL, NULL }, "TOS", target, checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
index 5e2b8602911843deb086621e6c8f9686312693fd..ae0904a4d5ed341425adcf402a23b4f600752bb5 100644 (file)
@@ -124,7 +124,7 @@ ipt_limit_checkentry(const char *tablename,
 }
 
 static struct ipt_match ipt_limit_reg
-= { { NULL, NULL }, "limit", ipt_limit_match, ipt_limit_checkentry,
+= { { NULL, NULL }, "limit", ipt_limit_match, ipt_limit_checkentry, NULL,
     THIS_MODULE };
 
 static int __init init(void)
index 7de7987675ab76e719ecab2b90f3c3a2e5359c98..1cc17398dbe8fb56cbb400acc3c3f94748ba6736 100644 (file)
@@ -46,7 +46,7 @@ ipt_mac_checkentry(const char *tablename,
 }
 
 static struct ipt_match mac_match
-= { { NULL, NULL }, "mac", &match, &ipt_mac_checkentry, THIS_MODULE };
+= { { NULL, NULL }, "mac", &match, &ipt_mac_checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
index 66c3d1186876185166c4623ea7fde9b051380305..b7528a4c237f2b6af51abfaca8086d4026a303e8 100644 (file)
@@ -34,7 +34,7 @@ checkentry(const char *tablename,
 }
 
 static struct ipt_match mark_match
-= { { NULL, NULL }, "mark", &match, &checkentry, THIS_MODULE };
+= { { NULL, NULL }, "mark", &match, &checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
index 6170ce65eb69a171a13dc7a19d937c04432de4b1..993f3fcaa25b467b64e143fb92df23f1895945a0 100644 (file)
@@ -84,7 +84,7 @@ checkentry(const char *tablename,
 }
 
 static struct ipt_match multiport_match
-= { { NULL, NULL }, "multiport", &match, &checkentry, THIS_MODULE };
+= { { NULL, NULL }, "multiport", &match, &checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
index 5019164148b89b7b72d038be3340a4bbe79ccbe5..000bd77af8a0515b74ab2a920340deccdb5cd251 100644 (file)
@@ -118,7 +118,7 @@ checkentry(const char *tablename,
 }
 
 static struct ipt_match owner_match
-= { { NULL, NULL }, "owner", &match, &checkentry, THIS_MODULE };
+= { { NULL, NULL }, "owner", &match, &checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
index b559e7f5660dc559345ffbc40b7ef8441ec53f9b..94f6bbfa5e087162ed77d204281a2114ced77e6d 100644 (file)
@@ -42,7 +42,7 @@ static int check(const char *tablename,
 }
 
 static struct ipt_match state_match
-= { { NULL, NULL }, "state", &match, &check, THIS_MODULE };
+= { { NULL, NULL }, "state", &match, &check, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
index b144704e48d30033167d020d02c4a5f5a9fceb13..dfbcb40e56cbcaacf49a24c950551258f7f9e250 100644 (file)
@@ -35,7 +35,7 @@ checkentry(const char *tablename,
 }
 
 static struct ipt_match tos_match
-= { { NULL, NULL }, "tos", &match, &checkentry, THIS_MODULE };
+= { { NULL, NULL }, "tos", &match, &checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
index 72fab2b18c3ec397f1496d9079355d6dbefc2137..19f699a608dd1f0415a48fab895fbfb14c1be02a 100644 (file)
@@ -558,7 +558,7 @@ checkentry(const char *tablename,
 }
 
 static struct ipt_match unclean_match
-= { { NULL, NULL }, "unclean", &match, &checkentry, THIS_MODULE };
+= { { NULL, NULL }, "unclean", &match, &checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
index a10bb36825faf2be4b46a640c4ea62c8cc53fe00..1b8b12f52a8d131d5ad3aa1fc8b29fb7b5349ec7 100644 (file)
@@ -121,8 +121,8 @@ static struct nf_hook_ops ipt_ops[]
                NF_IP_PRI_FILTER }
 };
 
-/* Default to no forward for security reasons. */
-static int forward = NF_DROP;
+/* Default to forward because I got too much mail already. */
+static int forward = NF_ACCEPT;
 MODULE_PARM(forward, "i");
 
 static int __init init(void)
index 75aaaa34af706f69f63987cd4ba85bbe03a621a9..dc8623aad1dd925a3422a26d16720658b33b923d 100644 (file)
@@ -466,9 +466,7 @@ static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len)
         ipxh->spx.allocseq      = htons(pdata->alloc);
 
        /* Reset/Set WD timer */
-        del_timer(&pdata->watchdog);
-        pdata->watchdog.expires = jiffies + VERIFY_TIMEOUT;
-        add_timer(&pdata->watchdog);
+        mod_timer(&pdata->watchdog, jiffies+VERIFY_TIMEOUT);
 
        switch(type)
        {
index e2de156ab669180b3066ae0addc3af52c94507ae..061ef312abd689fad1eff6e912e72742c7d1b8cb 100644 (file)
@@ -232,9 +232,7 @@ tbf_dequeue(struct Qdisc* sch)
                        if (delay == 0)
                                delay = 1;
 
-                       del_timer(&q->wd_timer);
-                       q->wd_timer.expires = jiffies + delay;
-                       add_timer(&q->wd_timer);
+                       mod_timer(&q->wd_timer, jiffies+delay);
                }
 
                /* Maybe we have a shorter packet in the queue,
index 660dbbb95823d6e4b2f51d474e17b9444cfbc193..42813acfad27d484bfa2016068ce42015942a8e8 100644 (file)
@@ -4,6 +4,9 @@
  * The generic interface for RPC authentication on the server side.
  * 
  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ *
+ * CHANGES
+ * 19-Apr-2000 Chris Evans      - Security fix
  */
 
 #include <linux/types.h>
@@ -116,8 +119,8 @@ svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
        struct svc_buf  *argp = &rqstp->rq_argbuf;
        struct svc_buf  *resp = &rqstp->rq_resbuf;
        struct svc_cred *cred = &rqstp->rq_cred;
-       u32             *bufp = argp->buf;
-       int             len   = argp->len, slen, i;
+       u32             *bufp = argp->buf, slen, i;
+       int             len   = argp->len;
 
        if ((len -= 3) < 0) {
                *statp = rpc_garbage_args;
@@ -127,7 +130,7 @@ svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
        bufp++;                                 /* length */
        bufp++;                                 /* time stamp */
        slen = (ntohl(*bufp++) + 3) >> 2;       /* machname length */
-       if (slen > 64 || (len -= slen) < 0)
+       if (slen > 64 || (len -= slen + 3) < 0)
                goto badcred;
        bufp += slen;                           /* skip machname */