Netdev List
 help / color / mirror / Atom feed
* [3/3] [NEIGH] Fix timer leak in neigh_changeaddr
From: Herbert Xu @ 2005-10-23  7:33 UTC (permalink / raw)
  To: Reuben Farrelly; +Cc: akpm, linux-kernel, netdev, acme, davem, greearb
In-Reply-To: <E1ETaJB-0004a0-00@gondolin.me.apana.org.au>

[-- Attachment #1: Type: text/plain, Size: 1058 bytes --]

[NEIGH] Fix timer leak in neigh_changeaddr

neigh_changeaddr attempts to delete neighbour timers without setting
nud_state.  This doesn't work because the timer may have already fired
when we acquire the write lock in neigh_changeaddr.  The result is that
the timer may keep firing for quite a while until the entry reaches
NEIGH_FAILED.

It should be setting the nud_state straight away so that if the timer
has already fired it can simply exit once we relinquish the lock.

In fact, this whole function is simply duplicating the logic in
neigh_ifdown which in turn is already doing the right thing when
it comes to deleting timers and setting nud_state.

So all we have to do is take that code out and put it into a common
function and make both neigh_changeaddr and neigh_ifdown call it.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

[-- Attachment #2: p3.patch --]
[-- Type: text/plain, Size: 1446 bytes --]

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -175,39 +175,10 @@ static void pneigh_queue_purge(struct sk
 	}
 }
 
-void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
+static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
 {
 	int i;
 
-	write_lock_bh(&tbl->lock);
-
-	for (i=0; i <= tbl->hash_mask; i++) {
-		struct neighbour *n, **np;
-
-		np = &tbl->hash_buckets[i];
-		while ((n = *np) != NULL) {
-			if (dev && n->dev != dev) {
-				np = &n->next;
-				continue;
-			}
-			*np = n->next;
-			write_lock_bh(&n->lock);
-			n->dead = 1;
-			neigh_del_timer(n);
-			write_unlock_bh(&n->lock);
-			neigh_release(n);
-		}
-	}
-
-        write_unlock_bh(&tbl->lock);
-}
-
-int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
-{
-	int i;
-
-	write_lock_bh(&tbl->lock);
-
 	for (i = 0; i <= tbl->hash_mask; i++) {
 		struct neighbour *n, **np = &tbl->hash_buckets[i];
 
@@ -243,7 +214,19 @@ int neigh_ifdown(struct neigh_table *tbl
 			neigh_release(n);
 		}
 	}
+}
 
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
+{
+	write_lock_bh(&tbl->lock);
+	neigh_flush_dev(tbl, dev);
+	write_unlock_bh(&tbl->lock);
+}
+
+int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
+{
+	write_lock_bh(&tbl->lock);
+	neigh_flush_dev(tbl, dev);
 	pneigh_ifdown(tbl, dev);
 	write_unlock_bh(&tbl->lock);
 

^ permalink raw reply

* [PATCH] e1000 : Fixes e1000_suspend warning when CONFIG_PM is not enabled
From: Ashutosh Naik @ 2005-10-23  8:13 UTC (permalink / raw)
  To: linux-net, netdev, linux-kernel, akpm; +Cc: linux.nics

[-- Attachment #1: Type: text/plain, Size: 171 bytes --]

This Patch fixes the warning

drivers/net/e1000/e1000_main.c:3645: warning: `e1000_suspend' defined
but not used

Signed-off-by: Ashutosh Naik <ashutosh_naik@adaptec.com>

[-- Attachment #2: e1000-patch.txt --]
[-- Type: text/plain, Size: 718 bytes --]

diff -ruNp linux-2.6.14-rc5/drivers/net/e1000/e1000_main.c linux-2.6.14-e1000-patch/drivers/net/e1000/e1000_main.c
--- linux-2.6.14-rc5/drivers/net/e1000/e1000_main.c	2005-10-23 13:06:51.000000000 +0530
+++ linux-2.6.14-e1000-patch/drivers/net/e1000/e1000_main.c	2005-10-23 13:19:32.000000000 +0530
@@ -162,8 +162,8 @@ static void e1000_vlan_rx_add_vid(struct
 static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
 static void e1000_restore_vlan(struct e1000_adapter *adapter);
 
-static int e1000_suspend(struct pci_dev *pdev, pm_message_t state);
 #ifdef CONFIG_PM
+static int e1000_suspend(struct pci_dev *pdev, pm_message_t state);
 static int e1000_resume(struct pci_dev *pdev);
 #endif
 

^ permalink raw reply

* Re: [BUG]NULL pointer dereference in ipv6_get_saddr()
From: Herbert Xu @ 2005-10-23 11:25 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / ????; +Cc: yanzheng, netdev, linux-kernel, yoshfuji
In-Reply-To: <20051019.012157.11460212.yoshfuji@linux-ipv6.org>

YOSHIFUJI Hideaki / ???? <yoshfuji@linux-ipv6.org> wrote:
>
> I think this is already fixed in head.
> I don't remember if we pushed this to stable...

Yep it was fixed by c62dba9011b93fd88fde929848582b2a98309878.

I agree that we should've pushed it to stable.  Unfortunately it
might be too late now.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [0/3] Fix timer bugs in neighbour cache
From: Arnaldo Carvalho de Melo @ 2005-10-23 16:16 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Reuben Farrelly, akpm, linux-kernel, netdev, davem, greearb
In-Reply-To: <E1ETaJB-0004a0-00@gondolin.me.apana.org.au>

Em Sun, Oct 23, 2005 at 05:30:21PM +1000, Herbert Xu escreveu:
> Reuben Farrelly <reuben-lkml@reub.net> wrote:
> > 
> > Oct 17 18:49:40 tornado kernel: NEIGH: BUG, double timer add, state is 1
> > Oct 17 18:51:04 tornado last message repeated 3 times
> > Oct 17 18:52:05 tornado last message repeated 5 times
> > Oct 17 18:52:11 tornado last message repeated 2 times
> 
> Excellent.  Looks like we actually caught something.  Pity we don't have
> a stack trace which means that there might be more bugs.
> 
> Anyway, here are three patches which should fix this.  This should go
> into 2.6.14.
> 
> Arnaldo, you can pull them from
> 
> master.kernel.org:/pub/scm/linux/kernel/git/herbert/net-2.6.git

Thanks, pulled.

I guess at some point I'll try to make the neighbour code more like the
sock one where we have things like sk_reset_timer and sk_stop_timer for
this purpose.

- Arnaldo

^ permalink raw reply

* Re: [3/3] [NEIGH] Fix timer leak in neigh_changeaddr
From: Ben Greear @ 2005-10-23 18:00 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Reuben Farrelly, akpm, linux-kernel, netdev, acme, davem
In-Reply-To: <20051023073331.GC17626@gondor.apana.org.au>

Herbert Xu wrote:
> [NEIGH] Fix timer leak in neigh_changeaddr
> 
> neigh_changeaddr attempts to delete neighbour timers without setting
> nud_state.  This doesn't work because the timer may have already fired
> when we acquire the write lock in neigh_changeaddr.  The result is that
> the timer may keep firing for quite a while until the entry reaches
> NEIGH_FAILED.
> 
> It should be setting the nud_state straight away so that if the timer
> has already fired it can simply exit once we relinquish the lock.
> 
> In fact, this whole function is simply duplicating the logic in
> neigh_ifdown which in turn is already doing the right thing when
> it comes to deleting timers and setting nud_state.
> 
> So all we have to do is take that code out and put it into a common
> function and make both neigh_changeaddr and neigh_ifdown call it.

Thanks for all who reproduced and fixed this...I'm glad to know I wasn't
insane when I first tried to fix it and then couldn't reproduce
the problem anymore! :)

Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* [PATCH] Re: IPW Question on menuconfig
From: Jan Niehusmann @ 2005-10-23 22:36 UTC (permalink / raw)
  To: Alejandro Bonilla Beeche; +Cc: netdev, linux-kernel, James Ketrenos
In-Reply-To: <434B2AE2.1070709@linuxwireless.org>

On Mon, Oct 10, 2005 at 09:00:50PM -0600, Alejandro Bonilla Beeche wrote:
> Network devices / Wireless, and the IPW2100 wasn't in the list. I went, 
> then Modularized the IEEE80211 and then IPW2100 was there. I think is 
> kind of estrange that IPW2100 wouldn't show just because it has a 
> dependencie, shouldn't IPW2100 show in the list, and if you select it, 
> then it would also select CONFIG_IEEE80211?

I think you are right, so the config script should be changed like shown
below. (But I'm not really familiar with the config language, so I may
be missing some obvious problems?)

Signed-off-by: Jan Niehusmann <jan@gondor.com>
(in case somebody cares for that for such a small change...)


diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -139,8 +139,9 @@ comment "Wireless 802.11b ISA/PCI cards 
 
 config IPW2100
 	tristate "Intel PRO/Wireless 2100 Network Connection"
-	depends on NET_RADIO && PCI && IEEE80211
+	depends on NET_RADIO && PCI
 	select FW_LOADER
+	select IEEE80211
 	---help---
           A driver for the Intel PRO/Wireless 2100 Network 
 	  Connection 802.11b wireless network adapter.
@@ -192,8 +193,9 @@ config IPW_DEBUG
 
 config IPW2200
 	tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
-	depends on IEEE80211 && PCI
+	depends on PCI
 	select FW_LOADER
+	select IEEE80211
 	---help---
           A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
 	  Connection adapters. 
 

^ permalink raw reply

* Re: [PATCH] X25: Add ITU-T facilites
From: Andrew Hendry @ 2005-10-24  1:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: eis, linux-x25, linux-kernel, netdev
In-Reply-To: <200510201430.17160.arnd@arndb.de>

Structure alignment corrected.

Adds options for ITU DTE facilities to X.25, called address extension and calling address extension

Signed-off-by: Andrew Hendry <ahendry@tusc.com.au>


diff -uprN -X dontdiff linux-2.6.13.4-vanilla/include/linux/x25.h linux-2.6.13.4/include/linux/x25.h
--- linux-2.6.13.4-vanilla/include/linux/x25.h	2005-10-11 04:54:29.000000000 +1000
+++ linux-2.6.13.4/include/linux/x25.h	2005-10-21 09:20:53.000000000 +1000
@@ -11,6 +11,8 @@
 #ifndef	X25_KERNEL_H
 #define	X25_KERNEL_H
 
+#include <linux/types.h>
+
 #define	SIOCX25GSUBSCRIP	(SIOCPROTOPRIVATE + 0)
 #define	SIOCX25SSUBSCRIP	(SIOCPROTOPRIVATE + 1)
 #define	SIOCX25GFACILITIES	(SIOCPROTOPRIVATE + 2)
@@ -21,6 +23,8 @@
 #define SIOCX25SCUDMATCHLEN	(SIOCPROTOPRIVATE + 7)
 #define SIOCX25CALLACCPTAPPRV   (SIOCPROTOPRIVATE + 8)
 #define SIOCX25SENDCALLACCPT    (SIOCPROTOPRIVATE + 9)
+#define SIOCX25GDTEFACILITIES   (SIOCPROTOPRIVATE + 10)
+#define SIOCX25SDTEFACILITIES   (SIOCPROTOPRIVATE + 11)
 
 /*
  *	Values for {get,set}sockopt.
@@ -77,6 +81,8 @@ struct x25_subscrip_struct {
 #define	X25_MASK_PACKET_SIZE	0x04
 #define	X25_MASK_WINDOW_SIZE	0x08
 
+#define X25_MASK_CALLING_AE     0x10
+#define X25_MASK_CALLED_AE      0x20
 
 
 /*
@@ -98,6 +104,26 @@ struct x25_facilities {
 	unsigned int	reverse;
 };
 
+/* 
+*     ITU DTE facilities
+*     Only the called and calling address
+*     extension are currently implemented.
+*     The rest are in place to avoid the struct
+*     changing size if someone needs them later
+*/
+
+struct x25_dte_facilities {
+	__u16		delay_cumul;
+	__u16		delay_target;
+	__u16		delay_max;
+	__u8		min_throughput;
+	__u8		expedited;
+	__u8		calling_len;
+	__u8		called_len;
+	__u8		calling_ae[20];
+	__u8		called_ae[20];
+};
+
 /*
  *	Call User Data structure.
  */
diff -uprN -X dontdiff linux-2.6.13.4-vanilla/include/net/x25.h linux-2.6.13.4/include/net/x25.h
--- linux-2.6.13.4-vanilla/include/net/x25.h	2005-10-11 04:54:29.000000000 +1000
+++ linux-2.6.13.4/include/net/x25.h	2005-10-21 09:20:16.000000000 +1000
@@ -101,9 +101,16 @@ enum {
 #define	X25_FAC_PACKET_SIZE	0x42
 #define	X25_FAC_WINDOW_SIZE	0x43
 
-#define	X25_MAX_FAC_LEN		20		/* Plenty to spare */
+#define	X25_MAX_FAC_LEN		60
 #define	X25_MAX_CUD_LEN		128
 
+#define X25_FAC_CALLING_AE      0xCB
+#define X25_FAC_CALLED_AE       0xC9
+
+#define X25_MARKER              0x00
+#define X25_DTE_SERVICES        0x0F
+#define X25_MAX_AE_LEN          32
+
 /**
  *	struct x25_route - x25 routing entry
  *	@node - entry in x25_list_lock
@@ -148,6 +155,7 @@ struct x25_sock {
 	struct timer_list	timer;
 	struct x25_causediag	causediag;
 	struct x25_facilities	facilities;
+	struct x25_dte_facilities dte_facilities;
 	struct x25_calluserdata	calluserdata;
 	unsigned long 		vc_facil_mask;	/* inc_call facilities mask */
 };
@@ -180,9 +188,9 @@ extern void x25_establish_link(struct x2
 extern void x25_terminate_link(struct x25_neigh *);
 
 /* x25_facilities.c */
-extern int  x25_parse_facilities(struct sk_buff *, struct x25_facilities *, unsigned long *);
-extern int  x25_create_facilities(unsigned char *, struct x25_facilities *, unsigned long);
-extern int  x25_negotiate_facilities(struct sk_buff *, struct sock *, struct x25_facilities *);
+extern int  x25_parse_facilities(struct sk_buff *, struct x25_facilities *, struct x25_dte_facilities *, unsigned long *);
+extern int  x25_create_facilities(unsigned char *, struct x25_facilities *, struct x25_dte_facilities *, unsigned long);
+extern int  x25_negotiate_facilities(struct sk_buff *, struct sock *, struct x25_facilities *, struct x25_dte_facilities *);
 extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);
 
 /* x25_in.c */
diff -uprN -X dontdiff linux-2.6.13.4-vanilla/net/x25/af_x25.c linux-2.6.13.4/net/x25/af_x25.c
--- linux-2.6.13.4-vanilla/net/x25/af_x25.c	2005-10-11 04:54:29.000000000 +1000
+++ linux-2.6.13.4/net/x25/af_x25.c	2005-10-21 09:20:16.000000000 +1000
@@ -513,6 +513,13 @@ static int x25_create(struct socket *soc
 	x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
 	x25->facilities.throughput  = X25_DEFAULT_THROUGHPUT;
 	x25->facilities.reverse     = X25_DEFAULT_REVERSE;
+	x25->dte_facilities.calling_len	= 0;
+	x25->dte_facilities.called_len	= 0;
+	memset(x25->dte_facilities.called_ae, '\0',
+		sizeof(x25->dte_facilities.called_ae));
+	memset(x25->dte_facilities.calling_ae, '\0',
+		sizeof(x25->dte_facilities.calling_ae));
+	
 	rc = 0;
 out:
 	return rc;
@@ -554,6 +561,7 @@ static struct sock *x25_make_new(struct 
 	x25->t2         = ox25->t2;
 	x25->facilities = ox25->facilities;
 	x25->qbitincl   = ox25->qbitincl;
+	x25->dte_facilities = ox25->dte_facilities;
 	x25->cudmatchlength = ox25->cudmatchlength;
 	x25->accptapprv = ox25->accptapprv;
 
@@ -833,6 +841,7 @@ int x25_rx_call_request(struct sk_buff *
 	struct x25_sock *makex25;
 	struct x25_address source_addr, dest_addr;
 	struct x25_facilities facilities;
+	struct x25_dte_facilities dte_facilities;
 	int len, rc;
 
 	/*
@@ -869,7 +878,8 @@ int x25_rx_call_request(struct sk_buff *
 	/*
 	 *	Try to reach a compromise on the requested facilities.
 	 */
-	if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1)
+	if ((len = x25_negotiate_facilities(skb, sk, &facilities, 
+		&dte_facilities)) == -1)
 		goto out_sock_put;
 
 	/*
@@ -900,9 +910,12 @@ int x25_rx_call_request(struct sk_buff *
 	makex25->source_addr   = source_addr;
 	makex25->neighbour     = nb;
 	makex25->facilities    = facilities;
+	makex25->dte_facilities= dte_facilities;
 	makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask;
 	/* ensure no reverse facil on accept */
 	makex25->vc_facil_mask &= ~X25_MASK_REVERSE;
+	/* ensure no calling address extension on accept */
+	makex25->vc_facil_mask &= ~X25_MASK_CALLING_AE;
 	makex25->cudmatchlength = x25_sk(sk)->cudmatchlength;
 
 	/* Normally all calls are accepted immediatly */
@@ -1309,6 +1322,34 @@ static int x25_ioctl(struct socket *sock
 			break;
 		}
 
+		case SIOCX25GDTEFACILITIES: {
+			rc = copy_to_user(argp, &x25->dte_facilities,
+				sizeof(x25->dte_facilities)) ? -EFAULT : 0;
+			break;
+		}
+
+		case SIOCX25SDTEFACILITIES: {
+			struct x25_dte_facilities dtefacs;
+			rc = -EFAULT;
+			if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))
+				break;
+			rc = -EINVAL;
+			if (sk->sk_state != TCP_LISTEN &&
+			    sk->sk_state != TCP_CLOSE)
+				break;
+			if (dtefacs.calling_len > X25_MAX_AE_LEN)
+				break;
+			if (dtefacs.calling_ae == NULL)
+				break;
+			if (dtefacs.called_len > X25_MAX_AE_LEN)
+				break;
+			if (dtefacs.called_ae == NULL)
+				break;
+			x25->dte_facilities = dtefacs;
+			rc = 0;
+			break;
+		}
+
 		case SIOCX25GCALLUSERDATA: {
 			struct x25_calluserdata cud = x25->calluserdata;
 			rc = copy_to_user(argp, &cud,
diff -uprN -X dontdiff linux-2.6.13.4-vanilla/net/x25/x25_facilities.c linux-2.6.13.4/net/x25/x25_facilities.c
--- linux-2.6.13.4-vanilla/net/x25/x25_facilities.c	2005-10-11 04:54:29.000000000 +1000
+++ linux-2.6.13.4/net/x25/x25_facilities.c	2005-10-21 09:20:16.000000000 +1000
@@ -28,11 +28,12 @@
 #include <net/x25.h>
 
 /*
- *	Parse a set of facilities into the facilities structure. Unrecognised
+ *	Parse a set of facilities into the facilities structures. Unrecognised
  *	facilities are written to the debug log file.
  */
 int x25_parse_facilities(struct sk_buff *skb,
 			 struct x25_facilities *facilities,
+			 struct x25_dte_facilities *dte_facs,
 			 unsigned long *vc_fac_mask)
 {
 	unsigned char *p = skb->data;
@@ -40,6 +41,16 @@ int x25_parse_facilities(struct sk_buff 
 
 	*vc_fac_mask = 0;
 
+	/* The kernel knows which facilities were set on an incoming call
+	 * but currently this information is not available to userspace.
+	 * Here we give userspace who read incoming call facilities
+	 * 0 length to indicate it wasn't set.
+	 */
+	dte_facs->calling_len = 0;
+	dte_facs->called_len = 0;
+	memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));
+	memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae));
+
 	while (len > 0) {
 		switch (*p & X25_FAC_CLASS_MASK) {
 		case X25_FAC_CLASS_A:
@@ -74,6 +85,8 @@ int x25_parse_facilities(struct sk_buff 
 				facilities->throughput = p[1];
 				*vc_fac_mask |= X25_MASK_THROUGHPUT;
 				break;
+			case X25_MARKER:
+				break;
 			default:
 				printk(KERN_DEBUG "X.25: unknown facility "
 				       "%02X, value %02X\n",
@@ -112,9 +125,28 @@ int x25_parse_facilities(struct sk_buff 
 			len -= 4;
 			break;
 		case X25_FAC_CLASS_D:
-			printk(KERN_DEBUG "X.25: unknown facility %02X, "
-			       "length %d, values %02X, %02X, %02X, %02X\n",
-			       p[0], p[1], p[2], p[3], p[4], p[5]);
+			switch (*p) {
+			case X25_FAC_CALLING_AE:
+				if (p[1] > 33)
+					break;
+				dte_facs->calling_len = p[2];
+				memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
+				*vc_fac_mask |= X25_MASK_CALLING_AE;
+				break;
+			case X25_FAC_CALLED_AE:
+				if (p[1] > 33)
+					break;
+				dte_facs->called_len = p[2];
+				memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
+				*vc_fac_mask |= X25_MASK_CALLED_AE;
+				break;
+			default:	
+				printk(KERN_DEBUG "X.25: unknown facility %02X,"
+				"length %d, values %02X, %02X, %02X, %02X\n",
+				 p[0], p[1], p[2], p[3], p[4], p[5]);
+				break;
+			}
+
 			len -= p[1] + 2;
 			p   += p[1] + 2;
 			break;
@@ -129,6 +161,7 @@ int x25_parse_facilities(struct sk_buff 
  */
 int x25_create_facilities(unsigned char *buffer,
 			  struct x25_facilities *facilities,
+			  struct x25_dte_facilities *dte_facs,
 			  unsigned long facil_mask)
 {
 	unsigned char *p = buffer + 1;
@@ -168,6 +201,34 @@ int x25_create_facilities(unsigned char 
 		*p++ = facilities->winsize_out ? : facilities->winsize_in;
 	}
 
+	if ((facil_mask & X25_MASK_CALLING_AE) || 
+	     (facil_mask & X25_MASK_CALLED_AE)) {
+		*p++ = X25_MARKER;
+		*p++ = X25_DTE_SERVICES;
+	}
+
+	if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) {
+		unsigned bytecount = (dte_facs->calling_len % 2) ?
+                        dte_facs->calling_len / 2 + 1 :
+			dte_facs->calling_len / 2;
+		*p++ = X25_FAC_CALLING_AE;
+		*p++ = 1 + bytecount;
+		*p++ = dte_facs->calling_len;
+		memcpy(p, dte_facs->calling_ae, bytecount);
+		p+=bytecount;
+	}
+
+	if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) {
+		unsigned bytecount = (dte_facs->called_len % 2) ?
+                        dte_facs->called_len / 2 + 1 :
+			dte_facs->called_len / 2;
+		*p++ = X25_FAC_CALLED_AE;
+		*p++ = 1 + bytecount;
+		*p++ = dte_facs->called_len;
+		memcpy(p, dte_facs->called_ae, bytecount);
+		p+=bytecount;
+	}
+
 	len       = p - buffer;
 	buffer[0] = len - 1;
 
@@ -180,7 +241,8 @@ int x25_create_facilities(unsigned char 
  *	The only real problem is with reverse charging.
  */
 int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
-			     struct x25_facilities *new)
+			     struct x25_facilities *new,
+			     struct x25_dte_facilities *dte)
 {
 	struct x25_sock *x25 = x25_sk(sk);
 	struct x25_facilities *ours = &x25->facilities;
@@ -190,7 +252,7 @@ int x25_negotiate_facilities(struct sk_b
 	memset(&theirs, 0, sizeof(theirs));
 	memcpy(new, ours, sizeof(*new));
 
-	len = x25_parse_facilities(skb, &theirs, &x25->vc_facil_mask);
+	len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask);
 
 	/*
 	 *	They want reverse charging, we won't accept it.
diff -uprN -X dontdiff linux-2.6.13.4-vanilla/net/x25/x25_in.c linux-2.6.13.4/net/x25/x25_in.c
--- linux-2.6.13.4-vanilla/net/x25/x25_in.c	2005-10-11 04:54:29.000000000 +1000
+++ linux-2.6.13.4/net/x25/x25_in.c	2005-10-21 09:20:16.000000000 +1000
@@ -106,6 +106,7 @@ static int x25_state1_machine(struct soc
 			skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
 			skb_pull(skb,
 				 x25_parse_facilities(skb, &x25->facilities,
+						      &x25->dte_facilities,
 						      &x25->vc_facil_mask));
 			/*
 			 *	Copy any Call User Data.
diff -uprN -X dontdiff linux-2.6.13.4-vanilla/net/x25/x25_subr.c linux-2.6.13.4/net/x25/x25_subr.c
--- linux-2.6.13.4-vanilla/net/x25/x25_subr.c	2005-10-11 04:54:29.000000000 +1000
+++ linux-2.6.13.4/net/x25/x25_subr.c	2005-10-21 09:20:16.000000000 +1000
@@ -191,6 +191,7 @@ void x25_write_internal(struct sock *sk,
 			memcpy(dptr, addresses, len);
 			len     = x25_create_facilities(facilities,
 							&x25->facilities,
+							&x25->dte_facilities,
 					     x25->neighbour->global_facil_mask);
 			dptr    = skb_put(skb, len);
 			memcpy(dptr, facilities, len);
@@ -206,6 +207,7 @@ void x25_write_internal(struct sock *sk,
 			*dptr++ = 0x00;		/* Address lengths */
 			len     = x25_create_facilities(facilities,
 							&x25->facilities,
+							&x25->dte_facilities,
 							x25->vc_facil_mask);
 			dptr    = skb_put(skb, len);
 			memcpy(dptr, facilities, len);



^ permalink raw reply

* Eliminate everything you owe with out sending another dime
From: jacquetta mcdonald @ 2005-10-24  1:47 UTC (permalink / raw)
  To: Angelic Burns

Calls about late payments are stopped dead in their tracks.
We have pioneered an advanced system of proven strategies 
that will get the creditors and debt collectors off your back for good

Our debt termination program has legally stopped millions of dollars worth
of debt from being collected.


check out our Elimination Program here
http://in.geocities.com/xena_toylens/?b=M



address on site along with no more feature




"extendable ears. look!" . "good afternoon," said dumbledore, holding out
his hand. mrs. cole simply gaped. 
the house-elf bowed low and addressed his own gnarled toes. "master said he
wanted regular reports on what the malfoy boy is doing, so kreacher has come
to give--"  

^ permalink raw reply

* [PATCH]IPv6: fix refcnt of struct ip6_flowlabel
From: Yan Zheng @ 2005-10-24 12:11 UTC (permalink / raw)
  To: netdev; +Cc: linux-kernel

Signed-off-by: Yan Zheng <yanzheng@21cn.com>


Index: net/ipv6/ip6_flowlabel.c
===================================================================
--- linux-2.6.14-rc5/net/ipv6/ip6_flowlabel.c	2005-10-22 10:31:13.000000000 +0800
+++ linux/net/ipv6/ip6_flowlabel.c	2005-10-24 19:55:23.000000000 +0800
@@ -483,7 +483,7 @@
 						goto done;
 					}
 					fl1 = sfl->fl;
-					atomic_inc(&fl->users);
+					atomic_inc(&fl1->users);
 					break;
 				}
 			}

^ permalink raw reply

* Re: [PATCH 2/2] forcedeth: scatter gather and segmentation offload support
From: Ayaz Abdulla @ 2005-10-24 16:48 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Manfred Spraul, Netdev
In-Reply-To: <43595C42.4080201@pobox.com>

[-- Attachment #1: Type: text/plain, Size: 130 bytes --]

Jeff,

I made the changes you requested. Here is the new patch.

Thanks,
Ayaz

Signed-off-By: Ayaz Abdulla <aabdulla@nvidia.com>


[-- Attachment #2: patch-forcedeth-044-sg-segmentation --]
[-- Type: text/plain, Size: 16585 bytes --]

--- orig-2.6/drivers/net/forcedeth.c	2005-10-24 12:40:05.000000000 -0400
+++ new-2.6/drivers/net/forcedeth.c	2005-10-24 12:39:12.000000000 -0400
@@ -96,6 +96,7 @@
  *	0.42: 06 Aug 2005: Fix lack of link speed initialization
  *			   in the second (and later) nv_open call
  *      0.43: 10 Aug 2005: Add support for tx checksum.
+ *      0.44: 20 Aug 2005: Add support for scatter gather and segmentation.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -107,7 +108,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION		"0.43"
+#define FORCEDETH_VERSION		"0.44"
 #define DRV_NAME			"forcedeth"
 
 #include <linux/module.h>
@@ -340,6 +341,8 @@
 /* error and valid are the same for both */
 #define NV_TX2_ERROR		(1<<30)
 #define NV_TX2_VALID		(1<<31)
+#define NV_TX2_TSO		(1<<28)
+#define NV_TX2_TSO_SHIFT	14
 #define NV_TX2_CHECKSUM_L3	(1<<27)
 #define NV_TX2_CHECKSUM_L4	(1<<26)
 
@@ -542,7 +545,7 @@
 
 static inline u8 __iomem *get_hwbase(struct net_device *dev)
 {
-	return get_nvpriv(dev)->base;
+  return ((struct fe_priv *)netdev_priv(dev))->base;
 }
 
 static inline void pci_push(u8 __iomem *base)
@@ -631,7 +634,7 @@
 
 static int phy_reset(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u32 miicontrol;
 	unsigned int tries = 0;
 
@@ -734,7 +737,7 @@
 
 static void nv_start_rx(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 
 	dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
@@ -790,7 +793,7 @@
 
 static void nv_txrx_reset(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 
 	dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name);
@@ -809,7 +812,7 @@
  */
 static struct net_device_stats *nv_get_stats(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 
 	/* It seems that the nic always generates interrupts and doesn't
 	 * accumulate errors internally. Thus the current values in np->stats
@@ -825,7 +828,7 @@
  */
 static int nv_alloc_rx(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	unsigned int refill_rx = np->refill_rx;
 	int nr;
 
@@ -869,7 +872,7 @@
 static void nv_do_rx_refill(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 
 	disable_irq(dev->irq);
 	if (nv_alloc_rx(dev)) {
@@ -883,7 +886,7 @@
 
 static void nv_init_rx(struct net_device *dev) 
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	int i;
 
 	np->cur_rx = RX_RING;
@@ -897,15 +900,17 @@
 
 static void nv_init_tx(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	int i;
 
 	np->next_tx = np->nic_tx = 0;
-	for (i = 0; i < TX_RING; i++)
+	for (i = 0; i < TX_RING; i++) {
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
 			np->tx_ring.orig[i].FlagLen = 0;
 	        else
 			np->tx_ring.ex[i].FlagLen = 0;
+		np->tx_skbuff[i] = NULL;
+	}
 }
 
 static int nv_init_ring(struct net_device *dev)
@@ -915,21 +920,44 @@
 	return nv_alloc_rx(dev);
 }
 
+static void nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+{
+	struct fe_priv *np = netdev_priv(dev);
+	struct sk_buff *skb = np->tx_skbuff[skbnr];
+	unsigned int j, entry, fragments;
+			
+	dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n",
+		dev->name, skbnr, np->tx_skbuff[skbnr]);
+	
+	entry = skbnr;
+	if ((fragments = skb_shinfo(skb)->nr_frags) != 0) {
+		for (j = fragments; j >= 1; j--) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1];
+			pci_unmap_page(np->pci_dev, np->tx_dma[entry],
+				       frag->size,
+				       PCI_DMA_TODEVICE);
+			entry = (entry - 1) % TX_RING;
+		}
+	}
+	pci_unmap_single(np->pci_dev, np->tx_dma[entry],
+			 skb->len - skb->data_len,
+			 PCI_DMA_TODEVICE);
+	dev_kfree_skb_irq(skb);
+	np->tx_skbuff[skbnr] = NULL;
+}
+
 static void nv_drain_tx(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
-	int i;
+	struct fe_priv *np = netdev_priv(dev);
+	unsigned int i;
+	
 	for (i = 0; i < TX_RING; i++) {
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
 			np->tx_ring.orig[i].FlagLen = 0;
 		else
 			np->tx_ring.ex[i].FlagLen = 0;
 		if (np->tx_skbuff[i]) {
-			pci_unmap_single(np->pci_dev, np->tx_dma[i],
-						np->tx_skbuff[i]->len,
-						PCI_DMA_TODEVICE);
-			dev_kfree_skb(np->tx_skbuff[i]);
-			np->tx_skbuff[i] = NULL;
+			nv_release_txskb(dev, i);
 			np->stats.tx_dropped++;
 		}
 	}
@@ -937,7 +965,7 @@
 
 static void nv_drain_rx(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	int i;
 	for (i = 0; i < RX_RING; i++) {
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
@@ -967,29 +995,69 @@
  */
 static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
-	int nr = np->next_tx % TX_RING;
-	u32 tx_checksum = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
+	struct fe_priv *np = netdev_priv(dev);
+	u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
+	unsigned int fragments = skb_shinfo(skb)->nr_frags;
+	unsigned int nr = (np->next_tx + fragments) % TX_RING;
+	unsigned int i;
+
+	spin_lock_irq(&np->lock);
+
+	if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) {
+		spin_unlock_irq(&np->lock);
+		netif_stop_queue(dev);
+		return NETDEV_TX_BUSY;
+	}
 
 	np->tx_skbuff[nr] = skb;
-	np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len,
-					PCI_DMA_TODEVICE);
+	
+	if (fragments) {
+		dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments);
+		/* setup descriptors in reverse order */
+		for (i = fragments; i >= 1; i--) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
+			np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size,
+							PCI_DMA_TODEVICE);
 
-	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+			if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+				np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+				np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+			} else {
+				np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+				np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+				np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+			}
+			
+			nr = (nr - 1) % TX_RING;
+
+			if (np->desc_ver == DESC_VER_1)
+				tx_flags_extra &= ~NV_TX_LASTPACKET;
+			else
+				tx_flags_extra &= ~NV_TX2_LASTPACKET;		
+		}
+	}
+
+#ifdef NETIF_F_TSO
+	if (skb_shinfo(skb)->tso_size)
+		tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
+	else
+#endif
+	tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
+
+	np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len,
+					PCI_DMA_TODEVICE);
+	
+	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 		np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
-	else {
+		np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+	} else {
 		np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
 		np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-	}
+		np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+	}	
 
-	spin_lock_irq(&np->lock);
-	wmb();
-	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-		np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags | tx_checksum);
-	else
-		np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags | tx_checksum);
-	dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission\n",
-				dev->name, np->next_tx);
+	dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n",
+				dev->name, np->next_tx, tx_flags_extra);
 	{
 		int j;
 		for (j=0; j<64; j++) {
@@ -1000,15 +1068,13 @@
 		dprintk("\n");
 	}
 
-	np->next_tx++;
+	np->next_tx += 1 + fragments;
 
 	dev->trans_start = jiffies;
-	if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP)
-		netif_stop_queue(dev);
 	spin_unlock_irq(&np->lock);
 	writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
 	pci_push(get_hwbase(dev));
-	return 0;
+	return NETDEV_TX_OK;
 }
 
 /*
@@ -1018,9 +1084,10 @@
  */
 static void nv_tx_done(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u32 Flags;
-	int i;
+	unsigned int i;
+	struct sk_buff *skb;
 
 	while (np->nic_tx != np->next_tx) {
 		i = np->nic_tx % TX_RING;
@@ -1035,35 +1102,38 @@
 		if (Flags & NV_TX_VALID)
 			break;
 		if (np->desc_ver == DESC_VER_1) {
-			if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
-							NV_TX_UNDERFLOW|NV_TX_ERROR)) {
-				if (Flags & NV_TX_UNDERFLOW)
-					np->stats.tx_fifo_errors++;
-				if (Flags & NV_TX_CARRIERLOST)
-					np->stats.tx_carrier_errors++;
-				np->stats.tx_errors++;
-			} else {
-				np->stats.tx_packets++;
-				np->stats.tx_bytes += np->tx_skbuff[i]->len;
+			if (Flags & NV_TX_LASTPACKET) {
+				skb = np->tx_skbuff[i];
+				if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
+					     NV_TX_UNDERFLOW|NV_TX_ERROR)) {
+					if (Flags & NV_TX_UNDERFLOW)
+						np->stats.tx_fifo_errors++;
+					if (Flags & NV_TX_CARRIERLOST)
+						np->stats.tx_carrier_errors++;
+					np->stats.tx_errors++;
+				} else {
+					np->stats.tx_packets++;
+					np->stats.tx_bytes += skb->len;
+				}
+				nv_release_txskb(dev, i);
 			}
 		} else {
-			if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
-							NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
-				if (Flags & NV_TX2_UNDERFLOW)
-					np->stats.tx_fifo_errors++;
-				if (Flags & NV_TX2_CARRIERLOST)
-					np->stats.tx_carrier_errors++;
-				np->stats.tx_errors++;
-			} else {
-				np->stats.tx_packets++;
-				np->stats.tx_bytes += np->tx_skbuff[i]->len;
+			if (Flags & NV_TX2_LASTPACKET) {
+				skb = np->tx_skbuff[i];
+				if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
+					     NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
+					if (Flags & NV_TX2_UNDERFLOW)
+						np->stats.tx_fifo_errors++;
+					if (Flags & NV_TX2_CARRIERLOST)
+						np->stats.tx_carrier_errors++;
+					np->stats.tx_errors++;
+				} else {
+					np->stats.tx_packets++;
+					np->stats.tx_bytes += skb->len;
+				}				
+				nv_release_txskb(dev, i);
 			}
 		}
-		pci_unmap_single(np->pci_dev, np->tx_dma[i],
-					np->tx_skbuff[i]->len,
-					PCI_DMA_TODEVICE);
-		dev_kfree_skb_irq(np->tx_skbuff[i]);
-		np->tx_skbuff[i] = NULL;
 		np->nic_tx++;
 	}
 	if (np->next_tx - np->nic_tx < TX_LIMIT_START)
@@ -1076,7 +1146,7 @@
  */
 static void nv_tx_timeout(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 
 	printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name,
@@ -1209,7 +1279,7 @@
 
 static void nv_rx_process(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u32 Flags;
 
 	for (;;) {
@@ -1364,7 +1434,7 @@
  */
 static int nv_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	int old_mtu;
 
 	if (new_mtu < 64 || new_mtu > np->pkt_limit)
@@ -1449,7 +1519,7 @@
  */
 static int nv_set_mac_address(struct net_device *dev, void *addr)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	struct sockaddr *macaddr = (struct sockaddr*)addr;
 
 	if(!is_valid_ether_addr(macaddr->sa_data))
@@ -1484,7 +1554,7 @@
  */
 static void nv_set_multicast(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	u32 addr[2];
 	u32 mask[2];
@@ -1544,7 +1614,7 @@
 
 static int nv_update_linkspeed(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	int adv, lpa;
 	int newls = np->linkspeed;
@@ -1714,7 +1784,7 @@
 static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) data;
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	u32 events;
 	int i;
@@ -1786,7 +1856,7 @@
 static void nv_do_nic_poll(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 
 	disable_irq(dev->irq);
@@ -1810,7 +1880,7 @@
 
 static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	strcpy(info->driver, "forcedeth");
 	strcpy(info->version, FORCEDETH_VERSION);
 	strcpy(info->bus_info, pci_name(np->pci_dev));
@@ -1818,7 +1888,7 @@
 
 static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	wolinfo->supported = WAKE_MAGIC;
 
 	spin_lock_irq(&np->lock);
@@ -1829,7 +1899,7 @@
 
 static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 
 	spin_lock_irq(&np->lock);
@@ -2030,7 +2100,7 @@
 
 static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	u32 *rbuf = buf;
 	int i;
@@ -2044,7 +2114,7 @@
 
 static int nv_nway_reset(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	int ret;
 
 	spin_lock_irq(&np->lock);
@@ -2078,7 +2148,7 @@
 
 static int nv_open(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	int ret, oom, i;
 
@@ -2214,7 +2284,7 @@
 
 static int nv_close(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base;
 
 	spin_lock_irq(&np->lock);
@@ -2270,7 +2340,7 @@
 	if (!dev)
 		goto out;
 
-	np = get_nvpriv(dev);
+	np = netdev_priv(dev);
 	np->pci_dev = pci_dev;
 	spin_lock_init(&np->lock);
 	SET_MODULE_OWNER(dev);
@@ -2322,6 +2392,8 @@
 		if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) {
 			printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
 					pci_name(pci_dev));
+		} else {
+			dev->features |= NETIF_F_HIGHDMA;
 		}
 		np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;
 	} else if (id->driver_data & DEV_HAS_LARGEDESC) {
@@ -2340,8 +2412,11 @@
 
 	if (id->driver_data & DEV_HAS_CHECKSUM) {
 		np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
-		dev->features |= NETIF_F_HW_CSUM;
-	}
+		dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
+#ifdef NETIF_F_TSO
+		dev->features |= NETIF_F_TSO;
+#endif
+ 	}
 
 	err = -ENOMEM;
 	np->base = ioremap(addr, NV_PCI_REGSZ);
@@ -2420,9 +2495,9 @@
 	np->wolenabled = 0;
 
 	if (np->desc_ver == DESC_VER_1) {
-		np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID;
+		np->tx_flags = NV_TX_VALID;
 	} else {
-		np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID;
+		np->tx_flags = NV_TX2_VALID;
 	}
 	np->irqmask = NVREG_IRQMASK_WANTED;
 	if (id->driver_data & DEV_NEED_TIMERIRQ)
@@ -2511,7 +2586,7 @@
 static void __devexit nv_remove(struct pci_dev *pci_dev)
 {
 	struct net_device *dev = pci_get_drvdata(pci_dev);
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 
 	unregister_netdev(dev);
 

^ permalink raw reply

* Re: [PATCH 2/2] forcedeth: scatter gather and segmentation offload support
From: Ayaz Abdulla @ 2005-10-24 17:05 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: Jeff Garzik, Manfred Spraul, Netdev
In-Reply-To: <20051024110003.53e37edd@dxpl.pdx.osdl.net>

[-- Attachment #1: Type: text/plain, Size: 59 bytes --]

Yes, forgot that indent.

Here it is again with that fix.


[-- Attachment #2: patch-forcedeth-044-sg-segmentation --]
[-- Type: text/plain, Size: 16584 bytes --]

--- orig-2.6/drivers/net/forcedeth.c	2005-10-24 12:40:05.000000000 -0400
+++ new-2.6/drivers/net/forcedeth.c	2005-10-24 13:03:30.000000000 -0400
@@ -96,6 +96,7 @@
  *	0.42: 06 Aug 2005: Fix lack of link speed initialization
  *			   in the second (and later) nv_open call
  *      0.43: 10 Aug 2005: Add support for tx checksum.
+ *      0.44: 20 Aug 2005: Add support for scatter gather and segmentation.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -107,7 +108,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION		"0.43"
+#define FORCEDETH_VERSION		"0.44"
 #define DRV_NAME			"forcedeth"
 
 #include <linux/module.h>
@@ -340,6 +341,8 @@
 /* error and valid are the same for both */
 #define NV_TX2_ERROR		(1<<30)
 #define NV_TX2_VALID		(1<<31)
+#define NV_TX2_TSO		(1<<28)
+#define NV_TX2_TSO_SHIFT	14
 #define NV_TX2_CHECKSUM_L3	(1<<27)
 #define NV_TX2_CHECKSUM_L4	(1<<26)
 
@@ -542,7 +545,7 @@
 
 static inline u8 __iomem *get_hwbase(struct net_device *dev)
 {
-	return get_nvpriv(dev)->base;
+	return ((struct fe_priv *)netdev_priv(dev))->base;
 }
 
 static inline void pci_push(u8 __iomem *base)
@@ -631,7 +634,7 @@
 
 static int phy_reset(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u32 miicontrol;
 	unsigned int tries = 0;
 
@@ -734,7 +737,7 @@
 
 static void nv_start_rx(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 
 	dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
@@ -790,7 +793,7 @@
 
 static void nv_txrx_reset(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 
 	dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name);
@@ -809,7 +812,7 @@
  */
 static struct net_device_stats *nv_get_stats(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 
 	/* It seems that the nic always generates interrupts and doesn't
 	 * accumulate errors internally. Thus the current values in np->stats
@@ -825,7 +828,7 @@
  */
 static int nv_alloc_rx(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	unsigned int refill_rx = np->refill_rx;
 	int nr;
 
@@ -869,7 +872,7 @@
 static void nv_do_rx_refill(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 
 	disable_irq(dev->irq);
 	if (nv_alloc_rx(dev)) {
@@ -883,7 +886,7 @@
 
 static void nv_init_rx(struct net_device *dev) 
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	int i;
 
 	np->cur_rx = RX_RING;
@@ -897,15 +900,17 @@
 
 static void nv_init_tx(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	int i;
 
 	np->next_tx = np->nic_tx = 0;
-	for (i = 0; i < TX_RING; i++)
+	for (i = 0; i < TX_RING; i++) {
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
 			np->tx_ring.orig[i].FlagLen = 0;
 	        else
 			np->tx_ring.ex[i].FlagLen = 0;
+		np->tx_skbuff[i] = NULL;
+	}
 }
 
 static int nv_init_ring(struct net_device *dev)
@@ -915,21 +920,44 @@
 	return nv_alloc_rx(dev);
 }
 
+static void nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+{
+	struct fe_priv *np = netdev_priv(dev);
+	struct sk_buff *skb = np->tx_skbuff[skbnr];
+	unsigned int j, entry, fragments;
+			
+	dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n",
+		dev->name, skbnr, np->tx_skbuff[skbnr]);
+	
+	entry = skbnr;
+	if ((fragments = skb_shinfo(skb)->nr_frags) != 0) {
+		for (j = fragments; j >= 1; j--) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1];
+			pci_unmap_page(np->pci_dev, np->tx_dma[entry],
+				       frag->size,
+				       PCI_DMA_TODEVICE);
+			entry = (entry - 1) % TX_RING;
+		}
+	}
+	pci_unmap_single(np->pci_dev, np->tx_dma[entry],
+			 skb->len - skb->data_len,
+			 PCI_DMA_TODEVICE);
+	dev_kfree_skb_irq(skb);
+	np->tx_skbuff[skbnr] = NULL;
+}
+
 static void nv_drain_tx(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
-	int i;
+	struct fe_priv *np = netdev_priv(dev);
+	unsigned int i;
+	
 	for (i = 0; i < TX_RING; i++) {
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
 			np->tx_ring.orig[i].FlagLen = 0;
 		else
 			np->tx_ring.ex[i].FlagLen = 0;
 		if (np->tx_skbuff[i]) {
-			pci_unmap_single(np->pci_dev, np->tx_dma[i],
-						np->tx_skbuff[i]->len,
-						PCI_DMA_TODEVICE);
-			dev_kfree_skb(np->tx_skbuff[i]);
-			np->tx_skbuff[i] = NULL;
+			nv_release_txskb(dev, i);
 			np->stats.tx_dropped++;
 		}
 	}
@@ -937,7 +965,7 @@
 
 static void nv_drain_rx(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	int i;
 	for (i = 0; i < RX_RING; i++) {
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
@@ -967,29 +995,69 @@
  */
 static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
-	int nr = np->next_tx % TX_RING;
-	u32 tx_checksum = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
+	struct fe_priv *np = netdev_priv(dev);
+	u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
+	unsigned int fragments = skb_shinfo(skb)->nr_frags;
+	unsigned int nr = (np->next_tx + fragments) % TX_RING;
+	unsigned int i;
+
+	spin_lock_irq(&np->lock);
+
+	if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) {
+		spin_unlock_irq(&np->lock);
+		netif_stop_queue(dev);
+		return NETDEV_TX_BUSY;
+	}
 
 	np->tx_skbuff[nr] = skb;
-	np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len,
-					PCI_DMA_TODEVICE);
+	
+	if (fragments) {
+		dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments);
+		/* setup descriptors in reverse order */
+		for (i = fragments; i >= 1; i--) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
+			np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size,
+							PCI_DMA_TODEVICE);
 
-	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+			if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+				np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+				np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+			} else {
+				np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+				np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+				np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+			}
+			
+			nr = (nr - 1) % TX_RING;
+
+			if (np->desc_ver == DESC_VER_1)
+				tx_flags_extra &= ~NV_TX_LASTPACKET;
+			else
+				tx_flags_extra &= ~NV_TX2_LASTPACKET;		
+		}
+	}
+
+#ifdef NETIF_F_TSO
+	if (skb_shinfo(skb)->tso_size)
+		tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
+	else
+#endif
+	tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
+
+	np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len,
+					PCI_DMA_TODEVICE);
+	
+	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 		np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
-	else {
+		np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+	} else {
 		np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
 		np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-	}
+		np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+	}	
 
-	spin_lock_irq(&np->lock);
-	wmb();
-	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-		np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags | tx_checksum);
-	else
-		np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags | tx_checksum);
-	dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission\n",
-				dev->name, np->next_tx);
+	dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n",
+				dev->name, np->next_tx, tx_flags_extra);
 	{
 		int j;
 		for (j=0; j<64; j++) {
@@ -1000,15 +1068,13 @@
 		dprintk("\n");
 	}
 
-	np->next_tx++;
+	np->next_tx += 1 + fragments;
 
 	dev->trans_start = jiffies;
-	if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP)
-		netif_stop_queue(dev);
 	spin_unlock_irq(&np->lock);
 	writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
 	pci_push(get_hwbase(dev));
-	return 0;
+	return NETDEV_TX_OK;
 }
 
 /*
@@ -1018,9 +1084,10 @@
  */
 static void nv_tx_done(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u32 Flags;
-	int i;
+	unsigned int i;
+	struct sk_buff *skb;
 
 	while (np->nic_tx != np->next_tx) {
 		i = np->nic_tx % TX_RING;
@@ -1035,35 +1102,38 @@
 		if (Flags & NV_TX_VALID)
 			break;
 		if (np->desc_ver == DESC_VER_1) {
-			if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
-							NV_TX_UNDERFLOW|NV_TX_ERROR)) {
-				if (Flags & NV_TX_UNDERFLOW)
-					np->stats.tx_fifo_errors++;
-				if (Flags & NV_TX_CARRIERLOST)
-					np->stats.tx_carrier_errors++;
-				np->stats.tx_errors++;
-			} else {
-				np->stats.tx_packets++;
-				np->stats.tx_bytes += np->tx_skbuff[i]->len;
+			if (Flags & NV_TX_LASTPACKET) {
+				skb = np->tx_skbuff[i];
+				if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
+					     NV_TX_UNDERFLOW|NV_TX_ERROR)) {
+					if (Flags & NV_TX_UNDERFLOW)
+						np->stats.tx_fifo_errors++;
+					if (Flags & NV_TX_CARRIERLOST)
+						np->stats.tx_carrier_errors++;
+					np->stats.tx_errors++;
+				} else {
+					np->stats.tx_packets++;
+					np->stats.tx_bytes += skb->len;
+				}
+				nv_release_txskb(dev, i);
 			}
 		} else {
-			if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
-							NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
-				if (Flags & NV_TX2_UNDERFLOW)
-					np->stats.tx_fifo_errors++;
-				if (Flags & NV_TX2_CARRIERLOST)
-					np->stats.tx_carrier_errors++;
-				np->stats.tx_errors++;
-			} else {
-				np->stats.tx_packets++;
-				np->stats.tx_bytes += np->tx_skbuff[i]->len;
+			if (Flags & NV_TX2_LASTPACKET) {
+				skb = np->tx_skbuff[i];
+				if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
+					     NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
+					if (Flags & NV_TX2_UNDERFLOW)
+						np->stats.tx_fifo_errors++;
+					if (Flags & NV_TX2_CARRIERLOST)
+						np->stats.tx_carrier_errors++;
+					np->stats.tx_errors++;
+				} else {
+					np->stats.tx_packets++;
+					np->stats.tx_bytes += skb->len;
+				}				
+				nv_release_txskb(dev, i);
 			}
 		}
-		pci_unmap_single(np->pci_dev, np->tx_dma[i],
-					np->tx_skbuff[i]->len,
-					PCI_DMA_TODEVICE);
-		dev_kfree_skb_irq(np->tx_skbuff[i]);
-		np->tx_skbuff[i] = NULL;
 		np->nic_tx++;
 	}
 	if (np->next_tx - np->nic_tx < TX_LIMIT_START)
@@ -1076,7 +1146,7 @@
  */
 static void nv_tx_timeout(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 
 	printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name,
@@ -1209,7 +1279,7 @@
 
 static void nv_rx_process(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u32 Flags;
 
 	for (;;) {
@@ -1364,7 +1434,7 @@
  */
 static int nv_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	int old_mtu;
 
 	if (new_mtu < 64 || new_mtu > np->pkt_limit)
@@ -1449,7 +1519,7 @@
  */
 static int nv_set_mac_address(struct net_device *dev, void *addr)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	struct sockaddr *macaddr = (struct sockaddr*)addr;
 
 	if(!is_valid_ether_addr(macaddr->sa_data))
@@ -1484,7 +1554,7 @@
  */
 static void nv_set_multicast(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	u32 addr[2];
 	u32 mask[2];
@@ -1544,7 +1614,7 @@
 
 static int nv_update_linkspeed(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	int adv, lpa;
 	int newls = np->linkspeed;
@@ -1714,7 +1784,7 @@
 static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) data;
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	u32 events;
 	int i;
@@ -1786,7 +1856,7 @@
 static void nv_do_nic_poll(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 
 	disable_irq(dev->irq);
@@ -1810,7 +1880,7 @@
 
 static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	strcpy(info->driver, "forcedeth");
 	strcpy(info->version, FORCEDETH_VERSION);
 	strcpy(info->bus_info, pci_name(np->pci_dev));
@@ -1818,7 +1888,7 @@
 
 static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	wolinfo->supported = WAKE_MAGIC;
 
 	spin_lock_irq(&np->lock);
@@ -1829,7 +1899,7 @@
 
 static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 
 	spin_lock_irq(&np->lock);
@@ -2030,7 +2100,7 @@
 
 static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	u32 *rbuf = buf;
 	int i;
@@ -2044,7 +2114,7 @@
 
 static int nv_nway_reset(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	int ret;
 
 	spin_lock_irq(&np->lock);
@@ -2078,7 +2148,7 @@
 
 static int nv_open(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	int ret, oom, i;
 
@@ -2214,7 +2284,7 @@
 
 static int nv_close(struct net_device *dev)
 {
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base;
 
 	spin_lock_irq(&np->lock);
@@ -2270,7 +2340,7 @@
 	if (!dev)
 		goto out;
 
-	np = get_nvpriv(dev);
+	np = netdev_priv(dev);
 	np->pci_dev = pci_dev;
 	spin_lock_init(&np->lock);
 	SET_MODULE_OWNER(dev);
@@ -2322,6 +2392,8 @@
 		if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) {
 			printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
 					pci_name(pci_dev));
+		} else {
+			dev->features |= NETIF_F_HIGHDMA;
 		}
 		np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;
 	} else if (id->driver_data & DEV_HAS_LARGEDESC) {
@@ -2340,8 +2412,11 @@
 
 	if (id->driver_data & DEV_HAS_CHECKSUM) {
 		np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
-		dev->features |= NETIF_F_HW_CSUM;
-	}
+		dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
+#ifdef NETIF_F_TSO
+		dev->features |= NETIF_F_TSO;
+#endif
+ 	}
 
 	err = -ENOMEM;
 	np->base = ioremap(addr, NV_PCI_REGSZ);
@@ -2420,9 +2495,9 @@
 	np->wolenabled = 0;
 
 	if (np->desc_ver == DESC_VER_1) {
-		np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID;
+		np->tx_flags = NV_TX_VALID;
 	} else {
-		np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID;
+		np->tx_flags = NV_TX2_VALID;
 	}
 	np->irqmask = NVREG_IRQMASK_WANTED;
 	if (id->driver_data & DEV_NEED_TIMERIRQ)
@@ -2511,7 +2586,7 @@
 static void __devexit nv_remove(struct pci_dev *pci_dev)
 {
 	struct net_device *dev = pci_get_drvdata(pci_dev);
-	struct fe_priv *np = get_nvpriv(dev);
+	struct fe_priv *np = netdev_priv(dev);
 
 	unregister_netdev(dev);
 

^ permalink raw reply

* Re: [PATCH 2/2] forcedeth: scatter gather and segmentation offload support
From: Stephen Hemminger @ 2005-10-24 18:00 UTC (permalink / raw)
  To: Ayaz Abdulla; +Cc: Jeff Garzik, Manfred Spraul, Netdev
In-Reply-To: <435D1047.2070401@nvidia.com>

On Mon, 24 Oct 2005 12:48:07 -0400
Ayaz Abdulla <aabdulla@nvidia.com> wrote:

> Jeff,
> 
> I made the changes you requested. Here is the new patch.
> 
> Thanks,
> Ayaz
> 
> Signed-off-By: Ayaz Abdulla <aabdulla@nvidia.com>
> 

> @@ -542,7 +545,7 @@
>  
>  static inline u8 __iomem *get_hwbase(struct net_device *dev)
>  {
> -	return get_nvpriv(dev)->base;
> +  return ((struct fe_priv *)netdev_priv(dev))->base;
>  }

Indentation?
Did you mean to leave the tab there.

-- 
Stephen Hemminger <shemminger@osdl.org>
OSDL http://developer.osdl.org/~shemminger

^ permalink raw reply

* Re: [PATCH]IPv6: fix refcnt of struct ip6_flowlabel
From: Arnaldo Carvalho de Melo @ 2005-10-24 18:35 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / 吉藤英明, Yan Zheng
  Cc: netdev, linux-kernel
In-Reply-To: <435CCF7B.6030907@21cn.com>

On 10/24/05, Yan Zheng <yanzheng@21cn.com> wrote:
> Signed-off-by: Yan Zheng <yanzheng@21cn.com>
>
>
> Index: net/ipv6/ip6_flowlabel.c
> ===================================================================
> --- linux-2.6.14-rc5/net/ipv6/ip6_flowlabel.c   2005-10-22 10:31:13.000000000 +0800
> +++ linux/net/ipv6/ip6_flowlabel.c      2005-10-24 19:55:23.000000000 +0800
> @@ -483,7 +483,7 @@
>                                                 goto done;
>                                         }
>                                         fl1 = sfl->fl;
> -                                       atomic_inc(&fl->users);
> +                                       atomic_inc(&fl1->users);
>                                         break;

Looks OK to me, Yoshifuji-san, ACK?

- Arnaldo

^ permalink raw reply

* Re: [PATCH 2/2] forcedeth: scatter gather and segmentation offload support
From: Stephen Hemminger @ 2005-10-24 21:21 UTC (permalink / raw)
  To: Ayaz Abdulla; +Cc: Jeff Garzik, Manfred Spraul, Netdev
In-Reply-To: <435D1047.2070401@nvidia.com>

On Mon, 24 Oct 2005 12:48:07 -0400
Ayaz Abdulla <aabdulla@nvidia.com> wrote:

> Jeff,
> 
> I made the changes you requested. Here is the new patch.
> 
> Thanks,
> Ayaz
> 
> Signed-off-By: Ayaz Abdulla <aabdulla@nvidia.com>
> 

There are really three patches in here.
	1. Use netdev_priv (trivial)
	2. scatter/gather support
	3. TSO support

Why do you set the fragments up in reverse order? Going backwards is
usually slow on most code.

The kernel coding style is to use lower case in local variable names (Flags)
and structure elements (PacketBuffer, FlagLen). 

-- 
Stephen Hemminger <shemminger@osdl.org>
OSDL http://developer.osdl.org/~shemminger

^ permalink raw reply

* Re: Request for an ARPHRD_
From: Daniele Orlandi @ 2005-10-24 21:33 UTC (permalink / raw)
  To: netdev; +Cc: netdev
In-Reply-To: <200510241807.23290.ak@suse.de>

On Monday 24 October 2005 18:07, Andi Kleen wrote:
>
> ETH_P_* is managed by the IEEE (part of the ethernet standard) You would
> need to ask them.

I need a pseudo protocol like it is already done for some internal protocol, 
e.g.:

/*
 *      Non DIX types. Won't clash for 1500 types.
 */
[.....]
#define ETH_P_WAN_PPP   0x0007          /* Dummy type for WAN PPP frames*/
#define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
#define ETH_P_LOCALTALK 0x0009          /* Localtalk pseudo type        */
#define ETH_P_PPPTALK   0x0010          /* Dummy type for Atalk over PPP*/
[....]

> Normally Linux doesn't pre-allocate ABIs for out of tree code, mostly
> because it is not guaranteed that the interface won't change there.

Could you clarify? What interface do you fear that could change?

My main concern is that without an ARPHRD_ constant guaranteed to be unique I 
wouldn't be able to propose a patch for libpcap people to map the (already 
allocated) DLT_ to the correct ARPHRD_.

Bye,

-- 
  Daniele Orlandi

^ permalink raw reply

* Re: [patch 2.6.13 0/5] normalize calculations of rx_dropped
From: Ben Greear @ 2005-10-24 21:35 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-kernel, netdev, Jeff Garzik
In-Reply-To: <20050912191419.GB19644@tuxdriver.com>

John W. Linville wrote:
> On Mon, Sep 12, 2005 at 02:53:31PM -0400, Jeff Garzik wrote:
> 
> 
>>For e.g. e1000, are we sure that packets dropped by hardware are 
>>accounted elsewhere?
> 
> 
> The e100 and tg3 patches move the count of those frames to
> rx_missed_errors.  e1000 and ixgb were already counting them there in
> addition to rx_discards, so they were simply removed from rx_discards.
> 3c59x was counting other errors in rx_discards, so they were removed
> from that count.

Whatever became of this discussion?  It seems that the e1000 driver
in 2.6.13.2 uses rx_errors as the total of all receive errors, while
the patch John was proposing broke them out into separate counters.

It doesn't matter too much to me either way, but I'd like for there to
be a precisely documented definition for the various net-stats so that
I can correctly show the values to user-space (I can certainly add rx_discards
to rx_errors for a 'total rx errors' value, but I need to know whether
rx_discards is already in rx_errors to keep from counting things twice.)

Jeff:  Could you lay down the law somewhere in the Documentation/
directory and then let us start fixing any driver that does it differently?

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* Re: Request for an ARPHRD_
From: Lennert Buytenhek @ 2005-10-24 21:51 UTC (permalink / raw)
  To: Daniele Orlandi; +Cc: netdev, netdev
In-Reply-To: <200510242333.05366.daniele@orlandi.com>

On Mon, Oct 24, 2005 at 11:33:04PM +0200, Daniele Orlandi wrote:

> My main concern is that without an ARPHRD_ constant guaranteed to be
> unique I wouldn't be able to propose a patch for libpcap people to map
> the (already allocated) DLT_ to the correct ARPHRD_.

First get your code in the kernel, then submit the patch to libpcap.


--L

^ permalink raw reply

* Re: [patch 2.6.13 0/5] normalize calculations of rx_dropped
From: John W. Linville @ 2005-10-24 21:57 UTC (permalink / raw)
  To: Ben Greear; +Cc: linux-kernel, netdev, Jeff Garzik
In-Reply-To: <435D53AE.3020401@candelatech.com>

On Mon, Oct 24, 2005 at 02:35:42PM -0700, Ben Greear wrote:

> It doesn't matter too much to me either way, but I'd like for there to
> be a precisely documented definition for the various net-stats so that
> I can correctly show the values to user-space (I can certainly add 
> rx_discards
> to rx_errors for a 'total rx errors' value, but I need to know whether
> rx_discards is already in rx_errors to keep from counting things twice.)

My opinion is that:

	-- rx_errors should count all "on the wire" hardware errors;

	-- rx_missed_errors should count frames w/ no "on the wire"
	errors that cannot be received by the hardware (generally
	due to lack of DMA bufers); and,

	-- rx_discards should count frames dropped by the kernel
	after successful reception by the hardware.

I do _not_ think rx_missed_errors should be counted as part of
rx_errors, but I could be persuaded otherwise.

> Jeff:  Could you lay down the law somewhere in the Documentation/
> directory and then let us start fixing any driver that does it differently?

It does seem like a netdev stats clarification doc would be
appropriate.  Does anyone have the beginnings of this?

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply

* Re: Request for an ARPHRD_
From: Daniele Orlandi @ 2005-10-24 22:08 UTC (permalink / raw)
  To: netdev; +Cc: netdev
In-Reply-To: <20051024215140.GA10872@xi.wantstofly.org>

On Monday 24 October 2005 23:51, Lennert Buytenhek wrote:
>
> First get your code in the kernel, then submit the patch to libpcap.

Hopefully I will but currently vISDN is not mature enough to be evaluated for 
kernel inclusion.

I would like to keep it out of the tree while it matures, however I would also 
like to avoid potential constants clashes with outher/future code.

You may see the constants allocation as the first step to include that code in 
the kernel.

Bye,

-- 
  Daniele Orlandi

^ permalink raw reply

* Re: Request for an ARPHRD_
From: Lennert Buytenhek @ 2005-10-24 22:22 UTC (permalink / raw)
  To: Daniele Orlandi; +Cc: netdev, netdev
In-Reply-To: <200510250008.10409.daniele@orlandi.com>

On Tue, Oct 25, 2005 at 12:08:09AM +0200, Daniele Orlandi wrote:

> > First get your code in the kernel, then submit the patch to libpcap.
> 
> Hopefully I will but currently vISDN is not mature enough to be
> evaluated for kernel inclusion.
> 
> I would like to keep it out of the tree while it matures, however I
> would also like to avoid potential constants clashes with outher/future
> code.
> 
> You may see the constants allocation as the first step to include that
> code in the kernel.

Your code might never end up in the kernel at all, for example if you
ever lose interest in it.  The situation that we'd like to avoid is
ending up with reserved constants for code that was never submitted
upstream at all.


cheers,
Lennert

^ permalink raw reply

* Re: Request for an ARPHRD_
From: Andi Kleen @ 2005-10-24 22:24 UTC (permalink / raw)
  To: Daniele Orlandi; +Cc: netdev, netdev
In-Reply-To: <200510242333.05366.daniele@orlandi.com>

On Monday 24 October 2005 23:33, Daniele Orlandi wrote:

> 
> > Normally Linux doesn't pre-allocate ABIs for out of tree code, mostly
> > because it is not guaranteed that the interface won't change there.
> 
> Could you clarify? What interface do you fear that could change?

Any interface implemented by your out of tree code for which you're
requesting to reserve constants.

-Andi

^ permalink raw reply

* Re: 2.6.14-rc5 e1000 and page allocation failures.. still
From: Jesse Brandeburg @ 2005-10-24 22:28 UTC (permalink / raw)
  To: Robert Hancock; +Cc: linux-kernel, Kernel Netdev Mailing List
In-Reply-To: <435C2D66.6030708@shaw.ca>

On 10/23/05, Robert Hancock <hancockr@shaw.ca> wrote:
> John Bäckstrand wrote:
> > Im seeing a massive amount of page allocation failures with 2.6.14-rc5,
> > and also earlier kernels, see "E1000 - page allocation failure - saga
[snip]
> It looks like you have enough memory free - the problem is that the
> driver is allocating a block of memory with order 3, which is 8 pages.
> Quite likely there are not enough contiguous free pages to satisfy that.
>
> That's an awful big buffer size for a packet - I assume you're using
> jumbo frames or something? Ideally the driver and hardware should be
> able to allocate a buffer for those packets in multiple chunks, but I
> have no idea if this is possible.

the latest e1000 driver (6.2.15) from http://sf.net/projects/e1000
fixes this by using multiple descriptors for jumbo frames, therefore
only doing order 0 (single page) page allocations.

let us know how it goes.

BTW why is this so much more common with recent kernels?

^ permalink raw reply

* Re: Request for an ARPHRD_
From: Daniele Orlandi @ 2005-10-24 22:58 UTC (permalink / raw)
  To: netdev; +Cc: netdev
In-Reply-To: <20051024222222.GA11005@xi.wantstofly.org>

On Tuesday 25 October 2005 00:22, Lennert Buytenhek wrote:
>
> Your code might never end up in the kernel at all, for example if you
> ever lose interest in it.  The situation that we'd like to avoid is
> ending up with reserved constants for code that was never submitted
> upstream at all.

Okay, I see your point.

IMHO I'd have preferred a more open politic like libpcap's. There may be valid 
reasons to keep code out of the tree and this makes maintenance even harder 
to perform than it already is.

Thanks anyway,

Bye,

-- 
  Daniele Orlandi

^ permalink raw reply

* Re: [patch 2.6.13 0/5] normalize calculations of rx_dropped
From: Ben Greear @ 2005-10-25  1:15 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-kernel, netdev, Jeff Garzik
In-Reply-To: <20051024215751.GH28212@tuxdriver.com>

John W. Linville wrote:
> On Mon, Oct 24, 2005 at 02:35:42PM -0700, Ben Greear wrote:
> 
> 
>>It doesn't matter too much to me either way, but I'd like for there to
>>be a precisely documented definition for the various net-stats so that
>>I can correctly show the values to user-space (I can certainly add 
>>rx_discards
>>to rx_errors for a 'total rx errors' value, but I need to know whether
>>rx_discards is already in rx_errors to keep from counting things twice.)
> 
> 
> My opinion is that:
> 
> 	-- rx_errors should count all "on the wire" hardware errors;
> 
> 	-- rx_missed_errors should count frames w/ no "on the wire"
> 	errors that cannot be received by the hardware (generally
> 	due to lack of DMA bufers); and,
> 
> 	-- rx_discards should count frames dropped by the kernel
> 	after successful reception by the hardware.
> 
> I do _not_ think rx_missed_errors should be counted as part of
> rx_errors, but I could be persuaded otherwise.

Well, if we have rx_errors containing any of the other more specific
error counts (reported in the net-stats struct), I don't see a reason
not to include all of them in the counter.  I think my preference would
be to have rx_errors be every conceivable frame that we know was sent to
us but which did not get properly delivered to the software stack.

Each error would also fall into it's more specific counters.

That way, the rx-errors counter can be used for folks who just care
that the packet was not correctly received, and those that care about
the details can look at the individual errors (and sum them up in various
configurations due to personal taste, etc.)

That said, rx-errors would then be duplicate info because we could arrive
at it's value by just adding up all the other error counters....

> It does seem like a netdev stats clarification doc would be
> appropriate.  Does anyone have the beginnings of this?

It's not authoritative, but I scrounged this info from various people,
including Mr Becker some years ago.  I undoubtedly made some of this up
myself, and there could be errors of course:

rx_errors:  Total of all rx errors
rx_dropped:  Dropped on receive, usually due to kernel being over-worked.
rx_length:  Dropped because pkt-length was invalid.
rx_over:  Dropped because we over-ran the NIC's rx buffers.
rx_crc:  Packets received with bad CRC errors.
rx_frame:  Framing errors (errors at the physical layer), usually cable or hardware error.
rx_fifo:  Dropped due to Kernel buffers being full (I guess rx-over could be NIC only, rx-fifo be kernel/driver only.)
rx_missed:  Dropped due to not handling IRQ in time.

tx_abort:  Failed to TX due to driver abort.
tx_carrier:  Failed to TX due to lack of carrier signal.
tx_fifo:  Over-ran the driver/kernel buffer(s).
tx_heartbeat:  Failed to TX due to transceiver heartbeat errors.
tx_window:  Failed to TX due to out-of-window error.

Thanks,
Ben

> 
> John


-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* Re: [patch 2.6.13 0/5] normalize calculations of rx_dropped
From: jamal @ 2005-10-25  1:42 UTC (permalink / raw)
  To: Ben Greear; +Cc: John W. Linville, linux-kernel, netdev, Jeff Garzik
In-Reply-To: <435D8717.9000107@candelatech.com>

On Mon, 2005-24-10 at 18:15 -0700, Ben Greear wrote:
[..]
> That way, the rx-errors counter can be used for folks who just care
> that the packet was not correctly received, and those that care about
> the details can look at the individual errors (and sum them up in various
> configurations due to personal taste, etc.)
> 

Look at http://www.faqs.org/rfcs/rfc2665.html
for a more finer breakdown.

rx/tx_errors may be further broken down.

cheers,
jamal

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox