[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#272067: kernel: via-velocitiy 2.6.8 problems



reassign 272067 kernel-source-2.6.8
tags 272067 +patch
thanks

Hi,

The attached patches comprise my backport of the 2.6.9 
velicity-via driver to kernel-source.2.6.8 (kernel 2.6.8.1).
Can somebody, anybody test them? 

-- 
Horms
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: PATCH] via-velocity: PCI ID move
## DP: Patch author: Francois Romieu <romieu@fr.zoreil.com>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: romieu (BitKeeper)
# cset: 1.1757.6.1 (2.6) key=40d4a9d5IfARZlR9KGSssVPEAvuatw
# inclusion: upstream
# descrition: [PATCH] via-velocity: PCI ID move
# revision date: Fri, 05 Nov 2004 11:37:51 +0900
#
# rset: ChangeSet|1.1757.1.3..1.1757.6.1
# rset: drivers/net/via-velocity.c|1.1..1.2
# rset: drivers/net/via-velocity.h|1.1..1.2
# rset: include/linux/pci_ids.h|1.167..1.168
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/06/19 17:02:13-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: PCI ID move
#   
#   (Note: this serie requires a -mm based kernel as the via-velocity patches
#   are not included in Jeff's -netdev patches).
#   
#   
#   
#   PCI ID moved from the driver to the kernel database. A change for the
#   pci.ids file project at souceforge has been submitted as well.
# 
# include/linux/pci_ids.h
#   2004/06/18 15:24:53-04:00 romieu@fr.zoreil.com +1 -0
#   via-velocity: PCI ID move
# 
# drivers/net/via-velocity.h
#   2004/06/18 15:32:00-04:00 romieu@fr.zoreil.com +0 -1
#   via-velocity: PCI ID move
# 
# drivers/net/via-velocity.c
#   2004/06/18 15:32:01-04:00 romieu@fr.zoreil.com +3 -2
#   via-velocity: PCI ID move
# 
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 11:37:51 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 11:37:51 +09:00
@@ -289,8 +289,9 @@
  */
 
 static struct pci_device_id velocity_id_table[] __devinitdata = {
-	{0x1106, 0x3119, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &chip_info_table[0]},
-	{0,}
+	{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) chip_info_table},
+	{0, }
 };
 
 MODULE_DEVICE_TABLE(pci, velocity_id_table);
diff -Nru a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
--- a/drivers/net/via-velocity.h	2004-11-05 11:37:51 +09:00
+++ b/drivers/net/via-velocity.h	2004-11-05 11:37:51 +09:00
@@ -37,7 +37,6 @@
 #define OPTION_DEFAULT      { [0 ... MAX_UNITS-1] = -1}
 
 #define REV_ID_VT6110       (0)
-#define DEVICE_ID           (0x3119)
 
 #define BYTE_REG_BITS_ON(x,p)       do { writeb(readb((p))|(x),(p));} while (0)
 #define WORD_REG_BITS_ON(x,p)       do { writew(readw((p))|(x),(p));} while (0)
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	2004-11-05 11:37:51 +09:00
+++ b/include/linux/pci_ids.h	2004-11-05 11:37:51 +09:00
@@ -1215,6 +1215,7 @@
 #define PCI_DEVICE_ID_VIA_8233C_0	0x3109
 #define PCI_DEVICE_ID_VIA_8361		0x3112
 #define PCI_DEVICE_ID_VIA_XM266		0x3116
+#define PCI_DEVICE_ID_VIA_612X		0x3119
 #define PCI_DEVICE_ID_VIA_862X_0	0x3123
 #define PCI_DEVICE_ID_VIA_8753_0	0x3128
 #define PCI_DEVICE_ID_VIA_8233A		0x3147
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: [PATCH] via-velocity: Rx buffers allocation rework
## DP: Patch author: Francois Romieu <romieu@fr.zoreil.com>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: romieu (BitKeeper)
# cset: 1.1757.6.5 (2.6) key=40d794ecl91sp3GhdHCCo9kg_q2pyg
# inclusion: upstream
# descrition: [PATCH] via-velocity: Rx buffers allocation rework
# revision date: Fri, 05 Nov 2004 11:38:01 +0900
#
# rset: ChangeSet|1.1757.6.4..1.1757.6.5
# rset: drivers/net/via-velocity.c|1.5..1.6
# rset: drivers/net/via-velocity.h|1.2..1.3
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/06/21 22:09:48-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: Rx buffers allocation rework
#   
#   Rework of the Rx buffers allocation:
#   - Rx irq handler (velocity_rx_srv): defer the Rx buffer allocation until
#     the packet processing loop is done;
#   - a separate index related to the Rx descriptor ("rd_dirty") is introduced
#     to distinguish the first Rx descriptor whose buffer has to be refilled.
#     This way the driver does not need to confuse this descriptor with the
#     most recently netif()ed one. Rationale: batch + rx_copybreak;
#   - dirty/empty Rx descriptors are identified through the whole driver
#     via an adequate NULL pointer in the velocity_rd_info[] array (see
#     velocity_rx_refill() and velocity_receive_frame());
#   - Rx descriptors need to be grouped by a multiple of 4 before they can
#     be handed back to the asic (hardware constraint). This task is moved
#     from the Rx processing loop to the Rx refill function;
#   - factorization of code in velocity_init_rd_ring().
# 
# drivers/net/via-velocity.h
#   2004/06/21 15:38:34-04:00 romieu@fr.zoreil.com +2 -1
#   via-velocity: Rx buffers allocation rework
# 
# drivers/net/via-velocity.c
#   2004/06/21 15:40:41-04:00 romieu@fr.zoreil.com +60 -47
#   via-velocity: Rx buffers allocation rework
# Reoved for Debian kernel-source-2.6.8 as it is included in 1.1803.34.1
# 
diff -Nru a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
--- a/drivers/net/via-velocity.h	2004-11-05 11:38:01 +09:00
+++ b/drivers/net/via-velocity.h	2004-11-05 11:38:01 +09:00
@@ -1771,7 +1771,8 @@
 	struct velocity_td_info *td_infos[TX_QUEUE_NO];
 
 	int rd_curr;
-	int rd_used;
+	int rd_dirty;
+	u32 rd_filled;
 	struct rx_desc *rd_ring;
 	struct velocity_rd_info *rd_info;	/* It's an array */
 
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: [PATCH] #ifdef cleanups in drivers/net
## DP: Patch author: Valdis.Kletnieks@vt.edu
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: Valdis.Kletnieks (BitKeeper)
# cset: 1.1832.32.51 (2.6) key=412f728fHOX4au9l001ND9KcY_uR4A
# inclusion: upstream
# descrition: [PATCH] #ifdef cleanups in drivers/net
# revision date: Fri, 05 Nov 2004 11:38:10 +0900
#
# rset: ChangeSet|1.1832.32.50..1.1832.32.51
# rset: drivers/net/amd8111e.c|1.21..1.22
# rset: drivers/net/via-velocity.h|1.4..1.5
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/08/27 10:42:39-07:00 Valdis.Kletnieks@vt.edu 
#   [PATCH] #ifdef cleanups in drivers/net
#   
#   Here's the last of them for 2.6.9-rc1 - two more #if/#ifdef cleanups.
#   
#   Signed-off-by: <valdis.kletnieks@vt.edu>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Linus Torvalds <torvalds@osdl.org>
# 
# drivers/net/via-velocity.h
#   2004/08/27 00:02:37-07:00 Valdis.Kletnieks@vt.edu +1 -1
#   #ifdef cleanups in drivers/net
# 
# drivers/net/amd8111e.c
#   2004/08/27 00:02:37-07:00 Valdis.Kletnieks@vt.edu +1 -1
#   #ifdef cleanups in drivers/net
# 
diff -Nru a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
--- a/drivers/net/amd8111e.c	2004-11-05 11:38:10 +09:00
+++ b/drivers/net/amd8111e.c	2004-11-05 11:38:10 +09:00
@@ -719,7 +719,7 @@
 	return 0;
 }
 
-#if CONFIG_AMD8111E_NAPI 
+#ifdef CONFIG_AMD8111E_NAPI
 /* This function handles the driver receive operation in polling mode */
 static int amd8111e_rx_poll(struct net_device *dev, int * budget)
 {
diff -Nru a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
--- a/drivers/net/via-velocity.h	2004-11-05 11:38:10 +09:00
+++ b/drivers/net/via-velocity.h	2004-11-05 11:38:10 +09:00
@@ -1739,7 +1739,7 @@
 	struct net_device *dev;
 	struct net_device_stats stats;
 
-#if CONFIG_PM
+#ifdef CONFIG_PM
 	u32 pci_state[16];
 #endif
 
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: Merge
## DP: Patch author: various
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: jgarzik (BitKeeper)
# cset: 1.1803.34.1 (2.6) key=4106922eiCFuZxDC8i7Kp6IeI0SxSw
# inclusion: upstream
# descrition: Merge pobox.com:/spare/repo/linux-2.6
# revision date: Fri, 05 Nov 2004 10:59:31 +0900
#
# rset: ChangeSet|1.1803.21.64+1.1784.1.1..1.1803.34.1
# rset: drivers/net/via-velocity.c|1.1.1.1..1.12
# rset: drivers/net/Kconfig|1.79.5.3..1.79.3.2
# rset: include/linux/pci_ids.h|1.170..1.171
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/07/27 13:34:38-04:00 jgarzik@pobox.com 
#   Merge pobox.com:/spare/repo/linux-2.6
#   into pobox.com:/spare/repo/netdev-2.6/velocity
# 
# include/linux/pci_ids.h
#   2004/07/27 13:34:33-04:00 jgarzik@pobox.com +0 -0
#   Auto merged
# 
# drivers/net/via-velocity.c
#   2004/07/27 13:34:33-04:00 jgarzik@pobox.com +0 -0
#   Auto merged
# 
# drivers/net/Kconfig
#   2004/07/27 13:34:33-04:00 jgarzik@pobox.com +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/03 02:21:07-04:00 jgarzik@pobox.com 
#   Merge pobox.com:/spare/repo/linux-2.6
#   into pobox.com:/spare/repo/netdev-2.6/velocity
# 
# include/linux/pci_ids.h
#   2004/07/03 02:21:04-04:00 jgarzik@pobox.com +0 -0
#   Auto merged
# Removed for Debian kernel-source-2.6.8
# 
# ChangeSet
#   2004/07/03 02:20:30-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: use common crc16 code for WOL
#   
#   - use common crc16 code for WOL;
#   - remove unused ether_crc.
#   
#   Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
# 
# drivers/net/via-velocity.c
#   2004/06/30 16:31:05-04:00 romieu@fr.zoreil.com +4 -105
#   via-velocity: use common crc16 code for WOL
# 
# drivers/net/Kconfig
#   2004/06/30 16:31:05-04:00 romieu@fr.zoreil.com +1 -0
#   via-velocity: use common crc16 code for WOL
# 
# ChangeSet
#   2004/07/02 15:01:24-04:00 jgarzik@pobox.com 
#   Merge pobox.com:/spare/repo/linux-2.6
#   into pobox.com:/spare/repo/netdev-2.6/velocity
# 
# include/linux/pci_ids.h
#   2004/07/02 15:01:20-04:00 jgarzik@pobox.com +0 -0
#   Auto merged
# Removed for Debian kernel-source-2.6.8
# 
# ChangeSet
#   2004/06/22 00:37:39-04:00 akpm@osdl.org 
#   [PATCH] via-velocity warning fixes
#   
#   With CONFIG_PM=n various functions (such as velocity_set_wol) are unused
#   and we get warnings and unused code.
#   
#   Fix that up by moving the functions so they fall inside the callers's #ifdef
#   CONFIG_PM.
#   
#   Remove now-unneeded forward declarations.
#   
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
# 
# drivers/net/via-velocity.c
#   2004/06/22 00:30:35-04:00 akpm@osdl.org +94 -98
#   via-velocity warning fixes
# 
# ChangeSet
#   2004/06/21 22:10:51-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: unneeded forward declarations
#   
#   Removal of unneeded forward declarations.
# 
# drivers/net/via-velocity.c
#   2004/06/21 17:46:19-04:00 romieu@fr.zoreil.com +0 -4
#   via-velocity: unneeded forward declarations
# 
# ChangeSet
#   2004/06/21 22:10:42-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: ordering of Rx descriptors operations
#   
#   Force strict ordering of operations on Rx descriptors to avoid any issue
#   related to inline optimization.
# 
# drivers/net/via-velocity.c
#   2004/06/21 16:20:35-04:00 romieu@fr.zoreil.com +2 -0
#   via-velocity: ordering of Rx descriptors operations
# 
# ChangeSet
#   2004/06/21 22:10:33-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: Rx copybreak
#   
#   Handle copybreak.
#   - velocity_rx_refill() is modified to allow the processing of a Rx desc
#     ring wherein the empty skb slots are not necessarily contiguous. Given
#     the preceeding changes, rx_copybreak should not need anything else;
#   - the driver does not rely on rd_info->skb_dma set to NULL any more;
#   - pci_dma_sync_single_for_{cpu/device} changes as a bonus;
#   - more function documentation.
#   
#   Some inspiration borrowed from similar r8169 code.
# 
# drivers/net/via-velocity.c
#   2004/06/21 15:50:55-04:00 romieu@fr.zoreil.com +72 -19
#   via-velocity: Rx copybreak
# 
# ChangeSet
#   2004/06/21 22:09:48-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: Rx buffers allocation rework
#   
#   Rework of the Rx buffers allocation:
#   - Rx irq handler (velocity_rx_srv): defer the Rx buffer allocation until
#     the packet processing loop is done;
#   - a separate index related to the Rx descriptor ("rd_dirty") is introduced
#     to distinguish the first Rx descriptor whose buffer has to be refilled.
#     This way the driver does not need to confuse this descriptor with the
#     most recently netif()ed one. Rationale: batch + rx_copybreak;
#   - dirty/empty Rx descriptors are identified through the whole driver
#     via an adequate NULL pointer in the velocity_rd_info[] array (see
#     velocity_rx_refill() and velocity_receive_frame());
#   - Rx descriptors need to be grouped by a multiple of 4 before they can
#     be handed back to the asic (hardware constraint). This task is moved
#     from the Rx processing loop to the Rx refill function;
#   - factorization of code in velocity_init_rd_ring().
# 
# drivers/net/via-velocity.h
#   2004/06/21 15:38:34-04:00 romieu@fr.zoreil.com +2 -1
#   via-velocity: Rx buffers allocation rework
# 
# drivers/net/via-velocity.c
#   2004/06/21 15:40:41-04:00 romieu@fr.zoreil.com +60 -47
#   via-velocity: Rx buffers allocation rework
# 
# ChangeSet
#   2004/06/19 17:06:39-04:00 akpm@osdl.org 
#   [PATCH] fix via-velocity oopses
#   
#   - Don't register the inet_addr notifier if the hardware is absent.  It
#     oopses when other interfaces are being upped.
#   
#   - Mark velocity_remove1() as __devexit_p in the pci_driver table.
#   
#   - c99ification.
#   
#   
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
# 
# drivers/net/via-velocity.c
#   2004/06/03 02:14:38-04:00 akpm@osdl.org +18 -11
#   fix via-velocity oopses
# 
# ChangeSet
#   2004/06/19 17:02:30-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: velocity_receive_frame diets
#   
#   Weight loss in velocity_receive_frame():
#   - isolate the ip header alignment tsk from velocity_receive_frame();
#   - following p.30 of the datasheet, rdesc0.len includes the CRC length:
#     the amount of data copied during the ip alignment can be shortened.
# 
# drivers/net/via-velocity.c
#   2004/06/18 15:58:58-04:00 romieu@fr.zoreil.com +26 -10
#   via-velocity: velocity_receive_frame diets
# 
# ChangeSet
#   2004/06/19 17:02:22-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: uniformize use of OWNED_BY_NIC
#   
#   Introduce velocity_give_rx_desc() to uniformize the use of OWNED_BY_NIC
#   through the driver.
# 
# drivers/net/via-velocity.c
#   2004/06/18 15:34:14-04:00 romieu@fr.zoreil.com +9 -4
#   via-velocity: uniformize use of OWNED_BY_NIC
# 
# ChangeSet
#   2004/06/19 17:02:13-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: PCI ID move
#   
#   (Note: this serie requires a -mm based kernel as the via-velocity patches
#   are not included in Jeff's -netdev patches).
#   
#   
#   
#   PCI ID moved from the driver to the kernel database. A change for the
#   pci.ids file project at souceforge has been submitted as well.
# 
# include/linux/pci_ids.h
#   2004/06/18 15:24:53-04:00 romieu@fr.zoreil.com +1 -0
#   via-velocity: PCI ID move
# Removed for Debian kernel-source-2.6.8
# 
# drivers/net/via-velocity.h
#   2004/06/18 15:32:00-04:00 romieu@fr.zoreil.com +0 -1
#   via-velocity: PCI ID move
# 
# drivers/net/via-velocity.c
#   2004/06/18 15:32:01-04:00 romieu@fr.zoreil.com +3 -2
#   via-velocity: PCI ID move
# Removed for Debian kernel-source-2.6.8 as it is included in 1.1757.6.1
# 
diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig
--- a/drivers/net/Kconfig	2004-11-05 10:59:31 +09:00
+++ b/drivers/net/Kconfig	2004-11-05 10:59:31 +09:00
@@ -1746,6 +1746,7 @@
 	tristate "VIA Velocity support"
 	depends on NET_PCI && PCI
 	select CRC32
+	select CRC16
 	select MII
 	help
 	  If you have a VIA "Velocity" based network card say Y here.
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 10:59:31 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 10:59:31 +09:00
@@ -78,6 +78,8 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
+#include <linux/crc16.h>
+#include <linux/crc32.h>
 
 #include "via-velocity.h"
 
@@ -226,7 +228,10 @@
 
 VELOCITY_PARAM(int_works, "Number of packets per interrupt services");
 
-static int velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int rx_copybreak = 200;
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
+
 static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info);
 static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
 static void velocity_print_info(struct velocity_info *vptr);
@@ -238,10 +243,8 @@
 static struct net_device_stats *velocity_get_stats(struct net_device *dev);
 static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int velocity_close(struct net_device *dev);
-static int velocity_rx_srv(struct velocity_info *vptr, int status);
 static int velocity_receive_frame(struct velocity_info *, int idx);
 static int velocity_alloc_rx_buf(struct velocity_info *, int idx);
-static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type);
 static void velocity_free_rd_ring(struct velocity_info *vptr);
 static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *);
 static int velocity_soft_reset(struct velocity_info *vptr);
@@ -254,12 +257,8 @@
 static void enable_mii_autopoll(struct mac_regs * regs);
 static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata);
 static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data);
-static int velocity_set_wol(struct velocity_info *vptr);
-static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context);
-static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context);
 static u32 mii_check_media_mode(struct mac_regs * regs);
 static u32 check_connection_type(struct mac_regs * regs);
-static void velocity_init_cam_filter(struct velocity_info *vptr);
 static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
 
 #ifdef CONFIG_PM
@@ -269,8 +268,9 @@
 static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr);
 
 static struct notifier_block velocity_inetaddr_notifier = {
-      notifier_call:velocity_netdev_event,
+      .notifier_call	= velocity_netdev_event,
 };
+static int velocity_notifier_registered;
 
 #endif				/* CONFIG_PM */
 
@@ -463,6 +464,12 @@
 	}
 }
 
+static inline void velocity_give_rx_desc(struct rx_desc *rd)
+{
+	*(u32 *)&rd->rdesc0 = 0;
+	rd->rdesc0.owner = cpu_to_le32(OWNED_BY_NIC);
+}
+
 /**
  *	velocity_rx_reset	-	handle a receive reset
  *	@vptr: velocity we are resetting
@@ -477,13 +484,13 @@
 	struct mac_regs * regs = vptr->mac_regs;
 	int i;
 
-	vptr->rd_used = vptr->rd_curr = 0;
+	vptr->rd_dirty = vptr->rd_filled = vptr->rd_curr = 0;
 
 	/*
 	 *	Init state, all RD entries belong to the NIC
 	 */
 	for (i = 0; i < vptr->options.numrx; ++i)
-		vptr->rd_ring[i].rdesc0.owner = cpu_to_le32(OWNED_BY_NIC);
+		velocity_give_rx_desc(vptr->rd_ring + i);
 
 	writew(vptr->options.numrx, &regs->RBRDU);
 	writel(vptr->rd_pool_dma, &regs->RDBaseLo);
@@ -776,6 +783,12 @@
 	
 	pci_set_power_state(pdev, 3);
 out:
+#ifdef CONFIG_PM
+	if (ret == 0 && !velocity_notifier_registered) {
+		velocity_notifier_registered = 1;
+		register_inetaddr_notifier(&velocity_inetaddr_notifier);
+	}
+#endif
 	return ret;
 
 err_iounmap:
@@ -966,6 +979,60 @@
 	pci_free_consistent(vptr->pdev, size, vptr->tx_bufs, vptr->tx_bufs_dma);
 }
 
+static inline void velocity_give_many_rx_descs(struct velocity_info *vptr)
+{
+	struct mac_regs *regs = vptr->mac_regs;
+	int avail, dirty, unusable;
+
+	/*
+	 * RD number must be equal to 4X per hardware spec
+	 * (programming guide rev 1.20, p.13)
+	 */
+	if (vptr->rd_filled < 4)
+		return;
+
+	wmb();
+
+	unusable = vptr->rd_filled | 0x0003;
+	dirty = vptr->rd_dirty - unusable + 1;
+	for (avail = vptr->rd_filled & 0xfffc; avail; avail--) {
+		dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
+		velocity_give_rx_desc(vptr->rd_ring + dirty);
+	}
+
+	writew(vptr->rd_filled & 0xfffc, &regs->RBRDU);
+	vptr->rd_filled = unusable;
+}
+
+static int velocity_rx_refill(struct velocity_info *vptr)
+{
+	int dirty = vptr->rd_dirty, done = 0, ret = 0;
+
+	do {
+		struct rx_desc *rd = vptr->rd_ring + dirty;
+
+		/* Fine for an all zero Rx desc at init time as well */
+		if (rd->rdesc0.owner == cpu_to_le32(OWNED_BY_NIC))
+			break;
+
+		if (!vptr->rd_info[dirty].skb) {
+			ret = velocity_alloc_rx_buf(vptr, dirty);
+			if (ret < 0)
+				break;
+		}
+		done++;
+		dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0;	
+	} while (dirty != vptr->rd_curr);
+
+	if (done) {
+		vptr->rd_dirty = dirty;
+		vptr->rd_filled += done;
+		velocity_give_many_rx_descs(vptr);
+	}
+
+	return ret;
+}
+
 /**
  *	velocity_init_rd_ring	-	set up receive ring
  *	@vptr: velocity to configure
@@ -976,9 +1043,7 @@
 
 static int velocity_init_rd_ring(struct velocity_info *vptr)
 {
-	int i, ret = -ENOMEM;
-	struct rx_desc *rd;
-	struct velocity_rd_info *rd_info;
+	int ret = -ENOMEM;
 	unsigned int rsize = sizeof(struct velocity_rd_info) * 
 					vptr->options.numrx;
 
@@ -987,22 +1052,14 @@
 		goto out;
 	memset(vptr->rd_info, 0, rsize);
 
-	/* Init the RD ring entries */
-	for (i = 0; i < vptr->options.numrx; i++) {
-		rd = &(vptr->rd_ring[i]);
-		rd_info = &(vptr->rd_info[i]);
+	vptr->rd_filled = vptr->rd_dirty = vptr->rd_curr = 0;
 
-		ret = velocity_alloc_rx_buf(vptr, i);
-		if (ret < 0) {
-			VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
-				"%s: failed to allocate RX buffer.\n", 
-				vptr->dev->name);
-			velocity_free_rd_ring(vptr);
-			goto out;
-		}
-		rd->rdesc0.owner = OWNED_BY_NIC;
+	ret = velocity_rx_refill(vptr);
+	if (ret < 0) {
+		VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
+			"%s: failed to allocate RX buffer.\n", vptr->dev->name);
+		velocity_free_rd_ring(vptr);
 	}
-	vptr->rd_used = vptr->rd_curr = 0;
 out:
 	return ret;
 }
@@ -1025,7 +1082,7 @@
 	for (i = 0; i < vptr->options.numrx; i++) {
 		struct velocity_rd_info *rd_info = &(vptr->rd_info[i]);
 
-		if (!rd_info->skb_dma)
+		if (!rd_info->skb)
 			continue;
 		pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz,
 				 PCI_DMA_FROMDEVICE);
@@ -1146,22 +1203,14 @@
  
 static int velocity_rx_srv(struct velocity_info *vptr, int status)
 {
-	struct rx_desc *rd;
 	struct net_device_stats *stats = &vptr->stats;
-	struct mac_regs * regs = vptr->mac_regs;
 	int rd_curr = vptr->rd_curr;
 	int works = 0;
 
 	while (1) {
+		struct rx_desc *rd = vptr->rd_ring + rd_curr;
 
-		rd = &(vptr->rd_ring[rd_curr]);
-
-		if ((vptr->rd_info[rd_curr]).skb == NULL) {
-			if (velocity_alloc_rx_buf(vptr, rd_curr) < 0)
-				break;
-		}
-
-		if (works++ > 15)
+		if (!vptr->rd_info[rd_curr].skb || (works++ > 15))
 			break;
 
 		if (rd->rdesc0.owner == OWNED_BY_NIC)
@@ -1169,17 +1218,10 @@
 
 		/*
 		 *	Don't drop CE or RL error frame although RXOK is off
-		 *	FIXME: need to handle copybreak
 		 */
 		if ((rd->rdesc0.RSR & RSR_RXOK) || (!(rd->rdesc0.RSR & RSR_RXOK) && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) {
-			if (velocity_receive_frame(vptr, rd_curr) == 0) {
-				if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) {
-					VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not allocate rx buf\n", vptr->dev->name);
-					break;
-				}
-			} else {
+			if (velocity_receive_frame(vptr, rd_curr) < 0)
 				stats->rx_dropped++;
-			}
 		} else {
 			if (rd->rdesc0.RSR & RSR_CRC)
 				stats->rx_crc_errors++;
@@ -1191,25 +1233,18 @@
 
 		rd->inten = 1;
 
-		if (++vptr->rd_used >= 4) {
-			int i, rd_prev = rd_curr;
-			for (i = 0; i < 4; i++) {
-				if (--rd_prev < 0)
-					rd_prev = vptr->options.numrx - 1;
-
-				rd = &(vptr->rd_ring[rd_prev]);
-				rd->rdesc0.owner = OWNED_BY_NIC;
-			}
-			writew(4, &(regs->RBRDU));
-			vptr->rd_used -= 4;
-		}
-
 		vptr->dev->last_rx = jiffies;
 
 		rd_curr++;
 		if (rd_curr >= vptr->options.numrx)
 			rd_curr = 0;
 	}
+
+	if (velocity_rx_refill(vptr) < 0) {
+		VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
+			"%s: rx buf allocation failure\n", vptr->dev->name);
+	}
+
 	vptr->rd_curr = rd_curr;
 	VAR_USED(stats);
 	return works;
@@ -1242,6 +1277,65 @@
 }
 
 /**
+ *	velocity_rx_copy	-	in place Rx copy for small packets
+ *	@rx_skb: network layer packet buffer candidate
+ *	@pkt_size: received data size
+ *	@rd: receive packet descriptor
+ *	@dev: network device
+ *
+ *	Replace the current skb that is scheduled for Rx processing by a
+ *	shorter, immediatly allocated skb, if the received packet is small
+ *	enough. This function returns a negative value if the received
+ *	packet is too big or if memory is exhausted.
+ */
+static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
+				   struct velocity_info *vptr)
+{
+	int ret = -1;
+
+	if (pkt_size < rx_copybreak) {
+		struct sk_buff *new_skb;
+
+		new_skb = dev_alloc_skb(pkt_size + 2);
+		if (new_skb) {
+			new_skb->dev = vptr->dev;
+			new_skb->ip_summed = rx_skb[0]->ip_summed;
+
+			if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN)
+				skb_reserve(new_skb, 2);
+
+			memcpy(new_skb->data, rx_skb[0]->tail, pkt_size);
+			*rx_skb = new_skb;
+			ret = 0;
+		}
+		
+	}
+	return ret;
+}
+
+/**
+ *	velocity_iph_realign	-	IP header alignment
+ *	@vptr: velocity we are handling
+ *	@skb: network layer packet buffer
+ *	@pkt_size: received data size
+ *
+ *	Align IP header on a 2 bytes boundary. This behavior can be
+ *	configured by the user.
+ */
+static inline void velocity_iph_realign(struct velocity_info *vptr,
+					struct sk_buff *skb, int pkt_size)
+{
+	/* FIXME - memmove ? */
+	if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) {
+		int i;
+
+		for (i = pkt_size; i >= 0; i--)
+			*(skb->data + i + 2) = *(skb->data + i);
+		skb_reserve(skb, 2);
+	}
+}
+
+/**
  *	velocity_receive_frame	-	received packet processor
  *	@vptr: velocity we are handling
  *	@idx: ring index
@@ -1252,9 +1346,11 @@
  
 static int velocity_receive_frame(struct velocity_info *vptr, int idx)
 {
+	void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
 	struct net_device_stats *stats = &vptr->stats;
 	struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]);
 	struct rx_desc *rd = &(vptr->rd_ring[idx]);
+	int pkt_len = rd->rdesc0.len;
 	struct sk_buff *skb;
 
 	if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) {
@@ -1269,22 +1365,8 @@
 	skb = rd_info->skb;
 	skb->dev = vptr->dev;
 
-	pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, 
-							PCI_DMA_FROMDEVICE);
-	rd_info->skb_dma = (dma_addr_t) NULL;
-	rd_info->skb = NULL;
-
-	/* FIXME - memmove ? */
-	if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) {
-		int i;
-		for (i = rd->rdesc0.len + 4; i >= 0; i--)
-			*(skb->data + i + 2) = *(skb->data + i);
-		skb->data += 2;
-		skb->tail += 2;
-	}
-
-	skb_put(skb, (rd->rdesc0.len - 4));
-	skb->protocol = eth_type_trans(skb, skb->dev);
+	pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma,
+				    vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
 	/*
 	 *	Drop frame not meeting IEEE 802.3
@@ -1297,13 +1379,23 @@
 		}
 	}
 
+	pci_action = pci_dma_sync_single_for_device;
+
 	velocity_rx_csum(rd, skb);
-	
-	/*
-	 *	FIXME: need rx_copybreak handling
-	 */
 
-	stats->rx_bytes += skb->len;
+	if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) {
+		velocity_iph_realign(vptr, skb, pkt_len);
+		pci_action = pci_unmap_single;
+		rd_info->skb = NULL;
+	}
+
+	pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz,
+		   PCI_DMA_FROMDEVICE);
+
+	skb_put(skb, pkt_len - 4);
+	skb->protocol = eth_type_trans(skb, skb->dev);	
+
+	stats->rx_bytes += pkt_len;
 	netif_rx(skb);
 
 	return 0;
@@ -1963,32 +2055,6 @@
 
 
 /**
- *	ether_crc	-	ethernet CRC function
- *
- *	Compute an ethernet CRC hash of the data block provided. This
- *	is not performance optimised but is not needed in performance
- *	critical code paths.
- *
- *	FIXME: could we use shared code here ?
- */
- 
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-	static unsigned const ethernet_polynomial = 0x04c11db7U;
-	
-	int crc = -1;
-
-	while (--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
-			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-		}
-	}
-	return crc;
-}
-
-/**
  *	velocity_set_multi	-	filter list change callback
  *	@dev: network device
  *
@@ -2123,13 +2189,13 @@
  */
  
 static struct pci_driver velocity_driver = {
-      name:VELOCITY_NAME,
-      id_table:velocity_id_table,
-      probe:velocity_found1,
-      remove:velocity_remove1,
+      .name	= VELOCITY_NAME,
+      .id_table	= velocity_id_table,
+      .probe	= velocity_found1,
+      .remove	= __devexit_p(velocity_remove1),
 #ifdef CONFIG_PM
-      suspend:velocity_suspend,
-      resume:velocity_resume,
+      .suspend	= velocity_suspend,
+      .resume	= velocity_resume,
 #endif
 };
 
@@ -2147,9 +2213,6 @@
 	int ret;
 	ret = pci_module_init(&velocity_driver);
 
-#ifdef CONFIG_PM
-	register_inetaddr_notifier(&velocity_inetaddr_notifier);
-#endif
 	return ret;
 }
 
@@ -2165,7 +2228,10 @@
 static void __exit velocity_cleanup_module(void)
 {
 #ifdef CONFIG_PM
-	unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+	if (velocity_notifier_registered) {
+		unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+		velocity_notifier_registered = 0;
+	}
 #endif
 	pci_unregister_driver(&velocity_driver);
 }
@@ -2992,172 +3058,6 @@
 
 }
 
