Netdev List
 help / color / mirror / Atom feed
* Re: [PKT_SCHED]: PSCHED_TADD() and PSCHED_TADD2() can result,tv_usec >= 1000000
From: Shuya MAEDA @ 2006-06-21  0:16 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20060619.235105.82052619.davem@davemloft.net>

Thank you for the comment.
I made the patch that used the loop instead of the divide and modulus.
Are there any comments?

David Miller wrote:
> From: Shuya MAEDA <maeda-sxb@necst.nec.co.jp>
> Date: Mon, 19 Jun 2006 14:36:46 +0900
> 
>>  #define PSCHED_TADD2(tv, delta, tv_res) \
>>  ({ \
>> -          int __delta = (tv).tv_usec + (delta); \
>> -          (tv_res).tv_sec = (tv).tv_sec; \
>> -          if (__delta > USEC_PER_SEC) { (tv_res).tv_sec++; __delta -= USEC_PER_SEC; } \
>> -          (tv_res).tv_usec = __delta; \
>> +          int __delta = (delta); \
>> +          (tv_res) = (tv); \
>> +          if((delta) > USEC_PER_SEC) { \
>> +                (tv_res).tv_sec += (delta) / USEC_PER_SEC; \
>> +                __delta -= (delta) % USEC_PER_SEC; \
>> +          } \
>> +          (tv_res).tv_usec += __delta; \
>> +          if((tv_res).tv_usec >= USEC_PER_SEC) { \
>> +                (tv_res).tv_sec++; \
>> +                (tv_res).tv_usec -= USEC_PER_SEC; \
>> +          } \
>>  })
> 
> Divide and modulus can be extremely expensive on some systems, so
> let's try to avoid using them.
> 
> It is probably sufficient to adjust the passed in delta only once if
> it is >= USEC_PER_SEC, but if you feel that is an unsafe assumption
> then please use a simply loop like this:
> 
> 	while (__delta >= USEC_PER_SEC) {
> 		(tv_res).tv_sec++;
> 		__delta -= USEC_PER_SEC;
> 	}
> 
> And please provide a proper "Signed-off-by: " line in your next
> patch submission.
> 
> Thank you very much.

Signed-off-by: Shuya MAEDA <maeda-sxb@necst.nec.co.jp>

diff -Nur linux-2.6.17.orig/include/net/pkt_sched.h linux-2.6.17.mypatch/include/net/pkt_sched.h
--- linux-2.6.17.orig/include/net/pkt_sched.h   2006-06-18 10:49:35.000000000 +0900
+++ linux-2.6.17.mypatch/include/net/pkt_sched.h        2006-06-20 17:17:34.000000000 +0900
@@ -169,17 +169,23 @@

  #define PSCHED_TADD2(tv, delta, tv_res) \
  ({ \
-          int __delta = (tv).tv_usec + (delta); \
-          (tv_res).tv_sec = (tv).tv_sec; \
-          if (__delta > USEC_PER_SEC) { (tv_res).tv_sec++; __delta -= USEC_PER_SEC; } \
+          int __delta = (delta); \
+          (tv_res) = (tv); \
+          while(__delta >= USEC_PER_SEC){ \
+                (tv_res).tv_sec++; \
+                __delta -= USEC_PER_SEC; \
+          } \
            (tv_res).tv_usec = __delta; \
  })

  #define PSCHED_TADD(tv, delta) \
  ({ \
-          (tv).tv_usec += (delta); \
-          if ((tv).tv_usec > USEC_PER_SEC) { (tv).tv_sec++; \
-                (tv).tv_usec -= USEC_PER_SEC; } \
+          int __delta = (delta); \
+          while(__delta >= USEC_PER_SEC){ \
+                (tv).tv_sec++; \
+                __delta -= USEC_PER_SEC; \
+          } \
+          (tv).tv_usec = __delta; \
  })

  /* Set/check that time is in the "past perfect";

-- 
Shuya MAEDA

^ permalink raw reply

* Re: DF, IP ID always 0 and the reassembly protections
From: David Miller @ 2006-06-21  0:19 UTC (permalink / raw)
  To: rick.jones2; +Cc: netdev
In-Reply-To: <44988877.2030205@hp.com>

From: Rick Jones <rick.jones2@hp.com>
Date: Tue, 20 Jun 2006 16:44:55 -0700

> Doesn't that mechanism rely on watching the IP ID's between the pair of 
> IPs?  For both fragmented and non-fragmented datagrams? If so, does 
> always setting the IP ID to zero when DF is set affect that mechanism?

Only the IDs in packets with DF clear matter.

^ permalink raw reply

* Re: Locking validator output on DCCP
From: Herbert Xu @ 2006-06-21  0:34 UTC (permalink / raw)
  To: Ian McDonald, Ingo Molnar
  Cc: netdev, DCCP Mailing List, Arnaldo Carvalho de Melo
In-Reply-To: <5640c7e00606201640wa1ad17fl46a32ceb49513867@mail.gmail.com>

On Tue, Jun 20, 2006 at 11:40:05PM +0000, Ian McDonald wrote:
> 
> I am getting this when I am using DCCP with 2.6.17-rc6-mm2 with Ingo's
> lock dependency patch:
> 
> Jun 21 09:38:58 localhost kernel: [  102.068588]
> Jun 21 09:38:58 localhost kernel: [  102.068592]
> =============================================
> Jun 21 09:38:58 localhost kernel: [  102.068602] [ INFO: possible
> recursive locking detected ]
> Jun 21 09:38:58 localhost kernel: [  102.068608]
> ---------------------------------------------
> Jun 21 09:38:58 localhost kernel: [  102.068615] idle/0 is trying to
> acquire lock:
> Jun 21 09:38:58 localhost kernel: [  102.068620]
> (&sk->sk_lock.slock#3){-+..}, at: [<c0245511>] sk_clone+0x5a/0x190
> Jun 21 09:38:58 localhost kernel: [  102.068644]
> Jun 21 09:38:58 localhost kernel: [  102.068646] but task is already
> holding lock:
> Jun 21 09:38:58 localhost kernel: [  102.068651]
> (&sk->sk_lock.slock#3){-+..}, at: [<c024650d>]
> sk_receive_skb+0xe6/0xfe

...
 
> As I read this it is not a recursive lock as sk_clone is occurring
> second and is actually creating a new socket so they are trying to
> lock on different sockets.
> 
> Can someone tell me whether I am correct in my thinking or not? If I
> am then I will work out how to tell the lock validator not to worry
> about it.

I agree, this looks bogus.  Ingo, could you please take a look?

Thanks,
-- 
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: DF, IP ID always 0 and the reassembly protections
From: Rick Jones @ 2006-06-21  0:35 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20060620.171912.70221261.davem@davemloft.net>

David Miller wrote:
> From: Rick Jones <rick.jones2@hp.com>
> Date: Tue, 20 Jun 2006 16:44:55 -0700
> 
> 
>>Doesn't that mechanism rely on watching the IP ID's between the pair of 
>>IPs?  For both fragmented and non-fragmented datagrams? If so, does 
>>always setting the IP ID to zero when DF is set affect that mechanism?
> 
> 
> Only the IDs in packets with DF clear matter.

I thought the ID's even in non-fragmented datagrams gave an idea of how 
many IP datagrams had been sent along, and so an idea of how "unlikely" 
it was that a datagram with holes could be reassembled?

rick jones

^ permalink raw reply

* Re: [PATCH 03/06] MLSXFRM: Add security sid to sock
From: Herbert Xu @ 2006-06-21  0:41 UTC (permalink / raw)
  To: Venkat Yekkirala; +Cc: netdev, selinux
In-Reply-To: <44983D36.8070609@trustedcs.com>

On Tue, Jun 20, 2006 at 06:23:50PM +0000, Venkat Yekkirala wrote:
>
> --- linux-2.6.16.vanilla/include/net/sock.h	2006-06-19 
> 17:02:23.000000000 -0500
> +++ linux-2.6.16/include/net/sock.h	2006-06-19 19:48:24.000000000 -0500
> @@ -964,6 +964,15 @@ static inline void sock_graft(struct soc
> 	write_unlock_bh(&sk->sk_callback_lock);
> }
> 
> +static inline void sock_copy(struct sock *nsk, const struct sock *osk)
> +{
> +	void *sptr = nsk->sk_security;
> +
> +	memcpy(nsk, osk, osk->sk_prot->obj_size);
> +	nsk->sk_security = sptr;

I don't get it.  Why do you put sk_security away and then set it back.
Doesn't memcpy already do this for you?
-- 
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: DF, IP ID always 0 and the reassembly protections
From: akepner @ 2006-06-21  0:38 UTC (permalink / raw)
  To: Rick Jones; +Cc: David Miller, netdev
In-Reply-To: <44989466.5070308@hp.com>

On Tue, 20 Jun 2006, Rick Jones wrote:
> ....
> I thought the ID's even in non-fragmented datagrams gave an idea of how many 
> IP datagrams had been sent along, and so an idea of how "unlikely" it was 
> that a datagram with holes could be reassembled?
>

Only fragmented datagrams get counted. This is arguably 
a weakness of the scheme, but it's still a big improvement 
in practice. And the more common non-fragmented datagram 
processing doesn't have to pay the price for the extra 
checks.

-- 
Arthur


^ permalink raw reply

* Re: DF, IP ID always 0 and the reassembly protections
From: David Miller @ 2006-06-21  0:43 UTC (permalink / raw)
  To: rick.jones2; +Cc: netdev
In-Reply-To: <44989466.5070308@hp.com>

From: Rick Jones <rick.jones2@hp.com>
Date: Tue, 20 Jun 2006 17:35:50 -0700

> I thought the ID's even in non-fragmented datagrams gave an idea of how 
> many IP datagrams had been sent along, and so an idea of how "unlikely" 
> it was that a datagram with holes could be reassembled?

The code you are thinking about is in net/ipv4/ip_fragment.c and it
attempts to avoid ID wrapping corruption.  It only looks at IP
fragments on input.

^ permalink raw reply

* RE: [PATCH 03/06] MLSXFRM: Add security sid to sock
From: Venkat Yekkirala @ 2006-06-21  0:50 UTC (permalink / raw)
  To: Herbert Xu; +Cc: netdev, selinux

> > +static inline void sock_copy(struct sock *nsk, const 
> struct sock *osk)
> > +{
> > +	void *sptr = nsk->sk_security;
> > +
> > +	memcpy(nsk, osk, osk->sk_prot->obj_size);
> > +	nsk->sk_security = sptr;
> 
> I don't get it.  Why do you put sk_security away and then set it back.
> Doesn't memcpy already do this for you?

Nope. It would actually overwrite the pointer, so we put it away before
memcpy
and set it back after memcpy.

^ permalink raw reply

* Re: Sanitise ethtool.h and mii.h for userspace.
From: Jeff Garzik @ 2006-06-21  1:18 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Linux Kernel Mailing List, Netdev List, Andrew Morton,
	Linus Torvalds
In-Reply-To: <200606202308.k5KN83bT013398@hera.kernel.org>

Linux Kernel Mailing List wrote:
> commit c3ce7e203af5d8eab7c3390fc991a1fcb152f741
> tree 43b0837c42a1deb5b0f87800bf6a5ed8eea2eafe
> parent 56142536868a2be34f261ed8fdca1610f8a73fbd
> author David Woodhouse <dwmw2@shinybook.infradead.org> Sat, 29 Apr 2006 01:53:47 +0100
> committer David Woodhouse <dwmw2@infradead.org> Sat, 29 Apr 2006 01:53:47 +0100
> 
> Sanitise ethtool.h and mii.h for userspace.
> 
> They shouldn't be using 'u32' et al in structures which are used for
> communication with userspace. Switch to the proper types (__u32 etc).
> 
> Signed-off-by: David Woodhouse <dwmw2@infradead.org>

How can reviewers make an informed decision, when you completely failed 
to note:

* This breaks the primary userspace user of this header, ethtool(8)
* The patch was NAK'd (and I don't even get a "Naked-by:" header :))
* Despite knowing all this for quite some time, no associated userspace 
fix patch has ever appeared.

If you are going to break stuff, AT LEAST TELL PEOPLE IN ALL CAPS ABOUT 
IT, rather than providing the highly deceptive description as above. 
And be courteous enough to help fix the breakage, if you please.

	Jeff, ethtool maintainer




^ permalink raw reply

* [PATCH 1/2 resend] 8139cp: fix eeprom read command length
From: Philip Craig @ 2006-06-21  1:33 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev
In-Reply-To: <4497B73A.4080804@pobox.com>

[-- Attachment #1: 8139cp-read-eeprom.patch --]
[-- Type: text/plain, Size: 863 bytes --]

The read command for the 93C46/93C56 EEPROMS should be 3 bits plus
the address.  This doesn't appear to affect the operation of the
read command, but similar errors for write commands do cause failures.

Signed-off-by: Philip Craig <philipc@snapgear.com>

Index: linux-2.6.17-rc6/drivers/net/8139cp.c
===================================================================
--- linux-2.6.17-rc6.orig/drivers/net/8139cp.c	2006-06-14 16:02:00.000000000 +1000
+++ linux-2.6.17-rc6/drivers/net/8139cp.c	2006-06-14 16:03:29.000000000 +1000
@@ -1628,7 +1628,7 @@ static int read_eeprom (void __iomem *io
 	eeprom_delay ();
 
 	/* Shift the read command bits out. */
-	for (i = 4 + addr_len; i >= 0; i--) {
+	for (i = 3 + addr_len - 1; i >= 0; i--) {
 		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
 		writeb (EE_ENB | dataval, ee_addr);
 		eeprom_delay ();

--


^ permalink raw reply

* [PATCH 2/2 resend] 8139cp: add ethtool eeprom support
From: Philip Craig @ 2006-06-21  1:33 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev
In-Reply-To: <4497B73A.4080804@pobox.com>

[-- Attachment #1: 8139cp-ethtool-eeprom.patch --]
[-- Type: text/plain, Size: 6379 bytes --]

Implement the ethtool eeprom operations for the 8139cp driver.
Tested on x86 and big-endian ARM.

Signed-off-by: Philip Craig <philipc@snapgear.com>

Index: linux-2.6.17-rc6/drivers/net/8139cp.c
===================================================================
--- linux-2.6.17-rc6.orig/drivers/net/8139cp.c	2006-06-14 15:59:26.000000000 +1000
+++ linux-2.6.17-rc6/drivers/net/8139cp.c	2006-06-14 15:59:53.000000000 +1000
@@ -401,6 +401,11 @@ static void cp_clean_rings (struct cp_pr
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void cp_poll_controller(struct net_device *dev);
 #endif
+static int cp_get_eeprom_len(struct net_device *dev);
+static int cp_get_eeprom(struct net_device *dev,
+			 struct ethtool_eeprom *eeprom, u8 *data);
+static int cp_set_eeprom(struct net_device *dev,
+			 struct ethtool_eeprom *eeprom, u8 *data);
 
 static struct pci_device_id cp_pci_tbl[] = {
 	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
@@ -1577,6 +1582,9 @@ static struct ethtool_ops cp_ethtool_ops
 	.get_strings		= cp_get_strings,
 	.get_ethtool_stats	= cp_get_ethtool_stats,
 	.get_perm_addr		= ethtool_op_get_perm_addr,
+	.get_eeprom_len		= cp_get_eeprom_len,
+	.get_eeprom		= cp_get_eeprom,
+	.set_eeprom		= cp_set_eeprom,
 };
 
 static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1612,24 +1620,32 @@ static int cp_ioctl (struct net_device *
 #define eeprom_delay()	readl(ee_addr)
 
 /* The EEPROM commands include the alway-set leading bit. */
+#define EE_EXTEND_CMD	(4)
 #define EE_WRITE_CMD	(5)
 #define EE_READ_CMD		(6)
 #define EE_ERASE_CMD	(7)
 
-static int read_eeprom (void __iomem *ioaddr, int location, int addr_len)
-{
-	int i;
-	unsigned retval = 0;
-	void __iomem *ee_addr = ioaddr + Cfg9346;
-	int read_cmd = location | (EE_READ_CMD << addr_len);
+#define EE_EWDS_ADDR	(0)
+#define EE_WRAL_ADDR	(1)
+#define EE_ERAL_ADDR	(2)
+#define EE_EWEN_ADDR	(3)
+
+#define CP_EEPROM_MAGIC PCI_DEVICE_ID_REALTEK_8139
 
+static void eeprom_cmd_start(void __iomem *ee_addr)
+{
 	writeb (EE_ENB & ~EE_CS, ee_addr);
 	writeb (EE_ENB, ee_addr);
 	eeprom_delay ();
+}
+
+static void eeprom_cmd(void __iomem *ee_addr, int cmd, int cmd_len)
+{
+	int i;
 
-	/* Shift the read command bits out. */
-	for (i = 3 + addr_len - 1; i >= 0; i--) {
-		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+	/* Shift the command bits out. */
+	for (i = cmd_len - 1; i >= 0; i--) {
+		int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
 		writeb (EE_ENB | dataval, ee_addr);
 		eeprom_delay ();
 		writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
@@ -1637,6 +1653,33 @@ static int read_eeprom (void __iomem *io
 	}
 	writeb (EE_ENB, ee_addr);
 	eeprom_delay ();
+}
+
+static void eeprom_cmd_end(void __iomem *ee_addr)
+{
+	writeb (~EE_CS, ee_addr);
+	eeprom_delay ();
+}
+
+static void eeprom_extend_cmd(void __iomem *ee_addr, int extend_cmd,
+			      int addr_len)
+{
+	int cmd = (EE_EXTEND_CMD << addr_len) | (extend_cmd << (addr_len - 2));
+
+	eeprom_cmd_start(ee_addr);
+	eeprom_cmd(ee_addr, cmd, 3 + addr_len);
+	eeprom_cmd_end(ee_addr);
+}
+
+static u16 read_eeprom (void __iomem *ioaddr, int location, int addr_len)
+{
+	int i;
+	u16 retval = 0;
+	void __iomem *ee_addr = ioaddr + Cfg9346;
+	int read_cmd = location | (EE_READ_CMD << addr_len);
+
+	eeprom_cmd_start(ee_addr);
+	eeprom_cmd(ee_addr, read_cmd, 3 + addr_len);
 
 	for (i = 16; i > 0; i--) {
 		writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
@@ -1648,13 +1691,125 @@ static int read_eeprom (void __iomem *io
 		eeprom_delay ();
 	}
 
-	/* Terminate the EEPROM access. */
-	writeb (~EE_CS, ee_addr);
-	eeprom_delay ();
+	eeprom_cmd_end(ee_addr);
 
 	return retval;
 }
 
+static void write_eeprom(void __iomem *ioaddr, int location, u16 val,
+			 int addr_len)
+{
+	int i;
+	void __iomem *ee_addr = ioaddr + Cfg9346;
+	int write_cmd = location | (EE_WRITE_CMD << addr_len);
+
+	eeprom_extend_cmd(ee_addr, EE_EWEN_ADDR, addr_len);
+
+	eeprom_cmd_start(ee_addr);
+	eeprom_cmd(ee_addr, write_cmd, 3 + addr_len);
+	eeprom_cmd(ee_addr, val, 16);
+	eeprom_cmd_end(ee_addr);
+
+	eeprom_cmd_start(ee_addr);
+	for (i = 0; i < 20000; i++)
+		if (readb(ee_addr) & EE_DATA_READ)
+			break;
+	eeprom_cmd_end(ee_addr);
+
+	eeprom_extend_cmd(ee_addr, EE_EWDS_ADDR, addr_len);
+}
+
+static int cp_get_eeprom_len(struct net_device *dev)
+{
+	struct cp_private *cp = netdev_priv(dev);
+	int size;
+
+	spin_lock_irq(&cp->lock);
+	size = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 256 : 128;
+	spin_unlock_irq(&cp->lock);
+
+	return size;
+}
+
+static int cp_get_eeprom(struct net_device *dev,
+			 struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct cp_private *cp = netdev_priv(dev);
+	unsigned int addr_len;
+	u16 val;
+	u32 offset = eeprom->offset >> 1;
+	u32 len = eeprom->len;
+	u32 i = 0;
+
+	eeprom->magic = CP_EEPROM_MAGIC;
+
+	spin_lock_irq(&cp->lock);
+
+	addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6;
+
+	if (eeprom->offset & 1) {
+		val = read_eeprom(cp->regs, offset, addr_len);
+		data[i++] = (u8)(val >> 8);
+		offset++;
+	}
+
+	while (i < len - 1) {
+		val = read_eeprom(cp->regs, offset, addr_len);
+		data[i++] = (u8)val;
+		data[i++] = (u8)(val >> 8);
+		offset++;
+	}
+
+	if (i < len) {
+		val = read_eeprom(cp->regs, offset, addr_len);
+		data[i] = (u8)val;
+	}
+
+	spin_unlock_irq(&cp->lock);
+	return 0;
+}
+
+static int cp_set_eeprom(struct net_device *dev,
+			 struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct cp_private *cp = netdev_priv(dev);
+	unsigned int addr_len;
+	u16 val;
+	u32 offset = eeprom->offset >> 1;
+	u32 len = eeprom->len;
+	u32 i = 0;
+
+	if (eeprom->magic != CP_EEPROM_MAGIC)
+		return -EINVAL;
+
+	spin_lock_irq(&cp->lock);
+
+	addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6;
+
+	if (eeprom->offset & 1) {
+		val = read_eeprom(cp->regs, offset, addr_len) & 0xff;
+		val |= (u16)data[i++] << 8;
+		write_eeprom(cp->regs, offset, val, addr_len);
+		offset++;
+	}
+
+	while (i < len - 1) {
+		val = (u16)data[i++];
+		val |= (u16)data[i++] << 8;
+		write_eeprom(cp->regs, offset, val, addr_len);
+		offset++;
+	}
+
+	if (i < len) {
+		val = read_eeprom(cp->regs, offset, addr_len) & 0xff00;
+		val |= (u16)data[i];
+		write_eeprom(cp->regs, offset, val, addr_len);
+	}
+
+	spin_unlock_irq(&cp->lock);
+	return 0;
+}
+
 /* Put the board into D3cold state and wait for WakeUp signal */
 static void cp_set_d3_state (struct cp_private *cp)
 {

--


^ permalink raw reply

* (unknown)
From: Anne Thrax @ 2006-06-21  2:04 UTC (permalink / raw)
  To: netdev

subscribe foobarfoobarfoobar@gmail.com

^ permalink raw reply

* Re: [patch] ieee80211: fix not allocating IV+ICV space when usingencryption in ieee80211_tx_frame
From: Hong Liu @ 2006-06-21  3:35 UTC (permalink / raw)
  To: linville; +Cc: netdev
In-Reply-To: <1150770394.26493.47.camel@devlinux-hong>

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

On Tue, 2006-06-20 at 10:26, Hong Liu wrote:
> We should preallocate IV+ICV space when encrypting the frame.
> Currently no problem shows up just because dev_alloc_skb aligns the
> data len to SMP_CACHE_BYTES which can be used for ICV.
> 
> Thanks,
> Hong
> 

Please apply this new patch.
The previous patch has a problem when security is not set.


[-- Attachment #2: ieee80211-1.1.14-newtxfix.patch --]
[-- Type: text/x-patch, Size: 1637 bytes --]

diff -urp a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
--- a/net/ieee80211/ieee80211_tx.c	2006-06-20 09:36:13.000000000 +0800
+++ b/net/ieee80211/ieee80211_tx.c	2006-06-21 11:22:56.000000000 +0800
@@ -562,10 +562,13 @@ int ieee80211_tx_frame(struct ieee80211_
 	struct net_device_stats *stats = &ieee->stats;
 	struct sk_buff *skb_frag;
 	int priority = -1;
+	int fraglen = total_len;
+	int headroom = ieee->tx_headroom;
+	struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
 
 	spin_lock_irqsave(&ieee->lock, flags);
 
-	if (encrypt_mpdu && !ieee->sec.encrypt)
+	if (encrypt_mpdu && (!ieee->sec.encrypt || !crypt))
 		encrypt_mpdu = 0;
 
 	/* If there is no driver handler to take the TXB, dont' bother
@@ -581,20 +584,24 @@ int ieee80211_tx_frame(struct ieee80211_
 		goto success;
 	}
 
-	if (encrypt_mpdu)
+	if (encrypt_mpdu) {
 		frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+		fraglen += crypt->ops->extra_mpdu_prefix_len +
+			   crypt->ops->extra_mpdu_postfix_len;
+		headroom += crypt->ops->extra_mpdu_prefix_len;
+	}
 
 	/* When we allocate the TXB we allocate enough space for the reserve
 	 * and full fragment bytes (bytes_per_frag doesn't include prefix,
 	 * postfix, header, FCS, etc.) */
-	txb = ieee80211_alloc_txb(1, total_len, ieee->tx_headroom, GFP_ATOMIC);
+	txb = ieee80211_alloc_txb(1, fraglen, headroom, GFP_ATOMIC);
 	if (unlikely(!txb)) {
 		printk(KERN_WARNING "%s: Could not allocate TXB\n",
 		       ieee->dev->name);
 		goto failed;
 	}
 	txb->encrypted = 0;
-	txb->payload_size = total_len;
+	txb->payload_size = fraglen;
 
 	skb_frag = txb->fragments[0];
 

^ permalink raw reply

* [PATCH] [2.6.17]   Add tsi108 Ethernet device driver support
From: Zang Roy-r61911 @ 2006-06-21  4:00 UTC (permalink / raw)
  To: jgarzik
  Cc: netdev, linux-kernel, Alexandre.Bounine, Zang Roy-r61911,
	Yang Xin-Xin-r48390

This patch adds a net device driver and configuration options for
Tundra Semiconductor Tsi108 integrated dual port Gigabit 
Ethernet controller
  
Signed-off-by: Alexandre Bounine <alexandreb@tundra.com>
Signed-off-by: Roy Zang	<tie-fei.zang@freescale.com>
  
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0c6b45a..360b85f 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2196,6 +2196,14 @@ config SPIDER_NET
 	  This driver supports the Gigabit Ethernet chips present on the
 	  Cell Processor-Based Blades from IBM.
 
+config TSI108_ETH
+	   tristate "Tundra TSI108 gigabit Ethernet support"
+	   depends on TSI108_BRIDGE
+	   help
+	     This driver supports Tundra TSI108 gigabit Ethernet ports.
+	     To compile this driver as a module, choose M here: the module
+	     will be called tsi108_eth.
+
 config GIANFAR
 	tristate "Gianfar Ethernet"
 	depends on 85xx || 83xx
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 1eced32..6bf8186 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -109,6 +109,7 @@ obj-$(CONFIG_B44) += b44.o
 obj-$(CONFIG_FORCEDETH) += forcedeth.o
 obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
 
+obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
 obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
 
 obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
new file mode 100644
index 0000000..77d5a11
--- /dev/null
+++ b/drivers/net/tsi108_eth.c
@@ -0,0 +1,1755 @@
+/*******************************************************************************
+  
+  Copyright(c) 2005 Tundra Semiconductor Corporation.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*******************************************************************************/
+
+/* This driver is based on the driver code originally developed	
+ * for the Intel IOC80314 (ForestLake) Gigabit Ethernet by
+ * scott.wood@timesys.com  * Copyright (C) 2003 TimeSys Corporation
+ *
+ * Currently changes from original version are:
+ * - portig to Tsi108-based platform and kernel 2.6 (kong.lai@tundra.com)
+ * - modifications to handle two ports independently and support for
+ *   additional PHY devices (alexandre.bounine@tundra.com)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/device.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/pci.h>
+#include <linux/rtnetlink.h>
+#include <linux/timer.h>
+#include <linux/platform_device.h>
+
+#include <asm/tsi108_irq.h>
+#include <asm/tsi108.h>
+#include "tsi108_eth.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+typedef struct net_device net_device;
+typedef struct sk_buff sk_buff;
+
+#define MII_READ_DELAY 10000	/* max link wait time in msec */
+
+#define TSI108_RXRING_LEN     256
+
+/* NOTE: The driver currently does not support receiving packets
+ * larger than the buffer size, so don't decrease this (unless you
+ * want to add such support).
+ */
+#define TSI108_RXBUF_SIZE     1536
+
+#define TSI108_TXRING_LEN     256
+
+#define TSI108_TX_INT_FREQ    64
+
+/* Check the phy status every half a second. */
+#define CHECK_PHY_INTERVAL (HZ/2)
+
+static int tsi108_init_one(struct platform_device *pdev);
+static int tsi108_ether_remove(struct platform_device *pdev);
+
+typedef struct {
+	volatile u32 regs;	/* Base of normal regs */
+	volatile u32 phyregs;	/* Base of register bank used for PHY access */
+	int phy;		/* Index of PHY for this interface */
+	int irq_num;
+
+	struct timer_list timer;/* Timer that triggers the check phy function */
+	int rxtail;		/* Next entry in rxring to read */
+	int rxhead;		/* Next entry in rxring to give a new buffer */
+	int rxfree;		/* Number of free, allocated RX buffers */
+
+	int rxpending;		/* Non-zero if there are still descriptors
+				 * to be processed from a previous descriptor
+				 * interrupt condition that has been cleared */
+
+	int txtail;		/* Next TX descriptor to check status on */
+	int txhead;		/* Next TX descriptor to use */
+
+	/* Number of free TX descriptors.  This could be calculated from
+	 * rxhead and rxtail if one descriptor were left unused to disambiguate
+	 * full and empty conditions, but it's simpler to just keep track
+	 * explicitly. */
+
+	int txfree;
+
+	int phy_ok;		/* The PHY is currently powered on. */
+
+	/* PHY status (duplex is 1 for half, 2 for full,
+	 * so that the default 0 indicates that neither has
+	 * yet been configured). */
+
+	int link_up;
+	int speed;
+	int duplex;
+
+	tx_desc *txring;
+	rx_desc *rxring;
+	sk_buff *txskbs[TSI108_TXRING_LEN];
+	sk_buff *rxskbs[TSI108_RXRING_LEN];
+
+	dma_addr_t txdma, rxdma;
+
+	/* txlock nests in misclock and phy_lock */
+
+	spinlock_t txlock, misclock;
+
+	/* stats is used to hold the upper bits of each hardware counter,
+	 * and tmpstats is used to hold the full values for returning
+	 * to the caller of get_stats().  They must be separate in case
+	 * an overflow interrupt occurs before the stats are consumed.
+	 */
+
+	struct net_device_stats stats;
+	struct net_device_stats tmpstats;
+
+	/* These stats are kept separate in hardware, thus require individual
+	 * fields for handling carry.  They are combined in get_stats.
+	 */
+
+	unsigned long rx_fcs;	/* Add to rx_frame_errors */
+	unsigned long rx_short_fcs;	/* Add to rx_frame_errors */
+	unsigned long rx_long_fcs;	/* Add to rx_frame_errors */
+	unsigned long rx_underruns;	/* Add to rx_length_errors */
+	unsigned long rx_overruns;	/* Add to rx_length_errors */
+
+	unsigned long tx_coll_abort;	/* Add to tx_aborted_errors/collisions */
+	unsigned long tx_pause_drop;	/* Add to tx_aborted_errors */
+
+	unsigned long mc_hash[16];
+} tsi108_prv_data;
+
+/* Structure for a device driver */
+
+static struct platform_driver tsi_eth_driver = {
+	.probe = tsi108_init_one,
+	.remove = tsi108_ether_remove,
+	.driver	= {
+		.name = "tsi-ethernet",
+	},
+};
+
+static void tsi108_timed_checker(unsigned long dev_ptr);
+
+static void dump_eth_one(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+
+	printk("Dumping %s...\n", dev->name);
+	printk("intstat %x intmask %x phy_ok %d"
+	       " link %d speed %d duplex %d\n",
+	       TSI108_ETH_READ_REG(TSI108_EC_INTSTAT),
+	       TSI108_ETH_READ_REG(TSI108_EC_INTMASK), data->phy_ok,
+	       data->link_up, data->speed, data->duplex);
+
+	printk("TX: head %d, tail %d, free %d, stat %x, estat %x, err %x\n",
+	       data->txhead, data->txtail, data->txfree,
+	       TSI108_ETH_READ_REG(TSI108_EC_TXSTAT),
+	       TSI108_ETH_READ_REG(TSI108_EC_TXESTAT),
+	       TSI108_ETH_READ_REG(TSI108_EC_TXERR));
+
+	printk("RX: head %d, tail %d, free %d, stat %x,"
+	       " estat %x, err %x, pending %d\n\n",
+	       data->rxhead, data->rxtail, data->rxfree,
+	       TSI108_ETH_READ_REG(TSI108_EC_RXSTAT),
+	       TSI108_ETH_READ_REG(TSI108_EC_RXESTAT),
+	       TSI108_ETH_READ_REG(TSI108_EC_RXERR), data->rxpending);
+}
+
+/* Synchronization is needed between the thread and up/down events.
+ * Note that the PHY is accessed through the same registers for both
+ * interfaces, so this can't be made interface-specific.
+ */
+
+static spinlock_t phy_lock = SPIN_LOCK_UNLOCKED;
+
+static inline u16 tsi108_read_mii(tsi108_prv_data * data, int reg, int *status)
+{
+	int i;
+	u16 ret;
+
+	TSI108_ETH_WRITE_PHYREG(TSI108_MAC_MII_ADDR,
+				(data->phy << TSI108_MAC_MII_ADDR_PHY) |
+				(reg << TSI108_MAC_MII_ADDR_REG));
+	mb();
+	TSI108_ETH_WRITE_PHYREG(TSI108_MAC_MII_CMD, 0);
+	mb();
+	TSI108_ETH_WRITE_PHYREG(TSI108_MAC_MII_CMD, TSI108_MAC_MII_CMD_READ);
+	mb();
+	for (i = 0; i < 100; i++) {
+		if (!(TSI108_ETH_READ_PHYREG(TSI108_MAC_MII_IND) &
+		      (TSI108_MAC_MII_IND_NOTVALID | TSI108_MAC_MII_IND_BUSY)))
+			break;
+		udelay(10);
+	}
+
+	if (i == 100) {
+		if (status)
+			*status = -EBUSY;
+
+		ret = 0xffff;
+	} else {
+		if (status)
+			*status = 0;
+
+		ret = TSI108_ETH_READ_PHYREG(TSI108_MAC_MII_DATAIN);
+	}
+
+	return ret;
+}
+
+static inline void tsi108_write_mii(tsi108_prv_data * data, int reg, u16 val)
+{
+	TSI108_ETH_WRITE_PHYREG(TSI108_MAC_MII_ADDR,
+				(data->phy << TSI108_MAC_MII_ADDR_PHY) |
+				(reg << TSI108_MAC_MII_ADDR_REG));
+	mb();
+	TSI108_ETH_WRITE_PHYREG(TSI108_MAC_MII_DATAOUT, val);
+	mb();
+	while (TSI108_ETH_READ_PHYREG(TSI108_MAC_MII_IND) &
+	       TSI108_MAC_MII_IND_BUSY) ;
+}
+
+static inline void tsi108_write_tbi(tsi108_prv_data * data, int reg, u16 val)
+{
+
+	TSI108_ETH_WRITE_REG(TSI108_MAC_MII_ADDR,
+			     (0x1e << TSI108_MAC_MII_ADDR_PHY)
+			     | (reg << TSI108_MAC_MII_ADDR_REG));
+	mb();
+
+	TSI108_ETH_WRITE_REG(TSI108_MAC_MII_DATAOUT, val);
+	mb();
+	while (TSI108_ETH_READ_REG(TSI108_MAC_MII_IND) &
+	       TSI108_MAC_MII_IND_BUSY) ;
+}
+
+static void tsi108_check_phy(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	u16 sumstat;
+	u32 mac_cfg2_reg, portctrl_reg;
+	u32 fdx_flag = 0, reg_update = 0;
+
+	/* Do a dummy read, as for some reason the first read
+	 * after a link becomes up returns link down, even if
+	 * it's been a while since the link came up.
+	 */
+
+	spin_lock(&phy_lock);
+
+	if (!data->phy_ok)
+		goto out;
+
+	tsi108_read_mii(data, PHY_STAT, NULL);
+
+	if (!(tsi108_read_mii(data, PHY_STAT, NULL) & PHY_STAT_LINKUP)) {
+		if (data->link_up == 1) {
+			netif_stop_queue(dev);
+			data->link_up = 0;
+			printk(KERN_NOTICE "%s : link is down\n", dev->name);
+			netif_carrier_off(dev);
+		}
+
+		goto out;
+	}
+
+	{
+		mac_cfg2_reg = TSI108_ETH_READ_REG(TSI108_MAC_CFG2);
+		portctrl_reg = TSI108_ETH_READ_REG(TSI108_EC_PORTCTRL);
+
+		sumstat = tsi108_read_mii(data, PHY_SUM_STAT, NULL);
+
+		switch (sumstat & PHY_SUM_STAT_SPEED_MASK) {
+		case PHY_SUM_STAT_1000T_FD:
+			fdx_flag++;
+		case PHY_SUM_STAT_1000T_HD:
+			if (data->speed != 1000) {
+				mac_cfg2_reg &= ~TSI108_MAC_CFG2_IFACE_MASK;
+				mac_cfg2_reg |= TSI108_MAC_CFG2_GIG;
+				portctrl_reg &= ~TSI108_EC_PORTCTRL_NOGIG;
+				data->speed = 1000;
+				reg_update++;
+			}
+			break;
+		case PHY_SUM_STAT_100TX_FD:
+			fdx_flag++;
+		case PHY_SUM_STAT_100TX_HD:
+			if (data->speed != 100) {
+				mac_cfg2_reg &= ~TSI108_MAC_CFG2_IFACE_MASK;
+				mac_cfg2_reg |= TSI108_MAC_CFG2_NOGIG;
+				portctrl_reg |= TSI108_EC_PORTCTRL_NOGIG;
+				data->speed = 100;
+				reg_update++;
+			}
+			break;
+
+		case PHY_SUM_STAT_10T_FD:
+			fdx_flag++;
+		case PHY_SUM_STAT_10T_HD:
+			if (data->speed != 10) {
+				mac_cfg2_reg &= ~TSI108_MAC_CFG2_IFACE_MASK;
+				mac_cfg2_reg |= TSI108_MAC_CFG2_NOGIG;
+				portctrl_reg |= TSI108_EC_PORTCTRL_NOGIG;
+				data->speed = 10;
+				reg_update++;
+			}
+			break;
+
+		default:
+			if (net_ratelimit())
+				printk(KERN_ERR "PHY reported invalid speed,"
+				       KERN_ERR " summary status %x\n",
+				       sumstat);
+			goto out;
+		}
+
+		if (fdx_flag || (sumstat & PHY_SUM_STAT_FULLDUPLEX)) {
+			if (data->duplex != 2) {
+				mac_cfg2_reg |= TSI108_MAC_CFG2_FULLDUPLEX;
+				portctrl_reg &= ~TSI108_EC_PORTCTRL_HALFDUPLEX;
+				data->duplex = 2;
+				reg_update++;
+			}
+		} else {
+			if (data->duplex != 1) {
+				mac_cfg2_reg &= ~TSI108_MAC_CFG2_FULLDUPLEX;
+				portctrl_reg |= TSI108_EC_PORTCTRL_HALFDUPLEX;
+				data->duplex = 1;
+				reg_update++;
+			}
+		}
+
+		if (reg_update) {
+			TSI108_ETH_WRITE_REG(TSI108_MAC_CFG2, mac_cfg2_reg);
+			mb();
+			TSI108_ETH_WRITE_REG(TSI108_EC_PORTCTRL, portctrl_reg);
+			mb();
+		}
+
+	}
+
+	if (data->link_up == 0) {
+		/* The manual says it can take 3-4 usecs for the speed change
+		 * to take effect.
+		 */
+		udelay(5);
+
+		spin_lock(&data->txlock);
+		if (netif_queue_stopped(dev)
+		    && is_valid_ether_addr(dev->dev_addr) && data->txfree)
+			netif_wake_queue(dev);
+
+		data->link_up = 1;
+		spin_unlock(&data->txlock);
+		printk("%s : link is up: %dMb %s-duplex\n",
+		       dev->name, data->speed,
+		       (data->duplex == 2) ? "full" : "half");
+		netif_carrier_on(dev);
+	}
+
+      out:
+	spin_unlock(&phy_lock);
+}
+
+static inline void
+tsi108_stat_carry_one(int carry, int carry_bit, int carry_shift,
+		      unsigned long *upper)
+{
+	if (carry & carry_bit)
+		*upper += carry_shift;
+}
+
+static void tsi108_stat_carry(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	u32 carry1, carry2;
+
+	spin_lock_irq(&data->misclock);
+
+	carry1 = TSI108_ETH_READ_REG(TSI108_STAT_CARRY1);
+	carry2 = TSI108_ETH_READ_REG(TSI108_STAT_CARRY2);
+
+	TSI108_ETH_WRITE_REG(TSI108_STAT_CARRY1, carry1);
+	TSI108_ETH_WRITE_REG(TSI108_STAT_CARRY2, carry2);
+
+	tsi108_stat_carry_one(carry1, TSI108_STAT_CARRY1_RXBYTES,
+			      TSI108_STAT_RXBYTES_CARRY, &data->stats.rx_bytes);
+
+	tsi108_stat_carry_one(carry1, TSI108_STAT_CARRY1_RXPKTS,
+			      TSI108_STAT_RXPKTS_CARRY,
+			      &data->stats.rx_packets);
+
+	tsi108_stat_carry_one(carry1, TSI108_STAT_CARRY1_RXFCS,
+			      TSI108_STAT_RXFCS_CARRY, &data->rx_fcs);
+
+	tsi108_stat_carry_one(carry1, TSI108_STAT_CARRY1_RXMCAST,
+			      TSI108_STAT_RXMCAST_CARRY,
+			      &data->stats.multicast);
+
+	tsi108_stat_carry_one(carry1, TSI108_STAT_CARRY1_RXALIGN,
+			      TSI108_STAT_RXALIGN_CARRY,
+			      &data->stats.rx_frame_errors);
+
+	tsi108_stat_carry_one(carry1, TSI108_STAT_CARRY1_RXLENGTH,
+			      TSI108_STAT_RXLENGTH_CARRY,
+			      &data->stats.rx_length_errors);
+
+	tsi108_stat_carry_one(carry1, TSI108_STAT_CARRY1_RXRUNT,
+			      TSI108_STAT_RXRUNT_CARRY, &data->rx_underruns);
+
+	tsi108_stat_carry_one(carry1, TSI108_STAT_CARRY1_RXJUMBO,
+			      TSI108_STAT_RXJUMBO_CARRY, &data->rx_overruns);
+
+	tsi108_stat_carry_one(carry1, TSI108_STAT_CARRY1_RXFRAG,
+			      TSI108_STAT_RXFRAG_CARRY, &data->rx_short_fcs);
+
+	tsi108_stat_carry_one(carry1, TSI108_STAT_CARRY1_RXJABBER,
+			      TSI108_STAT_RXJABBER_CARRY, &data->rx_long_fcs);
+
+	tsi108_stat_carry_one(carry1, TSI108_STAT_CARRY1_RXDROP,
+			      TSI108_STAT_RXDROP_CARRY,
+			      &data->stats.rx_missed_errors);
+
+	tsi108_stat_carry_one(carry2, TSI108_STAT_CARRY2_TXBYTES,
+			      TSI108_STAT_TXBYTES_CARRY, &data->stats.tx_bytes);
+
+	tsi108_stat_carry_one(carry2, TSI108_STAT_CARRY2_TXPKTS,
+			      TSI108_STAT_TXPKTS_CARRY,
+			      &data->stats.tx_packets);
+
+	tsi108_stat_carry_one(carry2, TSI108_STAT_CARRY2_TXEXDEF,
+			      TSI108_STAT_TXEXDEF_CARRY,
+			      &data->stats.tx_aborted_errors);
+
+	tsi108_stat_carry_one(carry2, TSI108_STAT_CARRY2_TXEXCOL,
+			      TSI108_STAT_TXEXCOL_CARRY, &data->tx_coll_abort);
+
+	tsi108_stat_carry_one(carry2, TSI108_STAT_CARRY2_TXTCOL,
+			      TSI108_STAT_TXTCOL_CARRY,
+			      &data->stats.collisions);
+
+	tsi108_stat_carry_one(carry2, TSI108_STAT_CARRY2_TXPAUSE,
+			      TSI108_STAT_TXPAUSEDROP_CARRY,
+			      &data->tx_pause_drop);
+
+	spin_unlock_irq(&data->misclock);
+}
+
+/* Read a stat counter atomically with respect to carries.
+ * data->misclock must be held.
+ */
+static inline unsigned long
+tsi108_read_stat(tsi108_prv_data * data, int reg, int carry_bit,
+		 int carry_shift, unsigned long *upper)
+{
+	int carryreg;
+	unsigned long val;
+
+	if (reg < 0xb0)
+		carryreg = TSI108_STAT_CARRY1;
+	else
+		carryreg = TSI108_STAT_CARRY2;
+
+      again:
+	val = TSI108_ETH_READ_REG(reg) | *upper;
+
+	rmb();
+
+	/* Check to see if it overflowed, but the interrupt hasn't
+	 * been serviced yet.  If so, handle the carry here, and
+	 * try again.
+	 */
+
+	if (unlikely(TSI108_ETH_READ_REG(carryreg) & carry_bit)) {
+		*upper += carry_shift;
+		TSI108_ETH_WRITE_REG(carryreg, carry_bit);
+		mb();
+
+		goto again;
+	}
+
+	return val;
+}
+
+static struct net_device_stats *tsi108_get_stats(net_device * dev)
+{
+	unsigned long excol;
+
+	tsi108_prv_data *data = netdev_priv(dev);
+	spin_lock_irq(&data->misclock);
+
+	data->tmpstats.rx_packets =
+	    tsi108_read_stat(data, TSI108_STAT_RXPKTS,
+			     TSI108_STAT_CARRY1_RXPKTS,
+			     TSI108_STAT_RXPKTS_CARRY, &data->stats.rx_packets);
+
+	data->tmpstats.tx_packets =
+	    tsi108_read_stat(data, TSI108_STAT_TXPKTS,
+			     TSI108_STAT_CARRY2_TXPKTS,
+			     TSI108_STAT_TXPKTS_CARRY, &data->stats.tx_packets);
+
+	data->tmpstats.rx_bytes =
+	    tsi108_read_stat(data, TSI108_STAT_RXBYTES,
+			     TSI108_STAT_CARRY1_RXBYTES,
+			     TSI108_STAT_RXBYTES_CARRY, &data->stats.rx_bytes);
+
+	data->tmpstats.tx_bytes =
+	    tsi108_read_stat(data, TSI108_STAT_TXBYTES,
+			     TSI108_STAT_CARRY2_TXBYTES,
+			     TSI108_STAT_TXBYTES_CARRY, &data->stats.tx_bytes);
+
+	data->tmpstats.multicast =
+	    tsi108_read_stat(data, TSI108_STAT_RXMCAST,
+			     TSI108_STAT_CARRY1_RXMCAST,
+			     TSI108_STAT_RXMCAST_CARRY, &data->stats.multicast);
+
+	excol = tsi108_read_stat(data, TSI108_STAT_TXEXCOL,
+				 TSI108_STAT_CARRY2_TXEXCOL,
+				 TSI108_STAT_TXEXCOL_CARRY,
+				 &data->tx_coll_abort);
+
+	data->tmpstats.collisions =
+	    tsi108_read_stat(data, TSI108_STAT_TXTCOL,
+			     TSI108_STAT_CARRY2_TXTCOL,
+			     TSI108_STAT_TXTCOL_CARRY, &data->stats.collisions);
+
+	data->tmpstats.collisions += excol;
+
+	data->tmpstats.rx_length_errors =
+	    tsi108_read_stat(data, TSI108_STAT_RXLENGTH,
+			     TSI108_STAT_CARRY1_RXLENGTH,
+			     TSI108_STAT_RXLENGTH_CARRY,
+			     &data->stats.rx_length_errors);
+
+	data->tmpstats.rx_length_errors +=
+	    tsi108_read_stat(data, TSI108_STAT_RXRUNT,
+			     TSI108_STAT_CARRY1_RXRUNT,
+			     TSI108_STAT_RXRUNT_CARRY, &data->rx_underruns);
+
+	data->tmpstats.rx_length_errors +=
+	    tsi108_read_stat(data, TSI108_STAT_RXJUMBO,
+			     TSI108_STAT_CARRY1_RXJUMBO,
+			     TSI108_STAT_RXJUMBO_CARRY, &data->rx_overruns);
+
+	data->tmpstats.rx_frame_errors =
+	    tsi108_read_stat(data, TSI108_STAT_RXALIGN,
+			     TSI108_STAT_CARRY1_RXALIGN,
+			     TSI108_STAT_RXALIGN_CARRY,
+			     &data->stats.rx_frame_errors);
+
+	data->tmpstats.rx_frame_errors +=
+	    tsi108_read_stat(data, TSI108_STAT_RXFCS,
+			     TSI108_STAT_CARRY1_RXFCS, TSI108_STAT_RXFCS_CARRY,
+			     &data->rx_fcs);
+
+	data->tmpstats.rx_frame_errors +=
+	    tsi108_read_stat(data, TSI108_STAT_RXFRAG,
+			     TSI108_STAT_CARRY1_RXFRAG,
+			     TSI108_STAT_RXFRAG_CARRY, &data->rx_short_fcs);
+
+	data->tmpstats.rx_missed_errors =
+	    tsi108_read_stat(data, TSI108_STAT_RXDROP,
+			     TSI108_STAT_CARRY1_RXDROP,
+			     TSI108_STAT_RXDROP_CARRY,
+			     &data->stats.rx_missed_errors);
+
+	/* These three are maintained by software. */
+	data->tmpstats.rx_fifo_errors = data->stats.rx_fifo_errors;
+	data->tmpstats.rx_crc_errors = data->stats.rx_crc_errors;
+
+	data->tmpstats.tx_aborted_errors =
+	    tsi108_read_stat(data, TSI108_STAT_TXEXDEF,
+			     TSI108_STAT_CARRY2_TXEXDEF,
+			     TSI108_STAT_TXEXDEF_CARRY,
+			     &data->stats.tx_aborted_errors);
+
+	data->tmpstats.tx_aborted_errors +=
+	    tsi108_read_stat(data, TSI108_STAT_TXPAUSEDROP,
+			     TSI108_STAT_CARRY2_TXPAUSE,
+			     TSI108_STAT_TXPAUSEDROP_CARRY,
+			     &data->tx_pause_drop);
+
+	data->tmpstats.tx_aborted_errors += excol;
+
+	data->tmpstats.tx_errors = data->tmpstats.tx_aborted_errors;
+	data->tmpstats.rx_errors = data->tmpstats.rx_length_errors +
+	    data->tmpstats.rx_crc_errors +
+	    data->tmpstats.rx_frame_errors +
+	    data->tmpstats.rx_fifo_errors + data->tmpstats.rx_missed_errors;
+
+	spin_unlock_irq(&data->misclock);
+	return &data->tmpstats;
+}
+
+static void tsi108_restart_rx(tsi108_prv_data * data, net_device * dev)
+{
+	TSI108_ETH_WRITE_REG(TSI108_EC_RXQ_PTRHIGH,
+			     TSI108_EC_RXQ_PTRHIGH_VALID);
+
+	wmb();
+	TSI108_ETH_WRITE_REG(TSI108_EC_RXCTRL, TSI108_EC_RXCTRL_GO
+			     | TSI108_EC_RXCTRL_QUEUE0);
+}
+
+static void tsi108_restart_tx(tsi108_prv_data * data)
+{
+	TSI108_ETH_WRITE_REG(TSI108_EC_TXQ_PTRHIGH,
+			     TSI108_EC_TXQ_PTRHIGH_VALID);
+
+	wmb();
+	TSI108_ETH_WRITE_REG(TSI108_EC_TXCTRL, TSI108_EC_TXCTRL_IDLEINT |
+			     TSI108_EC_TXCTRL_GO | TSI108_EC_TXCTRL_QUEUE0);
+}
+
+/* txlock must be held by caller, with IRQs disabled, and
+ * with permission to re-enable them when the lock is dropped.
+ */
+static void tsi108_check_for_completed_tx(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	int tx;
+	struct sk_buff *skb;
+	int release = 0;
+
+	while (!data->txfree || data->txhead != data->txtail) {
+		tx = data->txtail;
+
+		if (data->txring[tx].misc & TSI108_TX_OWN)
+			break;
+
+		skb = data->txskbs[tx];
+
+		if (!(data->txring[tx].misc & TSI108_TX_OK))
+			printk("%s: bad tx packet, misc %x\n",
+			       dev->name, data->txring[tx].misc);
+
+		data->txtail = (data->txtail + 1) % TSI108_TXRING_LEN;
+		data->txfree++;
+
+		if (data->txring[tx].misc & TSI108_TX_EOF) {
+			dev_kfree_skb_any(skb);
+			release++;
+		}
+	}
+
+	if (release) {
+
+		if (netif_queue_stopped(dev)
+		    && is_valid_ether_addr(dev->dev_addr) && data->link_up)
+			netif_wake_queue(dev);
+	}
+}
+
+static int tsi108_send_packet(sk_buff * skb, net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	int frags = skb_shinfo(skb)->nr_frags + 1;
+	int i;
+#ifdef FIXME_SG_CSUM_NOT_TESTED	/* FIXME: Not supported now. */
+	long csstart;
+	long csum;
+
+	csstart = skb->len - skb->data_len;
+	if (csstart > skb->len - skb->data_len)
+		BUG();
+	csum = 0;
+	if (csstart != skb->len)
+		csum = skb_checksum(skb, csstart, skb->len - csstart, 0);
+#endif
+
+	if (!data->phy_ok && net_ratelimit())
+		printk(KERN_ERR "%s: Transmit while PHY is down!\n", dev->name);
+
+	if (!data->link_up) {
+		printk(KERN_ERR "%s: Transmit while link is down!\n",
+		       dev->name);
+		netif_stop_queue(dev);
+		return 1;
+	}
+
+	if (data->txfree < MAX_SKB_FRAGS + 1) {
+		netif_stop_queue(dev);
+
+		if (net_ratelimit())
+			printk(KERN_ERR "%s: Transmit with full tx ring!\n",
+			       dev->name);
+		return 1;
+	}
+
+	if (data->txfree - frags < MAX_SKB_FRAGS + 1) {
+		netif_stop_queue(dev);
+	}
+
+	spin_lock_irq(&data->txlock);
+
+	for (i = 0; i < frags; i++) {
+		int misc = 0;
+		int tx = data->txhead;
+
+		/* This is done to mark every TSI108_TX_INT_FREQ tx buffers with
+		 * the interrupt bit.  TX descriptor-complete interrupts are
+		 * enabled when the queue fills up, and masked when there is
+		 * still free space.  This way, when saturating the outbound
+		 * link, the tx interrupts are kept to a reasonable level. 
+		 * When the queue is not full, reclamation of skbs still occurs
+		 * as new packets are transmitted, or on a queue-empty
+		 * interrupt.
+		 */
+
+		if ((tx % TSI108_TX_INT_FREQ == 0) &&
+		    ((TSI108_TXRING_LEN - data->txfree) >= TSI108_TX_INT_FREQ)
+		    )
+			misc = TSI108_TX_INT;
+
+		data->txskbs[tx] = skb;
+
+		if (i == 0) {
+			data->txring[tx].buf0 = virt_to_phys(skb->data);
+			data->txring[tx].len = skb->len - skb->data_len;
+			misc |= TSI108_TX_SOF;
+		} else {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
+
+			data->txring[tx].buf0 =
+			    page_to_phys(frag->page) + frag->page_offset;
+			data->txring[tx].len = frag->size;
+		}
+
+		if (i == frags - 1)
+			misc |= TSI108_TX_EOF;
+
+#ifdef TSI108_PRINT_TX_FRAME
+		{
+			int i;
+			printk("%s: Tx Frame contents (%d)\n", dev->name,
+			       skb->len);
+			for (i = 0; i < skb->len; i++)
+				printk(" %2.2x", skb->data[i]);
+			printk(".\n");
+		}
+#endif				/* TSI108_PRINT_TX_FRAME */
+
+		mb();
+		data->txring[tx].misc = misc | TSI108_TX_OWN;
+
+		data->txhead = (data->txhead + 1) % TSI108_TXRING_LEN;
+		data->txfree--;
+	}
+
+	tsi108_check_for_completed_tx(dev);
+
+	/* This must be done after the check for completed tx descriptors,
+	 * so that the tail pointer is correct.
+	 */
+
+	if (!(TSI108_ETH_READ_REG(TSI108_EC_TXSTAT) & TSI108_EC_TXSTAT_QUEUE0))
+		tsi108_restart_tx(data);
+
+	spin_unlock_irq(&data->txlock);
+	return 0;
+}
+
+static int tsi108_check_for_completed_rx(net_device * dev, int budget)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	int done = 0;
+
+	while (data->rxfree && done != budget) {
+		int rx = data->rxtail;
+		struct sk_buff *skb;
+
+		if (data->rxring[rx].misc & TSI108_RX_OWN)
+			break;
+
+		skb = data->rxskbs[rx];
+		data->rxtail = (data->rxtail + 1) % TSI108_RXRING_LEN;
+		data->rxfree--;
+		done++;
+
+		if (data->rxring[rx].misc & TSI108_RX_BAD) {
+			spin_lock_irq(&data->misclock);
+
+			if (data->rxring[rx].misc & TSI108_RX_CRC)
+				data->stats.rx_crc_errors++;
+			if (data->rxring[rx].misc & TSI108_RX_OVER)
+				data->stats.rx_fifo_errors++;
+
+			spin_unlock_irq(&data->misclock);
+
+			dev_kfree_skb_any(skb);
+			continue;
+		}
+#ifdef TSI108_PRINT_RX_FRAME
+		{
+			int i;
+			printk("%s: Rx Frame contents (%d)\n",
+			       dev->name, data->rxring[rx].len);
+			for (i = 0; i < data->rxring[rx].len; i++)
+				printk(" %2.2x", skb->data[i]);
+			printk(".\n");
+		}
+#endif				/* TSI108_PRINT_RX_FRAME */
+
+		skb->dev = dev;
+		skb_put(skb, data->rxring[rx].len);
+		skb->protocol = eth_type_trans(skb, dev);
+		netif_receive_skb(skb);
+		dev->last_rx = jiffies;
+	}
+
+	return done;
+}
+
+static int tsi108_refill_rx(net_device * dev, int budget)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	int done = 0;
+
+	while (data->rxfree != TSI108_RXRING_LEN && done != budget) {
+		int rx = data->rxhead;
+		sk_buff *skb;
+
+		data->rxskbs[rx] = skb = dev_alloc_skb(TSI108_RXBUF_SIZE + 2);
+		if (!skb)
+			break;
+
+		skb_reserve(skb, 2);	/* Align the data on a 4-byte boundary. */
+
+		data->rxring[rx].buf0 = virt_to_phys(skb->data);
+
+		/* Sometimes the hardware sets blen to zero after packet
+		 * reception, even though the manual says that it's only ever
+		 * modified by the driver.
+		 */
+
+		data->rxring[rx].blen = 1536;
+		mb();
+		data->rxring[rx].misc = TSI108_RX_OWN | TSI108_RX_INT;
+
+		data->rxhead = (data->rxhead + 1) % TSI108_RXRING_LEN;
+		data->rxfree++;
+		done++;
+	}
+
+	mb();
+
+	if (done != 0 && !(TSI108_ETH_READ_REG(TSI108_EC_RXSTAT) &
+			   TSI108_EC_RXSTAT_QUEUE0))
+		tsi108_restart_rx(data, dev);
+
+	return done;
+}
+
+static int tsi108_poll(net_device * dev, int *budget)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	u32 estat = TSI108_ETH_READ_REG(TSI108_EC_RXESTAT);
+	u32 intstat = TSI108_ETH_READ_REG(TSI108_EC_INTSTAT);
+	int total_budget = min(*budget, dev->quota);
+	int num_received = 0, num_filled = 0, budget_used;
+
+	intstat &= TSI108_INT_RXQUEUE0 | TSI108_INT_RXTHRESH |
+	    TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT;
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_RXESTAT, estat);
+	TSI108_ETH_WRITE_REG(TSI108_EC_INTSTAT, intstat);
+
+	if (data->rxpending || (estat & TSI108_EC_RXESTAT_Q0_DESCINT))
+		num_received = tsi108_check_for_completed_rx(dev, total_budget);
+
+	/* This should normally fill no more slots than the number of
+	 * packets received in tsi108_check_for_completed_rx().  The exception
+	 * is when we previously ran out of memory for RX SKBs.  In that
+	 * case, it's helpful to obey the budget, not only so that the
+	 * CPU isn't hogged, but so that memory (which may still be low)
+	 * is not hogged by one device.
+	 *
+	 * A work unit is considered to be two SKBs to allow us to catch
+	 * up when the ring has shrunk due to out-of-memory but we're
+	 * still removing the full budget's worth of packets each time.
+	 */
+
+	if (data->rxfree < TSI108_RXRING_LEN)
+		num_filled = tsi108_refill_rx(dev, total_budget * 2);
+
+	if (intstat & TSI108_INT_RXERROR) {
+		u32 err = TSI108_ETH_READ_REG(TSI108_EC_RXERR);
+		TSI108_ETH_WRITE_REG(TSI108_EC_RXERR, err);
+
+		if (err) {
+			if (net_ratelimit())
+				printk(KERN_DEBUG "%s: RX error %x\n",
+				       dev->name, err);
+
+			if (!(TSI108_ETH_READ_REG(TSI108_EC_RXSTAT) &
+			      TSI108_EC_RXSTAT_QUEUE0))
+				tsi108_restart_rx(data, dev);
+		}
+	}
+
+	if (intstat & TSI108_INT_RXOVERRUN) {
+		spin_lock_irq(&data->misclock);
+		data->stats.rx_fifo_errors++;
+		spin_unlock_irq(&data->misclock);
+	}
+
+	budget_used = max(num_received, num_filled / 2);
+
+	*budget -= budget_used;
+	dev->quota -= budget_used;
+
+	if (budget_used != total_budget) {
+		data->rxpending = 0;
+		netif_rx_complete(dev);
+
+		TSI108_ETH_WRITE_REG(TSI108_EC_INTMASK,
+				     TSI108_ETH_READ_REG(TSI108_EC_INTMASK)
+				     & ~(TSI108_INT_RXQUEUE0
+					 | TSI108_INT_RXTHRESH |
+					 TSI108_INT_RXOVERRUN |
+					 TSI108_INT_RXERROR |
+					 TSI108_INT_RXWAIT));
+
+		mb();
+
+		/* IRQs are level-triggered, so no need to re-check */
+		return 0;
+	} else {
+		data->rxpending = 1;
+	}
+
+	return 1;
+}
+
+static void tsi108_rx_int(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+
+	/* A race could cause dev to already be scheduled, so it's not an
+	 * error if that happens (and interrupts shouldn't be re-masked,
+	 * because that can cause harmful races, if poll has already
+	 * unmasked them but not cleared LINK_STATE_SCHED).  
+	 *
+	 * This can happen if this code races with tsi108_poll(), which masks
+	 * the interrupts after tsi108_irq_one() read the mask, but before
+	 * netif_rx_schedule is called.  It could also happen due to calls
+	 * from tsi108_check_rxring().
+	 */
+
+	if (netif_rx_schedule_prep(dev)) {
+		/* Mask, rather than ack, the receive interrupts.  The ack
+		 * will happen in tsi108_poll().
+		 */
+
+		TSI108_ETH_WRITE_REG(TSI108_EC_INTMASK,
+				     TSI108_ETH_READ_REG(TSI108_EC_INTMASK) |
+				     TSI108_INT_RXQUEUE0
+				     | TSI108_INT_RXTHRESH |
+				     TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR |
+				     TSI108_INT_RXWAIT);
+		mb();
+		__netif_rx_schedule(dev);
+	} else {
+		if (!netif_running(dev)) {
+			/* This can happen if an interrupt occurs while the
+			 * interface is being brought down, as the START
+			 * bit is cleared before the stop function is called.
+			 *
+			 * In this case, the interrupts must be masked, or
+			 * they will continue indefinitely.
+			 *
+			 * There's a race here if the interface is brought down
+			 * and then up in rapid succession, as the device could
+			 * be made running after the above check and before
+			 * the masking below.  This will only happen if the IRQ
+			 * thread has a lower priority than the task brining
+			 * up the interface.  Fixing this race would likely
+			 * require changes in generic code.
+			 */
+
+			TSI108_ETH_WRITE_REG(TSI108_EC_INTMASK,
+					     TSI108_ETH_READ_REG
+					     (TSI108_EC_INTMASK) |
+					     TSI108_INT_RXQUEUE0 |
+					     TSI108_INT_RXTHRESH |
+					     TSI108_INT_RXOVERRUN |
+					     TSI108_INT_RXERROR |
+					     TSI108_INT_RXWAIT);
+			mb();
+		}
+	}
+}
+
+/* If the RX ring has run out of memory, try periodically
+ * to allocate some more, as otherwise poll would never
+ * get called (apart from the initial end-of-queue condition).
+ *
+ * This is called once per second (by default) from the thread.
+ */
+
+static void tsi108_check_rxring(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+
+	/* A poll is scheduled, as opposed to caling tsi108_refill_rx 
+	 * directly, so as to keep the receive path single-threaded
+	 * (and thus not needing a lock).
+	 */
+
+	if (netif_running(dev) && data->rxfree < TSI108_RXRING_LEN / 4)
+		tsi108_rx_int(dev);
+}
+
+static void tsi108_tx_int(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	u32 estat = TSI108_ETH_READ_REG(TSI108_EC_TXESTAT);
+
+	mb();
+	TSI108_ETH_WRITE_REG(TSI108_EC_TXESTAT, estat);
+	mb();
+	TSI108_ETH_WRITE_REG(TSI108_EC_INTSTAT, TSI108_INT_TXQUEUE0 |
+			     TSI108_INT_TXIDLE | TSI108_INT_TXERROR);
+	mb();
+	if (estat & TSI108_EC_TXESTAT_Q0_ERR) {
+		u32 err = TSI108_ETH_READ_REG(TSI108_EC_TXERR);
+		TSI108_ETH_WRITE_REG(TSI108_EC_TXERR, err);
+
+		if (err && net_ratelimit())
+			printk(KERN_ERR "%s: TX error %x\n", dev->name, err);
+	}
+
+	if (estat & (TSI108_EC_TXESTAT_Q0_DESCINT | TSI108_EC_TXESTAT_Q0_EOQ)) {
+		spin_lock(&data->txlock);
+		tsi108_check_for_completed_tx(dev);
+		spin_unlock(&data->txlock);
+	}
+}
+
+static irqreturn_t tsi108_irq_one(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	u32 stat = TSI108_ETH_READ_REG(TSI108_EC_INTSTAT);
+
+	if (!(stat & TSI108_INT_ANY))
+		return IRQ_NONE;	/* Not our interrupt */
+
+	stat &= ~TSI108_ETH_READ_REG(TSI108_EC_INTMASK);
+
+	if (stat & (TSI108_INT_TXQUEUE0 | TSI108_INT_TXIDLE |
+		    TSI108_INT_TXERROR))
+		tsi108_tx_int(dev);
+	if (stat & (TSI108_INT_RXQUEUE0 | TSI108_INT_RXTHRESH |
+		    TSI108_INT_RXWAIT | TSI108_INT_RXOVERRUN |
+		    TSI108_INT_RXERROR))
+		tsi108_rx_int(dev);
+
+	if (stat & TSI108_INT_SFN) {
+		if (net_ratelimit())
+			printk(KERN_DEBUG "%s: SFN error\n", dev->name);
+		TSI108_ETH_WRITE_REG(TSI108_EC_INTSTAT, TSI108_INT_SFN);
+	}
+
+	if (stat & TSI108_INT_STATCARRY) {
+		tsi108_stat_carry(dev);
+		TSI108_ETH_WRITE_REG(TSI108_EC_INTSTAT, TSI108_INT_STATCARRY);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t tsi108_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if ((IRQ_TSI108_GIGE0 != irq) && (IRQ_TSI108_GIGE1 != irq))
+		return IRQ_NONE;	/* Not our interrupt */
+
+	return tsi108_irq_one((struct net_device *)dev_id);
+}
+
+static void tsi108_stop_ethernet(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+
+	/* Disable all TX and RX queues ... */
+	TSI108_ETH_WRITE_REG(TSI108_EC_TXCTRL, 0);
+	TSI108_ETH_WRITE_REG(TSI108_EC_RXCTRL, 0);
+
+	/* ...and wait for them to become idle */
+	mb();
+	while (TSI108_ETH_READ_REG(TSI108_EC_TXSTAT) &
+	       TSI108_EC_TXSTAT_ACTIVE) ;
+	while (TSI108_ETH_READ_REG(TSI108_EC_RXSTAT) &
+	       TSI108_EC_RXSTAT_ACTIVE) ;
+}
+
+static void tsi108_reset_ether(tsi108_prv_data * data)
+{
+	TSI108_ETH_WRITE_REG(TSI108_MAC_CFG1, TSI108_MAC_CFG1_SOFTRST);
+	udelay(100);
+	TSI108_ETH_WRITE_REG(TSI108_MAC_CFG1, 0);
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_PORTCTRL, TSI108_EC_PORTCTRL_STATRST);
+	udelay(100);
+	TSI108_ETH_WRITE_REG(TSI108_EC_PORTCTRL,
+			     TSI108_ETH_READ_REG(TSI108_EC_PORTCTRL) &
+			     ~TSI108_EC_PORTCTRL_STATRST);
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_TXCFG, TSI108_EC_TXCFG_RST);
+	udelay(100);
+	TSI108_ETH_WRITE_REG(TSI108_EC_TXCFG,
+			     TSI108_ETH_READ_REG(TSI108_EC_TXCFG) &
+			     ~TSI108_EC_TXCFG_RST);
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_RXCFG, TSI108_EC_RXCFG_RST);
+	udelay(100);
+	TSI108_ETH_WRITE_REG(TSI108_EC_RXCFG,
+			     TSI108_ETH_READ_REG(TSI108_EC_RXCFG) &
+			     ~TSI108_EC_RXCFG_RST);
+
+	TSI108_ETH_WRITE_REG(TSI108_MAC_MII_MGMT_CFG,
+			     TSI108_ETH_READ_REG(TSI108_MAC_MII_MGMT_CFG) |
+			     TSI108_MAC_MII_MGMT_RST);
+	udelay(100);
+	TSI108_ETH_WRITE_REG(TSI108_MAC_MII_MGMT_CFG,
+			     TSI108_ETH_READ_REG(TSI108_MAC_MII_MGMT_CFG) &
+			     ~(TSI108_MAC_MII_MGMT_RST |
+			       TSI108_MAC_MII_MGMT_CLK));
+
+	TSI108_ETH_WRITE_REG(TSI108_MAC_MII_MGMT_CFG,
+			     TSI108_ETH_READ_REG(TSI108_MAC_MII_MGMT_CFG) |
+			     TSI108_MAC_MII_MGMT_CLK);
+}
+
+static int tsi108_get_mac(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+
+	u32 word1 = TSI108_ETH_READ_REG(TSI108_MAC_ADDR1);
+	u32 word2 = TSI108_ETH_READ_REG(TSI108_MAC_ADDR2);
+
+	/* Note that the octets are reversed from what the manual says,
+	 * producing an even weirder ordering...
+	 */
+	if (word2 == 0 && word1 == 0) {
+		dev->dev_addr[0] = 0x00;
+		dev->dev_addr[1] = 0x06;
+		dev->dev_addr[2] = 0xd2;
+		dev->dev_addr[3] = 0x00;
+		dev->dev_addr[4] = 0x00;
+		if (0x8 == data->phy)
+			dev->dev_addr[5] = 0x01;
+		else
+			dev->dev_addr[5] = 0x02;
+
+		word2 = (dev->dev_addr[0] << 16) | (dev->dev_addr[1] << 24);
+
+		word1 = (dev->dev_addr[2] << 0) | (dev->dev_addr[3] << 8) |
+		    (dev->dev_addr[4] << 16) | (dev->dev_addr[5] << 24);
+
+		TSI108_ETH_WRITE_REG(TSI108_MAC_ADDR1, word1);
+		TSI108_ETH_WRITE_REG(TSI108_MAC_ADDR2, word2);
+	} else {
+		dev->dev_addr[0] = (word2 >> 16) & 0xff;
+		dev->dev_addr[1] = (word2 >> 24) & 0xff;
+		dev->dev_addr[2] = (word1 >> 0) & 0xff;
+		dev->dev_addr[3] = (word1 >> 8) & 0xff;
+		dev->dev_addr[4] = (word1 >> 16) & 0xff;
+		dev->dev_addr[5] = (word1 >> 24) & 0xff;
+	}
+
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk("KERN_ERR: word1: %08x, word2: %08x\n", word1, word2);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tsi108_set_mac(net_device * dev, void *addr)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	u32 word1, word2;
+	int i;
+
+	if (!is_valid_ether_addr(addr))
+		return -EINVAL;
+
+	for (i = 0; i < 6; i++)
+		/* +2 is for the offset of the HW addr type */
+		dev->dev_addr[i] = ((unsigned char *)addr)[i + 2];
+
+	word2 = (dev->dev_addr[0] << 16) | (dev->dev_addr[1] << 24);
+
+	word1 = (dev->dev_addr[2] << 0) | (dev->dev_addr[3] << 8) |
+	    (dev->dev_addr[4] << 16) | (dev->dev_addr[5] << 24);
+
+	spin_lock_irq(&data->misclock);
+	TSI108_ETH_WRITE_REG(TSI108_MAC_ADDR1, word1);
+	TSI108_ETH_WRITE_REG(TSI108_MAC_ADDR2, word2);
+	spin_lock(&data->txlock);
+
+	if (netif_queue_stopped(dev) && data->txfree && data->link_up)
+		netif_wake_queue(dev);
+
+	spin_unlock(&data->txlock);
+	spin_unlock_irq(&data->misclock);
+	return 0;
+}
+
+/* Protected by dev->xmit_lock. */
+static void tsi108_set_rx_mode(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	u32 rxcfg = TSI108_ETH_READ_REG(TSI108_EC_RXCFG);
+
+	if (dev->flags & IFF_PROMISC) {
+		rxcfg &= ~(TSI108_EC_RXCFG_UC_HASH | TSI108_EC_RXCFG_MC_HASH);
+		rxcfg |= TSI108_EC_RXCFG_UFE | TSI108_EC_RXCFG_MFE;
+		goto out;
+	}
+
+	rxcfg &= ~(TSI108_EC_RXCFG_UFE | TSI108_EC_RXCFG_MFE);
+
+	if (dev->mc_count) {
+		int i;
+		struct dev_mc_list *mc = dev->mc_list;
+		rxcfg |= TSI108_EC_RXCFG_MFE | TSI108_EC_RXCFG_MC_HASH;
+
+		memset(data->mc_hash, 0, sizeof(data->mc_hash));
+
+		while (mc) {
+			u32 hash, crc;
+
+			if (mc->dmi_addrlen == 6) {
+				crc = ether_crc(6, mc->dmi_addr);
+				hash = crc >> 23;
+
+				__set_bit(hash, &data->mc_hash[0]);
+			} else {
+				printk(KERN_ERR
+				       "%s: got multicast address of length %d "
+				       "instead of 6.\n", dev->name,
+				       mc->dmi_addrlen);
+			}
+
+			mc = mc->next;
+		}
+
+		TSI108_ETH_WRITE_REG(TSI108_EC_HASHADDR,
+				     TSI108_EC_HASHADDR_AUTOINC |
+				     TSI108_EC_HASHADDR_MCAST);
+
+		for (i = 0; i < 16; i++) {
+			/* The manual says that the hardware may drop
+			 * back-to-back writes to the data register.
+			 */
+			udelay(1);
+			mb();
+			TSI108_ETH_WRITE_REG(TSI108_EC_HASHDATA,
+					     data->mc_hash[i]);
+			mb();
+		}
+	}
+
+      out:
+	mb();
+	TSI108_ETH_WRITE_REG(TSI108_EC_RXCFG, rxcfg);
+}
+
+static void tsi108_init_phy(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	u32 i = 0;
+	u16 phyVal = 0;
+
+	spin_lock_irq(&phy_lock);
+
+	tsi108_write_mii(data, PHY_CTRL, PHY_CTRL_RESET);
+	mb();
+	while (tsi108_read_mii(data, PHY_CTRL, NULL) & PHY_CTRL_RESET) ;
+
+#if (TSI108_PHY_TYPE == PHY_BCM54XX)	/* Broadcom BCM54xx PHY */
+	tsi108_write_mii(data, 0x09, 0x0300);
+	tsi108_write_mii(data, 0x10, 0x1020);
+	tsi108_write_mii(data, 0x1c, 0x8c00);
+	mb();
+#endif
+
+	tsi108_write_mii(data,
+			 PHY_CTRL,
+			 PHY_CTRL_AUTONEG_EN | PHY_CTRL_AUTONEG_START);
+	mb();
+	while (tsi108_read_mii(data, PHY_CTRL, NULL) & PHY_CTRL_AUTONEG_START) ;
+
+	/* Set G/MII mode and receive clock select in TBI control #2.  The
+	 * second port won't work if this isn't done, even though we don't
+	 * use TBI mode.
+	 */
+
+	tsi108_write_tbi(data, 0x11, 0x30);
+
+	/* FIXME: It seems to take more than 2 back-to-back reads to the
+	 * PHY_STAT register before the link up status bit is set.
+	 */
+
+	data->link_up = 1;
+
+	while (!((phyVal = tsi108_read_mii(data, PHY_STAT, NULL)) &
+		 PHY_STAT_LINKUP)) {
+		if (i++ > (MII_READ_DELAY / 10)) {
+			data->link_up = 0;
+			break;
+		}
+		mdelay(10);
+	}
+
+	printk(KERN_DEBUG "PHY_STAT reg contains %08x\n", phyVal);
+	data->phy_ok = 1;
+	spin_unlock_irq(&phy_lock);
+}
+
+static void tsi108_kill_phy(struct net_device *dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+
+	spin_lock_irq(&phy_lock);
+	tsi108_write_mii(data, PHY_CTRL, PHY_CTRL_POWERDOWN);
+	data->phy_ok = 0;
+	spin_unlock_irq(&phy_lock);
+}
+
+static int tsi108_open(struct net_device *dev)
+{
+	int i;
+	tsi108_prv_data *data = netdev_priv(dev);
+	unsigned int rxring_size = TSI108_RXRING_LEN * sizeof(rx_desc);
+	unsigned int txring_size = TSI108_TXRING_LEN * sizeof(tx_desc);
+
+	printk(KERN_DEBUG "Inside tsi108_open()!\n");
+
+	i = request_irq(data->irq_num, tsi108_irq, 0, dev->name, dev);
+	if (i != 0) {
+		printk(KERN_ERR "tsi108_eth%d: Could not allocate IRQ%d.\n",
+		       data->irq_num % IRQ_TSI108_GIGE0, data->irq_num);
+		return i;
+	} else {
+		dev->irq = data->irq_num;
+		printk(KERN_NOTICE
+		       "tsi108_open : Port %d Assigned IRQ %d to %s\n",
+		       data->irq_num % IRQ_TSI108_GIGE0, dev->irq, dev->name);
+	}
+
+	data->rxring = pci_alloc_consistent(NULL, rxring_size, &data->rxdma);
+
+	if (!data->rxring) {
+		printk(KERN_DEBUG
+		       "TSI108_ETH: failed to allocate memory for rxring!\n");
+		return -ENOMEM;
+	} else {
+		memset(data->rxring, 0, rxring_size);
+	}
+
+	data->txring = pci_alloc_consistent(NULL, txring_size, &data->txdma);
+
+	if (!data->txring) {
+		printk(KERN_DEBUG
+		       "TSI108_ETH: failed to allocate memory for txring!\n");
+		pci_free_consistent(0, rxring_size, data->rxring, data->rxdma);
+		return -ENOMEM;
+	} else {
+		memset(data->txring, 0, txring_size);
+	}
+
+	for (i = 0; i < TSI108_RXRING_LEN; i++) {
+		data->rxring[i].next0 = data->rxdma + (i + 1) * sizeof(rx_desc);
+		data->rxring[i].blen = TSI108_RXBUF_SIZE;
+		data->rxring[i].vlan = 0;
+	}
+
+	data->rxring[TSI108_RXRING_LEN - 1].next0 = data->rxdma;
+
+	data->rxtail = 0;
+	data->rxhead = 0;
+
+	for (i = 0; i < TSI108_RXRING_LEN; i++) {
+		sk_buff *skb = dev_alloc_skb(TSI108_RXBUF_SIZE + NET_IP_ALIGN);
+
+		if (!skb) {
+			/* Bah.  No memory for now, but maybe we'll get
+			 * some more later.
+			 * For now, we'll live with the smaller ring.
+			 */
+			printk(KERN_WARNING
+			       "%s: Could only allocate %d receive skb(s).\n",
+			       dev->name, i);
+			data->rxhead = i;
+			break;
+		}
+
+		data->rxskbs[i] = skb;
+		/* Align the payload on a 4-byte boundary */
+		skb_reserve(skb, 2);
+		data->rxskbs[i] = skb;
+		data->rxring[i].buf0 = virt_to_phys(data->rxskbs[i]->data);
+		data->rxring[i].misc = TSI108_RX_OWN | TSI108_RX_INT;
+	}
+
+	data->rxfree = i;
+	TSI108_ETH_WRITE_REG(TSI108_EC_RXQ_PTRLOW, data->rxdma);
+
+	for (i = 0; i < TSI108_TXRING_LEN; i++) {
+		data->txring[i].next0 = data->txdma + (i + 1) * sizeof(tx_desc);
+		data->txring[i].misc = 0;
+	}
+
+	data->txring[TSI108_TXRING_LEN - 1].next0 = data->txdma;
+	data->txtail = 0;
+	data->txhead = 0;
+	data->txfree = TSI108_TXRING_LEN;
+	TSI108_ETH_WRITE_REG(TSI108_EC_TXQ_PTRLOW, data->txdma);
+	tsi108_init_phy(dev);
+
+	init_timer(&data->timer);
+	data->timer.expires = jiffies + 1;
+	data->timer.data = (unsigned long)dev;
+	data->timer.function = &tsi108_timed_checker;	/* timer handler */
+	add_timer(&data->timer);
+
+	tsi108_restart_rx(data, dev);
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_INTSTAT, ~0);
+	mb();
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_INTMASK,
+			     ~(TSI108_INT_TXQUEUE0 | TSI108_INT_RXERROR |
+			       TSI108_INT_RXTHRESH | TSI108_INT_RXQUEUE0 |
+			       TSI108_INT_RXOVERRUN | TSI108_INT_RXWAIT |
+			       TSI108_INT_SFN | TSI108_INT_STATCARRY));
+
+	TSI108_ETH_WRITE_REG(TSI108_MAC_CFG1,
+			     TSI108_MAC_CFG1_RXEN | TSI108_MAC_CFG1_TXEN);
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int tsi108_close(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+
+	netif_stop_queue(dev);
+
+	del_timer_sync(&data->timer);
+
+	printk(KERN_DEBUG "Inside tsi108_ifdown!\n");
+
+	tsi108_stop_ethernet(dev);
+	tsi108_kill_phy(dev);
+	TSI108_ETH_WRITE_REG(TSI108_EC_INTMASK, ~0);
+	TSI108_ETH_WRITE_REG(TSI108_MAC_CFG1, 0);
+
+	/* Check for any pending TX packets, and drop them. */
+
+	while (!data->txfree || data->txhead != data->txtail) {
+		int tx = data->txtail;
+		struct sk_buff *skb;
+		skb = data->txskbs[tx];
+		data->txtail = (data->txtail + 1) % TSI108_TXRING_LEN;
+		data->txfree++;
+		dev_kfree_skb(skb);
+	}
+
+	synchronize_irq(data->irq_num);
+	free_irq(data->irq_num, dev);
+
+	/* Discard the RX ring. */
+
+	while (data->rxfree) {
+		int rx = data->rxtail;
+		struct sk_buff *skb;
+
+		skb = data->rxskbs[rx];
+		data->rxtail = (data->rxtail + 1) % TSI108_RXRING_LEN;
+		data->rxfree--;
+		dev_kfree_skb(skb);
+	}
+
+	pci_free_consistent(0,
+			    TSI108_RXRING_LEN * sizeof(rx_desc),
+			    data->rxring, data->rxdma);
+	pci_free_consistent(0,
+			    TSI108_TXRING_LEN * sizeof(tx_desc),
+			    data->txring, data->txdma);
+
+	return 0;
+}
+
+static void tsi108_init_mac(net_device * dev)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+
+	TSI108_ETH_WRITE_REG(TSI108_MAC_CFG2, TSI108_MAC_CFG2_DFLT_PREAMBLE |
+			     TSI108_MAC_CFG2_PADCRC);
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_TXTHRESH,
+			     (192 << TSI108_EC_TXTHRESH_STARTFILL) |
+			     (192 << TSI108_EC_TXTHRESH_STOPFILL));
+
+	TSI108_ETH_WRITE_REG(TSI108_STAT_CARRYMASK1,
+			     ~(TSI108_STAT_CARRY1_RXBYTES |
+			       TSI108_STAT_CARRY1_RXPKTS |
+			       TSI108_STAT_CARRY1_RXFCS |
+			       TSI108_STAT_CARRY1_RXMCAST |
+			       TSI108_STAT_CARRY1_RXALIGN |
+			       TSI108_STAT_CARRY1_RXLENGTH |
+			       TSI108_STAT_CARRY1_RXRUNT |
+			       TSI108_STAT_CARRY1_RXJUMBO |
+			       TSI108_STAT_CARRY1_RXFRAG |
+			       TSI108_STAT_CARRY1_RXJABBER |
+			       TSI108_STAT_CARRY1_RXDROP));
+
+	TSI108_ETH_WRITE_REG(TSI108_STAT_CARRYMASK2,
+			     ~(TSI108_STAT_CARRY2_TXBYTES |
+			       TSI108_STAT_CARRY2_TXPKTS |
+			       TSI108_STAT_CARRY2_TXEXDEF |
+			       TSI108_STAT_CARRY2_TXEXCOL |
+			       TSI108_STAT_CARRY2_TXTCOL |
+			       TSI108_STAT_CARRY2_TXPAUSE));
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_PORTCTRL, TSI108_EC_PORTCTRL_STATEN);
+	TSI108_ETH_WRITE_REG(TSI108_MAC_CFG1, 0);
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_RXCFG,
+			     TSI108_EC_RXCFG_SE | TSI108_EC_RXCFG_BFE);
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_TXQ_CFG, TSI108_EC_TXQ_CFG_DESC_INT |
+			     TSI108_EC_TXQ_CFG_EOQ_OWN_INT |
+			     TSI108_EC_TXQ_CFG_WSWP | (TSI108_PBM_PORT <<
+						       TSI108_EC_TXQ_CFG_SFNPORT));
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_RXQ_CFG, TSI108_EC_RXQ_CFG_DESC_INT |
+			     TSI108_EC_RXQ_CFG_EOQ_OWN_INT |
+			     TSI108_EC_RXQ_CFG_WSWP | (TSI108_PBM_PORT <<
+						       TSI108_EC_RXQ_CFG_SFNPORT));
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_TXQ_BUFCFG,
+			     TSI108_EC_TXQ_BUFCFG_BURST256 |
+			     TSI108_EC_TXQ_BUFCFG_BSWP | (TSI108_PBM_PORT <<
+							  TSI108_EC_TXQ_BUFCFG_SFNPORT));
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_RXQ_BUFCFG,
+			     TSI108_EC_RXQ_BUFCFG_BURST256 |
+			     TSI108_EC_RXQ_BUFCFG_BSWP | (TSI108_PBM_PORT <<
+							  TSI108_EC_RXQ_BUFCFG_SFNPORT));
+
+	TSI108_ETH_WRITE_REG(TSI108_EC_INTMASK, ~0);
+}
+
+static int tsi108_ioctl(net_device * dev, struct ifreq *rq, int cmd)
+{
+	tsi108_prv_data *data = netdev_priv(dev);
+	struct mii_ioctl_data *mii_data =
+	    (struct mii_ioctl_data *)&rq->ifr_data;
+	int ret;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		mii_data->phy_id = data->phy;
+		ret = 0;
+		break;
+
+	case SIOCGMIIREG:
+		spin_lock_irq(&phy_lock);
+		mii_data->val_out =
+		    tsi108_read_mii(data, mii_data->reg_num, &ret);
+		spin_unlock_irq(&phy_lock);
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	return ret;
+}
+
+static int
+tsi108_init_one(struct platform_device *pdev)
+{
+	struct net_device *dev = NULL;
+	tsi108_prv_data *data = NULL;
+	hw_info *einfo;
+	int ret;
+	
+	einfo = ( hw_info *) pdev->dev.platform_data;
+	
+	if (NULL == einfo) {
+		printk(KERN_ERR "tsi-eth %d: Missing additional data!\n",
+		       pdev->id);
+		return -ENODEV;
+	}
+
+	/* Create an ethernet device instance */
+
+	dev = alloc_etherdev(sizeof(tsi108_prv_data));
+	if (!dev) {
+		printk("tsi108_eth: Could not allocate a device structure\n");
+		return -ENOMEM;
+	}
+
+	printk("tsi108_eth%d: probe...\n", pdev->id);
+	data = netdev_priv(dev);
+	memset(data, 0, sizeof(tsi108_prv_data));
+
+	DBG("tsi108_eth%d: regs:phyresgs:phy:irq_num=0x%x:0x%x:0x%x:0x%x\n",
+			pdev->id, einfo->regs, einfo->phyregs,
+			einfo->phy, einfo->irq_num);
+
+	data->regs = (u32)ioremap(einfo->regs, 0x400);	/*FIX ME */
+	data->phyregs = (u32)ioremap(einfo->phyregs, 0x400); 	/*FIX ME */
+	data->phy = einfo->phy;
+	data->irq_num = einfo->irq_num;
+	dev->open = tsi108_open;
+	dev->stop = tsi108_close;
+	dev->hard_start_xmit = tsi108_send_packet;
+	dev->set_mac_address = tsi108_set_mac;
+	dev->set_multicast_list = tsi108_set_rx_mode;
+	dev->get_stats = tsi108_get_stats;
+	dev->poll = tsi108_poll;
+	dev->do_ioctl = tsi108_ioctl;
+	dev->weight = 64;	/* 64 is more suitable for GigE interface - klai */
+
+	/* Apparently, the Linux networking code won't use scatter-gather
+	 * if the hardware doesn't do checksums.  However, it's faster
+	 * to checksum in place and use SG, as (among other reasons)
+	 * the cache won't be dirtied (which then has to be flushed
+	 * before DMA).  The checksumming is done by the driver (via
+	 * a new function skb_csum_dev() in net/core/skbuff.c).
+	 */
+
+#ifdef FIXME_SG_CSUM_NOT_TESTED	/* FIXME: Not supported now. */
+	dev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_HW_CSUM;
+#else
+	dev->features = NETIF_F_HIGHDMA;
+#endif
+	SET_MODULE_OWNER(dev);
+
+	spin_lock_init(&data->txlock);
+	spin_lock_init(&data->misclock);
+
+	tsi108_reset_ether(data);
+	tsi108_kill_phy(dev);
+
+	if (tsi108_get_mac(dev) != 0)
+		printk(KERN_ERR "%s: Invalid MAC address.  Please correct.\n",
+		       dev->name);
+
+	tsi108_init_mac(dev);
+	ret = register_netdev(dev);
+	if (ret < 0) {
+		kfree(dev);
+		return ret;
+	}
+
+	printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: "
+	       "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
+	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+#ifdef DEBUG
+	dump_eth_one(dev);
+#endif
+
+	return 0;
+}
+
+/* There's no way to either get interrupts from the PHY when
+ * something changes, or to have the Tsi108 automatically communicate
+ * with the PHY to reconfigure itself.
+ *
+ * Thus, we have to do it using a timer. 
+ */
+
+static void tsi108_timed_checker(unsigned long dev_ptr)
+{
+	struct net_device *dev = (struct net_device *)dev_ptr;
+	tsi108_prv_data *data = netdev_priv(dev);
+
+	tsi108_check_phy(dev);
+	tsi108_check_rxring(dev);
+	data->timer.expires = jiffies + CHECK_PHY_INTERVAL;
+	add_timer(&data->timer);
+}
+
+static int tsi108_ether_init(void)
+{
+	int ret;
+	ret = platform_driver_register (&tsi_eth_driver);
+	if (ret < 0){
+		printk("tsi108_ether_init: error initializing ethernet "
+		       "device\n");
+		return ret;
+	}
+	return 0;
+}
+
+static int tsi108_ether_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	tsi108_prv_data *priv = netdev_priv(dev);
+	
+	unregister_netdev(dev);
+	tsi108_stop_ethernet(dev);
+	platform_set_drvdata(pdev, NULL);
+	iounmap((void __iomem *)priv->regs);
+	iounmap((void __iomem *)priv->phyregs);
+	free_netdev(dev);
+	
+	return 0;
+}
+static void tsi108_ether_exit(void)
+{
+	platform_driver_unregister(&tsi_eth_driver);
+}
+
+module_init(tsi108_ether_init);
+module_exit(tsi108_ether_exit);
+
+MODULE_AUTHOR("Tundra Semiconductor Corporation");
+MODULE_DESCRIPTION("Tsi108 Gigabit Ethernet driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/tsi108_eth.h b/drivers/net/tsi108_eth.h
new file mode 100644
index 0000000..e491056
--- /dev/null
+++ b/drivers/net/tsi108_eth.h
@@ -0,0 +1,401 @@
+/*
+ * (C) Copyright 2005 Tundra Semiconductor Corp.
+ * Kong Lai, <kong.lai@tundra.com).
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * net/tsi108_eth.h - definitions for Tsi108 GIGE network controller.
+ */
+
+#ifndef __TSI108_ETH_H
+#define __TSI108_ETH_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+#define TSI108_ETH_WRITE_REG(offset, val) \
+	out_be32((volatile u32 *)(data->regs + offset), val)
+
+#define TSI108_ETH_READ_REG(offset) \
+	in_be32((volatile u32 *)(data->regs + offset))
+
+#define TSI108_ETH_WRITE_PHYREG(offset, val) \
+	out_be32((volatile u32 *)(data->phyregs + offset), val)
+
+#define TSI108_ETH_READ_PHYREG(offset) \
+	in_be32((volatile u32 *)(data->phyregs + offset))
+
+/*
+ * PHY Configuration Options
+ *
+ * NOTE: Enable set of definitions corresponding to your board type
+ */
+#define PHY_MV88E	1	/* Marvel 88Exxxx PHY */
+#define PHY_BCM54XX	2	/* Broardcom BCM54xx PHY */
+#define TSI108_PHY_TYPE	PHY_MV88E
+
+/*
+ * TSI108 GIGE port registers
+ */
+
+#define TSI108_ETH_PORT_NUM		2
+#define TSI108_PBM_PORT			2
+#define TSI108_SDRAM_PORT		4
+
+#define TSI108_MAC_CFG1			(0x000)
+#define TSI108_MAC_CFG1_SOFTRST		(1 << 31)
+#define TSI108_MAC_CFG1_LOOPBACK	(1 << 8)
+#define TSI108_MAC_CFG1_RXEN		(1 << 2)
+#define TSI108_MAC_CFG1_TXEN		(1 << 0)
+
+#define TSI108_MAC_CFG2			(0x004)
+#define TSI108_MAC_CFG2_DFLT_PREAMBLE	(7 << 12)
+#define TSI108_MAC_CFG2_IFACE_MASK	(3 << 8)
+#define TSI108_MAC_CFG2_NOGIG		(1 << 8)
+#define TSI108_MAC_CFG2_GIG		(2 << 8)
+#define TSI108_MAC_CFG2_PADCRC		(1 << 2)
+#define TSI108_MAC_CFG2_FULLDUPLEX	(1 << 0)
+
+#define TSI108_MAC_MII_MGMT_CFG		(0x020)
+#define TSI108_MAC_MII_MGMT_CLK		(7 << 0)
+#define TSI108_MAC_MII_MGMT_RST		(1 << 31)
+
+#define TSI108_MAC_MII_CMD		(0x024)
+#define TSI108_MAC_MII_CMD_READ		(1 << 0)
+
+#define TSI108_MAC_MII_ADDR		(0x028)
+#define TSI108_MAC_MII_ADDR_REG		0
+#define TSI108_MAC_MII_ADDR_PHY		8
+
+#define TSI108_MAC_MII_DATAOUT		(0x02c)
+#define TSI108_MAC_MII_DATAIN		(0x030)
+
+#define TSI108_MAC_MII_IND		(0x034)
+#define TSI108_MAC_MII_IND_NOTVALID	(1 << 2)
+#define TSI108_MAC_MII_IND_SCANNING	(1 << 1)
+#define TSI108_MAC_MII_IND_BUSY		(1 << 0)
+
+#define TSI108_MAC_IFCTRL		(0x038)
+#define TSI108_MAC_IFCTRL_PHYMODE	(1 << 24)
+
+#define TSI108_MAC_ADDR1		(0x040)
+#define TSI108_MAC_ADDR2		(0x044)
+
+#define TSI108_STAT_RXBYTES		(0x06c)
+#define TSI108_STAT_RXBYTES_CARRY	(1 << 24)
+
+#define TSI108_STAT_RXPKTS		(0x070)
+#define TSI108_STAT_RXPKTS_CARRY	(1 << 18)
+
+#define TSI108_STAT_RXFCS		(0x074)
+#define TSI108_STAT_RXFCS_CARRY		(1 << 12)
+
+#define TSI108_STAT_RXMCAST		(0x078)
+#define TSI108_STAT_RXMCAST_CARRY	(1 << 18)
+
+#define TSI108_STAT_RXALIGN		(0x08c)
+#define TSI108_STAT_RXALIGN_CARRY	(1 << 12)
+
+#define TSI108_STAT_RXLENGTH		(0x090)
+#define TSI108_STAT_RXLENGTH_CARRY	(1 << 12)
+
+#define TSI108_STAT_RXRUNT		(0x09c)
+#define TSI108_STAT_RXRUNT_CARRY	(1 << 12)
+
+#define TSI108_STAT_RXJUMBO		(0x0a0)
+#define TSI108_STAT_RXJUMBO_CARRY	(1 << 12)
+
+#define TSI108_STAT_RXFRAG		(0x0a4)
+#define TSI108_STAT_RXFRAG_CARRY	(1 << 12)
+
+#define TSI108_STAT_RXJABBER		(0x0a8)
+#define TSI108_STAT_RXJABBER_CARRY	(1 << 12)
+
+#define TSI108_STAT_RXDROP		(0x0ac)
+#define TSI108_STAT_RXDROP_CARRY	(1 << 12)
+
+#define TSI108_STAT_TXBYTES		(0x0b0)
+#define TSI108_STAT_TXBYTES_CARRY	(1 << 24)
+
+#define TSI108_STAT_TXPKTS		(0x0b4)
+#define TSI108_STAT_TXPKTS_CARRY	(1 << 18)
+
+#define TSI108_STAT_TXEXDEF		(0x0c8)
+#define TSI108_STAT_TXEXDEF_CARRY	(1 << 12)
+
+#define TSI108_STAT_TXEXCOL		(0x0d8)
+#define TSI108_STAT_TXEXCOL_CARRY	(1 << 12)
+
+#define TSI108_STAT_TXTCOL		(0x0dc)
+#define TSI108_STAT_TXTCOL_CARRY	(1 << 13)
+
+#define TSI108_STAT_TXPAUSEDROP		(0x0e4)
+#define TSI108_STAT_TXPAUSEDROP_CARRY	(1 << 12)
+
+#define TSI108_STAT_CARRY1		(0x100)
+#define TSI108_STAT_CARRY1_RXBYTES	(1 << 16)
+#define TSI108_STAT_CARRY1_RXPKTS	(1 << 15)
+#define TSI108_STAT_CARRY1_RXFCS	(1 << 14)
+#define TSI108_STAT_CARRY1_RXMCAST	(1 << 13)
+#define TSI108_STAT_CARRY1_RXALIGN	(1 << 8)
+#define TSI108_STAT_CARRY1_RXLENGTH	(1 << 7)
+#define TSI108_STAT_CARRY1_RXRUNT	(1 << 4)
+#define TSI108_STAT_CARRY1_RXJUMBO	(1 << 3)
+#define TSI108_STAT_CARRY1_RXFRAG	(1 << 2)
+#define TSI108_STAT_CARRY1_RXJABBER	(1 << 1)
+#define TSI108_STAT_CARRY1_RXDROP	(1 << 0)
+
+#define TSI108_STAT_CARRY2		(0x104)
+#define TSI108_STAT_CARRY2_TXBYTES	(1 << 13)
+#define TSI108_STAT_CARRY2_TXPKTS	(1 << 12)
+#define TSI108_STAT_CARRY2_TXEXDEF	(1 << 7)
+#define TSI108_STAT_CARRY2_TXEXCOL	(1 << 3)
+#define TSI108_STAT_CARRY2_TXTCOL	(1 << 2)
+#define TSI108_STAT_CARRY2_TXPAUSE	(1 << 0)
+
+#define TSI108_STAT_CARRYMASK1		(0x108)
+#define TSI108_STAT_CARRYMASK2		(0x10c)
+
+#define TSI108_EC_PORTCTRL		(0x200)
+#define TSI108_EC_PORTCTRL_STATRST	(1 << 31)
+#define TSI108_EC_PORTCTRL_STATEN	(1 << 28)
+#define TSI108_EC_PORTCTRL_NOGIG	(1 << 18)
+#define TSI108_EC_PORTCTRL_HALFDUPLEX	(1 << 16)
+
+#define TSI108_EC_INTSTAT		(0x204)
+#define TSI108_EC_INTMASK		(0x208)
+
+#define TSI108_INT_ANY			(1 << 31)
+#define TSI108_INT_SFN			(1 << 30)
+#define TSI108_INT_RXIDLE		(1 << 29)
+#define TSI108_INT_RXABORT		(1 << 28)
+#define TSI108_INT_RXERROR		(1 << 27)
+#define TSI108_INT_RXOVERRUN		(1 << 26)
+#define TSI108_INT_RXTHRESH		(1 << 25)
+#define TSI108_INT_RXWAIT		(1 << 24)
+#define TSI108_INT_RXQUEUE0		(1 << 16)
+#define TSI108_INT_STATCARRY		(1 << 15)
+#define TSI108_INT_TXIDLE		(1 << 13)
+#define TSI108_INT_TXABORT		(1 << 12)
+#define TSI108_INT_TXERROR		(1 << 11)
+#define TSI108_INT_TXUNDERRUN		(1 << 10)
+#define TSI108_INT_TXTHRESH		(1 <<  9)
+#define TSI108_INT_TXWAIT		(1 <<  8)
+#define TSI108_INT_TXQUEUE0		(1 <<  0)
+
+#define TSI108_EC_TXCFG			(0x220)
+#define TSI108_EC_TXCFG_RST		(1 << 31)
+
+#define TSI108_EC_TXCTRL		(0x224)
+#define TSI108_EC_TXCTRL_IDLEINT	(1 << 31)
+#define TSI108_EC_TXCTRL_ABORT		(1 << 30)
+#define TSI108_EC_TXCTRL_GO		(1 << 15)
+#define TSI108_EC_TXCTRL_QUEUE0		(1 <<  0)
+
+#define TSI108_EC_TXSTAT		(0x228)
+#define TSI108_EC_TXSTAT_ACTIVE		(1 << 15)
+#define TSI108_EC_TXSTAT_QUEUE0		(1 << 0)
+
+#define TSI108_EC_TXESTAT		(0x22c)
+#define TSI108_EC_TXESTAT_Q0_ERR	(1 << 24)
+#define TSI108_EC_TXESTAT_Q0_DESCINT	(1 << 16)
+#define TSI108_EC_TXESTAT_Q0_EOF	(1 <<  8)
+#define TSI108_EC_TXESTAT_Q0_EOQ	(1 <<  0)
+
+#define TSI108_EC_TXERR			(0x278)
+
+#define TSI108_EC_TXQ_CFG		(0x280)
+#define TSI108_EC_TXQ_CFG_DESC_INT	(1 << 20)
+#define TSI108_EC_TXQ_CFG_EOQ_OWN_INT	(1 << 19)
+#define TSI108_EC_TXQ_CFG_WSWP		(1 << 11)
+#define TSI108_EC_TXQ_CFG_BSWP		(1 << 10)
+#define TSI108_EC_TXQ_CFG_SFNPORT	0
+
+#define TSI108_EC_TXQ_BUFCFG		(0x284)
+#define TSI108_EC_TXQ_BUFCFG_BURST8	(0 << 8)
+#define TSI108_EC_TXQ_BUFCFG_BURST32	(1 << 8)
+#define TSI108_EC_TXQ_BUFCFG_BURST128	(2 << 8)
+#define TSI108_EC_TXQ_BUFCFG_BURST256	(3 << 8)
+#define TSI108_EC_TXQ_BUFCFG_WSWP	(1 << 11)
+#define TSI108_EC_TXQ_BUFCFG_BSWP	(1 << 10)
+#define TSI108_EC_TXQ_BUFCFG_SFNPORT	0
+
+#define TSI108_EC_TXQ_PTRLOW		(0x288)
+
+#define TSI108_EC_TXQ_PTRHIGH		(0x28c)
+#define TSI108_EC_TXQ_PTRHIGH_VALID	(1 << 31)
+
+#define TSI108_EC_TXTHRESH		(0x230)
+#define TSI108_EC_TXTHRESH_STARTFILL	0
+#define TSI108_EC_TXTHRESH_STOPFILL	16
+
+#define TSI108_EC_RXCFG			(0x320)
+#define TSI108_EC_RXCFG_RST		(1 << 31)
+
+#define TSI108_EC_RXSTAT		(0x328)
+#define TSI108_EC_RXSTAT_ACTIVE		(1 << 15)
+#define TSI108_EC_RXSTAT_QUEUE0		(1 << 0)
+
+#define TSI108_EC_RXESTAT		(0x32c)
+#define TSI108_EC_RXESTAT_Q0_ERR	(1 << 24)
+#define TSI108_EC_RXESTAT_Q0_DESCINT	(1 << 16)
+#define TSI108_EC_RXESTAT_Q0_EOF	(1 <<  8)
+#define TSI108_EC_RXESTAT_Q0_EOQ	(1 <<  0)
+
+#define TSI108_EC_HASHADDR		(0x360)
+#define TSI108_EC_HASHADDR_AUTOINC	(1 << 31)
+#define TSI108_EC_HASHADDR_DO1STREAD	(1 << 30)
+#define TSI108_EC_HASHADDR_UNICAST	(0 <<  4)
+#define TSI108_EC_HASHADDR_MCAST	(1 <<  4)
+
+#define TSI108_EC_HASHDATA		(0x364)
+
+#define TSI108_EC_RXQ_PTRLOW		(0x388)
+
+#define TSI108_EC_RXQ_PTRHIGH		(0x38c)
+#define TSI108_EC_RXQ_PTRHIGH_VALID	(1 << 31)
+
+/* Station Enable -- accept packets destined for us */
+#define TSI108_EC_RXCFG_SE		(1 << 13)
+/* Unicast Frame Enable -- for packets not destined for us */
+#define TSI108_EC_RXCFG_UFE		(1 << 12)
+/* Multicast Frame Enable */
+#define TSI108_EC_RXCFG_MFE		(1 << 11)
+/* Broadcast Frame Enable */
+#define TSI108_EC_RXCFG_BFE		(1 << 10)
+#define TSI108_EC_RXCFG_UC_HASH		(1 <<  9)
+#define TSI108_EC_RXCFG_MC_HASH		(1 <<  8)
+
+#define TSI108_EC_RXQ_CFG		(0x380)
+#define TSI108_EC_RXQ_CFG_DESC_INT	(1 << 20)
+#define TSI108_EC_RXQ_CFG_EOQ_OWN_INT	(1 << 19)
+#define TSI108_EC_RXQ_CFG_WSWP		(1 << 11)
+#define TSI108_EC_RXQ_CFG_BSWP		(1 << 10)
+#define TSI108_EC_RXQ_CFG_SFNPORT	0
+
+#define TSI108_EC_RXQ_BUFCFG		(0x384)
+#define TSI108_EC_RXQ_BUFCFG_BURST8	(0 << 8)
+#define TSI108_EC_RXQ_BUFCFG_BURST32	(1 << 8)
+#define TSI108_EC_RXQ_BUFCFG_BURST128	(2 << 8)
+#define TSI108_EC_RXQ_BUFCFG_BURST256	(3 << 8)
+#define TSI108_EC_RXQ_BUFCFG_WSWP	(1 << 11)
+#define TSI108_EC_RXQ_BUFCFG_BSWP	(1 << 10)
+#define TSI108_EC_RXQ_BUFCFG_SFNPORT	0
+
+#define TSI108_EC_RXCTRL		(0x324)
+#define TSI108_EC_RXCTRL_ABORT		(1 << 30)
+#define TSI108_EC_RXCTRL_GO		(1 << 15)
+#define TSI108_EC_RXCTRL_QUEUE0		(1 << 0)
+
+#define TSI108_EC_RXERR			(0x378)
+
+#define PHY_CTRL			0
+#define PHY_CTRL_RESET			(1 << 15)
+#define PHY_CTRL_AUTONEG_EN		(1 << 12)
+#define PHY_CTRL_POWERDOWN		(1 << 11)
+#define PHY_CTRL_AUTONEG_START		(1 << 9)
+
+#define PHY_STAT			1
+#define PHY_STAT_LINKUP			(1 << 2)
+
+#if (TSI108_PHY_TYPE == PHY_MV88E)
+/* Marvel 88E1xxx-specific */
+#define PHY_SUM_STAT			0x11
+#define PHY_SUM_STAT_SPEED_MASK		(3 << 14)
+#define PHY_SUM_STAT_SPEED_10		(0 << 14)
+#define PHY_SUM_STAT_SPEED_100		(1 << 14)
+#define PHY_SUM_STAT_SPEED_1000		(2 << 14)
+#define PHY_SUM_STAT_FULLDUPLEX		(1 << 13)
+
+#define PHY_SUM_STAT_1000T_FD    (PHY_SUM_STAT_SPEED_1000 | PHY_SUM_STAT_FULLDUPLEX)
+#define PHY_SUM_STAT_1000T_HD    (PHY_SUM_STAT_SPEED_1000)
+#define PHY_SUM_STAT_100TX_FD    (PHY_SUM_STAT_SPEED_100 | PHY_SUM_STAT_FULLDUPLEX)
+#define PHY_SUM_STAT_100TX_HD    (PHY_SUM_STAT_SPEED_100)
+#define PHY_SUM_STAT_10T_FD	    (PHY_SUM_STAT_SPEED_10 | PHY_SUM_STAT_FULLDUPLEX)
+#define PHY_SUM_STAT_10T_HD	    (PHY_SUM_STAT_SPEED_10)
+#elif (TSI108_PHY_TYPE == PHY_BCM54XX)
+/*Broadcom BCM54xx */
+#define PHY_SUM_STAT			0x19
+#define PHY_SUM_STAT_SPEED_MASK		(7 << 8)	/* Auto Negotiation HCD */
+#define PHY_SUM_STAT_1000T_FD		(7 << 8)	/* 1000BASE-T Full-Duplex */
+#define PHY_SUM_STAT_1000T_HD		(6 << 8)	/* 1000BASE-T Half-Duplex */
+#define PHY_SUM_STAT_100TX_FD		(5 << 8)	/* 100BASE-TX Full-Duplex */
+#define PHY_SUM_STAT_100T4		(4 << 8)	/* 100BASE-T4 */
+#define PHY_SUM_STAT_100TX_HD		(3 << 8)	/* 100BASE-TX Half-Duplex */
+#define PHY_SUM_STAT_10T_FD		(2 << 8)	/* 10BASE-T Full-Duplex */
+#define PHY_SUM_STAT_10T_HD		(1 << 8)	/* 10BASE-T Half-Duplex */
+#define PHY_SUM_STAT_AN_FAIL		(0 << 8)	/* 1000BASE-T Half-Duplex */
+#else
+#error "PHY Device not specified"
+#endif				/* MV88_PHY */
+
+#define TSI108_TX_EOF	(1 << 0)	/* End of frame; last fragment of packet */
+#define TSI108_TX_SOF	(1 << 1)	/* Start of frame; first frag. of packet */
+#define TSI108_TX_VLAN	(1 << 2)	/* Per-frame VLAN: enables VLAN override */
+#define TSI108_TX_HUGE	(1 << 3)	/* Huge frame enable */
+#define TSI108_TX_PAD	(1 << 4)	/* Pad the packet if too short */
+#define TSI108_TX_CRC	(1 << 5)	/* Generate CRC for this packet */
+#define TSI108_TX_INT	(1 << 14)	/* Generate an IRQ after frag. processed */
+#define TSI108_TX_RETRY	16	/* 4 bit field indicating num. of retries */
+#define TSI108_TX_COL	(1 << 20)	/* Set if a collision occured */
+#define TSI108_TX_LCOL	(1 << 24)	/* Set if a late collision occured */
+#define TSI108_TX_UNDER	(1 << 25)	/* Set if a FIFO underrun occured */
+#define TSI108_TX_RLIM	(1 << 26)	/* Set if the retry limit was reached */
+#define TSI108_TX_OK	(1 << 30)	/* Set if the frame TX was successful */
+#define TSI108_TX_OWN	(1 << 31)	/* Set if the device owns the descriptor */
+
+/* Note: the descriptor layouts assume big-endian byte order. */
+typedef struct {
+	u32 buf0;
+	u32 buf1;		/* Base address of buffer */
+	u32 next0;		/* Address of next descriptor, if any */
+	u32 next1;
+	u16 vlan;		/* VLAN, if override enabled for this packet */
+	u16 len;		/* Length of buffer in bytes */
+	u32 misc;		/* See TSI108_TX_* above */
+	u32 reserved0;		/*reserved0 and reserved1 are added to make the desc */
+	u32 reserved1;		/* 32-byte aligned */
+} __attribute__ ((aligned(32))) tx_desc;
+
+#define TSI108_RX_EOF	(1 << 0)	/* End of frame; last fragment of packet */
+#define TSI108_RX_SOF	(1 << 1)	/* Start of frame; first frag. of packet */
+#define TSI108_RX_VLAN	(1 << 2)	/* Set on SOF if packet has a VLAN */
+#define TSI108_RX_FTYPE	(1 << 3)	/* Length/Type field is type, not length */
+#define TSI108_RX_RUNT	(1 << 4)/* Packet is less than minimum size */
+#define TSI108_RX_HASH	(1 << 7)/* Hash table match */
+#define TSI108_RX_BAD	(1 << 8)	/* Bad frame */
+#define TSI108_RX_OVER	(1 << 9)	/* FIFO overrun occured */
+#define TSI108_RX_TRUNC	(1 << 11)	/* Packet truncated due to excess length */
+#define TSI108_RX_CRC	(1 << 12)	/* Packet had a CRC error */
+#define TSI108_RX_INT	(1 << 13)	/* Generate an IRQ after frag. processed */
+#define TSI108_RX_OWN	(1 << 15)	/* Set if the device owns the descriptor */
+
+typedef struct {
+	u32 buf0;		/* Base address of buffer */
+	u32 buf1;		/* Base address of buffer */
+	u32 next0;		/* Address of next descriptor, if any */
+	u32 next1;		/* Address of next descriptor, if any */
+	u16 vlan;		/* VLAN of received packet, first frag only */
+	u16 len;		/* Length of received fragment in bytes */
+	u16 blen;		/* Length of buffer in bytes */
+	u16 misc;		/* See TSI108_RX_* above */
+	u32 reserved0;		/* reserved0 and reserved1 are added to make the desc */
+	u32 reserved1;		/* 32-byte aligned */
+} __attribute__ ((aligned(32))) rx_desc;
+
+#endif				/* __TSI108_ETH_H */

^ permalink raw reply related

* Re: [PATCH 03/06] MLSXFRM: Add security sid to sock
From: Herbert Xu @ 2006-06-21  4:35 UTC (permalink / raw)
  To: Venkat Yekkirala; +Cc: netdev, selinux
In-Reply-To: <36282A1733C57546BE392885C06185920132401F@chaos.tcs.tcs-sec.com>

On Tue, Jun 20, 2006 at 08:50:55PM -0400, Venkat Yekkirala wrote:
>
> Nope. It would actually overwrite the pointer, so we put it away before
> memcpy
> and set it back after memcpy.

Right, I misread it as sptr = osk->sk_security.  Still, it'd be nice to
optimise it away for the !SECURITY case.

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: + myri10ge-build-fix.patch added to -mm tree
From: Herbert Xu @ 2006-06-21  4:41 UTC (permalink / raw)
  To: akpm; +Cc: mm-commits, bgoglin, davem, jeff, netdev
In-Reply-To: <200606210433.k5L4XgmP008626@shell0.pdx.osdl.net>

On Tue, Jun 20, 2006 at 09:33:42PM -0700, akpm@osdl.org wrote:
>
> diff -puN drivers/net/myri10ge/myri10ge.c~myri10ge-build-fix drivers/net/myri10ge/myri10ge.c
> --- a/drivers/net/myri10ge/myri10ge.c~myri10ge-build-fix
> +++ a/drivers/net/myri10ge/myri10ge.c
> @@ -2120,7 +2120,7 @@ abort_linearize:
>  		goto drop;
>  	}
>  
> -	if (skb_linearize(skb, GFP_ATOMIC))
> +	if (skb_linearize(skb))
>  		goto drop;

Actually I think this driver (in conjunction with TSO) is buggy.
It has a maximum segment count of 12.  However TSO can send 13 pages
or more of data on i386.  If this happens it looks like this driver
will go into an infinite loop forever trying to linearize the skb.

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: [PATCH 03/06] MLSXFRM: Add security sid to sock
From: James Morris @ 2006-06-21  5:12 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Venkat Yekkirala, netdev, selinux
In-Reply-To: <20060621043502.GA899@gondor.apana.org.au>

On Wed, 21 Jun 2006, Herbert Xu wrote:

> On Tue, Jun 20, 2006 at 08:50:55PM -0400, Venkat Yekkirala wrote:
> >
> > Nope. It would actually overwrite the pointer, so we put it away before
> > memcpy
> > and set it back after memcpy.
> 
> Right, I misread it as sptr = osk->sk_security.  Still, it'd be nice to
> optimise it away for the !SECURITY case.

Indeed, there should be zero overhead for core networking code when LSM is 
not configured.


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply

* Re: [PATCH 01/06] MLSXFRM: Granular IPSec associations for use in MLS environments
From: James Morris @ 2006-06-21  5:24 UTC (permalink / raw)
  To: Venkat Yekkirala; +Cc: netdev, selinux
In-Reply-To: <44983D1F.1050306@trustedcs.com>

On Tue, 20 Jun 2006, Venkat Yekkirala wrote:

> The current approach to labeling Security Associations for SELinux 
> purposes uses a one-to-one mapping between xfrm policy rules and 
> security associations. This doesn?t address the needs of real world MLS 
> (Multi-level System, traditional Bell-LaPadula) environments where a 
> single xfrm policy rule (pertaining to a range, classified to secret for 
> example) might need to map to multiple Security Associations (one each 
> for classified, secret, top secret and all the compartments applicable 
> to these security levels).

Can you clarify whether, with this patch, Linux will then have a complete 
labeled network implementation in terms of both LSPP compliance and common 
user requirements?

> Outstanding items/issues: 
> - Timewait acknowledgements and such are generated in the 
> current/upstream implementation using a NULL socket resulting in the 
> any_socket sid (SYSTEM_HIGH) to be used. This problem is not addressed 
> by this patch set.

This needs to be resolved, along with labeling for all kernel owned 
socket/tw objects.  I'm not entirely clear on why this doesn't already 
work, as it is using IPsec, which should certainly be able to encapsulate 
all of this traffic.

It would also be interesting to know what kind of testing this code as 
had.


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply

* Can I make ipv6 module inactive at my pentaval driver?
From: SangOg Na @ 2006-06-21  5:41 UTC (permalink / raw)
  To: netdev

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

Hi!

I'm working for pentamedia in Korea.
My company makes one-way satellite receiver card whose name is pentavalue.
Pentavalue cards receive DVB-S packets and extract IP packets and
push them into TCP/IP stack.
pentavalue driver works in linux kernel 2.4.20.
I'm porting pentavalue driver to 2.6.17 kernel, but reference count problem 
occurs.
There is no code updating reference count in driver source.
I insert debug code in kernel source at dev_put and dev_hold
in include/linux/netdevice.h file.
 static inline void dev_put(struct net_device *dev)
 {
         atomic_dec(&dev->refcnt);
+        if (*(dev)->name=='p') {
+                printk("-%s- %d\n",dev->name,atomic_read(&dev->refcnt));
+                dump_stack();
+        }
 }

 static inline void dev_hold(struct net_device *dev)
 {
         atomic_inc(&dev->refcnt);
+        if (*(dev)->name=='p') {
+                printk("+%s+ %d\n",dev->name,atomic_read(&dev->refcnt));
+                dump_stack();
+        }
 }

I found ipv6 module notifier increase refcnt and not decrease refcnt.
refcnt increases by 3 when the device opens and closes using ifconfig.
I modified driver source for enabling rmmod by setting refcnt to 4 before 
cleanup module.
I will attach command log file. 

[-- Attachment #2: pentaval.log --]
[-- Type: application/octet-stream, Size: 15883 bytes --]


# modprobe pentaval
# dmesg -c

PentaVal_init_one: [bus:0x0,device:0x8,function:0x0]
PentaVal_init_one: [vender/device/subvendor/subdevice:0x109e,0x036e,0x15c8,0x0133]
PentaVal_init_board: MMIO region size:start 0xF7FFF000-> 0xF7FFFFFF,len:0x1000
ACPI: PCI Interrupt 0000:00:08.0[A] -> GSI 16 (level, low) -> IRQ 20
PentaVal_init_board: Physical MMIO region start 0xF7FFF000
PentaVal_init_board: Virtual MMIO region start 0xDE87E000
PentaVal_init_one: PCI FN0 Physical start:0xF7FFF000
PentaVal_init_one: PCI FN0 Virtual start:0xDE87E000
PentaVal_init_one: [bus:0x0,device:0x8,function:0x1]
PentaVal_init_one: [vender/device/subvendor/subdevice:0x109e,0x0878,0x15c8,0x0133]
PentaVal_init_board: MMIO region size:start 0xF7FFE000-> 0xF7FFEFFF,len:0x1000
ACPI: PCI Interrupt 0000:00:08.1[A] -> GSI 16 (level, low) -> IRQ 20
PentaVal_init_board: Physical MMIO region start 0xF7FFE000
PentaVal_init_board: Virtual MMIO region start 0xDEC24000
PentaVal_init_one: PCI FN1 Physical start:0xF7FFE000
PentaVal_init_one: PCI FN1 Virtual start:0xDEC24000

+pentaval0+ 1
 <c035d577> alloc_divert_blk+0x6b/0x6f  <c035560f> register_netdevice+0x67/0x2b5
 <c03558b8> register_netdev+0x5b/0x68  <ded805d8> PentaVal_init_one+0x26d/0x30f [pentaval]
 <c01cca22> pci_call_probe+0xf/0x12  <c01cca58> __pci_device_probe+0x33/0x47
 <c01cca8b> pci_device_probe+0x1f/0x34  <c021ce2e> driver_probe_device+0x43/0x9c
 <c021cee7> __driver_attach+0x0/0x5c  <c021cf1e> __driver_attach+0x37/0x5c
 <c021c57d> bus_for_each_dev+0x46/0x6c  <c01c5225> kobject_add+0x94/0xb3
 <c021cf57> driver_attach+0x14/0x18  <c021cee7> __driver_attach+0x0/0x5c
 <c021c992> bus_add_driver+0x54/0x84  <c021d33d> driver_register+0x7b/0x80
 <c01ccc46> __pci_register_driver+0x3e/0x4f  <c011d80d> blocking_notifier_call_chain+0x20/0x37
 <de82c00f> PentaVal_init_module+0xf/0x12 [pentaval]  <c0127ca4> sys_init_module+0x89/0x13d
 <c0102487> syscall_call+0x7/0xb 

+pentaval0+ 2
 <c0355830> register_netdevice+0x288/0x2b5  <c03558b8> register_netdev+0x5b/0x68
 <ded805d8> PentaVal_init_one+0x26d/0x30f [pentaval]  <c01cca22> pci_call_probe+0xf/0x12
 <c01cca58> __pci_device_probe+0x33/0x47  <c01cca8b> pci_device_probe+0x1f/0x34
 <c021ce2e> driver_probe_device+0x43/0x9c  <c021cee7> __driver_attach+0x0/0x5c
 <c021cf1e> __driver_attach+0x37/0x5c  <c021c57d> bus_for_each_dev+0x46/0x6c
 <c01c5225> kobject_add+0x94/0xb3  <c021cf57> driver_attach+0x14/0x18
 <c021cee7> __driver_attach+0x0/0x5c  <c021c992> bus_add_driver+0x54/0x84
 <c021d33d> driver_register+0x7b/0x80  <c01ccc46> __pci_register_driver+0x3e/0x4f
 <c011d80d> blocking_notifier_call_chain+0x20/0x37  <de82c00f> PentaVal_init_module+0xf/0x12 [pentaval]
 <c0127ca4> sys_init_module+0x89/0x13d  <c0102487> syscall_call+0x7/0xb
-> www.pentamedia.com/english/products/penta-value.htm
Pentamedia Satellite Data Broadcast Receiver PCI Pent@VALUE(#1)
pentaval0: at 0xf7fff000 0xf7ffe000 IRQ 20
pentaval0: vendor 0x109e device 0x878
pentaval0: subsystem 0x15c8 subsystem vendor 0x133
pentaval0: ver 2.1.10  release date 2002/11/11

# ifconfig pentaval0 up
# dmesg -c

#nso:2
PentaVal_open: pentaval0: Starting up Pent@VALUE card (card idx = 0)
#nso:2

+pentaval0+ 3
 <c0361b8e> qdisc_alloc+0xa8/0xc2  <ded82e13> HWP_SetMultiCast+0xe5/0xf3 [pentaval]
 <ded81046> PentaVal_set_rx_mode+0x0/0xa1 [pentaval]  <c0361bb8> qdisc_create_dflt+0x10/0x3e
 <c0361df9> dev_activate+0x26/0xd1  <c0353cf6> dev_open+0x4e/0x65
 <c0354f18> dev_change_flags+0x49/0xeb  <c038b083> devinet_ioctl+0x24b/0x4bc
 <c038c9ce> inet_ioctl+0x44/0x63  <c034c6cf> sock_ioctl+0x1aa/0x1c7
 <c015011e> do_ioctl+0x26/0x4f  <c0150375> vfs_ioctl+0x16c/0x179
 <c01503ad> sys_ioctl+0x2b/0x46  <c0102487> syscall_call+0x7/0xb

+pentaval0+ 4
 <c0358e10> neigh_parms_alloc+0xa5/0xd7  <ded50ffc> ipv6_add_dev+0x92/0x1d1 [ipv6]
 <ded5117b> ipv6_find_idev+0x40/0x5b [ipv6]  <ded5292e> addrconf_add_dev+0x36/0x52 [ipv6]
 <ded533b2> addrconf_dev_config+0x5d/0x9a [ipv6]  <c035ba9a> rtmsg_ifinfo+0x69/0x71
 <ded535e0> addrconf_notify+0xc5/0x19b [ipv6]  <c011d6e2> notifier_call_chain+0x1c/0x33
 <c011d855> raw_notifier_call_chain+0x11/0x15  <c0353d03> dev_open+0x5b/0x65
 <c0354f18> dev_change_flags+0x49/0xeb  <c038b083> devinet_ioctl+0x24b/0x4bc
 <c038c9ce> inet_ioctl+0x44/0x63  <c034c6cf> sock_ioctl+0x1aa/0x1c7
 <c015011e> do_ioctl+0x26/0x4f  <c0150375> vfs_ioctl+0x16c/0x179
 <c01503ad> sys_ioctl+0x2b/0x46  <c0102487> syscall_call+0x7/0xb

+pentaval0+ 5
 <ded51037> ipv6_add_dev+0xcd/0x1d1 [ipv6]  <ded5117b> ipv6_find_idev+0x40/0x5b [ipv6]
 <ded5292e> addrconf_add_dev+0x36/0x52 [ipv6]  <ded533b2> addrconf_dev_config+0x5d/0x9a [ipv6]
 <c035ba9a> rtmsg_ifinfo+0x69/0x71  <ded535e0> addrconf_notify+0xc5/0x19b [ipv6]
 <c011d6e2> notifier_call_chain+0x1c/0x33  <c011d855> raw_notifier_call_chain+0x11/0x15
 <c0353d03> dev_open+0x5b/0x65  <c0354f18> dev_change_flags+0x49/0xeb
 <c038b083> devinet_ioctl+0x24b/0x4bc  <c038c9ce> inet_ioctl+0x44/0x63
 <c034c6cf> sock_ioctl+0x1aa/0x1c7  <c015011e> do_ioctl+0x26/0x4f
 <c0150375> vfs_ioctl+0x16c/0x179  <c01503ad> sys_ioctl+0x2b/0x46
 <c0102487> syscall_call+0x7/0xb 

+pentaval0+ 6
 <c03537d0> dev_get_by_index+0x36/0x3a  <ded56fc6> ip6_route_add+0x73/0x635 [ipv6]
 <c0118a66> register_proc_table+0xcb/0xdf  <ded5286f> addrconf_add_mroute+0x66/0x6b [ipv6]
 <ded5293d> addrconf_add_dev+0x45/0x52 [ipv6]  <ded533b2> addrconf_dev_config+0x5d/0x9a [ipv6]
 <c035ba9a> rtmsg_ifinfo+0x69/0x71  <ded535e0> addrconf_notify+0xc5/0x19b [ipv6]
 <c011d6e2> notifier_call_chain+0x1c/0x33  <c011d855> raw_notifier_call_chain+0x11/0x15
 <c0353d03> dev_open+0x5b/0x65  <c0354f18> dev_change_flags+0x49/0xeb
 <c038b083> devinet_ioctl+0x24b/0x4bc  <c038c9ce> inet_ioctl+0x44/0x63
 <c034c6cf> sock_ioctl+0x1aa/0x1c7  <c015011e> do_ioctl+0x26/0x4f
 <c0150375> vfs_ioctl+0x16c/0x179  <c01503ad> sys_ioctl+0x2b/0x46
 <c0102487> syscall_call+0x7/0xb 

+pentaval0+ 7
 <c03537d0> dev_get_by_index+0x36/0x3a  <ded56fc6> ip6_route_add+0x73/0x635 [ipv6]
 <ded52801> addrconf_prefix_route+0x7d/0x85 [ipv6]  <ded528f4> addrconf_add_lroute+0x34/0x38 [ipv6]
 <ded52943> addrconf_add_dev+0x4b/0x52 [ipv6]  <ded533b2> addrconf_dev_config+0x5d/0x9a [ipv6]
 <c035ba9a> rtmsg_ifinfo+0x69/0x71  <ded535e0> addrconf_notify+0xc5/0x19b [ipv6]
 <c011d6e2> notifier_call_chain+0x1c/0x33  <c011d855> raw_notifier_call_chain+0x11/0x15
 <c0353d03> dev_open+0x5b/0x65  <c0354f18> dev_change_flags+0x49/0xeb
 <c038b083> devinet_ioctl+0x24b/0x4bc  <c038c9ce> inet_ioctl+0x44/0x63
 <c034c6cf> sock_ioctl+0x1aa/0x1c7  <c015011e> do_ioctl+0x26/0x4f
 <c0150375> vfs_ioctl+0x16c/0x179  <c01503ad> sys_ioctl+0x2b/0x46
 <c0102487> syscall_call+0x7/0xb 

+pentaval0+ 8
 <c03537d0> dev_get_by_index+0x36/0x3a  <ded56fc6> ip6_route_add+0x73/0x635 [ipv6]
 <ded52801> addrconf_prefix_route+0x7d/0x85 [ipv6]  <ded53a79> addrconf_dad_start+0x36/0xb9 [ipv6]
 <ded5333d> addrconf_add_linklocal+0x2b/0x43 [ipv6]  <ded533e5> addrconf_dev_config+0x90/0x9a [ipv6]
 <ded535e0> addrconf_notify+0xc5/0x19b [ipv6]  <c011d6e2> notifier_call_chain+0x1c/0x33
 <c011d855> raw_notifier_call_chain+0x11/0x15  <c0353d03> dev_open+0x5b/0x65
 <c0354f18> dev_change_flags+0x49/0xeb  <c038b083> devinet_ioctl+0x24b/0x4bc
 <c038c9ce> inet_ioctl+0x44/0x63  <c034c6cf> sock_ioctl+0x1aa/0x1c7
 <c015011e> do_ioctl+0x26/0x4f  <c0150375> vfs_ioctl+0x16c/0x179
 <c01503ad> sys_ioctl+0x2b/0x46  <c0102487> syscall_call+0x7/0xb

-pentaval0- 7
 <c0357527> dst_destroy+0x88/0xc1  <ded5915f> fib6_add+0xa3/0xb7 [ipv6]
 <ded5675c> ip6_ins_rt+0x29/0x37 [ipv6]  <ded52801> addrconf_prefix_route+0x7d/0x85 [ipv6]
 <ded53a79> addrconf_dad_start+0x36/0xb9 [ipv6]  <ded5333d> addrconf_add_linklocal+0x2b/0x43 [ipv6]
 <ded533e5> addrconf_dev_config+0x90/0x9a [ipv6]  <ded535e0> addrconf_notify+0xc5/0x19b [ipv6]
 <c011d6e2> notifier_call_chain+0x1c/0x33  <c011d855> raw_notifier_call_chain+0x11/0x15
 <c0353d03> dev_open+0x5b/0x65  <c0354f18> dev_change_flags+0x49/0xeb
 <c038b083> devinet_ioctl+0x24b/0x4bc  <c038c9ce> inet_ioctl+0x44/0x63
 <c034c6cf> sock_ioctl+0x1aa/0x1c7  <c015011e> do_ioctl+0x26/0x4f
 <c0150375> vfs_ioctl+0x16c/0x179  <c01503ad> sys_ioctl+0x2b/0x46
 <c0102487> syscall_call+0x7/0xb 

+pentaval0+ 8
 <ded56d65> ndisc_dst_alloc+0x70/0x121 [ipv6]  <ded5b998> ndisc_send_rs+0x5e/0x363 [ipv6]
 <ded4e7f3> ip6_output+0x0/0x40 [ipv6]  <ded5996a> fib6_prune_clones+0x14/0x18 [ipv6]
 <ded59943> fib6_prune_clone+0x0/0x13 [ipv6]  <ded53c38> addrconf_dad_completed+0x69/0xa5 [ipv6]
 <ded5333d> addrconf_add_linklocal+0x2b/0x43 [ipv6]  <ded533e5> addrconf_dev_config+0x90/0x9a [ipv6]
 <ded535e0> addrconf_notify+0xc5/0x19b [ipv6]  <c011d6e2> notifier_call_chain+0x1c/0x33
 <c011d855> raw_notifier_call_chain+0x11/0x15  <c0353d03> dev_open+0x5b/0x65
 <c0354f18> dev_change_flags+0x49/0xeb  <c038b083> devinet_ioctl+0x24b/0x4bc
 <c038c9ce> inet_ioctl+0x44/0x63  <c034c6cf> sock_ioctl+0x1aa/0x1c7
 <c015011e> do_ioctl+0x26/0x4f  <c0150375> vfs_ioctl+0x16c/0x179
 <c01503ad> sys_ioctl+0x2b/0x46  <c0102487> syscall_call+0x7/0xb

+pentaval0+ 9
 <c0357c63> neigh_create+0x67/0x1a6  <c0357b13> neigh_lookup+0x1a/0x87
 <c0357b79> neigh_lookup+0x80/0x87  <ded56d93> ndisc_dst_alloc+0x9e/0x121 [ipv6]
 <ded5b998> ndisc_send_rs+0x5e/0x363 [ipv6]  <ded4e7f3> ip6_output+0x0/0x40 [ipv6]
 <ded5996a> fib6_prune_clones+0x14/0x18 [ipv6]  <ded59943> fib6_prune_clone+0x0/0x13 [ipv6]
 <ded53c38> addrconf_dad_completed+0x69/0xa5 [ipv6]  <ded5333d> addrconf_add_linklocal+0x2b/0x43 [ipv6]
 <ded533e5> addrconf_dev_config+0x90/0x9a [ipv6]  <ded535e0> addrconf_notify+0xc5/0x19b [ipv6]
 <c011d6e2> notifier_call_chain+0x1c/0x33  <c011d855> raw_notifier_call_chain+0x11/0x15
 <c0353d03> dev_open+0x5b/0x65  <c0354f18> dev_change_flags+0x49/0xeb
 <c038b083> devinet_ioctl+0x24b/0x4bc  <c038c9ce> inet_ioctl+0x44/0x63
 <c034c6cf> sock_ioctl+0x1aa/0x1c7  <c015011e> do_ioctl+0x26/0x4f
 <c0150375> vfs_ioctl+0x16c/0x179  <c01503ad> sys_ioctl+0x2b/0x46
 <c0102487> syscall_call+0x7/0xb 

+pentaval0+ 10
 <ded56d65> ndisc_dst_alloc+0x70/0x121 [ipv6]  <ded5b998> ndisc_send_rs+0x5e/0x363 [ipv6]
 <ded4e7f3> ip6_output+0x0/0x40 [ipv6]  <ded53962> addrconf_rs_timer+0x0/0xa7 [ipv6]
 <ded539df> addrconf_rs_timer+0x7d/0xa7 [ipv6]  <c011ac27> run_timer_softirq+0x114/0x157
 <c0117bb0> __do_softirq+0x34/0x7d  <c0117c1b> do_softirq+0x22/0x26
 <c0104996> do_IRQ+0x1e/0x24  <c01033fa> common_interrupt+0x1a/0x20
 <c0100bcd> mwait_idle+0x1a/0x2a  <c0100b25> cpu_idle+0x42/0x57
 <c0520612> start_kernel+0x17b/0x17d 

+pentaval0+ 11
 <ded56d65> ndisc_dst_alloc+0x70/0x121 [ipv6]  <ded5b998> ndisc_send_rs+0x5e/0x363 [ipv6]
 <ded4e7f3> ip6_output+0x0/0x40 [ipv6]  <c034fb22> kfree_skbmem+0x69/0x6d
 <ded53962> addrconf_rs_timer+0x0/0xa7 [ipv6]  <ded539df> addrconf_rs_timer+0x7d/0xa7 [ipv6]
 <c011ac27> run_timer_softirq+0x114/0x157  <c0117bb0> __do_softirq+0x34/0x7d
 <c0117c1b> do_softirq+0x22/0x26  <c0104996> do_IRQ+0x1e/0x24
 <c01033fa> common_interrupt+0x1a/0x20  <c0100bcd> mwait_idle+0x1a/0x2a
 <c0100b25> cpu_idle+0x42/0x57  <c0520612> start_kernel+0x17b/0x17d
pentaval0: no IPv6 routers present

# ifconfig pentaval0 down
# dmesg -c

=nso:11
PentaVal_close: pentaval0: Shutting down Pent@VALUE card (card idx =0)
=nso:11

-pentaval0- 10
 <c0357527> dst_destroy+0x88/0xc1  <ded59686> fib6_del_route+0x134/0x14d [ipv6]
 <ded596f9> fib6_del+0x5a/0xb3 [ipv6]  <ded598ca> fib6_clean_node+0x29/0x6b [ipv6]
 <ded597d7> fib6_walk_continue+0x85/0xe6 [ipv6]  <ded59877> fib6_walk+0x3f/0x69 [ipv6]
 <ded5993f> fib6_clean_tree+0x33/0x37 [ipv6]  <ded598a1> fib6_clean_node+0x0/0x6b [ipv6]
 <ded5993f> fib6_clean_tree+0x33/0x37 [ipv6]  <ded57e7b> fib6_ifdown+0x0/0x1f [ipv6]
 <ded57ebe> rt6_ifdown+0x24/0x2c [ipv6]  <ded57e7b> fib6_ifdown+0x0/0x1f [ipv6]
 <ded53707> addrconf_ifdown+0x51/0x2ac [ipv6]  <ded53667> addrconf_notify+0x14c/0x19b [ipv6]
 <c011d6e2> notifier_call_chain+0x1c/0x33  <c011d855> raw_notifier_call_chain+0x11/0x15
 <c0353d68> dev_close+0x5b/0x62  <c0354f18> dev_change_flags+0x49/0xeb
 <c038b083> devinet_ioctl+0x24b/0x4bc  <c038c9ce> inet_ioctl+0x44/0x63
 <c034c6cf> sock_ioctl+0x1aa/0x1c7  <c015011e> do_ioctl+0x26/0x4f
 <c0150375> vfs_ioctl+0x16c/0x179  <c01503ad> sys_ioctl+0x2b/0x46
 <c0102487> syscall_call+0x7/0xb 

-pentaval0- 9
 <c0357527> dst_destroy+0x88/0xc1  <ded59686> fib6_del_route+0x134/0x14d [ipv6]
 <ded596f9> fib6_del+0x5a/0xb3 [ipv6]  <ded598ca> fib6_clean_node+0x29/0x6b [ipv6]
 <ded597d7> fib6_walk_continue+0x85/0xe6 [ipv6]  <ded59877> fib6_walk+0x3f/0x69 [ipv6]
 <ded5993f> fib6_clean_tree+0x33/0x37 [ipv6]  <ded598a1> fib6_clean_node+0x0/0x6b [ipv6]
 <ded5993f> fib6_clean_tree+0x33/0x37 [ipv6]  <ded57e7b> fib6_ifdown+0x0/0x1f [ipv6]
 <ded57ebe> rt6_ifdown+0x24/0x2c [ipv6]  <ded57e7b> fib6_ifdown+0x0/0x1f [ipv6]
 <ded53707> addrconf_ifdown+0x51/0x2ac [ipv6]  <ded53667> addrconf_notify+0x14c/0x19b [ipv6]
 <c011d6e2> notifier_call_chain+0x1c/0x33  <c011d855> raw_notifier_call_chain+0x11/0x15
 <c0353d68> dev_close+0x5b/0x62  <c0354f18> dev_change_flags+0x49/0xeb
 <c038b083> devinet_ioctl+0x24b/0x4bc  <c038c9ce> inet_ioctl+0x44/0x63
 <c034c6cf> sock_ioctl+0x1aa/0x1c7  <c015011e> do_ioctl+0x26/0x4f
 <c0150375> vfs_ioctl+0x16c/0x179  <c01503ad> sys_ioctl+0x2b/0x46
 <c0102487> syscall_call+0x7/0xb 

# rmmod pentaval
# dmesg -c

nso:9
mtu:1500

-pentaval0- 3
 <c0358ed3> neigh_parms_release+0x76/0xa5  <ded53938> addrconf_ifdown+0x282/0x2ac [ipv6]
 <ded53667> addrconf_notify+0x14c/0x19b [ipv6]  <c011d6e2> notifier_call_chain+0x1c/0x33
 <c011d855> raw_notifier_call_chain+0x11/0x15  <c0355cc8> unregister_netdevice+0x151/0x1e1
 <c0355d68> unregister_netdev+0x10/0x18  <ded8072f> PentaVal_remove_one+0xb5/0x11d [pentaval]
 <c01ccab9> pci_device_remove+0x19/0x2c  <c021cfb3> __device_release_driver+0x58/0x85
 <c021d04f> driver_detach+0x49/0x76  <c021c9ee> bus_remove_driver+0x2c/0x4d
 <c021d34d> driver_unregister+0xb/0x15  <c01ccc65> pci_unregister_driver+0xe/0x19
 <ded84c0a> PentaVal_cleanup_module+0xa/0xc [pentaval]  <c01266c7> sys_delete_module+0x10d/0x132
 <c01375e5> do_munmap+0xdf/0xeb  <c0137622> sys_munmap+0x31/0x4b
 <c0102487> syscall_call+0x7/0xb 

-pentaval0- 2
 <c0355d07> unregister_netdevice+0x190/0x1e1  <c0355d68> unregister_netdev+0x10/0x18
 <ded8072f> PentaVal_remove_one+0xb5/0x11d [pentaval]  <c01ccab9> pci_device_remove+0x19/0x2c
 <c021cfb3> __device_release_driver+0x58/0x85  <c021d04f> driver_detach+0x49/0x76
 <c021c9ee> bus_remove_driver+0x2c/0x4d  <c021d34d> driver_unregister+0xb/0x15
 <c01ccc65> pci_unregister_driver+0xe/0x19  <ded84c0a> PentaVal_cleanup_module+0xa/0xc [pentaval]
 <c01266c7> sys_delete_module+0x10d/0x132  <c01375e5> do_munmap+0xdf/0xeb
 <c0137622> sys_munmap+0x31/0x4b  <c0102487> syscall_call+0x7/0xb

-pentaval0- 1
 <c0361c6f> __qdisc_destroy+0x76/0x84  <c01205fe> rcu_do_batch+0x1a/0x71
 <c01207a4> rcu_process_callbacks+0xf/0x22  <c0117dc3> tasklet_action+0x3a/0x59
 <c0117bb0> __do_softirq+0x34/0x7d  <c0117c1b> do_softirq+0x22/0x26
 <c0104996> do_IRQ+0x1e/0x24  <c01033fa> common_interrupt+0x1a/0x20
 <c0100bcd> mwait_idle+0x1a/0x2a  <c0100b25> cpu_idle+0x42/0x57
 <c0520612> start_kernel+0x17b/0x17d 

-pentaval0- 0
 <c0355d52> unregister_netdevice+0x1db/0x1e1  <c0355d68> unregister_netdev+0x10/0x18
 <ded8072f> PentaVal_remove_one+0xb5/0x11d [pentaval]  <c01ccab9> pci_device_remove+0x19/0x2c
 <c021cfb3> __device_release_driver+0x58/0x85  <c021d04f> driver_detach+0x49/0x76
 <c021c9ee> bus_remove_driver+0x2c/0x4d  <c021d34d> driver_unregister+0xb/0x15
 <c01ccc65> pci_unregister_driver+0xe/0x19  <ded84c0a> PentaVal_cleanup_module+0xa/0xc [pentaval]
 <c01266c7> sys_delete_module+0x10d/0x132  <c01375e5> do_munmap+0xdf/0xeb
 <c0137622> sys_munmap+0x31/0x4b  <c0102487> syscall_call+0x7/0xb
ACPI: PCI interrupt for device 0000:00:08.1 disabled

^ permalink raw reply

* You cum very quickly and without any control!
From: Richie @ 2006-06-21  6:18 UTC (permalink / raw)
  To: netdev

It is absolutely safety for your health!The success is guaranteed with this perfect tab! Oh, you are not able to control your feelings!Wow, you used to cum within 5 minutes! http://gcubia.com/gall/get I have no such a problem!


^ permalink raw reply

* Re: [PATCH 2/3] FS_ENET: use PAL for mii management
From: Gerhard Jaeger @ 2006-06-21  7:20 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: Vitaly Bordug, netdev, linux-kernel
In-Reply-To: <20060620145840.24807.30296.stgit@vitb.ru.mvista.com>

Hi,

On Tuesday 20 June 2006 16:58, Vitaly Bordug wrote:
> 
> This patch should update the fs_enet infrastructure to utilize
> Phy Abstraction Layer subsystem. Inside there are generic driver rehaul,
> board-specific portion to respect driver changes (for 8272ads and 866ads).
> 
> Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
> ---
> 
>  arch/ppc/platforms/mpc8272ads_setup.c |  154 ++++++----
>  arch/ppc/platforms/mpc866ads_setup.c  |  192 ++++++------
>  arch/ppc/platforms/mpc885ads_setup.c  |  179 ++++--------
>  arch/ppc/syslib/mpc8xx_devices.c      |    8 +
>  arch/ppc/syslib/mpc8xx_sys.c          |    6 
>  arch/ppc/syslib/pq2_devices.c         |    5 
>  arch/ppc/syslib/pq2_sys.c             |    3 
>  drivers/net/fs_enet/Makefile          |    6 
>  drivers/net/fs_enet/fec.h             |   42 +++
>  drivers/net/fs_enet/fs_enet-main.c    |  207 ++++++++-----
>  drivers/net/fs_enet/fs_enet-mii.c     |  507 ---------------------------------
>  drivers/net/fs_enet/fs_enet.h         |   40 ++-
>  drivers/net/fs_enet/mac-fcc.c         |   10 -
>  drivers/net/fs_enet/mac-fec.c         |  132 +--------
>  drivers/net/fs_enet/mac-scc.c         |    4 
>  drivers/net/fs_enet/mii-bitbang.c     |  384 +++++++++++++++----------
>  drivers/net/fs_enet/mii-fec.c         |  243 ++++++++++++++++
>  drivers/net/fs_enet/mii-fixed.c       |   92 ------
>  include/asm-ppc/mpc8260.h             |    1 
>  include/asm-ppc/mpc8xx.h              |    1 
>  include/linux/fs_enet_pd.h            |   50 +--
>  21 files changed, 983 insertions(+), 1283 deletions(-)

[SNIPSNAP]
> diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
> index 24a5e2e..145bf4c 100644
> --- a/drivers/net/fs_enet/mii-bitbang.c
> +++ b/drivers/net/fs_enet/mii-bitbang.c
> @@ -34,6 +34,7 @@
>  #include <linux/mii.h>
>  #include <linux/ethtool.h>
>  #include <linux/bitops.h>
> +#include <linux/platform_device.h>
>  
>  #include <asm/pgtable.h>
>  #include <asm/irq.h>
> @@ -41,6 +42,7 @@
>  
>  #include "fs_enet.h"
>  
> +
>  #ifdef CONFIG_8xx
>  static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit)
>  {
> @@ -106,64 +108,25 @@ static int bitbang_prep_bit(u8 **dirp, u
>  }
>  #endif
>  
> -#ifdef CONFIG_8260
> -static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit)
> +static int bitbang_prep_bit(u8 **datp, u8 *mskp,
> +		struct fs_mii_bit *mii_bit)

is it possible, that in case of CONFIG_8xx you'll have two times this 
bitbang_prep_bit() function? 

Gerhard

-- 
Gerhard Jaeger <gjaeger@sysgo.com>            
SYSGO AG                      Embedded and Real-Time Software
www.sysgo.com | www.elinos.com | www.pikeos.com | www.osek.de 

^ permalink raw reply

* Re: [PATCH 2/3] FS_ENET: use PAL for mii management
From: Vitaly Bordug @ 2006-06-21  7:38 UTC (permalink / raw)
  To: Gerhard Jaeger; +Cc: netdev, linux-kernel, linuxppc-embedded
In-Reply-To: <200606210920.37295.g.jaeger@sysgo.com>

На Wed, 21 Jun 2006 09:20:36 +0200
Gerhard Jaeger <g.jaeger@sysgo.com> записано:

> Hi,
> 
> On Tuesday 20 June 2006 16:58, Vitaly Bordug wrote:
> > 
> > This patch should update the fs_enet infrastructure to utilize
> > Phy Abstraction Layer subsystem. Inside there are generic driver
> > rehaul, board-specific portion to respect driver changes (for
> > 8272ads and 866ads).
> > 
> > Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
> > ---
> > 
> >  arch/ppc/platforms/mpc8272ads_setup.c |  154 ++++++----
> >  arch/ppc/platforms/mpc866ads_setup.c  |  192 ++++++------
> >  arch/ppc/platforms/mpc885ads_setup.c  |  179 ++++--------
> >  arch/ppc/syslib/mpc8xx_devices.c      |    8 +
> >  arch/ppc/syslib/mpc8xx_sys.c          |    6 
> >  arch/ppc/syslib/pq2_devices.c         |    5 
> >  arch/ppc/syslib/pq2_sys.c             |    3 
> >  drivers/net/fs_enet/Makefile          |    6 
> >  drivers/net/fs_enet/fec.h             |   42 +++
> >  drivers/net/fs_enet/fs_enet-main.c    |  207 ++++++++-----
> >  drivers/net/fs_enet/fs_enet-mii.c     |  507
> > ---------------------------------
> > drivers/net/fs_enet/fs_enet.h         |   40 ++-
> > drivers/net/fs_enet/mac-fcc.c         |   10 -
> > drivers/net/fs_enet/mac-fec.c         |  132 +--------
> > drivers/net/fs_enet/mac-scc.c         |    4
> > drivers/net/fs_enet/mii-bitbang.c     |  384
> > +++++++++++++++---------- drivers/net/fs_enet/mii-fec.c         |
> > 243 ++++++++++++++++ drivers/net/fs_enet/mii-fixed.c       |   92
> > ------ include/asm-ppc/mpc8260.h             |    1
> > include/asm-ppc/mpc8xx.h              |    1
> > include/linux/fs_enet_pd.h            |   50 +-- 21 files changed,
> > 983 insertions(+), 1283 deletions(-)
> 
> [SNIPSNAP]
> > diff --git a/drivers/net/fs_enet/mii-bitbang.c
> > b/drivers/net/fs_enet/mii-bitbang.c index 24a5e2e..145bf4c 100644
> > --- a/drivers/net/fs_enet/mii-bitbang.c
> > +++ b/drivers/net/fs_enet/mii-bitbang.c
> > @@ -34,6 +34,7 @@
> >  #include <linux/mii.h>
> >  #include <linux/ethtool.h>
> >  #include <linux/bitops.h>
> > +#include <linux/platform_device.h>
> >  
> >  #include <asm/pgtable.h>
> >  #include <asm/irq.h>
> > @@ -41,6 +42,7 @@
> >  
> >  #include "fs_enet.h"
> >  
> > +
> >  #ifdef CONFIG_8xx
> >  static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int
> > port, int bit) {
> > @@ -106,64 +108,25 @@ static int bitbang_prep_bit(u8 **dirp, u
> >  }
> >  #endif
> >  
> > -#ifdef CONFIG_8260
> > -static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int
> > port, int bit) +static int bitbang_prep_bit(u8 **datp, u8 *mskp,
> > +		struct fs_mii_bit *mii_bit)
> 
> is it possible, that in case of CONFIG_8xx you'll have two times this 
> bitbang_prep_bit() function? 
> 
Hmm, yes, thanks for pointing that out. The problem is in other
thing though - the bitbang stuff got unified so there should be no
board-specific ifdefs like those.

This issue must have missed the cleanup, I'll fix and redo the patches.

--
Sincerely, Vitaly
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

^ permalink raw reply

* Re: Sanitise ethtool.h and mii.h for userspace.
From: David Woodhouse @ 2006-06-21  8:23 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Linux Kernel Mailing List, Netdev List, Andrew Morton,
	Linus Torvalds
In-Reply-To: <44989E63.9010300@garzik.org>

On Tue, 2006-06-20 at 21:18 -0400, Jeff Garzik wrote:
> How can reviewers make an informed decision, when you completely failed 
> to note:
> 
> * This breaks the primary userspace user of this header, ethtool(8)

I cannot reproduce with either an ethtool-3 tarball or a fresh checkout
from your git tree. Can you show me the error?

It's a somewhat surprising allegation, because ethtool doesn't even
_use_ the header directly from the kernel. It has its own copy, and
currently includes it like this...

typedef unsigned long long u64;         /* hack, so we may include kernel's ethtool.h */
typedef __uint32_t u32;         /* ditto */
typedef __uint16_t u16;         /* ditto */
typedef __uint8_t u8;           /* ditto */
#include "ethtool-copy.h"

> * The patch was NAK'd (and I don't even get a "Naked-by:" header :))

Sorry, my recollection was that you backed down after everyone turned on
you and declared that "but I _want_ to use 'u32' for userspace stuff
because underscores hurt my eyes" was too silly for words. You didn't
get a mention in the commit comment because I'd already committed it by
the time we had the discussion. But I did mention it to Andrew at the
time I asked him to put the hdrcleanup tree into -mm, and he seemed
perfectly happy with the change.

> * Despite knowing all this for quite some time, no associated userspace 
> fix patch has ever appeared.

That's because to the best of my knowledge, userspace doesn't _need_ any
fix at the moment. We've built the whole of the Fedora Core 6 test 1
release against (a subset of) these headers, and that includes ethtool.

> If you are going to break stuff, AT LEAST TELL PEOPLE IN ALL CAPS ABOUT 
> IT, rather than providing the highly deceptive description as above. 
> And be courteous enough to help fix the breakage, if you please. 

If I break stuff, I promise I'll bear that in mind.

-- 
dwmw2


^ permalink raw reply

* skge 1.6
From: Beschorner Daniel @ 2006-06-21  8:46 UTC (permalink / raw)
  To: 'Stephen Hemminger'
  Cc: 'david@mantara.com', 'Krzysztof Oledzki', netdev

Crashing keeps on, but I want to emphasize that it crashes during excessive
Rx not Tx.
I can copy a 1GB file smoothly from the server, but in the other direction
after some seconds the box hangs.

Sorry, couldn't test other then SMB yet on our production system.

Daniel

^ permalink raw reply

* Re: Suspending 802.11 drivers
From: Stefan Rompf @ 2006-06-21  9:42 UTC (permalink / raw)
  To: Michael Buesch; +Cc: Jiri Benc, John W. Linville, netdev, bcm43xx-dev
In-Reply-To: <200606162036.26518.stefan@loplof.de>

Am Freitag 16 Juni 2006 20:36 schrieb Stefan Rompf:

> (But that's an interesting point. Will sniff whether ipw2200 hardware sends
> a final packet on suspend.)

neither on suspend to RAM nor on suspend to disk a disassociation is sent by 
ipw2200 - for the AP, the client just vanishes.

Stefan

^ 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