-static int velocity_suspend(struct pci_dev *pdev, u32 state)
-{
-	struct velocity_info *vptr = pci_get_drvdata(pdev);
-	unsigned long flags;
-	
-	if(!netif_running(vptr->dev))
-		return 0;
-		
-	netif_device_detach(vptr->dev);
-	
-	spin_lock_irqsave(&vptr->lock, flags);
-	pci_save_state(pdev, vptr->pci_state);
-#ifdef ETHTOOL_GWOL
-	if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
-		velocity_get_ip(vptr);
-		velocity_save_context(vptr, &vptr->context);
-		velocity_shutdown(vptr);
-		velocity_set_wol(vptr);
-		pci_enable_wake(pdev, 3, 1);
-		pci_set_power_state(pdev, 3);
-	} else {
-		velocity_save_context(vptr, &vptr->context);
-		velocity_shutdown(vptr);
-		pci_disable_device(pdev);
-		pci_set_power_state(pdev, state);
-	}
-#else
-	pci_set_power_state(pdev, state);
-#endif
-	spin_unlock_irqrestore(&vptr->lock, flags);
-	return 0;
-}
-
-static int velocity_resume(struct pci_dev *pdev)
-{
-	struct velocity_info *vptr = pci_get_drvdata(pdev);
-	unsigned long flags;
-	int i;
-	
-	if(!netif_running(vptr->dev))
-		return 0;
-		
-	pci_set_power_state(pdev, 0);
-	pci_enable_wake(pdev, 0, 0);
-	pci_restore_state(pdev, vptr->pci_state);
-
-	mac_wol_reset(vptr->mac_regs);
-
-	spin_lock_irqsave(&vptr->lock, flags);
-	velocity_restore_context(vptr, &vptr->context);
-	velocity_init_registers(vptr, VELOCITY_INIT_WOL);
-	mac_disable_int(vptr->mac_regs);
-
-	velocity_tx_srv(vptr, 0);
-
-	for (i = 0; i < vptr->num_txq; i++) {
-		if (vptr->td_used[i]) {
-			mac_tx_queue_wake(vptr->mac_regs, i);
-		}
-	}
-
-	mac_enable_int(vptr->mac_regs);
-	spin_unlock_irqrestore(&vptr->lock, flags);
-	netif_device_attach(vptr->dev);
-
-	return 0;
-}
-
-static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
-{
-	struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
-	struct net_device *dev;
-	struct velocity_info *vptr;
-
-	if (ifa) {
-		dev = ifa->ifa_dev->dev;
-		vptr = dev->priv;
-		velocity_get_ip(vptr);
-	}
-	return NOTIFY_DONE;
-}
-#endif
-
-/*
- * Purpose: Functions to set WOL.
- */
-
-const static unsigned short crc16_tab[256] = {
-	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
-	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
-	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
-	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
-	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
-	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
-	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
-	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
-	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
-	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
-	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
-	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
-	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
-	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
-	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
-	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
-	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
-	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
-	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
-	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
-	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
-	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
-	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
-	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
-	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
-	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
-	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
-	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
-	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
-	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
-	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
-	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
-};
-
-
-static u32 mask_pattern[2][4] = {
-	{0x00203000, 0x000003C0, 0x00000000, 0x0000000},	/* ARP		*/
-	{0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff}		/* Magic Packet */ 
-};
-
-/**
- *	ether_crc16	-	compute ethernet CRC
- *	@len: buffer length
- *	@cp: buffer
- *	@crc16: initial CRC
- *
- *	Compute a CRC value for a block of data. 
- *	FIXME: can we use generic functions ?
- */
- 
-static u16 ether_crc16(int len, u8 * cp, u16 crc16)
-{
-	while (len--)
-		crc16 = (crc16 >> 8) ^ crc16_tab[(crc16 ^ *cp++) & 0xff];
-	return (crc16);
-}
-
-/**
- *	bit_reverse		-	16bit reverse
- *	@data: 16bit data t reverse
- *
- *	Reverse the order of a 16bit value and return the reversed bits
- */
- 
-static u16 bit_reverse(u16 data)
-{
-	u32 new = 0x00000000;
-	int ii;
-
-
-	for (ii = 0; ii < 16; ii++) {
-		new |= ((u32) (data & 1) << (31 - ii));
-		data >>= 1;
-	}
-
-	return (u16) (new >> 16);
-}
-
 /**
  *	wol_calc_crc		-	WOL CRC
  *	@pattern: data pattern
@@ -3166,7 +3066,7 @@
  *	Compute the wake on lan crc hashes for the packet header
  *	we are interested in.
  */
- 
+
 u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
 {
 	u16 crc = 0xFFFF;
@@ -3186,12 +3086,12 @@
 				continue;
 			}
 			mask >>= 1;
-			crc = ether_crc16(1, &(pattern[i * 8 + j]), crc);
+			crc = crc16(crc, &(pattern[i * 8 + j]), 1);
 		}
 	}
 	/*	Finally, invert the result once to get the correct data */
 	crc = ~crc;
-	return bit_reverse(crc);
+	return bitreverse(crc) >> 16;
 }
 
 /**
@@ -3203,13 +3103,18 @@
  *
  *	FIXME: check static buffer is safe here
  */
- 
+
 static int velocity_set_wol(struct velocity_info *vptr)
 {
 	struct mac_regs * regs = vptr->mac_regs;
 	static u8 buf[256];
 	int i;
 
+	static u32 mask_pattern[2][4] = {
+		{0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */
+		{0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff}	 /* Magic Packet */
+	};
+
 	writew(0xFFFF, &regs->WOLCRClr);
 	writeb(WOLCFG_SAB | WOLCFG_SAM, &regs->WOLCFGSet);
 	writew(WOLCR_MAGIC_EN, &regs->WOLCRSet);
@@ -3236,7 +3141,8 @@
 
 		memcpy(arp->ar_tip, vptr->ip_addr, 4);
 
-		crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, (u8 *) & mask_pattern[0][0]);
+		crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf,
+				(u8 *) & mask_pattern[0][0]);
 
 		writew(crc, &regs->PatternCRC[0]);
 		writew(WOLCR_ARP_EN, &regs->WOLCRSet);
@@ -3275,3 +3181,85 @@
 	return 0;
 }
 
+static int velocity_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct velocity_info *vptr = pci_get_drvdata(pdev);
+	unsigned long flags;
+
+	if(!netif_running(vptr->dev))
+		return 0;
+
+	netif_device_detach(vptr->dev);
+
+	spin_lock_irqsave(&vptr->lock, flags);
+	pci_save_state(pdev, vptr->pci_state);
+#ifdef ETHTOOL_GWOL
+	if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
+		velocity_get_ip(vptr);
+		velocity_save_context(vptr, &vptr->context);
+		velocity_shutdown(vptr);
+		velocity_set_wol(vptr);
+		pci_enable_wake(pdev, 3, 1);
+		pci_set_power_state(pdev, 3);
+	} else {
+		velocity_save_context(vptr, &vptr->context);
+		velocity_shutdown(vptr);
+		pci_disable_device(pdev);
+		pci_set_power_state(pdev, state);
+	}
+#else
+	pci_set_power_state(pdev, state);
+#endif
+	spin_unlock_irqrestore(&vptr->lock, flags);
+	return 0;
+}
+
+static int velocity_resume(struct pci_dev *pdev)
+{
+	struct velocity_info *vptr = pci_get_drvdata(pdev);
+	unsigned long flags;
+	int i;
+
+	if(!netif_running(vptr->dev))
+		return 0;
+
+	pci_set_power_state(pdev, 0);
+	pci_enable_wake(pdev, 0, 0);
+	pci_restore_state(pdev, vptr->pci_state);
+
+	mac_wol_reset(vptr->mac_regs);
+
+	spin_lock_irqsave(&vptr->lock, flags);
+	velocity_restore_context(vptr, &vptr->context);
+	velocity_init_registers(vptr, VELOCITY_INIT_WOL);
+	mac_disable_int(vptr->mac_regs);
+
+	velocity_tx_srv(vptr, 0);
+
+	for (i = 0; i < vptr->num_txq; i++) {
+		if (vptr->td_used[i]) {
+			mac_tx_queue_wake(vptr->mac_regs, i);
+		}
+	}
+
+	mac_enable_int(vptr->mac_regs);
+	spin_unlock_irqrestore(&vptr->lock, flags);
+	netif_device_attach(vptr->dev);
+
+	return 0;
+}
+
+static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
+{
+	struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
+	struct net_device *dev;
+	struct velocity_info *vptr;
+
+	if (ifa) {
+		dev = ifa->ifa_dev->dev;
+		vptr = dev->priv;
+		velocity_get_ip(vptr);
+	}
+	return NOTIFY_DONE;
+}
+#endif
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: [PATCH] CRC16 renaming in VIA Velocity ethernet driver
## DP: Patch author: Andrey Panin <pazke@donpac.ru>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: pazke (BitKeeper)
# cset: 1.1803.144.220 (2.6) key=412a4eeatO0kCVlyT2LNUdcd4c9gAg
# inclusion: upstream
# descrition: [PATCH] CRC16 renaming in VIA Velocity ethernet driver
# revision date: Fri, 05 Nov 2004 10:59:41 +0900
#
# rset: ChangeSet|1.1803.144.219..1.1803.144.220
# rset: drivers/net/via-velocity.c|1.12..1.13
# rset: drivers/net/Kconfig|1.86..1.87
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/08/23 13:09:14-07:00 pazke@donpac.ru 
#   [PATCH] CRC16 renaming in VIA Velocity ethernet driver
#   
#   Signed-off-by: Andrey Panin <pazke@donpac.ru>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Linus Torvalds <torvalds@osdl.org>
# 
# drivers/net/via-velocity.c
#   2004/08/23 01:15:29-07:00 pazke@donpac.ru +2 -2
#   CRC16 renaming in VIA Velocity ethernet driver
# 
# drivers/net/Kconfig
#   2004/08/23 01:15:29-07:00 pazke@donpac.ru +0 -1
#   CRC16 renaming in VIA Velocity ethernet driver
# 
diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig
--- a/drivers/net/Kconfig	2004-11-05 10:59:41 +09:00
+++ b/drivers/net/Kconfig	2004-11-05 10:59:41 +09:00
@@ -1746,7 +1746,6 @@
 	tristate "VIA Velocity support"
 	depends on NET_PCI && PCI
 	select CRC32
-	select CRC16
 	select MII
 	help
 	  If you have a VIA "Velocity" based network card say Y here.
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 10:59:41 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 10:59:41 +09:00
@@ -78,7 +78,7 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
-#include <linux/crc16.h>
+#include <linux/crc-ccitt.h>
 #include <linux/crc32.h>
 
 #include "via-velocity.h"
@@ -3086,7 +3086,7 @@
 				continue;
 			}
 			mask >>= 1;
-			crc = crc16(crc, &(pattern[i * 8 + j]), 1);
+			crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1);
 		}
 	}
 	/*	Finally, invert the result once to get the correct data */
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: [PATCH] via-velocity: more inetaddr_notifier fix
## DP: Patch author: Francois Romieu <romieu@fr.zoreil.com>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: akpm (BitKeeper)
# cset: 1.1832.13.11 (2.6) key=412c06e4eBj9-JEPzz-rKBqwx-047A
# inclusion: upstream
# descrition: [PATCH] via-velocity: more inetaddr_notifier fix
# revision date: Fri, 05 Nov 2004 10:59:51 +0900
#
# rset: ChangeSet|1.1832.13.10..1.1832.13.11
# rset: drivers/net/via-velocity.c|1.13..1.14
# rset: drivers/net/via-velocity.h|1.3..1.4
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/08/24 23:26:28-04:00 akpm@osdl.org 
#   [PATCH] via-velocity: more inetaddr_notifier fix
#   
#   From: Francois Romieu <romieu@fr.zoreil.com>
#   
#   There is no guarantee that the event which gets passed is associated to a
#   via-velocity device, thus preventing to dereference dev->priv as if it
#   always was a struct velocity_info *.  The via-velocity devices are kept in
#   a module private list for comparison.
#   
#   Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
# 
# drivers/net/via-velocity.h
#   2004/08/24 22:18:34-04:00 akpm@osdl.org +1 -2
#   via-velocity: more inetaddr_notifier fix
# 
# drivers/net/via-velocity.c
#   2004/08/24 22:18:34-04:00 akpm@osdl.org +54 -18
#   via-velocity: more inetaddr_notifier fix
# 
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 10:59:51 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 10:59:51 +09:00
@@ -262,6 +262,7 @@
 static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
 
 #ifdef CONFIG_PM
+
 static int velocity_suspend(struct pci_dev *pdev, u32 state);
 static int velocity_resume(struct pci_dev *pdev);
 
@@ -270,9 +271,26 @@
 static struct notifier_block velocity_inetaddr_notifier = {
       .notifier_call	= velocity_netdev_event,
 };
-static int velocity_notifier_registered;
 
-#endif				/* CONFIG_PM */
+static spinlock_t velocity_dev_list_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(velocity_dev_list);
+
+static void velocity_register_notifier(void)
+{
+	register_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
+
+static void velocity_unregister_notifier(void)
+{
+	unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
+
+#else				/* CONFIG_PM */
+
+#define velocity_register_notifier()	do {} while (0)
+#define velocity_unregister_notifier()	do {} while (0)
+
+#endif				/* !CONFIG_PM */
 
 /*
  *	Internal board variants. At the moment we have only one
@@ -327,6 +345,14 @@
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct velocity_info *vptr = dev->priv;
 
+#ifdef CONFIG_PM
+	unsigned long flags;
+
+	spin_lock_irqsave(&velocity_dev_list_lock, flags);
+	if (!list_empty(&velocity_dev_list))
+		list_del(&vptr->list);
+	spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
+#endif
 	unregister_netdev(dev);
 	iounmap(vptr->mac_regs);
 	pci_release_regions(pdev);
@@ -782,13 +808,16 @@
 	/* and leave the chip powered down */
 	
 	pci_set_power_state(pdev, 3);
-out:
 #ifdef CONFIG_PM
-	if (ret == 0 && !velocity_notifier_registered) {
-		velocity_notifier_registered = 1;
-		register_inetaddr_notifier(&velocity_inetaddr_notifier);
+	{
+		unsigned long flags;
+
+		spin_lock_irqsave(&velocity_dev_list_lock, flags);
+		list_add(&vptr->list, &velocity_dev_list);
+		spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
 	}
 #endif
+out:
 	return ret;
 
 err_iounmap:
@@ -843,6 +872,8 @@
 
 	spin_lock_init(&vptr->lock);
 	spin_lock_init(&vptr->xmit_lock);
+
+	INIT_LIST_HEAD(&vptr->list);
 }
 
 /**
@@ -2211,8 +2242,11 @@
 static int __init velocity_init_module(void)
 {
 	int ret;
-	ret = pci_module_init(&velocity_driver);
 
+	velocity_register_notifier();
+	ret = pci_module_init(&velocity_driver);
+	if (ret < 0)
+		velocity_unregister_notifier();
 	return ret;
 }
 
@@ -2227,12 +2261,7 @@
  
 static void __exit velocity_cleanup_module(void)
 {
-#ifdef CONFIG_PM
-	if (velocity_notifier_registered) {
-		unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
-		velocity_notifier_registered = 0;
-	}
-#endif
+	velocity_unregister_notifier();
 	pci_unregister_driver(&velocity_driver);
 }
 
@@ -3252,13 +3281,20 @@
 static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
 {
 	struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
-	struct net_device *dev;
-	struct velocity_info *vptr;
 
 	if (ifa) {
-		dev = ifa->ifa_dev->dev;
-		vptr = dev->priv;
-		velocity_get_ip(vptr);
+		struct net_device *dev = ifa->ifa_dev->dev;
+		struct velocity_info *vptr;
+		unsigned long flags;
+
+		spin_lock_irqsave(&velocity_dev_list_lock, flags);
+		list_for_each_entry(vptr, &velocity_dev_list, list) {
+			if (vptr->dev == dev) {
+				velocity_get_ip(vptr);
+				break;
+			}
+		}
+		spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
 	}
 	return NOTIFY_DONE;
 }
diff -Nru a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
--- a/drivers/net/via-velocity.h	2004-11-05 10:59:51 +09:00
+++ b/drivers/net/via-velocity.h	2004-11-05 10:59:51 +09:00
@@ -1733,8 +1733,7 @@
 };
 
 struct velocity_info {
-	struct velocity_info *next;
-	struct velocity_info *prev;
+	struct list_head list;
 
 	struct pci_dev *pdev;
 	struct net_device *dev;
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: [PATCH] via-velocity: properly manage the count of adapters
## DP: Patch author: Tejun Heo <tj@home-tj.org>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: romieu (BitKeeper)
# cset: 1.1988.54.2 (2.6) key=4161bc26pxXCHECI3j2fS0f04iJlDA
# inclusion: upstream
# descrition: [PATCH] via-velocity: properly manage the count of adapters
# revision date: Fri, 05 Nov 2004 11:00:01 +0900
#
# rset: ChangeSet|1.1988.54.1..1.1988.54.2
# rset: drivers/net/via-velocity.c|1.14..1.15
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/04 17:09:58-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: properly manage the count of adapters
#   
#   velocity_nics wasn't managed properly.
#   
#   Signed-off-by: Tejun Heo <tj@home-tj.org>
# 
# drivers/net/via-velocity.c
#   2004/10/01 15:37:28-04:00 romieu@fr.zoreil.com +5 -2
#   via-velocity: properly manage the count of adapters
# 
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 11:00:01 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 11:00:01 +09:00
@@ -359,6 +359,8 @@
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 	free_netdev(dev);
+
+	velocity_nics--;
 }
 
 /**
@@ -695,7 +697,7 @@
 	struct mac_regs * regs;
 	int ret = -ENOMEM;
 
-	if (velocity_nics++ >= MAX_UNITS) {
+	if (velocity_nics >= MAX_UNITS) {
 		printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n", 
 				velocity_nics);
 		return -ENODEV;
@@ -762,7 +764,7 @@
 		dev->dev_addr[i] = readb(&regs->PAR[i]);
 
 
-	velocity_get_options(&vptr->options, velocity_nics - 1, dev->name);
+	velocity_get_options(&vptr->options, velocity_nics, dev->name);
 
 	/* 
 	 *	Mask out the options cannot be set to the chip
@@ -817,6 +819,7 @@
 		spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
 	}
 #endif
+	velocity_nics++;
 out:
 	return ret;
 
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: [PATCH] via-velocity: removal of unused velocity_info.xmit_lock
## DP: Patch author: Tejun Heo <tj@home-tj.org>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: romieu (BitKeeper)
# cset: 1.1988.54.3 (2.6) key=4161bc34iMeaQlErqZQufrVxbWvMWA
# inclusion: upstream
# descrition: [PATCH] via-velocity: removal of unused velocity_info.xmit_lock
# revision date: Fri, 05 Nov 2004 11:00:11 +0900
#
# rset: ChangeSet|1.1988.54.2..1.1988.54.3
# rset: drivers/net/via-velocity.c|1.15..1.16
# rset: drivers/net/via-velocity.h|1.5..1.6
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/04 17:10:12-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: removal of unused velocity_info.xmit_lock
#   
#   Removed unused velocity_info.xmit_lock.
#   
#   Signed-off-by: Tejun Heo <tj@home-tj.org>
# 
# drivers/net/via-velocity.h
#   2004/10/01 15:37:31-04:00 romieu@fr.zoreil.com +0 -1
#   via-velocity: removal of unused velocity_info.xmit_lock
# 
# drivers/net/via-velocity.c
#   2004/10/01 15:37:31-04:00 romieu@fr.zoreil.com +0 -3
#   via-velocity: removal of unused velocity_info.xmit_lock
# 
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 11:00:11 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 11:00:11 +09:00
@@ -872,10 +872,7 @@
 	vptr->io_size = info->io_size;
 	vptr->num_txq = info->txqueue;
 	vptr->multicast_limit = MCAM_SIZE;
-
 	spin_lock_init(&vptr->lock);
-	spin_lock_init(&vptr->xmit_lock);
-
 	INIT_LIST_HEAD(&vptr->list);
 }
 
diff -Nru a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
--- a/drivers/net/via-velocity.h	2004-11-05 11:00:11 +09:00
+++ b/drivers/net/via-velocity.h	2004-11-05 11:00:11 +09:00
@@ -1792,7 +1792,6 @@
 	u8 mCAMmask[(MCAM_SIZE / 8)];
 
 	spinlock_t lock;
-	spinlock_t xmit_lock;
 
 	int wol_opts;
 	u8 wol_passwd[6];
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: PATCH] via-velocity: velocity_give_rx_desc() removal
## DP: Patch author: Francois Romieu <romieu@fr.zoreil.com>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: romieu (BitKeeper)
# cset: 1.1988.54.4 (2.6) key=4161bc41FDrwlBLCKHlWbztzwl3m7A
# inclusion: upstream
# descrition: [PATCH] via-velocity: velocity_give_rx_desc() removal
# revision date: Fri, 05 Nov 2004 11:00:21 +0900
#
# rset: ChangeSet|1.1988.54.3..1.1988.54.4
# rset: drivers/net/via-velocity.c|1.16..1.17
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/04 17:10:25-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: velocity_give_rx_desc() removal
#   
#   In velocity_give_rx_desc(), there should be a wmb() between resetting the
#   first four bytes of rdesc0 and setting owner. As resetting the first four
#   bytes isn't necessary, I just removed the function and directly set owner.
#   Another rationale for removing the function:
#   The function doesn't handle synchronization. We should do wmb() before
#   calling the function.  So, I think using bare assignment makes the fact
#   more explicit.
#   
#   Signed-off-by: Tejun Heo <tj@home-tj.org>
# 
# drivers/net/via-velocity.c
#   2004/10/01 15:37:34-04:00 romieu@fr.zoreil.com +2 -8
#   via-velocity: velocity_give_rx_desc() removal
# 
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 11:00:21 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 11:00:21 +09:00
@@ -492,12 +492,6 @@
 	}
 }
 
-static inline void velocity_give_rx_desc(struct rx_desc *rd)
-{
-	*(u32 *)&rd->rdesc0 = 0;
-	rd->rdesc0.owner = cpu_to_le32(OWNED_BY_NIC);
-}
-
 /**
  *	velocity_rx_reset	-	handle a receive reset
  *	@vptr: velocity we are resetting
@@ -518,7 +512,7 @@
 	 *	Init state, all RD entries belong to the NIC
 	 */
 	for (i = 0; i < vptr->options.numrx; ++i)
-		velocity_give_rx_desc(vptr->rd_ring + i);
+		vptr->rd_ring[i].rdesc0.owner = OWNED_BY_NIC;
 
 	writew(vptr->options.numrx, &regs->RBRDU);
 	writel(vptr->rd_pool_dma, &regs->RDBaseLo);
@@ -1028,7 +1022,7 @@
 	dirty = vptr->rd_dirty - unusable + 1;
 	for (avail = vptr->rd_filled & 0xfffc; avail; avail--) {
 		dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
-		velocity_give_rx_desc(vptr->rd_ring + dirty);
+		vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC;
 	}
 
 	writew(vptr->rd_filled & 0xfffc, &regs->RBRDU);
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: [PATCH] via-velocity: received ring wrong index and missing barriers
## DP: Patch author: Francois Romieu <romieu@fr.zoreil.com>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: romieu (BitKeeper)
# cset: 1.1988.54.5 (2.6) key=4161bc4f_AKSdbMURB6jBiiHcb86hw
# inclusion: upstream
# descrition: [PATCH] via-velocity: received ring wrong index and missing barriers
# revision date: Fri, 05 Nov 2004 11:00:31 +0900
#
# rset: ChangeSet|1.1988.54.4..1.1988.54.5
# rset: drivers/net/via-velocity.c|1.17..1.18
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/04 17:10:39-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: received ring wrong index and missing barriers
#   
#   There were several receive ring related bugs.
#   
#   In velocity_give_many_rx_descs(), index calculation was incorrect.
#   This and bugs in velocity_rx_srv() described in the following paragraph
#   caused packet loss, truncation and infinite error interrupt generation.
#   
#   In velocity_rx_srv(), velocity_rx_refill() could be called without any
#   dirty slot.  With proper timing, This can result in refilling yet
#   unreceived packets and pushing dirty pointer ahead of the current pointer.
#   And vptr->rd_curr which is used by velocity_rx_refill() was updated after
#   calling velocity_rx_refill() thus screwing receive descriptor ring.
#   Also, between checking owner and reading the packet, rmb() is missing.
#   
#   Signed-off-by: Tejun Heo <tj@home-tj.org>
# 
# drivers/net/via-velocity.c
#   2004/10/01 15:37:37-04:00 romieu@fr.zoreil.com +10 -7
#   via-velocity: received ring wrong index and missing barriers
# 
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 11:00:31 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 11:00:31 +09:00
@@ -1018,8 +1018,8 @@
 
 	wmb();
 
-	unusable = vptr->rd_filled | 0x0003;
-	dirty = vptr->rd_dirty - unusable + 1;
+	unusable = vptr->rd_filled & 0x0003;
+	dirty = vptr->rd_dirty - unusable;
 	for (avail = vptr->rd_filled & 0xfffc; avail; avail--) {
 		dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
 		vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC;
@@ -1232,15 +1232,17 @@
 	int rd_curr = vptr->rd_curr;
 	int works = 0;
 
-	while (1) {
+	do {
 		struct rx_desc *rd = vptr->rd_ring + rd_curr;
 
-		if (!vptr->rd_info[rd_curr].skb || (works++ > 15))
+		if (!vptr->rd_info[rd_curr].skb)
 			break;
 
 		if (rd->rdesc0.owner == OWNED_BY_NIC)
 			break;
 
+		rmb();
+
 		/*
 		 *	Don't drop CE or RL error frame although RXOK is off
 		 */
@@ -1263,14 +1265,15 @@
 		rd_curr++;
 		if (rd_curr >= vptr->options.numrx)
 			rd_curr = 0;
-	}
+	} while (++works <= 15);
 
-	if (velocity_rx_refill(vptr) < 0) {
+	vptr->rd_curr = rd_curr;
+
+	if (works > 0 && velocity_rx_refill(vptr) < 0) {
 		VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
 			"%s: rx buf allocation failure\n", vptr->dev->name);
 	}
 
-	vptr->rd_curr = rd_curr;
 	VAR_USED(stats);
 	return works;
 }
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: [PATCH] via-velocity: early invocation of init_cam_filter()
## DP: Patch author: Tejun Heo <tj@home-tj.org>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: romieu (BitKeeper)
# cset: 1.1988.54.6 (2.6) key=4161bc5beGDcY-ENb8vOu3-q902T0g
# inclusion: upstream
# descrition: [PATCH] via-velocity: early invocation of init_cam_filter()
# revision date: Fri, 05 Nov 2004 11:00:41 +0900
#
# rset: ChangeSet|1.1988.54.5..1.1988.54.6
# rset: drivers/net/via-velocity.c|1.18..1.19
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/04 17:10:51-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: early invocation of init_cam_filter()
#   
#   In velocity_init_registers(), init_cam_filter() clears mCAMmask which
#   might have been set by set_multi() (not sure if this can ever occur).
#   Modified to invoke init_cam_filter() first. Also, clear_isr() is called
#   twice. Removed the first invocation.
#   
#   In velocity_found1(), there was a unneeded assignment from vptr to
#   dev->priv.  Removed.
#   
#   Signed-off-by: Tejun Heo <tj@home-tj.org>
# 
# drivers/net/via-velocity.c
#   2004/10/01 15:37:40-04:00 romieu@fr.zoreil.com +5 -4
#   via-velocity: early invocation of init_cam_filter()
# 
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 11:00:41 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 11:00:41 +09:00
@@ -592,6 +592,11 @@
 		BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), &regs->CFGB);
 
 		/*
+		 *	Init CAM filter
+		 */
+		velocity_init_cam_filter(vptr);
+
+		/*
 		 *	Set packet filter: Receive directed and broadcast address
 		 */
 		velocity_set_multi(vptr->dev);
@@ -615,8 +620,6 @@
 			mac_tx_queue_run(regs, i);
 		}
 
-		velocity_init_cam_filter(vptr);
-
 		init_flow_control_register(vptr);
 
 		writel(CR0_STOP, &regs->CR0Clr);
@@ -624,7 +627,6 @@
 
 		mii_status = velocity_get_opt_media_mode(vptr);
 		netif_stop_queue(vptr->dev);
-		mac_clear_isr(regs);
 
 		mii_init(vptr, mii_status);
 
@@ -723,7 +725,6 @@
 
 	vptr->dev = dev;
 
-	dev->priv = vptr;
 	dev->irq = pdev->irq;
 
 	ret = pci_enable_device(pdev);
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: PATCH] via-velocity: removal of incomplete endianness handling
## DP: Patch author: Francois Romieu <romieu@fr.zoreil.com>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: romieu (BitKeeper)
# cset: 1.1988.54.7 (2.6) key=4161bc69Wafvc1SgyEXiEskeU27tfg
# inclusion: upstream
# descrition: [PATCH] via-velocity: removal of incomplete endianness handling
# revision date: Fri, 05 Nov 2004 11:00:51 +0900
#
# rset: ChangeSet|1.1988.54.6..1.1988.54.7
# rset: drivers/net/via-velocity.c|1.19..1.20
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/04 17:11:05-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: removal of incomplete endianness handling
#   
#   Removed cpu_to_le32 call on OWNED_BY_NIC. This will produce 0x01000000 on
#   big endian machines while rdesc0.owner still evaluates to 0x00000000 or
#   0x00000001. BTW, unless we reorder bit fields on big endian machines or
#   use u32's and cpu_to_le32'd bit mask macros, current code won't work on big
#   endian machines.
#   
#   Signed-off-by: Tejun Heo <tj@home-tj.org>
# 
# drivers/net/via-velocity.c
#   2004/10/01 15:37:43-04:00 romieu@fr.zoreil.com +1 -1
#   via-velocity: removal of incomplete endianness handling
# 
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 11:00:51 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 11:00:51 +09:00
@@ -1038,7 +1038,7 @@
 		struct rx_desc *rd = vptr->rd_ring + dirty;
 
 		/* Fine for an all zero Rx desc at init time as well */
-		if (rd->rdesc0.owner == cpu_to_le32(OWNED_BY_NIC))
+		if (rd->rdesc0.owner == OWNED_BY_NIC)
 			break;
 
 		if (!vptr->rd_info[dirty].skb) {
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: [PATCH] via-velocity: wrong buffer offset in velocity_init_td_ring()
## DP: Patch author: Francois Romieu <romieu@fr.zoreil.com>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: romieu (BitKeeper)
# cset: 1.1988.54.8 (2.6) key=4161bc78T6I51pLQUWLhP04Oi5KxZg
# inclusion: upstream
# descrition: [PATCH] via-velocity: wrong buffer offset in velocity_init_td_ring()
# revision date: Fri, 05 Nov 2004 11:01:01 +0900
#
# rset: ChangeSet|1.1988.54.7..1.1988.54.8
# rset: drivers/net/via-velocity.c|1.20..1.21
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/04 17:11:20-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: wrong buffer offset in velocity_init_td_ring()
#   
#   Buffer offset calculation was incorrect in velocity_init_td_ring().
#   This didn't cause any trouble because we only use the first td ring.
#   
#   Signed-off-by: Tejun Heo <tj@home-tj.org>
# 
# drivers/net/via-velocity.c
#   2004/10/01 15:37:46-04:00 romieu@fr.zoreil.com +4 -2
#   via-velocity: wrong buffer offset in velocity_init_td_ring()
# 
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 11:01:01 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 11:01:01 +09:00
@@ -1156,8 +1156,10 @@
 		for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) {
 			td = &(vptr->td_rings[j][i]);
 			td_info = &(vptr->td_infos[j][i]);
-			td_info->buf = vptr->tx_bufs + (i + j) * PKT_BUF_SZ;
-			td_info->buf_dma = vptr->tx_bufs_dma + (i + j) * PKT_BUF_SZ;
+			td_info->buf = vptr->tx_bufs +
+				(j * vptr->options.numtx + i) * PKT_BUF_SZ;
+			td_info->buf_dma = vptr->tx_bufs_dma +
+				(j * vptr->options.numtx + i) * PKT_BUF_SZ;
 		}
 		vptr->td_tail[j] = vptr->td_curr[j] = vptr->td_used[j] = 0;
 	}
#! /bin/sh -e 
## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Description: [PATCH] via-velocity: comment fixes
## DP: Patch author: Tejun Heo <tj@home-tj.org>
## DP: Upstream status: backport

. $(dirname $0)/DPATCH

@DPATCH@
# origin: romieu (BitKeeper)
# cset: 1.1988.54.9 (2.6) key=4161bc87710HRjRqCEgDQn7rp5MgKA
# inclusion: upstream
# descrition: [PATCH] via-velocity: comment fixes
# revision date: Fri, 05 Nov 2004 11:01:11 +0900
#
# rset: ChangeSet|1.1988.54.8..1.1988.54.9
# rset: drivers/net/via-velocity.c|1.21..1.22
# rset: drivers/net/via-velocity.h|1.6..1.7
#
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/04 17:11:35-04:00 romieu@fr.zoreil.com 
#   [PATCH] via-velocity: comment fixes
#   
#   Comment fixes.
#   
#   Signed-off-by: Tejun Heo <tj@home-tj.org>
# 
# drivers/net/via-velocity.h
#   2004/10/01 15:37:50-04:00 romieu@fr.zoreil.com +3 -3
#   via-velocity: comment fixes
# 
# drivers/net/via-velocity.c
#   2004/10/01 15:37:50-04:00 romieu@fr.zoreil.com +3 -3
#   via-velocity: comment fixes
# 
diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
--- a/drivers/net/via-velocity.c	2004-11-05 11:01:11 +09:00
+++ b/drivers/net/via-velocity.c	2004-11-05 11:01:11 +09:00
@@ -464,7 +464,7 @@
 {
 	struct mac_regs * regs = vptr->mac_regs;
 
-	/* T urn on MCFG_PQEN, turn off MCFG_RTGOPT */
+	/* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
 	WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
 	WORD_REG_BITS_ON(MCFG_VIDFR, &regs->MCFG);
 
@@ -587,7 +587,7 @@
 
 		writeb(WOLCFG_SAM | WOLCFG_SAB, &regs->WOLCFGSet);
 		/*
-		 *	Bback off algorithm use original IEEE standard
+		 *	Back off algorithm use original IEEE standard
 		 */
 		BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), &regs->CFGB);
 
@@ -1091,7 +1091,7 @@
 }
 
 /**
- *	velocity_free_rd_ring	-	set up receive ring
+ *	velocity_free_rd_ring	-	free receive ring
  *	@vptr: velocity to clean up
  *
  *	Free the receive buffers for each ring slot and any
diff -Nru a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
--- a/drivers/net/via-velocity.h	2004-11-05 11:01:11 +09:00
+++ b/drivers/net/via-velocity.h	2004-11-05 11:01:11 +09:00
@@ -1319,7 +1319,7 @@
 	/* disable CAMEN */
 	writeb(0, &regs->CAMADDR);
 
-	/* Select CAM mask */
+	/* Select mar */
 	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
 }
 
@@ -1360,7 +1360,7 @@
 
 	writeb(0, &regs->CAMADDR);
 
-	/* Select CAM mask */
+	/* Select mar */
 	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
 }
 
@@ -1401,7 +1401,7 @@
 
 	writeb(0, &regs->CAMADDR);
 
-	/* Select CAM mask */
+	/* Select mar */
 	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
 }
 

Reply to: