Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH 2/3] [VLAN]: Update iif when receiving via VLAN device
From: Patrick McHardy @ 2006-06-26 22:49 UTC (permalink / raw)
  To: Thomas Graf; +Cc: David Miller, netdev
In-Reply-To: <44A05FE0.7070203@trash.net>

Patrick McHardy wrote:
> All my testing (quite a lot) in this area so far suggested that queueing
> at ingress doesn't work and is actually counter-productive. It gets
> worse with increasing signal propagation delays (signal in this case
> means congestion indications). I actually wish I never introduced
> the stupid IMQ device, it raises false hope and a lot of people seem
> to fall for it.

Small clarification: with queueing at ingress I mean queueing after
the bottleneck. It might work if you introduce a virtual bottleneck,
but in that case in my experience the bandwidth limit you have to use
is dependant on the number of TCP flows, so usually you can't specify
a limit that will always work, and its wasteful if there is a smaller
number of TCP flows. The reason why you would do it, limiting or
prioritizing incoming traffic on the _real_ bottleneck, is not
achievable of course. Also noteworthy is that policers don't behave
any better, and any other schemes I've tried (I also experienced a
lot of with TCP rate control) have similar or related problems.


^ permalink raw reply

* [PATCH] Fix tulip shutdown DMA/irq race
From: Valerie Henson @ 2006-06-26 22:31 UTC (permalink / raw)
  To: Grant Grundler; +Cc: Jeff Garzik, Andrew Morton, netdev
In-Reply-To: <20060623050029.GB23383@colo.lackof.org>

From: Grant Grundler <grundler@parisc-linux.org>

IRQs are racing with tulip_down(). DMA can be restarted by the
interrupt handler _after_ we call tulip_stop_rxtx() and the DMA
buffers are unmapped.  The result is an MCA (hard crash on ia64)
because of an IO TLB miss.  The long-term fix is to make the interrupt
handler shutdown aware.

Signed-off-by: Grant Grundler <grundler@parisc-linux.org>
Acked-by: Valerie Henson <val_henson@linux.intel.com>

---

 tulip_core.c |   37 ++++++++++++++++++++++++-------------
 1 files changed, 24 insertions(+), 13 deletions(-)

diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
--- a/drivers/net/tulip/tulip_core.c	2006-06-22 16:24:11 -07:00
+++ b/drivers/net/tulip/tulip_core.c	2006-06-22 16:24:11 -07:00
@@ -18,11 +18,11 @@
 
 #define DRV_NAME	"tulip"
 #ifdef CONFIG_TULIP_NAPI
-#define DRV_VERSION    "1.1.13-NAPI" /* Keep at least for test */
+#define DRV_VERSION    "1.1.14-NAPI" /* Keep at least for test */
 #else
-#define DRV_VERSION	"1.1.13"
+#define DRV_VERSION	"1.1.14"
 #endif
-#define DRV_RELDATE	"May 11, 2002"
+#define DRV_RELDATE	"May 6, 2006"
 
 
 #include <linux/module.h>
@@ -739,23 +739,36 @@
 #endif
 	spin_lock_irqsave (&tp->lock, flags);
 
+	/*
+	  FIXME: We should really add a shutdown-in-progress flag and
+	  check it in the interrupt handler to see whether we should
+	  reenable DMA or not.  The preferred ordering here would be:
+	 
+	  stop DMA engine
+	  disable interrupts
+	  remove DMA resources
+	  free_irq()
+
+	  The below works but is non-obvious and doesn't match the
+	  ordering of bring-up. -VAL
+	*/
+
 	/* Disable interrupts by clearing the interrupt mask. */
 	iowrite32 (0x00000000, ioaddr + CSR7);
+	ioread32 (ioaddr + CSR7);	/* flush posted write */
 
-	/* Stop the Tx and Rx processes. */
-	tulip_stop_rxtx(tp);
+	spin_unlock_irqrestore (&tp->lock, flags);
 
-	/* prepare receive buffers */
-	tulip_refill_rx(dev);
+	free_irq (dev->irq, dev);	/* no more races after this */
+	tulip_stop_rxtx(tp);		/* Stop DMA */
 
-	/* release any unconsumed transmit buffers */
-	tulip_clean_tx_ring(tp);
+	/* Put driver back into the state we start with */
+	tulip_refill_rx(dev);		/* prepare RX buffers */
+	tulip_clean_tx_ring(tp);	/* clean up unsent TX buffers */
 
 	if (ioread32 (ioaddr + CSR6) != 0xffffffff)
 		tp->stats.rx_missed_errors += ioread32 (ioaddr + CSR8) & 0xffff;
 
-	spin_unlock_irqrestore (&tp->lock, flags);
-
 	init_timer(&tp->timer);
 	tp->timer.data = (unsigned long)dev;
 	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
@@ -781,7 +794,6 @@
 		printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
 			dev->name, ioread32 (ioaddr + CSR5));
 
-	free_irq (dev->irq, dev);
 
 	/* Free all the skbuffs in the Rx queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
@@ -1752,7 +1764,6 @@
 		tulip_down(dev);
 
 	netif_device_detach(dev);
-	free_irq(dev->irq, dev);
 
 	pci_save_state(pdev);
 	pci_disable_device(pdev);

^ permalink raw reply

* Re: [Repost PATCH 6/6] PMC MSP85x0 gigabit ethernet driver
From: Francois Romieu @ 2006-06-26 22:31 UTC (permalink / raw)
  To: Kiran Thota; +Cc: 'Yoichi Yuasa', linux-mips, netdev, Raj Palani, ralf
In-Reply-To: <C28979E4F697C249ABDA83AC0C33CDF80B6BC8@sjc1exm07.pmc_nt.nt.pmc-sierra.bc.ca>

Kiran Thota <Kiran_Thota@pmc-sierra.com> :
[...]
>  - Based on linux-2.6.12 from 
>  http://www.linux-mips.org/pub/linux/mips/kernel/v2.6/linux-2.6.12.tar.gz

Is there a reason why the patch is not diffed against a more recent
version of the mips tree ?

The patch includes ~130 lines ending with a tab or space delimiter.
They could be removed.

[...]
> diff -Naur a/drivers/net/msp85x0_ge.c b/drivers/net/msp85x0_ge.c
> --- a/drivers/net/msp85x0_ge.c	1969-12-31 16:00:00.000000000 -0800
> +++ b/drivers/net/msp85x0_ge.c	2006-06-26 12:12:39.000000000 -0700
[...]
> +/* Static Function Declarations	 */
> +static int msp85x0_ge_eth_open(struct net_device *);
> +static int msp85x0_ge_eth_reopen(struct net_device *netdev);
> +static void msp85x0_ge_eth_stop(struct net_device *);
> +static struct net_device_stats *msp85x0_ge_get_stats(struct net_device *);
> +static int msp85x0_ge_init_rx_desc_ring(msp85x0_ge_port_info *, int, int,
> +				      unsigned long, unsigned long,
> +				      unsigned long);
> +static int msp85x0_ge_init_tx_desc_ring(msp85x0_ge_port_info *, int,
> +				      unsigned long, unsigned long);
> +
> +static int msp85x0_ge_open(struct net_device *);
> +static int msp85x0_ge_start_xmit(struct sk_buff *, struct net_device *);
> +static int msp85x0_ge_stop(struct net_device *);
> +
> +static unsigned int msp85x0_ge_tx_coal(int);
> +
> +static void msp85x0_ge_port_reset(unsigned int);
> +static int msp85x0_ge_free_tx_queue(struct net_device *);
> +static int msp85x0_ge_rx_task(struct net_device *, msp85x0_ge_port_info *);
> +static int msp85x0_ge_port_start(struct net_device *);
> +static int msp85x0_eth_setup_tx_rx_fifo(struct net_device *dev);
> +static int msp85x0_ge_xdma_reset(void);

You should be able to remove the forward declarations by correctly
reordering the code.

[...]
> +static struct platform_device *msp85x0_ge_device[NO_PORTS];
> +static struct net_device *msp85x0_eth[NO_PORTS];
> +static unsigned int msp85x0_ge_sram;
> +static unsigned int port_number;

The way it is used, port_number should be a local variable.

> +
> +/*
> + * The MSP85x0 GE has two alignment requirements:
> + * -> skb->data to be cacheline aligned (32 byte)
> + * -> IP header alignment to 16 bytes
> + *
> + * The latter is not implemented. So, that results in an extra copy on
> + * the Rx. This is a big performance hog. For the former case, the
> + * dev_alloc_skb() has been replaced with msp85x0_ge_alloc_skb(). The size
> + * requested is calculated:
> + *
> + * Ethernet Frame Size : 1518
> + * Ethernet Header     : 14
> + * Future MSP85x0 change for IP header alignment : 2
> + *
> + * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes.  For IP header
> + * alignment, we use skb_reserve().
> + */
> +#define ALIGNED_RX_SKB_ADDR(addr) \
> +	((((unsigned long)(addr) + (32UL - 1UL)) \
> +	& ~(32UL - 1UL)) - (unsigned long)(addr))
> +#define msp85x0_ge_alloc_skb(__length, __gfp_flags) \
> +({      struct sk_buff *__skb; \
> +	__skb = alloc_skb((__length),(__gfp_flags)); \
> +	if(__skb){ \
> +		int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \
> +		if(__offset) \
> +			skb_reserve(__skb, __offset); \
> +	} \
> +	__skb; \
> +})

Please use a function for msp85x0_ge_alloc_skb.

> +
> +int increment_tx_pkt_count(unsigned int port)

static

> +{
> +	unsigned int flags;
> +	spin_lock_irqsave(&msp85x0_lock,flags);
> +	if(port==0){

CodingStyle: if (port == 0) {
(or 'if (!port)')

> +		port0_pkt_count++;
> +	}
> +	else{

	} else {

> +		port1_pkt_count++;	
> +	}
> +	spin_unlock_irqrestore(&msp85x0_lock,flags);

increment_tx_pkt_count() is only issued from msp85x0_ge_tx_queue(),
itself only issued from msp85x0_ge_start_xmit and xmit handlers run
with irq enabled. The save/restore is not needed.

> +	return 0;

Useless return.

> +}
> +
> +unsigned int get_tx_pkt_count(unsigned int port)

static

> +{
> +	unsigned int flags,pktCount,tx_pending_pkt;

Mixed case can be avoided here.

> +	spin_lock_irqsave(&msp85x0_lock,flags);

See above.

> +	tx_pending_pkt=MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_TX_DMA_STS + (port << XDMA_PORT_OFFSET));
> +	if(port==0){
> +		pktCount=port0_pkt_count - tx_pending_pkt;
> +	}
> +	else{

Sic.

> +		pktCount=port1_pkt_count - tx_pending_pkt;	
> +	}
> +	spin_unlock_irqrestore(&msp85x0_lock,flags);
> +	return pktCount;	
> +}
> +
> +unsigned int decrement_tx_pkt_count(unsigned int port)

static

[...]
> +void msp85x0_bringup_sequence(int port)

static

> +{
> +   	unsigned int reg_data;
> +
> +	/* SDQPF */
> +	reg_data=MSP85x0_GE_READ(MSP85x0_GE_SDQPF_RXFIFO_CTL + (port << 8));

reg_data = MSP85x0_GE_READ(MSP85x0_GE_...


[...]
> +static void msp85x0_ge_gmii_config(int port_num)
> +{
[...]
> +	if (phy_reg & 0x8000) {
> +		if (phy_reg & 0x2000) {
> +			/* Full Duplex and 1000 Mbps */
> +			MSP85x0_GE_WRITE((MSP85x0_GE_GMII_CONFIG_MODE +
> +					(port_num << MII_PORT_OFFSET)), 0x201);
> +		}  else {
> +			/* Half Duplex and 1000 Mbps */
> +			MSP85x0_GE_WRITE((MSP85x0_GE_GMII_CONFIG_MODE +
> +					(port_num << MII_PORT_OFFSET)), 0x2201);
> +			}
> +	}

:o(
		mode = (phy_reg & 0x2000) ? 0x0201 : 0x2201;
		MSP85x0_GE_WRITE((MSP85x0_GE_GMII_CONFIG_MODE +
				 (port_num << MII_PORT_OFFSET)), mode);
> +	if (phy_reg & 0x4000) {
> +		if (phy_reg & 0x2000) {
> +			/* Full Duplex and 100 Mbps */
> +			MSP85x0_GE_WRITE((MSP85x0_GE_GMII_CONFIG_MODE +
> +					(port_num << MII_PORT_OFFSET)), 0x100);
> +		} else {
> +			/* Half Duplex and 100 Mbps */
> +			MSP85x0_GE_WRITE((MSP85x0_GE_GMII_CONFIG_MODE +
> +					(port_num << MII_PORT_OFFSET)), 0x2100);
> +		}
> +	}

I'd bet you could make a single MSP85x0_GE_WRITE for this one and the two
above.

[...]
> +static void msp85x0_ge_update_afx(msp85x0_ge_port_info * msp85x0_ge_eth)
> +{
> +	int port = msp85x0_ge_eth->port_num;
> +	unsigned int i;
> +	volatile unsigned long reg_data = 0;

Mantra: volatile is not the answer.

Now, what's the question ? :o)


[...]
> +static void msp85x0_ge_tx_timeout_task(struct net_device *netdev)
> +{
> +	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
> +	int port = msp85x0_ge_eth->port_num;
> +
> +	printk("MSP85x0 GE: Transmit timed out. Resetting ... \n");

Missing KERN_xyz

[...]
> +static int msp85x0_ge_change_mtu(struct net_device *netdev, int new_mtu)
> +{
[...]
> +	if (netif_running(netdev)) {
> +		msp85x0_ge_eth_stop(netdev);
> +            	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_MAX_FRAME_LEN + (msp85x0_ge_eth->port_num << MAC_PORT_OFFSET)), new_mtu + 2); // for the padded bytes
> +
> +		if (msp85x0_ge_eth_reopen(netdev) != 0) {
> +			printk(KERN_ERR
> +			       "%s: Fatal error on opening device\n",
> +			       netdev->name);
> +			spin_unlock_irqrestore(&msp85x0_ge_eth->lock, flags);
> +			return -1;

Please use -Esomething.

You may consider goto to balance spin_{lock/unlock}.

[...]
> +static irqreturn_t msp85x0_ge_sequoia_int_handler(int irq, void *dev_id,
> +	struct pt_regs *regs)
> +{
> +	struct net_device *netdev = (struct net_device *) dev_id;

Useless cast from void *.

[...]
> +        /* Handle the Rx next */
> +        if (eth_int_cause1 & (RX_INT << (port_num * 16))) {
> +	      clear_xdma_interrupts(port_num,RX_INT);
> +              if (netif_rx_schedule_prep(netdev)) {
> +		   msp85x0_ge_disable_rx_int(port_num);	
> +                   __netif_rx_schedule(netdev);			       		

The indentation went badly wrong.

[...]
> +static int msp85x0_ge_open(struct net_device *netdev)
> +{
> +	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
> +	unsigned int port_num = msp85x0_ge_eth->port_num;
> +	unsigned int irq;
> +	int retval;       
> +
> +	spin_lock_irq(&(msp85x0_ge_eth->lock));
> +
> +	if (msp85x0_ge_eth_open(netdev) != MSP85x0_OK) {
> +		spin_unlock_irq(&(msp85x0_ge_eth->lock));
> +		printk("%s: Error opening interface \n", netdev->name);

Missing KERN_xyz

> +		free_irq(netdev->irq, netdev);

request_irq() comes later.

> +		return -EBUSY;

Why not propagate an usual return status code from msp85x0_ge_eth_open ?

> +	}
> +
> +	spin_unlock_irq(&(msp85x0_ge_eth->lock));
> +
> +        irq = MSP85x0_ETH_PORT_IRQ;
> +
> +	retval = request_irq(irq, INTERRUPT_HANDLER,
> +		     SA_SAMPLE_RANDOM | SA_SHIRQ, netdev->name, netdev);
> +
> +	if (retval != 0) {
> +		printk(KERN_ERR "Cannot assign IRQ number to MSP85x0 GE \n");
> +		return -1;

- msp85x0_ge_eth_open() should be balanced a bit (stop queuing for instance) ;
- no need to throw away retval.

(some sleep needed here, sorry)

-- 
Ueimor

^ permalink raw reply

* Re: [PATCH 2/3] [VLAN]: Update iif when receiving via VLAN device
From: Patrick McHardy @ 2006-06-26 22:29 UTC (permalink / raw)
  To: Thomas Graf; +Cc: David Miller, netdev
In-Reply-To: <20060626184424.GT1376@postel.suug.ch>

Thomas Graf wrote:
> * David Miller <davem@davemloft.net> 2006-06-26 10:46
> 
>>From: Patrick McHardy <kaber@trash.net>
>>Date: Mon, 26 Jun 2006 19:04:15 +0200
>>
>>
>>>I know this was discussed before, but I can't remember the
>>>exact outcome. Why don't we just unconditionally update iif
>>>in netif_receive_skb()?
>>
>>Software devices might have interesting semantics that would
>>make not setting iif desirable.
>>
>>Once you set iif, you can't just undo it because the information
>>is lost.
>>
>>I also would really prefer to set it unconditionally in
>>netif_receive_skb(), but Jamal's concerns in this area are real.
>>We really need to evaluate this on a case-by-case basis.
> 
> 
> I'm playing with a FIFO device based on Jamal's previous
> work to replace the broken IMQ device and provide real
> queueing at ingress.

All my testing (quite a lot) in this area so far suggested that queueing
at ingress doesn't work and is actually counter-productive. It gets
worse with increasing signal propagation delays (signal in this case
means congestion indications). I actually wish I never introduced
the stupid IMQ device, it raises false hope and a lot of people seem
to fall for it.

> A set of VLAN devices could be redirected
> to such a FIFO device and let applications bind to it in order
> to implement trivial bind(INADDR_ANY) namespaces based on anything
> that can be selected by classifiers. This example would benefit
> from a conditional iif update (given that the mirred action is
> extended to take a flag to steer this) so applications like a
> dhcp daemon could use a raw socket on the FIFO device and thus
> benefit from the bind namespace but still access the original
> interface the packet was received from using pktinfo cmsg.
> 
> Maybe silly but the best I could come up with :-)

Doesn't sound too silly (actually quite nifty in my opinion),
but I'm not sure I understand correctly, binding to ifb doesn't
work since it changes both skb->dev and skb->input_dev.


^ permalink raw reply

* IOAT stuff
From: Randy.Dunlap @ 2006-06-26 22:29 UTC (permalink / raw)
  To: christopher.leech, andrew.grover; +Cc: netdev


drivers/dma/ioatdma.c:830: warning: no return statement in function returning non-void
drivers/dma/ioatdma.c:830: warning: control reaches end of non-void function

Maybe insert "return" in front of:

	pci_module_init(&ioat_pci_drv);

or is there some reason not to do that?

BTW, pci_module_init() is obsolete.  Drivers should be using
pci_register_driver() instead.


PS:  IOAT/DMA (whatever) needs a MAINTAINERS entry.

---
~Randy

^ permalink raw reply

* RE: [PATCH 01/06] MLSXFRM: Granular IPSec associations for use in MLS environments
From: Chad Hanson @ 2006-06-26 22:24 UTC (permalink / raw)
  To: James Morris, Venkat Yekkirala
  Cc: netdev, selinux, David S. Miller, Stephen Smalley

 
> There's also the question of ongoing maintenance in the
> mainline kernel.  Unfortunately, there's been an increasing
> trend recently for companies to drop code over the wall.  For 
> example, once they get it to some basic level of completeness,
> and the initial patches are merged, their developers are 
> reassigned to other projects and the upstream maintainers 
> are left with code that's not yet up to Linux kernel quality
> and also something they may not understand very well.  So, we
> need to know whether TCS or anyone else with expert knowledge
> of MLS will be helping months or years down the track, once this
> code has been merged.

We are prepared to help with ongoing support for maintenance and 
improvement of the code accepted into the kernel. We like having
the benefit of providing guidance for the OS security development,
which is needed for our solutions, even though there is some added
cost. This is one the reasons we are porting our solutions to Linux.
The bottom line is the security functionality is a necessary 
component for our applications, and we don't want to be dependent
on others to make sure the functionality is being maintained
correctly. 

-Chad

^ permalink raw reply

* Re: [patch 2/6] [Network namespace] Network device sharing by view
From: Ben Greear @ 2006-06-26 22:13 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Herbert Poetzl, Daniel Lezcano, Andrey Savochkin, linux-kernel,
	netdev, serue, haveblue, clg, Andrew Morton, dev, devel, sam,
	viro, Alexey Kuznetsov
In-Reply-To: <m1u067r9qk.fsf@ebiederm.dsl.xmission.com>

Eric W. Biederman wrote:

> Basically it is just a matter of:
> if (dest_mac == my_mac1) it is for device 1.
> If (dest_mac == my_mac2) it is for device 2.
> etc.
> 
> At a small count of macs it is trivial to understand it will go
> fast for a larger count of macs it only works with a good data
> structure.  We don't hit any extra cache lines of the packet,
> and the above test can be collapsed with other routing lookup tests.

I think you should do this at the layer-2 level, well before you get
to routing.  That will make the virtual mac-vlan work with arbitrary
protocols and appear very much like a regular ethernet interface.  This
approach worked well with .1q vlans, and with my version of the mac-vlan
module.

Using the mac-vlan and source-based routing tables, I can give a unique
'interface' to each process and have each process able to bind to the
same IP port, for instance.  Using source-based routing (by binding to a local
IP explicitly and adding a route table for that source IP), I can give unique
default routes to each interface as well.  Since we cannot have more than 256
routing tables, this approach is currently limitted to around 250 virtual
interfaces, but that is still a substantial amount.

My mac-vlan patch, redirect-device patch, and other hackings are consolidated
in this patch:

http://www.candelatech.com/oss/candela_2.6.16.patch

Thanks,
Ben

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


^ permalink raw reply

* Re: [patch 2/6] [Network namespace] Network device sharing by view
From: Eric W. Biederman @ 2006-06-26 22:11 UTC (permalink / raw)
  To: Herbert Poetzl
  Cc: Daniel Lezcano, Andrey Savochkin, linux-kernel, netdev, serue,
	haveblue, clg, Andrew Morton, dev, devel, sam, viro,
	Alexey Kuznetsov
In-Reply-To: <20060626212616.GA6053@MAIL.13thfloor.at>

Herbert Poetzl <herbert@13thfloor.at> writes:

> On Mon, Jun 26, 2006 at 02:37:15PM -0600, Eric W. Biederman wrote:
>> Herbert Poetzl <herbert@13thfloor.at> writes:
>> 
>> > On Mon, Jun 26, 2006 at 01:35:15PM -0600, Eric W. Biederman wrote:
>> >> Herbert Poetzl <herbert@13thfloor.at> writes:
>> >
>> > yes, but you will not be able to apply policy on
>> > the parent, restricting the child networking in a
>> > proper way without jumping through hoops ...
>> 
>> ?  I don't understand where you are coming from.
>> There is no restriction on where you can apply policy.
>
> in a fully hierarchical system (not that I really think
> this is required here) you would be able to 'delegate'
> certain addresses (ranges) to a namespace (the child)
> below the current one (the parent) with the ability to
> limit/control the input/output (which is required for 
> security)

All of that is possible with the current design.
It is merely a matter of using the features the kernel
currently has.

The trick is know that a child namespace only has a loopback
by default, and has to have a network interface added from
the parent to be able to talk to anything.


>> >> I really do not believe we have a hotpath issue, if this
>> >> is implemented properly. Benchmarks of course need to be taken,
>> >> to prove this.
>> >
>> > I'm fine with proper testing and good numbers here
>> > but until then, I can only consider it a prototype
>> 
>> We are taking the first steps to get this all sorted out.
>> I think what we have is more than a prototype but less then
>> the final implementation.  Call it the very first draft version.
>
> what we are desperately missing here is a proper way
> to testing this, maybe the network folks can come up
> with some test equipment/ideas here ...
>

>> That assumes on the wire stuff is noticeably slower.
>> You can achieve over 1GB/s on some networks.
>
> well, have you ever tried how much you can achieve
> over loopback :)

Not recently.

> well, local is fine, but you cannot utilize that 
> on-wire which basically means that you would have
> either to 'map' the MAC on transmission (to the
> real one) which would basically make the approach
> useless, or to use addresses which are fine within
> a certain range of routers ...

I believe on the wire is fine as well.  Certainly I had
no problems when I tested it.  I do agree that it increases
the chance for a mac address collision so should be handled
carefully.  But we are talking a number with almost as many random
bits as a UUID.

As I recall the rule from the birthday paradox is something like: if
you have N possibilities you get a 50% chance of collision when
you have sqrt(N) items present.  sqrt(2**40) = 2**20 ~= 1 Million.

So as long as you have a good random generator the odds of a collision
are quite small until you have used a million local mac addresses.

Now while I can see some small chance of that happening on a very
crowded local area network, using lots of logical servers the
kernel arp cache and switch mac cache limits would start causing
real problems long before you got that far.  So you would need to
start routing at which point the practical problem goes away.

>
> well, for loopback that would mean half the bandwidth
> and twice the latency, no?

Not at all.  The usual bottle neck is copying the data.  The data
only gets put in a skb once and then pointers to the skb are
passed around.  So you get copied in once and copied out once.
We are certainly not going to add an extra copy to it.

For practical purposes the fast path through the network stack 
is a series of hash table looks.

That added to the fact that we don't make a full trip through
the network stack on both sides (unless someone is running tcp dump)
for example.

>> If it does we have a lot more to optimize in the network stack than
>> just this code.
>
> why? duplicate stack traversal takes roughly twice
> the time, or am I wrong here? if so, please enlighten
> me ...

The network stack is how we decide what goes where.  Sending
and receiving packets should always have hardware as the bottleneck,
not software.  So software should be a tiny percentage of the time
it takes to send or receive any packet.

With packets limited to 1.5K and below things aren't always that
clear cut but the ideal remains.  But basically anything we can
do besides remove the copy in and the copy out of the network stack
we should do.

The copy in and the copy out are fundamentally hard to remove without
modifying page tables which because of tlb invalidates can be even
more expensive than a copy.

The best you can hope for on a loopback scenario is a single copy
from one user space buffer to another skipping the intermediate
kernel buffer.  But that is tricky for an entirely different set
of reasons.

Eric


^ permalink raw reply

* Re: [patch 1/2] tulip: fix for 64-bit mips
From: Valerie Henson @ 2006-06-26 22:07 UTC (permalink / raw)
  To: Grant Grundler
  Cc: Martin Michlmayr, akpm, jeff, netdev, maillist, pdh,
	Kyle McMartin
In-Reply-To: <20060625234400.GB29506@colo.lackof.org>

On Sun, Jun 25, 2006 at 05:44:00PM -0600, Grant Grundler wrote:
> On Sun, Jun 25, 2006 at 10:31:08AM +0100, Martin Michlmayr wrote:
> > * akpm@osdl.org <akpm@osdl.org> [2006-06-25 01:45]:
> > > Cc: Valerie Henson <val_henson@linux.intel.com>
> > > 
> > > [akpm: this is a previously-nacked patch, but the problem is real]
> 
> ia64 and parisc need the changes to tulip_select_media() too.
> 
> 
> > And, for the record, Jeff's suggestion as to how to rework the patch:
> > 
> > | Answer hasn't changed since this was last discussed:  sleep, rather than
> > | delay for an extra-long time.  That's the only hurdle for the tulip
> > | patches you keep resending.
> > 
> > | Francois Romieu even had an untested patch that attempted this,
> > | somewhere.
> > 
> > Now we just need someone to complete this work...
> 
> Kyle McMartin has the work queue patch merged into the cvs.parisc-linux.org
> CVS tree. It would be easiest to accept this patch and then add the
> tulip work queue patch next.

I like the work queue approach; I'll be talking with Kyle and Grant
about it.

> Note that the work queue does NOT solve all of the "spin delay with
> interrupts blocked" problems. tulip_stop_rxtx() polls for nearly as long
> and tulip_select_media().

Let's chat...

-VAL

^ permalink raw reply

* Re: [patch 2/6] [Network namespace] Network device sharing by view
From: Ben Greear @ 2006-06-26 21:59 UTC (permalink / raw)
  To: Herbert Poetzl
  Cc: Eric W. Biederman, Daniel Lezcano, Andrey Savochkin, linux-kernel,
	netdev, serue, haveblue, clg, Andrew Morton, dev, devel, sam,
	viro, Alexey Kuznetsov
In-Reply-To: <20060626212616.GA6053@MAIL.13thfloor.at>

Herbert Poetzl wrote:
> On Mon, Jun 26, 2006 at 02:37:15PM -0600, Eric W. Biederman wrote:
> 
>>Herbert Poetzl <herbert@13thfloor.at> writes:
>>
>>
>>>On Mon, Jun 26, 2006 at 01:35:15PM -0600, Eric W. Biederman wrote:
>>>
>>>>Herbert Poetzl <herbert@13thfloor.at> writes:
>>>
>>>yes, but you will not be able to apply policy on
>>>the parent, restricting the child networking in a
>>>proper way without jumping through hoops ...
>>
>>?  I don't understand where you are coming from.
>>There is no restriction on where you can apply policy.
> 
> 
> in a fully hierarchical system (not that I really think
> this is required here) you would be able to 'delegate'
> certain addresses (ranges) to a namespace (the child)
> below the current one (the parent) with the ability to
> limit/control the input/output (which is required for 
> security)
> 
> 
>>>>I really do not believe we have a hotpath issue, if this
>>>>is implemented properly. Benchmarks of course need to be taken,
>>>>to prove this.
>>>
>>>I'm fine with proper testing and good numbers here
>>>but until then, I can only consider it a prototype
>>
>>We are taking the first steps to get this all sorted out.
>>I think what we have is more than a prototype but less then
>>the final implementation.  Call it the very first draft version.
> 
> 
> what we are desperately missing here is a proper way
> to testing this, maybe the network folks can come up
> with some test equipment/ideas here ...
> 
> 
>>>>There are only two places a sane implementation should show issues.
>>>>- When the access to a pointer goes through a pointer to find
>>>>  that global variable.
>>>>- When doing a lookup in a hash table we need to look at an additional
>>>>  field to verify a hash match.  Because having a completely separate
>>>>  hash table is likely too expensive.
>>>>
>>>>If that can be shown to really slow down packets on the hot path I am
>>>>willing to consider other possibilities. Until then I think we are on
>>>>path to the simplest and most powerful version of building a network
>>>>namespace usable by containers.
>>>
>>>keep in mind that you actually have three kinds
>>>of network traffic on a typical host/guest system:
>>>
>>> - traffic between unit and outside
>>>   - host traffic should be quite minimal
>>>   - guest traffic will be quite high
>>>
>>> - traffic between host and guest
>>>   probably minimal too (only for shared services)
>>>
>>> - traffic between guests
>>>   can be as high (or even higher) than the
>>>   outbound traffic, just think web guest and
>>>   database guest
>>
>>Interesting.
>>
>>
>>>>The routing between network namespaces does have the potential to be
>>>>more expensive than just a packet trivially coming off the wire into a
>>>>socket.
>>>
>>>IMHO the routing between network namespaces should
>>>not require more than the current local traffic
>>>does (i.e. you should be able to achieve loopback
>>>speed within an insignificant tolerance) and not
>>>nearly the time required for on-wire stuff ...
>>
>>That assumes on the wire stuff is noticeably slower.
>>You can achieve over 1GB/s on some networks.
> 
> 
> well, have you ever tried how much you can achieve
> over loopback :)
> 
> 
>>But I agree that the cost should resemble the current
>>loopback device.  I have seen nothing that suggests
>>it is not.
>>
>>
>>>>However that is fundamentally from a lack of hardware. If the
>>>>rest works smarter filters in the drivers should enable to remove the
>>>>cost.
>>>>
>>>>Basically it is just a matter of:
>>>>if (dest_mac == my_mac1) it is for device 1.
>>>>If (dest_mac == my_mac2) it is for device 2.
>>>>etc.
>>>
>>>hmm, so you plan on providing a different MAC for
>>>each guest? how should that be handled from the
>>>user PoV? you cannot simply make up MACs as you
>>>go, and, depending on the network card, operation
>>>in promisc mode might be slower than for a given
>>>set (maybe only one) MAC, no?

> well, local is fine, but you cannot utilize that 
> on-wire which basically means that you would have
> either to 'map' the MAC on transmission (to the
> real one) which would basically make the approach
> useless, or to use addresses which are fine within
> a certain range of routers ...
> 
> 
>>With that set it is just a matter of using a decent random
>>number generator.  The kernel already does this is some places.
> 
> 
> sure you can make up MACs, but you will never
> be able to use them 'outside' the box 

I do it all the time with my mac-vlan patch and it works fine..so
long as you pay minimal attention.  Just let the user specify the
MAC addr and they can manage the uniqueness as they wish....

Ben

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


^ permalink raw reply

* Please pull 'upstream' branch of wireless-2.6
From: John W. Linville @ 2006-06-26 21:25 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit fcc18e83e1f6fd9fa6b333735bf0fcd530655511:
  Malcolm Parsons:
        uclinux: use PER_LINUX_32BIT in binfmt_flat

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake:
      bcm43xx: use softmac-suggested TX rate
      bcm43xx: enable shared key authentication

Eric Sesterhenn:
      skb used after passing to netif_rx in net/ieee80211/ieee80211_rx.c

Faidon Liambotis:
      Add two PLX device IDs

Hong Liu:
      ieee80211: fix not allocating IV+ICV space when usingencryption in ieee80211_tx_frame

Horms:
      CONFIG_WIRELESS_EXT is neccessary after all

John W. Linville:
      softmac: fix build-break from 881ee6999d66c8fc903b429b73bbe6045b38c549

Joseph Jezak:
      SoftMAC: Prevent multiple authentication attempts on the same network
      SoftMAC: Add network to ieee80211softmac_call_events when associate times out

Larry Finger:
      Convert bcm43xx-softmac to use the ieee80211_is_valid_channel routine
      2.6.17 missing a call to ieee80211softmac_capabilities from ieee80211softmac_assoc_req

Michael Buesch:
      bcm43xx: suspend MAC while executing long pwork
      bcm43xx: workaround init_board vs. IRQ race

 drivers/net/wireless/bcm43xx/bcm43xx.h         |    2 +
 drivers/net/wireless/bcm43xx/bcm43xx_main.c    |   82 +++++++++++++++---------
 drivers/net/wireless/bcm43xx/bcm43xx_main.h    |   24 -------
 drivers/net/wireless/bcm43xx/bcm43xx_radio.c   |    7 +-
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c      |    2 -
 drivers/net/wireless/bcm43xx/bcm43xx_xmit.c    |    5 +
 drivers/net/wireless/hostap/hostap_plx.c       |    2 +
 include/net/ieee80211softmac.h                 |    1 
 net/ieee80211/ieee80211_rx.c                   |    4 +
 net/ieee80211/ieee80211_tx.c                   |   15 +++-
 net/ieee80211/softmac/ieee80211softmac_assoc.c |   31 +++++++--
 net/ieee80211/softmac/ieee80211softmac_auth.c  |    4 +
 net/ieee80211/softmac/ieee80211softmac_io.c    |    3 +
 net/ieee80211/softmac/ieee80211softmac_wx.c    |   36 ++++++++++-
 14 files changed, 139 insertions(+), 79 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index d8f917c..d5e10e2 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -722,6 +722,8 @@ #endif
 	u32 irq_savedstate;
 	/* Link Quality calculation context. */
 	struct bcm43xx_noise_calculation noisecalc;
+	/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+	int mac_suspended;
 
 	/* Threshold values. */
 	//TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 085d785..af97755 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -1885,6 +1885,15 @@ static irqreturn_t bcm43xx_interrupt_han
 
 	spin_lock(&bcm->irq_lock);
 
+	/* Only accept IRQs, if we are initialized properly.
+	 * This avoids an RX race while initializing.
+	 * We should probably not enable IRQs before we are initialized
+	 * completely, but some careful work is needed to fix this. I think it
+	 * is best to stay with this cheap workaround for now... .
+	 */
+	if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
+		goto out;
+
 	reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
 	if (reason == 0xffffffff) {
 		/* irq not for us (shared irq) */
@@ -1906,19 +1915,11 @@ static irqreturn_t bcm43xx_interrupt_han
 
 	bcm43xx_interrupt_ack(bcm, reason);
 
-	/* Only accept IRQs, if we are initialized properly.
-	 * This avoids an RX race while initializing.
-	 * We should probably not enable IRQs before we are initialized
-	 * completely, but some careful work is needed to fix this. I think it
-	 * is best to stay with this cheap workaround for now... .
-	 */
-	if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
-		/* disable all IRQs. They are enabled again in the bottom half. */
-		bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-		/* save the reason code and call our bottom half. */
-		bcm->irq_reason = reason;
-		tasklet_schedule(&bcm->isr_tasklet);
-	}
+	/* disable all IRQs. They are enabled again in the bottom half. */
+	bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+	/* save the reason code and call our bottom half. */
+	bcm->irq_reason = reason;
+	tasklet_schedule(&bcm->isr_tasklet);
 
 out:
 	mmiowb();
@@ -2297,13 +2298,17 @@ static int bcm43xx_gpio_cleanup(struct b
 /* http://bcm-specs.sipsolutions.net/EnableMac */
 void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
 {
-	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
-	                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
-			| BCM43xx_SBF_MAC_ENABLED);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
-	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
-	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
-	bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+	bcm->mac_suspended--;
+	assert(bcm->mac_suspended >= 0);
+	if (bcm->mac_suspended == 0) {
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				| BCM43xx_SBF_MAC_ENABLED);
+		bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
+		bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+		bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+		bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+	}
 }
 
 /* http://bcm-specs.sipsolutions.net/SuspendMAC */
@@ -2312,18 +2317,23 @@ void bcm43xx_mac_suspend(struct bcm43xx_
 	int i;
 	u32 tmp;
 
-	bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
-	                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
-			& ~BCM43xx_SBF_MAC_ENABLED);
-	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
-	for (i = 100000; i; i--) {
-		tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
-		if (tmp & BCM43xx_IRQ_READY)
-			return;
-		udelay(10);
+	assert(bcm->mac_suspended >= 0);
+	if (bcm->mac_suspended == 0) {
+		bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				& ~BCM43xx_SBF_MAC_ENABLED);
+		bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+		for (i = 100000; i; i--) {
+			tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+			if (tmp & BCM43xx_IRQ_READY)
+				goto out;
+			udelay(10);
+		}
+		printkl(KERN_ERR PFX "MAC suspend failed\n");
 	}
-	printkl(KERN_ERR PFX "MAC suspend failed\n");
+out:
+	bcm->mac_suspended++;
 }
 
 void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
@@ -3181,8 +3191,10 @@ static void bcm43xx_periodic_work_handle
 		/* Periodic work will take a long time, so we want it to
 		 * be preemtible.
 		 */
-		bcm43xx_lock_irqonly(bcm, flags);
 		netif_stop_queue(bcm->net_dev);
+		synchronize_net();
+		bcm43xx_lock_irqonly(bcm, flags);
+		bcm43xx_mac_suspend(bcm);
 		if (bcm43xx_using_pio(bcm))
 			bcm43xx_pio_freeze_txqueues(bcm);
 		savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
@@ -3205,6 +3217,7 @@ static void bcm43xx_periodic_work_handle
 			bcm43xx_interrupt_enable(bcm, savedirqs);
 			if (bcm43xx_using_pio(bcm))
 				bcm43xx_pio_thaw_txqueues(bcm);
+			bcm43xx_mac_enable(bcm);
 		}
 		netif_wake_queue(bcm->net_dev);
 		mmiowb();
@@ -3661,6 +3674,10 @@ static void bcm43xx_ieee80211_set_securi
 		secinfo->encrypt = sec->encrypt;
 		dprintk(", .encrypt = %d", sec->encrypt);
 	}
+	if (sec->flags & SEC_AUTH_MODE) {
+		secinfo->auth_mode = sec->auth_mode;
+		dprintk(", .auth_mode = %d\n", sec->auth_mode);
+	}
 	dprintk("\n");
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
 	    !bcm->ieee->host_encrypt) {
@@ -3776,6 +3793,7 @@ static int bcm43xx_init_private(struct b
 	bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
 
 	bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+	bcm->mac_suspended = 1;
 	bcm->pci_dev = pci_dev;
 	bcm->net_dev = net_dev;
 	bcm->bad_frames_preempt = modparam_bad_frames_preempt;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index 30a202b..1164936 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -112,30 +112,6 @@ int bcm43xx_channel_to_freq(struct bcm43
 	return bcm43xx_channel_to_freq_bg(channel);
 }
 
-/* Lightweight function to check if a channel number is valid.
- * Note that this does _NOT_ check for geographical restrictions!
- */
-static inline
-int bcm43xx_is_valid_channel_a(u8 channel)
-{
-	return (channel >= IEEE80211_52GHZ_MIN_CHANNEL
-	       && channel <= IEEE80211_52GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel_bg(u8 channel)
-{
-	return (channel >= IEEE80211_24GHZ_MIN_CHANNEL
-	       && channel <= IEEE80211_24GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
-			     u8 channel)
-{
-	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
-		return bcm43xx_is_valid_channel_a(channel);
-	return bcm43xx_is_valid_channel_bg(channel);
-}
-
 void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
 void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index af5c0bf..bb9c484 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1594,11 +1594,11 @@ int bcm43xx_radio_selectchannel(struct b
 	u16 r8, tmp;
 	u16 freq;
 
+	if (!ieee80211_is_valid_channel(bcm->ieee, channel))
+		return -EINVAL;
 	if ((radio->manufact == 0x17F) &&
 	    (radio->version == 0x2060) &&
 	    (radio->revision == 1)) {
-		if (channel > 200)
-			return -EINVAL;
 		freq = channel2freq_a(channel);
 
 		r8 = bcm43xx_radio_read16(bcm, 0x0008);
@@ -1651,9 +1651,6 @@ int bcm43xx_radio_selectchannel(struct b
 		TODO();	//TODO:	TSSI2dbm workaround
 		bcm43xx_phy_xmitpower(bcm);//FIXME correct?
 	} else {
-		if ((channel < 1) || (channel > 14))
-			return -EINVAL;
-
 		if (synthetic_pu_workaround)
 			bcm43xx_synth_pu_workaround(bcm, channel);
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index c35cb3a..5c36e29 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -119,7 +119,7 @@ static int bcm43xx_wx_set_channelfreq(st
 		channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
 		freq = data->freq.m;
 	}
-	if (!bcm43xx_is_valid_channel(bcm, channel))
+	if (!ieee80211_is_valid_channel(bcm->ieee, channel))
 		goto out_unlock;
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		//ieee80211softmac_disassoc(softmac, $REASON);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index d8ece28..6dbd855 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -296,11 +296,14 @@ void bcm43xx_generate_txhdr(struct bcm43
 	u16 control = 0;
 	u16 wsec_rate = 0;
 	u16 encrypt_frame;
+	const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl));
+	const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT);
 
 	/* Now construct the TX header. */
 	memset(txhdr, 0, sizeof(*txhdr));
 
-	bitrate = bcm->softmac->txrates.default_rate;
+	bitrate = ieee80211softmac_suggest_txrate(bcm->softmac,
+		is_multicast_ether_addr(wireless_header->addr1), is_mgt);
 	ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
 	fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
 	fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index edaaa94..39c545e 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -67,10 +67,12 @@ static struct pci_device_id prism2_plx_i
 	PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
 	PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
 	PLXDEV(0x126c, 0x8030, "Nortel emobility"),
+	PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
 	PLXDEV(0x1385, 0x4100, "Netgear MA301"),
 	PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
 	PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
 	PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
+	PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
 	PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
 	PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
 	PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h
index 7a483ab..00ad810 100644
--- a/include/net/ieee80211softmac.h
+++ b/include/net/ieee80211softmac.h
@@ -104,6 +104,7 @@ struct ieee80211softmac_assoc_info {
 	 */
 	u8 static_essid:1,
 	   associating:1,
+	   assoc_wait:1,
 	   bssvalid:1,
 	   bssfixed:1;
 
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 2bf567f..b2fabbb 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -369,6 +369,7 @@ #endif
 
 	/* Put this code here so that we avoid duplicating it in all
 	 * Rx paths. - Jean II */
+#ifdef CONFIG_WIRELESS_EXT
 #ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
 	/* If spy monitoring on */
 	if (ieee->spy_data.spy_number > 0) {
@@ -397,15 +398,16 @@ #ifdef IW_WIRELESS_SPY		/* defined in iw
 		wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
 	}
 #endif				/* IW_WIRELESS_SPY */
+#endif				/* CONFIG_WIRELESS_EXT */
 
 #ifdef NOT_YET
 	hostap_update_rx_stats(local->ap, hdr, rx_stats);
 #endif
 
 	if (ieee->iw_mode == IW_MODE_MONITOR) {
-		ieee80211_monitor_rx(ieee, skb, rx_stats);
 		stats->rx_packets++;
 		stats->rx_bytes += skb->len;
+		ieee80211_monitor_rx(ieee, skb, rx_stats);
 		return 1;
 	}
 
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index 6a5de1b..e63bf77 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -563,10 +563,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
@@ -582,20 +585,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];
 
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index 5e9a906..44215ce 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -47,9 +47,7 @@ ieee80211softmac_assoc(struct ieee80211s
 	
 	dprintk(KERN_INFO PFX "sent association request!\n");
 
-	/* Change the state to associating */
 	spin_lock_irqsave(&mac->lock, flags);
-	mac->associnfo.associating = 1;
 	mac->associated = 0; /* just to make sure */
 
 	/* Set a timer for timeout */
@@ -63,6 +61,7 @@ void
 ieee80211softmac_assoc_timeout(void *d)
 {
 	struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
+	struct ieee80211softmac_network *n;
 	unsigned long flags;
 
 	spin_lock_irqsave(&mac->lock, flags);
@@ -75,11 +74,12 @@ ieee80211softmac_assoc_timeout(void *d)
 	mac->associnfo.associating = 0;
 	mac->associnfo.bssvalid = 0;
 	mac->associated = 0;
+
+	n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
 	spin_unlock_irqrestore(&mac->lock, flags);
 
 	dprintk(KERN_INFO PFX "assoc request timed out!\n");
-	/* FIXME: we need to know the network here. that requires a bit of restructuring */
-	ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
+	ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
 }
 
 void
@@ -203,6 +203,10 @@ ieee80211softmac_assoc_work(void *d)
 	if (mac->associated)
 		ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
 
+	spin_lock_irqsave(&mac->lock, flags);
+	mac->associnfo.associating = 1;
+	spin_unlock_irqrestore(&mac->lock, flags);
+
 	/* try to find the requested network in our list, if we found one already */
 	if (bssvalid || mac->associnfo.bssfixed)
 		found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);	
@@ -295,19 +299,32 @@ ieee80211softmac_assoc_work(void *d)
 	memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
 	
 	/* we found a network! authenticate (if necessary) and associate to it. */
-	if (!found->authenticated) {
+	if (found->authenticating) {
+		dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
+		if(!mac->associnfo.assoc_wait) {
+			mac->associnfo.assoc_wait = 1;
+			ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+		}
+		return;
+	}
+	if (!found->authenticated && !found->authenticating) {
 		/* This relies on the fact that _auth_req only queues the work,
 		 * otherwise adding the notification would be racy. */
 		if (!ieee80211softmac_auth_req(mac, found)) {
-			dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n");
-			ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+			if(!mac->associnfo.assoc_wait) {
+				dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n");
+				mac->associnfo.assoc_wait = 1;
+				ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+			}
 		} else {
 			printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
+			mac->associnfo.assoc_wait = 0;
 			ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
 		}
 		return;
 	}
 	/* finally! now we can start associating */
+	mac->associnfo.assoc_wait = 0;
 	ieee80211softmac_assoc(mac, found);
 }
 
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
index 90b8484..ebc33ca 100644
--- a/net/ieee80211/softmac/ieee80211softmac_auth.c
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -36,8 +36,9 @@ ieee80211softmac_auth_req(struct ieee802
 	struct ieee80211softmac_auth_queue_item *auth;
 	unsigned long flags;
 	
-	if (net->authenticating)
+	if (net->authenticating || net->authenticated)
 		return 0;
+	net->authenticating = 1;
 
 	/* Add the network if it's not already added */
 	ieee80211softmac_add_network(mac, net);
@@ -92,7 +93,6 @@ ieee80211softmac_auth_queue(void *data)
 			return;
 		}
 		net->authenticated = 0;
-		net->authenticating = 1;
 		/* add a timeout call so we eventually give up waiting for an auth reply */
 		schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
 		auth->retry--;
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
index 0954161..8cc8b20 100644
--- a/net/ieee80211/softmac/ieee80211softmac_io.c
+++ b/net/ieee80211/softmac/ieee80211softmac_io.c
@@ -229,6 +229,9 @@ ieee80211softmac_assoc_req(struct ieee80
 		return 0;
 	ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
 
+	/* Fill in the capabilities */
+	(*pkt)->capability = ieee80211softmac_capabilities(mac, net);
+
 	/* Fill in Listen Interval (?) */
 	(*pkt)->listen_interval = cpu_to_le16(10);
 	
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 0e65ff4..75320b6 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -70,12 +70,44 @@ ieee80211softmac_wx_set_essid(struct net
 			      char *extra)
 {
 	struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
+	struct ieee80211softmac_network *n;
+	struct ieee80211softmac_auth_queue_item *authptr;
 	int length = 0;
 	unsigned long flags;
-	
+
+	/* Check if we're already associating to this or another network
+	 * If it's another network, cancel and start over with our new network
+	 * If it's our network, ignore the change, we're already doing it!
+	 */
+	if((sm->associnfo.associating || sm->associated) &&
+	   (data->essid.flags && data->essid.length && extra)) {
+		/* Get the associating network */
+		n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
+		if(n && n->essid.len == (data->essid.length - 1) &&
+		   !memcmp(n->essid.data, extra, n->essid.len)) {
+			dprintk(KERN_INFO PFX "Already associating or associated to "MAC_FMT"\n",
+				MAC_ARG(sm->associnfo.bssid));
+			return 0;
+		} else {
+			dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
+			spin_lock_irqsave(&sm->lock,flags);
+			/* Cancel assoc work */
+			cancel_delayed_work(&sm->associnfo.work);
+			/* We don't have to do this, but it's a little cleaner */
+			list_for_each_entry(authptr, &sm->auth_queue, list)
+				cancel_delayed_work(&authptr->work);
+			sm->associnfo.bssvalid = 0;
+			sm->associnfo.bssfixed = 0;
+			spin_unlock_irqrestore(&sm->lock,flags);
+			flush_scheduled_work();
+		}
+	}
+
+
 	spin_lock_irqsave(&sm->lock, flags);
-	
+
 	sm->associnfo.static_essid = 0;
+	sm->associnfo.assoc_wait = 0;
 
 	if (data->essid.flags && data->essid.length && extra /*required?*/) {
 		length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related

* Re: [patch 2/6] [Network namespace] Network device sharing by view
From: Herbert Poetzl @ 2006-06-26 21:26 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Daniel Lezcano, Andrey Savochkin, linux-kernel, netdev, serue,
	haveblue, clg, Andrew Morton, dev, devel, sam, viro,
	Alexey Kuznetsov
In-Reply-To: <m1u067psas.fsf@ebiederm.dsl.xmission.com>

On Mon, Jun 26, 2006 at 02:37:15PM -0600, Eric W. Biederman wrote:
> Herbert Poetzl <herbert@13thfloor.at> writes:
> 
> > On Mon, Jun 26, 2006 at 01:35:15PM -0600, Eric W. Biederman wrote:
> >> Herbert Poetzl <herbert@13thfloor.at> writes:
> >
> > yes, but you will not be able to apply policy on
> > the parent, restricting the child networking in a
> > proper way without jumping through hoops ...
> 
> ?  I don't understand where you are coming from.
> There is no restriction on where you can apply policy.

in a fully hierarchical system (not that I really think
this is required here) you would be able to 'delegate'
certain addresses (ranges) to a namespace (the child)
below the current one (the parent) with the ability to
limit/control the input/output (which is required for 
security)

> >> I really do not believe we have a hotpath issue, if this
> >> is implemented properly. Benchmarks of course need to be taken,
> >> to prove this.
> >
> > I'm fine with proper testing and good numbers here
> > but until then, I can only consider it a prototype
> 
> We are taking the first steps to get this all sorted out.
> I think what we have is more than a prototype but less then
> the final implementation.  Call it the very first draft version.

what we are desperately missing here is a proper way
to testing this, maybe the network folks can come up
with some test equipment/ideas here ...

> >> There are only two places a sane implementation should show issues.
> >> - When the access to a pointer goes through a pointer to find
> >>   that global variable.
> >> - When doing a lookup in a hash table we need to look at an additional
> >>   field to verify a hash match.  Because having a completely separate
> >>   hash table is likely too expensive.
> >> 
> >> If that can be shown to really slow down packets on the hot path I am
> >> willing to consider other possibilities. Until then I think we are on
> >> path to the simplest and most powerful version of building a network
> >> namespace usable by containers.
> >
> > keep in mind that you actually have three kinds
> > of network traffic on a typical host/guest system:
> >
> >  - traffic between unit and outside
> >    - host traffic should be quite minimal
> >    - guest traffic will be quite high
> >
> >  - traffic between host and guest
> >    probably minimal too (only for shared services)
> >
> >  - traffic between guests
> >    can be as high (or even higher) than the
> >    outbound traffic, just think web guest and
> >    database guest
> 
> Interesting.
> 
> >> The routing between network namespaces does have the potential to be
> >> more expensive than just a packet trivially coming off the wire into a
> >> socket.
> >
> > IMHO the routing between network namespaces should
> > not require more than the current local traffic
> > does (i.e. you should be able to achieve loopback
> > speed within an insignificant tolerance) and not
> > nearly the time required for on-wire stuff ...
> 
> That assumes on the wire stuff is noticeably slower.
> You can achieve over 1GB/s on some networks.

well, have you ever tried how much you can achieve
over loopback :)

> But I agree that the cost should resemble the current
> loopback device.  I have seen nothing that suggests
> it is not.
> 
> >> However that is fundamentally from a lack of hardware. If the
> >> rest works smarter filters in the drivers should enable to remove the
> >> cost.
> >> 
> >> Basically it is just a matter of:
> >> if (dest_mac == my_mac1) it is for device 1.
> >> If (dest_mac == my_mac2) it is for device 2.
> >> etc.
> >
> > hmm, so you plan on providing a different MAC for
> > each guest? how should that be handled from the
> > user PoV? you cannot simply make up MACs as you
> > go, and, depending on the network card, operation
> > in promisc mode might be slower than for a given
> > set (maybe only one) MAC, no?
> 
> The speed is a factor certainly.  As for making up
> macs.  There is a local assignment bit that you can set.

well, local is fine, but you cannot utilize that 
on-wire which basically means that you would have
either to 'map' the MAC on transmission (to the
real one) which would basically make the approach
useless, or to use addresses which are fine within
a certain range of routers ...

> With that set it is just a matter of using a decent random
> number generator.  The kernel already does this is some places.

sure you can make up MACs, but you will never
be able to use them 'outside' the box 

> >> At a small count of macs it is trivial to understand it will go
> >> fast for a larger count of macs it only works with a good data
> >> structure.  We don't hit any extra cache lines of the packet,
> >> and the above test can be collapsed with other routing lookup tests.
> >
> > well, I'm absolutely not against flexibility or
> > full virtualization, but the proposed 'routing'
> > on the host effectively doubles the time the
> > packet spends in the network stack(s), so I can
> > not believe that this approach would not add
> > (significant) overhead to the hot path ...
> 
> It might, but I am pretty certain it won't double
> the cost, as you don't do 2 full network stack traversals.

> And even at a full doubling I doubt it will affect bandwith
> or latency very much.  

well, for loopback that would mean half the bandwidth
and twice the latency, no?

> If it does we have a lot more to optimize in the network stack than
> just this code.

why? duplicate stack traversal takes roughly twice
the time, or am I wrong here? if so, please enlighten
me ...

best,
Herbert

> Eric

^ permalink raw reply

* Re: [patch 1/4] Network namespaces: cleanup of dev_base list use
From: Eric W. Biederman @ 2006-06-26 21:02 UTC (permalink / raw)
  To: Andrey Savochkin
  Cc: dlezcano, linux-kernel, netdev, serue, haveblue, clg,
	Andrew Morton, dev, herbert, devel, sam, viro, Alexey Kuznetsov
In-Reply-To: <20060627001437.A5285@castle.nmd.msu.ru>

Andrey Savochkin <saw@swsoft.com> writes:

> Eric,
>
> On Mon, Jun 26, 2006 at 10:26:23AM -0600, Eric W. Biederman wrote:
>> 
>> 
> [snip]
>> It is a big enough problem that I don't think we want to gate on
>> that development but we need to be ready to take advantage of it when
>> it happens.
>
> Well, ok, implicit namespace reference will take advantage of it
> if it happens.

And if fact in that case we don't have to do anything special because
the process pointer will always be correct.

>> >> However short of always having code always execute in the proper
>> >> context I'm not comfortable with implicit parameters to functions.
>> >> Not that this the contents of this patch should address this but the
>> >> later patches should.
>> >
>> > We just have too many layers in networking code, and FIB/routing
>> > illustrates it well.
>> 
>> I don't follow this comment.  How does a lot of layers affect
>> the choice of implicit or explicit parameters?  If you are maintaining
>> a patch outside the kernel I could see how there could be a win for
>> touching the least amount of code possible but for merged code that
>> you only have to go through once I don't see how the number of layers
>> affects things.
>
> I agree that implicit vs explicit parameters is a topic for discussion.
> From what you see from my patch, I vote for implicit ones in this case :)

Yes.  I tend to be against implicit namespaces references mostly because
the explicit ones tend to make the code clearer.

> I was talking about layers because they imply changing more code,
> and usually imply adding more parameters to functions and passing these
> additional parameters to next layers.
> In "routing" code it goes from routing entry points, to routing cache, to
> general FIB functions, to table-specific code (FIB hash).

Yes.  Although as I recall you don't have to pass anything down very far.
Because most functions once you have done the table lookup operate
on just a subset of the table, when they are getting the real work done.

> These additional parameters bloat the code to some extent.
> Sometimes it's possible to save here and there by fetching the parameter
> (namespace pointer) indirectly from structures you already have at hand,
> but it can't be done universally.
>
> One of the properties of implicit argument which I especially like
> is that both input and output paths are absolutely symmetric in how
> the namespace pointer is extracted.

There is an element of that.  In the output path for the most part everything
works implicitly because you are in the proper context.

I need to dig out my code and start comparing to what you have done.

Eric

^ permalink raw reply

* [Repost PATCH 6/6] PMC MSP85x0 gigabit ethernet driver
From: Kiran Thota @ 2006-06-26 20:58 UTC (permalink / raw)
  To: 'Yoichi Yuasa'; +Cc: linux-mips, netdev, Raj Palani, ralf

Yoichi, your suggestion implemented...
  
 - Based on linux-2.6.12 from 
 http://www.linux-mips.org/pub/linux/mips/kernel/v2.6/linux-2.6.12.tar.gz
 - Rewritten clean driver for PMC MSP85x0 gigabit ethernet driver (planning a rewritten titan driver) \
   source, Kconfig and makefile

Signed-off-by: Kiran Kumar Thota <Kiran_Thota@pmc-sierra.com>


diff -Naur a/drivers/net/Kconfig b/drivers/net/Kconfig
--- a/drivers/net/Kconfig	2005-07-11 11:28:10.000000000 -0700
+++ b/drivers/net/Kconfig	2006-06-26 10:14:44.000000000 -0700
@@ -2103,6 +2103,13 @@
 	  This enables support for the the integrated ethernet of
 	  PMC-Sierra's Titan SoC.
 
+config MSP85X0_GE
+	bool "PMC-Sierra MSP85x0/RM915x Gigabit Ethernet Support"
+	depends on PMC_SEQUOIA
+	help
+	  This enables support for the the integrated ethernet of
+	  PMC-Sierra's MSP85x0/RM915X SoC.
+
 endmenu
 
 #
diff -Naur a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	2005-07-11 11:28:10.000000000 -0700
+++ b/drivers/net/Makefile	2006-06-26 10:15:12.000000000 -0700
@@ -103,6 +103,7 @@
 obj-$(CONFIG_GALILEO_64240_ETH) += gt64240eth.o
 obj-$(CONFIG_MV64340_ETH) += mv64340_eth.o
 obj-$(CONFIG_BIG_SUR_FE) += big_sur_ge.o
+obj-$(CONFIG_MSP85X0_GE) += titan_mdio.o msp85x0_ge.o
 obj-$(CONFIG_TITAN_GE) += titan_mdio.o titan_ge.o
 
 obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
diff -Naur a/drivers/net/msp85x0_ge.c b/drivers/net/msp85x0_ge.c
--- a/drivers/net/msp85x0_ge.c	1969-12-31 16:00:00.000000000 -0800
+++ b/drivers/net/msp85x0_ge.c	2006-06-26 12:12:39.000000000 -0700
@@ -0,0 +1,2142 @@
+/*
+ * drivers/net/msp85x0_ge.c - Driver for MSP85x0 ethernet ports
+ *
+ * Copyright (C) 2006 PMC-Sierra Inc.
+ *
+ * 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.
+ */
+
+/*
+ * The MAC unit of the MSP85x0 consists of the following:
+ *
+ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO
+ * -> FIFO is where the incoming and outgoing data is placed
+ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes
+ *    the data into the FIFO for Rx
+ * -> TMAC is the outgoing MAC interface and RMAC is the incoming.
+ * -> AFX is the address filtering block
+ * -> GMII block to communicate with the PHY
+ *
+ * Rx will look like the following:
+ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory
+ *
+ * Tx will look like the following:
+ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII
+ *
+ * The MSP85x0 driver has support for the following performance features:
+ * -> Rx side checksumming
+ * -> Jumbo Frames
+ * -> Interrupt Coalscing
+ * -> Rx NAPI
+ * -> SKB Recycling
+ * -> Transmit/Receive descriptors in SRAM
+ * -> Fast routing for IP forwarding
+ *
+ * 19Apr2006 -  Rewritten the code with functions modularized,  
+ *	 	hardcoding registers values removed, cleaned up the code
+ *		to support only the msp85x0. The interrupt handler,
+ *		poll function, descriptor freeing routine and close
+ *		routines are modified. 
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <linux/in.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/prefetch.h>
+
+/* For MII specifc registers, msp85x0_mdio.h should be included */
+#include <net/ip.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/pmc_sequoia.h>
+#include <linux/proc_fs.h>
+#include <linux/netpoll.h>
+#include <linux/timer.h>
+
+#include "msp85x0_ge.h"
+#include "titan_mdio.h"
+
+#ifdef MSP85x0_GE_DEBUG
+#define GE_DBG(x,y) 		printk(KERN_DBG x , y) 
+#define DUMP_SKB_DATA(x)	dump_skb_data(x)
+#define DUMP_SKB_FRAME(x)	dump_skb_frame(x)
+#else
+#define DUMP_SKB_DATA(x)
+#define DUMP_SKB_FRAME(x)
+#define GE_DBG(x,y)
+#endif
+
+#define GET_GE_VERSION(x)	(x & 0x0f000000) >> 16
+#define GET_GE_ID(x)		(x & 0x00ffffff)
+#define XDMA_PORT_OFFSET	9
+#define SQDPF_RX_PORT_OFFSET	0x60
+#define SQDPF_TX_PORT_OFFSET	0x0C
+#define XDMA_CHANNEL_OFFSET	16
+#define NO_ADDRESS_FILTERS	16
+#define NO_PORTS 		2
+#define INTERRUPT_HANDLER	msp85x0_ge_sequoia_int_handler
+
+#define PKT_PAD_BYTES(x)	((x) | (x << 8) | ( x << 16) | (x << 24))
+#define	TX_THRESHOLD		8 
+#define	RX_THRESHOLD		32
+#define TRTG2_PORT_OFFSET	12
+#define MAC_PORT_OFFSET		12
+#define MII_PORT_OFFSET		12
+
+	
+#define TX_INT	2
+#define RX_INT	1
+
+#define MSP85x0_GE_WRITE	TITAN_GE_WRITE
+#define MSP85x0_GE_READ		TITAN_GE_READ
+
+#define ETHERNET_FCS_SIZE            4
+
+#define DMA_CACHE_WBACK_INV(x,y)
+#define       IOMAP(x,y)              ioremap_nocache((x),(y))
+
+// Function declared in arch/mips/pmc-sierra/sequoia/setup.c
+extern unsigned long titan_ge_base;
+
+extern unsigned long rm9150_dma_base;
+
+static spinlock_t msp85x0_lock;
+
+static unsigned int port0_pkt_count=0, port1_pkt_count=0;
+
+/* Static Function Declarations	 */
+static int msp85x0_ge_eth_open(struct net_device *);
+static int msp85x0_ge_eth_reopen(struct net_device *netdev);
+static void msp85x0_ge_eth_stop(struct net_device *);
+static struct net_device_stats *msp85x0_ge_get_stats(struct net_device *);
+static int msp85x0_ge_init_rx_desc_ring(msp85x0_ge_port_info *, int, int,
+				      unsigned long, unsigned long,
+				      unsigned long);
+static int msp85x0_ge_init_tx_desc_ring(msp85x0_ge_port_info *, int,
+				      unsigned long, unsigned long);
+
+static int msp85x0_ge_open(struct net_device *);
+static int msp85x0_ge_start_xmit(struct sk_buff *, struct net_device *);
+static int msp85x0_ge_stop(struct net_device *);
+
+static unsigned int msp85x0_ge_tx_coal(int);
+
+static void msp85x0_ge_port_reset(unsigned int);
+static int msp85x0_ge_free_tx_queue(struct net_device *);
+static int msp85x0_ge_rx_task(struct net_device *, msp85x0_ge_port_info *);
+static int msp85x0_ge_port_start(struct net_device *);
+static int msp85x0_eth_setup_tx_rx_fifo(struct net_device *dev);
+static int msp85x0_ge_xdma_reset(void);
+
+/*
+ * Some configuration for the FIFO and the XDMA channel needs
+ * to be done only once for all the ports. This flag controls
+ * that
+ */
+static unsigned long config_done;
+
+/*
+ * One time out of memory flag
+ */
+static unsigned int oom_flag;
+
+static int msp85x0_ge_poll(struct net_device *netdev, int *budget);
+static int msp85x0_ge_receive_queue(struct net_device *);
+
+static struct platform_device *msp85x0_ge_device[NO_PORTS];
+static struct net_device *msp85x0_eth[NO_PORTS];
+static unsigned int msp85x0_ge_sram;
+static unsigned int port_number;
+
+/*
+ * The MSP85x0 GE has two alignment requirements:
+ * -> skb->data to be cacheline aligned (32 byte)
+ * -> IP header alignment to 16 bytes
+ *
+ * The latter is not implemented. So, that results in an extra copy on
+ * the Rx. This is a big performance hog. For the former case, the
+ * dev_alloc_skb() has been replaced with msp85x0_ge_alloc_skb(). The size
+ * requested is calculated:
+ *
+ * Ethernet Frame Size : 1518
+ * Ethernet Header     : 14
+ * Future MSP85x0 change for IP header alignment : 2
+ *
+ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes.  For IP header
+ * alignment, we use skb_reserve().
+ */
+#define ALIGNED_RX_SKB_ADDR(addr) \
+	((((unsigned long)(addr) + (32UL - 1UL)) \
+	& ~(32UL - 1UL)) - (unsigned long)(addr))
+#define msp85x0_ge_alloc_skb(__length, __gfp_flags) \
+({      struct sk_buff *__skb; \
+	__skb = alloc_skb((__length),(__gfp_flags)); \
+	if(__skb){ \
+		int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \
+		if(__offset) \
+			skb_reserve(__skb, __offset); \
+	} \
+	__skb; \
+})
+
+int increment_tx_pkt_count(unsigned int port)
+{
+	unsigned int flags;
+	spin_lock_irqsave(&msp85x0_lock,flags);
+	if(port==0){
+		port0_pkt_count++;
+	}
+	else{
+		port1_pkt_count++;	
+	}
+	spin_unlock_irqrestore(&msp85x0_lock,flags);
+	return 0;
+}
+
+unsigned int get_tx_pkt_count(unsigned int port)
+{
+	unsigned int flags,pktCount,tx_pending_pkt;
+	spin_lock_irqsave(&msp85x0_lock,flags);
+	tx_pending_pkt=MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_TX_DMA_STS + (port << XDMA_PORT_OFFSET));
+	if(port==0){
+		pktCount=port0_pkt_count - tx_pending_pkt;
+	}
+	else{
+		pktCount=port1_pkt_count - tx_pending_pkt;	
+	}
+	spin_unlock_irqrestore(&msp85x0_lock,flags);
+	return pktCount;	
+}
+
+unsigned int decrement_tx_pkt_count(unsigned int port)
+{
+	unsigned int flags;
+	spin_lock_irqsave(&msp85x0_lock,flags);
+	if(port==0){
+		port0_pkt_count--;
+	}
+	else{
+		port1_pkt_count--;	
+	}
+	spin_unlock_irqrestore(&msp85x0_lock,flags);
+	return 0;	
+}
+void msp85x0_bringup_sequence(int port)
+{
+   	unsigned int reg_data;
+
+	/* SDQPF */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_SDQPF_RXFIFO_CTL + (port << 8));
+	reg_data &=~(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_SDQPF_RXFIFO_CTL + (port << 8),reg_data);
+	/* TRTG  */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_TRTG_CONFIG + (port << TRTG2_PORT_OFFSET));
+	reg_data |=(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_TRTG_CONFIG + (port << TRTG2_PORT_OFFSET),reg_data);
+	/* GMII TX/RX DISABLE PORT 0  */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_GMII_CONFIG_GENERAL + (port << MAC_PORT_OFFSET));
+	reg_data |=(0x3);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_GMII_CONFIG_GENERAL + (port << MAC_PORT_OFFSET),reg_data);
+	/* TMAC */    
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_TMAC_CONFIG_1 + (port << MAC_PORT_OFFSET));
+	reg_data |=(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_TMAC_CONFIG_1 + (port << MAC_PORT_OFFSET),reg_data);
+	/* L1TPP */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_L1TPP_CONFIG + (port << MAC_PORT_OFFSET));
+	reg_data &=~(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_L1TPP_CONFIG + (port << MAC_PORT_OFFSET),reg_data);
+	/* L1RPP */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_L1RPP_CONFIG_STS+ (port << MAC_PORT_OFFSET));
+	reg_data &=~(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_L1RPP_CONFIG_STS + (port << MAC_PORT_OFFSET),reg_data);
+	/* RTIF  */ 
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_RTIF_CONFIG + (port << MAC_PORT_OFFSET));
+	reg_data |=(0x4000);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_RTIF_CONFIG + (port << MAC_PORT_OFFSET),reg_data);
+	/* RMAC  */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_RMAC_CONFIG_1+ (port << MAC_PORT_OFFSET));
+	reg_data |=(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_RMAC_CONFIG_1+ (port << MAC_PORT_OFFSET),reg_data);
+}
+
+void msp85x0_reset_sequence(int port)
+{
+   	unsigned int reg_data;
+	/* RMAC */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_RMAC_CONFIG_1+ (port << MAC_PORT_OFFSET));
+	reg_data &=~(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_RMAC_CONFIG_1+ (port << MAC_PORT_OFFSET),reg_data);
+	/* RTIF */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_RTIF_CONFIG + (port << MAC_PORT_OFFSET));
+	reg_data &=~(0x4000);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_RTIF_CONFIG + (port << MAC_PORT_OFFSET),reg_data);
+	/* L1RPP */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_L1RPP_CONFIG_STS+ (port << MAC_PORT_OFFSET));
+	reg_data &=~(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_L1RPP_CONFIG_STS + (port << MAC_PORT_OFFSET),reg_data);
+	/* L1TPP */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_L1TPP_CONFIG + (port << MAC_PORT_OFFSET));
+	reg_data &=~(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_L1TPP_CONFIG + (port << MAC_PORT_OFFSET),reg_data);
+	/* TMAC  */    
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_TMAC_CONFIG_1 + (port << MAC_PORT_OFFSET));
+	reg_data &=~(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_TMAC_CONFIG_1 + (port << MAC_PORT_OFFSET),reg_data);
+	/* GMII TX/RX DISABLE PORT 0  */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_GMII_CONFIG_GENERAL + (port << MAC_PORT_OFFSET));
+	reg_data &=~(0x3);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_GMII_CONFIG_GENERAL + (port << MAC_PORT_OFFSET),reg_data);
+	/* TRTG  */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_TRTG_CONFIG + (port << TRTG2_PORT_OFFSET));
+	reg_data &=~(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_TRTG_CONFIG + (port << TRTG2_PORT_OFFSET),reg_data);
+	/* SDQPF */
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_SDQPF_RXFIFO_CTL + (port << 8));
+	reg_data |=0x1;	
+	MSP85x0_GE_WRITE(MSP85x0_GE_SDQPF_RXFIFO_CTL + (port << 8),reg_data);
+	reg_data &=~(0x1);	
+	MSP85x0_GE_WRITE(MSP85x0_GE_SDQPF_RXFIFO_CTL + (port << 8),reg_data);
+}
+
+static int msp85x0_ge_xdma_reset()
+{
+	unsigned int reg_data;
+
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_RESET);
+	reg_data |= 1 << (8);
+	MSP85x0_GE_WRITE(MSP85x0_GE_RESET,reg_data);
+	mdelay(50);
+	reg_data &= ~(1 << 8);
+	MSP85x0_GE_WRITE(MSP85x0_GE_RESET,reg_data);
+	return 0;
+}
+
+/*
+ * Configure the GMII block of the MSP85x0 based on what the PHY tells us
+ */
+static void msp85x0_ge_gmii_config(int port_num)
+{
+	unsigned int reg_data = 0, phy_reg;
+	int err;
+
+	err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
+
+	if (err == TITAN_GE_MDIO_ERROR) {
+		printk(KERN_ERR
+		       "Could not read PHY control register 0x11 \n");
+		
+		printk(KERN_ERR
+			"Setting speed to 1000 Mbps and Duplex to Full \n");
+
+		return;
+	}
+
+	err = titan_ge_mdio_write(port_num, TITAN_GE_MDIO_PHY_IE, 0);
+
+	if (phy_reg & 0x8000) {
+		if (phy_reg & 0x2000) {
+			/* Full Duplex and 1000 Mbps */
+			MSP85x0_GE_WRITE((MSP85x0_GE_GMII_CONFIG_MODE +
+					(port_num << MII_PORT_OFFSET)), 0x201);
+		}  else {
+			/* Half Duplex and 1000 Mbps */
+			MSP85x0_GE_WRITE((MSP85x0_GE_GMII_CONFIG_MODE +
+					(port_num << MII_PORT_OFFSET)), 0x2201);
+			}
+	}
+	if (phy_reg & 0x4000) {
+		if (phy_reg & 0x2000) {
+			/* Full Duplex and 100 Mbps */
+			MSP85x0_GE_WRITE((MSP85x0_GE_GMII_CONFIG_MODE +
+					(port_num << MII_PORT_OFFSET)), 0x100);
+		} else {
+			/* Half Duplex and 100 Mbps */
+			MSP85x0_GE_WRITE((MSP85x0_GE_GMII_CONFIG_MODE +
+					(port_num << MII_PORT_OFFSET)), 0x2100);
+		}
+	}
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_GMII_CONFIG_GENERAL +
+				(port_num << MII_PORT_OFFSET));
+	reg_data |= 0x3;
+	MSP85x0_GE_WRITE((MSP85x0_GE_GMII_CONFIG_GENERAL +
+			(port_num << MII_PORT_OFFSET)), reg_data);
+}
+
+/*
+ * Enable the TMAC if it is not
+ */
+static void msp85x0_ge_enable_tx(unsigned int port_num)
+{
+	unsigned long reg_data;
+
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_TMAC_CONFIG_1 + (port_num << MAC_PORT_OFFSET));
+	if (!(reg_data & 0x8000)) {
+		printk("TMAC disabled for port %d!! \n", port_num);
+
+		reg_data |= 0x0001;	/* Enable TMAC */
+		reg_data |= 0x4000;	/* CRC Check Enable */
+		reg_data |= 0x2000;	/* Padding enable */
+		reg_data |= 0x0800;	/* CRC Add enable */
+		//reg_data |= 0x0080;	/* PAUSE frame */
+
+		MSP85x0_GE_WRITE((MSP85x0_GE_TMAC_CONFIG_1 +
+				(port_num << MAC_PORT_OFFSET)), reg_data);
+	}
+}
+
+/*
+ * Tx Timeout function
+ */
+static void msp85x0_ge_tx_timeout(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+
+	printk(KERN_INFO "%s: TX timeout  ", netdev->name);
+	printk(KERN_INFO "Resetting card \n");
+
+	/* Do the reset outside of interrupt context */
+	schedule_work(&msp85x0_ge_eth->tx_timeout_task);
+}
+
+/*
+ * Update the AFX tables for UC and MC for slice 0 only
+ */
+static void msp85x0_ge_update_afx(msp85x0_ge_port_info * msp85x0_ge_eth)
+{
+	int port = msp85x0_ge_eth->port_num;
+	unsigned int i;
+	volatile unsigned long reg_data = 0;
+	u8 p_addr[6];
+
+	memcpy(p_addr, msp85x0_ge_eth->port_mac_addr, 6);
+
+	/* Set the MAC address here for TMAC and RMAC */
+	MSP85x0_GE_WRITE((MSP85x0_GE_TMAC_STATION_HI + (port << MAC_PORT_OFFSET)),
+		       ((p_addr[5] << 8) | p_addr[4]));
+	MSP85x0_GE_WRITE((MSP85x0_GE_TMAC_STATION_MID + (port << MAC_PORT_OFFSET)),
+		       ((p_addr[3] << 8) | p_addr[2]));
+	MSP85x0_GE_WRITE((MSP85x0_GE_TMAC_STATION_LOW + (port << MAC_PORT_OFFSET)),
+		       ((p_addr[1] << 8) | p_addr[0]));
+
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_STATION_HI + (port << MAC_PORT_OFFSET)),
+		       ((p_addr[5] << 8) | p_addr[4]));
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_STATION_MID + (port << MAC_PORT_OFFSET)),
+		       ((p_addr[3] << 8) | p_addr[2]));
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_STATION_LOW + (port << MAC_PORT_OFFSET)),
+		       ((p_addr[1] << 8) | p_addr[0]));
+
+	/* Configure the eight address filters */
+
+	/* Select first filter to match our address */
+	MSP85x0_GE_WRITE((MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_2 +
+				(port << MAC_PORT_OFFSET)), 0);
+	wmb();
+	/* Configure the match */
+	reg_data = 0x9;	/* Forward Enable Bit */
+	MSP85x0_GE_WRITE((MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_0 +
+				(port << MAC_PORT_OFFSET)), reg_data);
+
+	/* Finally, AFX Exact Match Address Registers */
+	MSP85x0_GE_WRITE((MSP85x0_GE_AFX_EXACT_MATCH_LOW + (port << MAC_PORT_OFFSET)),
+			       ((p_addr[1] << 8) | p_addr[0]));
+	MSP85x0_GE_WRITE((MSP85x0_GE_AFX_EXACT_MATCH_MID + (port << MAC_PORT_OFFSET)),
+			       ((p_addr[3] << 8) | p_addr[2]));
+	MSP85x0_GE_WRITE((MSP85x0_GE_AFX_EXACT_MATCH_HIGH + (port << MAC_PORT_OFFSET)),
+			       ((p_addr[5] << 8) | p_addr[4]));
+
+	/* VLAN id set to 0 */
+	MSP85x0_GE_WRITE((MSP85x0_GE_AFX_EXACT_MATCH_VID +
+				(port << MAC_PORT_OFFSET)), 0);
+	wmb();
+
+	MSP85x0_GE_WRITE((MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_3 | (port << MAC_PORT_OFFSET)), 0x1);
+
+	for (i = 1; i < NO_ADDRESS_FILTERS; i++) {
+		/* Select each of the eight filters */
+		MSP85x0_GE_WRITE((MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_2 +
+				(port << MAC_PORT_OFFSET)), i);
+
+		/* Configure the match */
+		reg_data = 0x0;	/* Disable filter */
+		MSP85x0_GE_WRITE((MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_0 +
+				(port << MAC_PORT_OFFSET)), reg_data);
+
+		MSP85x0_GE_WRITE((MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_3 | (port << MAC_PORT_OFFSET)), 0);
+
+	}
+}
+
+/*
+ * Actual Routine to reset the adapter when the timeout occurred
+ */
+
+static void msp85x0_ge_tx_timeout_task(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	int port = msp85x0_ge_eth->port_num;
+
+	printk("MSP85x0 GE: Transmit timed out. Resetting ... \n");
+
+	/* Dump debug info */
+	printk(KERN_ERR "TRTG cause : %x \n",
+			MSP85x0_GE_READ(MSP85x0_GE_TRTG2_INTERRUPT_IND + (port << TRTG2_PORT_OFFSET)));
+
+	/* Fix this for the other ports */
+	printk(KERN_ERR "FIFO cause : %x \n", MSP85x0_GE_READ(MSP85x0_GE_SDQPF_RXFIFO_INTR));
+	printk(KERN_ERR "IE cause : %x \n", MSP85x0_GE_READ(MSP85x0_GE_INTR_GRP0_STATUS));
+	printk(KERN_ERR "XDMA GDI ERROR : %x \n",
+			MSP85x0_GE_READ(MSP85x0_GE_GXDMA_INT_STS + (port << XDMA_PORT_OFFSET)));
+	printk(KERN_ERR "CHANNEL ERROR: %x \n",MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_INTERRUPT
+						+ (port << XDMA_PORT_OFFSET)));
+
+	netif_device_detach(netdev);
+	msp85x0_ge_port_reset(msp85x0_ge_eth->port_num);
+	msp85x0_ge_port_start(netdev);
+	netif_device_attach(netdev);
+}
+
+/*
+ * Change the MTU of the Ethernet Device
+ */
+static int msp85x0_ge_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned long flags;
+#ifdef MSP85x0_GE_JUMBO_FRAMES
+	if ((new_mtu > 9500) || (new_mtu < 64))
+		return -EINVAL;
+#else
+	if ((new_mtu > 1518) || (new_mtu < 64))
+		return -EINVAL;
+#endif
+	spin_lock_irqsave(&msp85x0_ge_eth->lock, flags);
+
+	netdev->mtu = new_mtu;
+	/* Now we have to reopen the interface so that SKBs with the new
+	 * size will be allocated */
+	if (netif_running(netdev)) {
+		msp85x0_ge_eth_stop(netdev);
+            	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_MAX_FRAME_LEN + (msp85x0_ge_eth->port_num << MAC_PORT_OFFSET)), new_mtu + 2); // for the padded bytes
+
+		if (msp85x0_ge_eth_reopen(netdev) != 0) {
+			printk(KERN_ERR
+			       "%s: Fatal error on opening device\n",
+			       netdev->name);
+			spin_unlock_irqrestore(&msp85x0_ge_eth->lock, flags);
+			return -1;
+		}
+	}
+	spin_unlock_irqrestore(&msp85x0_ge_eth->lock, flags);
+	return 0;
+}
+
+static int handle_phy_interrupt(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int port_num = msp85x0_ge_eth->port_num;
+	unsigned int err,reg_data;
+	  
+        err =titan_ge_mdio_read(port_num,TITAN_GE_MDIO_PHY_IS, &reg_data);
+        if (reg_data & 0x0400) {
+               /* Link status change */
+               titan_ge_mdio_read(port_num,TITAN_GE_MDIO_PHY_STATUS, &reg_data);
+               if (!(reg_data & 0x0400)) {
+                    /* Link is down */
+                    netif_carrier_off(netdev);
+                    netif_stop_queue(netdev);
+               } else {
+                    /* Link is up */
+                    netif_carrier_on(netdev);
+                    netif_wake_queue(netdev);
+                    /* Enable the queue */
+                    msp85x0_ge_enable_tx(port_num);
+               }
+        }
+	return 0;
+}
+
+static int handle_error_interrupts(unsigned int cause,unsigned char shift,unsigned int port_num)
+{ 
+       /* Handle error interrupts */
+        if (cause && (cause != 0x2)) {
+                printk(KERN_ERR"XDMA Channel Error : %x  on port %d\n",
+					cause, port_num);
+                printk(KERN_ERR"XDMA GDI Hardware error : %x  on port %d\n",
+                        MSP85x0_GE_READ(MSP85x0_GE_GXDMA_INT_STS + (port_num << shift)), port_num);
+                printk(KERN_ERR"XDMA currently has %d Rx descriptors \n",
+                        MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_RX_DMA_STS + (port_num << shift)));
+                printk(KERN_ERR
+                        "XDMA currently has prefetcted %d Rx descriptors \n",
+                        MSP85x0_GE_READ(MSP85x0_GE_GXDMA0_DESC_PREFETCH_CNT + (port_num << shift)));
+                MSP85x0_GE_WRITE((MSP85x0_GE_CHANNEL0_INTERRUPT +
+                               (port_num << shift)), cause);
+        }
+	return 0;
+}
+
+
+/*
+ * Enable the Tx & Rx side interrupts
+ */
+static void msp85x0_ge_enable_rx_int(unsigned int port)
+{
+	unsigned long reg_data = MSP85x0_GE_READ(MSP85x0_GE_INTR_XDMA_IE);
+        reg_data |=(RX_INT << (XDMA_CHANNEL_OFFSET * port));
+	MSP85x0_GE_WRITE(MSP85x0_GE_INTR_XDMA_IE, reg_data);
+}
+/*
+ * Disable the Tx & Rx side interrupts
+ */
+static void msp85x0_ge_disable_rx_int(unsigned int port)
+{
+	unsigned long reg_data = MSP85x0_GE_READ(MSP85x0_GE_INTR_XDMA_IE);
+        reg_data &=~(RX_INT << (XDMA_CHANNEL_OFFSET * port));
+	MSP85x0_GE_WRITE(MSP85x0_GE_INTR_XDMA_IE, reg_data);
+}
+
+static void clear_xdma_interrupts(unsigned int port,unsigned int tx_rx)
+{
+     MSP85x0_GE_WRITE(MSP85x0_GE_INTR_XDMA_CORE_A,tx_rx << (XDMA_CHANNEL_OFFSET * port));
+}
+/*
+ * MSP85x0 Gbe Interrupt Handler. All the three ports send interrupt to one line
+ * only. Once an interrupt is triggered, figure out the port and then check
+ * the Interrupt channel.
+ */
+static irqreturn_t msp85x0_ge_sequoia_int_handler(int irq, void *dev_id,
+	struct pt_regs *regs)
+{
+	struct net_device *netdev = (struct net_device *) dev_id;
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int port_num = msp85x0_ge_eth->port_num;
+	unsigned int eth_int_cause_error = 0, is;
+	unsigned long eth_int_cause1,eth_rx_ood_error;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msp85x0_ge_eth->lock, flags);
+        /* Ack the CPU interrupt */
+	is=*(volatile unsigned int *)(RM9150_DMA_DCR + 0x8000 + RM9150_GCIC_INT3_STATUS);
+	*(volatile unsigned int *)(RM9150_DMA_DCR + 0x8000 + RM9150_GCIC_INT3_CLEAR)=is;
+
+        eth_int_cause1 = MSP85x0_GE_READ(MSP85x0_GE_INTR_XDMA_CORE_A);	
+        if (eth_int_cause1 == 0) {
+                eth_int_cause_error = MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_INTERRUPT
+                                                + (port_num << 9));
+                if (eth_int_cause_error == 0)
+		{
+			spin_unlock_irqrestore(&msp85x0_ge_eth->lock, flags);
+                        return IRQ_NONE;
+		}
+
+        }
+        /* Handle the Rx next */
+        if (eth_int_cause1 & (RX_INT << (port_num * 16))) {
+	      clear_xdma_interrupts(port_num,RX_INT);
+              if (netif_rx_schedule_prep(netdev)) {
+		   msp85x0_ge_disable_rx_int(port_num);	
+                   __netif_rx_schedule(netdev);			       		
+
+              }
+        }
+	/* Handle error interrupts */
+	handle_error_interrupts(eth_int_cause_error,9,port_num);
+
+	/* Handle Rx OOD */ 
+        eth_rx_ood_error = MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_INTERRUPT + (port_num << 9));
+	if(eth_rx_ood_error & 0x2)
+	{
+              if (netif_rx_schedule_prep(netdev)){
+		   msp85x0_ge_disable_rx_int(port_num);	
+                   __netif_rx_schedule(netdev);
+	      }
+	}	
+
+        /*
+         * PHY interrupt to inform abt the changes. Reading the
+         * PHY Status register will clear the interrupt
+         */
+        if ((!(eth_int_cause1 & (0x3 << (port_num * 16)))) &&
+                (eth_int_cause_error == 0)) {
+			handle_phy_interrupt(netdev);
+        }
+	spin_unlock_irqrestore(&msp85x0_ge_eth->lock, flags);
+	return IRQ_HANDLED;
+}
+/*
+ * Multicast and Promiscuous mode set. The
+ * set_multi entry point is called whenever the
+ * multicast address list or the network interface
+ * flags are updated.
+ */
+static void msp85x0_ge_set_multi(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int port_num = msp85x0_ge_eth->port_num;
+	unsigned long reg_data;
+
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_1 +
+				(port_num << MAC_PORT_OFFSET));
+
+	if (netdev->flags & IFF_PROMISC) {
+		reg_data |= 0x2;
+	}
+	else if (netdev->flags & IFF_ALLMULTI) {
+		reg_data |= 0x01;
+		reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */
+	}
+	else {
+		reg_data = 0x2;
+	}
+
+	MSP85x0_GE_WRITE((MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_1 +
+			(port_num << MAC_PORT_OFFSET)), reg_data);
+	if (reg_data & 0x01) {
+		MSP85x0_GE_WRITE((MSP85x0_GE_AFX_MULTICAST_HASH_LOW +
+				(port_num << MAC_PORT_OFFSET)), 0xffff);
+		MSP85x0_GE_WRITE((MSP85x0_GE_AFX_MULTICAST_HASH_MIDLOW +
+				(port_num << MAC_PORT_OFFSET)), 0xffff);
+		MSP85x0_GE_WRITE((MSP85x0_GE_AFX_MULTICAST_HASH_MIDHI +
+				(port_num << MAC_PORT_OFFSET)), 0xffff);
+		MSP85x0_GE_WRITE((MSP85x0_GE_AFX_MULTICAST_HASH_HI +
+				(port_num << MAC_PORT_OFFSET)), 0xffff);
+	}
+}
+
+/*
+ * Open the network device
+ */
+static int msp85x0_ge_open(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int port_num = msp85x0_ge_eth->port_num;
+	unsigned int irq;
+	int retval;       
+
+	spin_lock_irq(&(msp85x0_ge_eth->lock));
+
+	if (msp85x0_ge_eth_open(netdev) != MSP85x0_OK) {
+		spin_unlock_irq(&(msp85x0_ge_eth->lock));
+		printk("%s: Error opening interface \n", netdev->name);
+		free_irq(netdev->irq, netdev);
+		return -EBUSY;
+	}
+
+	spin_unlock_irq(&(msp85x0_ge_eth->lock));
+
+        irq = MSP85x0_ETH_PORT_IRQ;
+
+	retval = request_irq(irq, INTERRUPT_HANDLER,
+		     SA_SAMPLE_RANDOM | SA_SHIRQ, netdev->name, netdev);
+
+	if (retval != 0) {
+		printk(KERN_ERR "Cannot assign IRQ number to MSP85x0 GE \n");
+		return -1;
+	}
+
+	netdev->irq = irq;
+	printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, port_num);
+
+	return 0;
+}
+
+/*
+ * Allocate the SKBs for the Rx ring. Also used
+ * for refilling the queue
+ */
+
+static int msp85x0_ge_rx_task(struct net_device *netdev,
+				msp85x0_ge_port_info *msp85x0_ge_eth)
+{
+	struct device *device = &msp85x0_ge_device[msp85x0_ge_eth->port_num]->dev;
+	volatile msp85x0_ge_rx_desc *rx_desc;
+	struct sk_buff *skb;
+	int rx_used_desc;
+	int count = 0;
+	oom_flag=0;
+	while (msp85x0_ge_eth->rx_ring_skbs < msp85x0_ge_eth->rx_ring_size) {
+		/* First try to get the skb from the recycler */
+		skb = msp85x0_ge_alloc_skb(MSP85x0_GE_RX_BUFSIZE, GFP_ATOMIC);
+		if (unlikely(!skb)) {
+			/* OOM, set the flag */
+			oom_flag = 1;
+			break;
+		}
+		count++;
+		skb->dev = netdev;
+		msp85x0_ge_eth->rx_ring_skbs++;
+		rx_used_desc = msp85x0_ge_eth->rx_used_desc_q;
+		rx_desc = &(msp85x0_ge_eth->rx_desc_area[rx_used_desc]);
+		rx_desc->buffer_addr = dma_map_single(device, skb->data,
+				MSP85x0_GE_RX_BUFSIZE - 2, DMA_FROM_DEVICE);
+		msp85x0_ge_eth->rx_skb[rx_used_desc] = skb;
+		rx_desc->cmd_sts = MSP85x0_GE_RX_BUFFER_OWNED;
+   		DMA_CACHE_WBACK_INV((unsigned long)rx_desc,sizeof(msp85x0_ge_rx_desc));
+		if((rx_used_desc + 1) == MSP85x0_GE_RX_QUEUE)
+			msp85x0_ge_eth->rx_used_desc_q =0;
+		else
+			msp85x0_ge_eth->rx_used_desc_q = (rx_used_desc + 1);	
+	}
+	return count;
+}
+
+/*
+ * Actual init of the Tital GE port. There is one register for
+ * the channel configuration
+ */
+static void msp85x0_port_init(struct net_device *netdev,
+			    msp85x0_ge_port_info * msp85x0_ge_eth)
+{
+	unsigned long reg_data;
+	unsigned int port_num;	
+
+	port_num = msp85x0_ge_eth->port_num;
+	for (port_num = 0; port_num < NO_PORTS; port_num++)
+	{
+		msp85x0_ge_port_reset(port_num);
+
+		/* First reset the TMAC */
+		reg_data = MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_CONFIG + (port_num << XDMA_PORT_OFFSET));
+		reg_data |= XDMA_TMAC_RESET;
+		MSP85x0_GE_WRITE(MSP85x0_GE_CHANNEL0_CONFIG + (port_num << XDMA_PORT_OFFSET), reg_data);
+		/* RMAC */
+		reg_data = MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_CONFIG + (port_num << XDMA_PORT_OFFSET));
+		reg_data |= XDMA_RMAC_RESET;
+		MSP85x0_GE_WRITE(MSP85x0_GE_CHANNEL0_CONFIG + (port_num << XDMA_PORT_OFFSET), reg_data);
+	}
+}
+
+static int start_tx_and_rx_activity(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int port_num = msp85x0_ge_eth->port_num;
+	unsigned int reg_data;
+
+	MSP85x0_GE_WRITE((MSP85x0_GE_TMAC_CONFIG_2 + (port_num << MAC_PORT_OFFSET)), 0xe1b7);
+#ifdef MSP85x0_GE_JUMBO_FRAMES
+	MSP85x0_GE_WRITE((MSP85x0_GE_TMAC_MAX_FRAME_LEN + (port_num << MAC_PORT_OFFSET)), 0x4000);
+#endif
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_TMAC_CONFIG_1 + (port_num << MAC_PORT_OFFSET));
+	reg_data |= (0x0001 << 14);	/* CRC Check Enable */		
+	reg_data |= (0x0002 << 12);	/* Padding enable */	
+	reg_data |= (0x0001 << 11);	/* CRC Add enable */		
+	reg_data |= (0x0001 << 10);	/* Min. frame length check */	
+	reg_data |= (0x0001 <<  6);	/* Pause, if FIFO full */	
+	reg_data &=~(0x0001 <<  6);	/* Disable pause frame */
+	reg_data |= (0x0001 <<  5);	/* Send XON */			
+	reg_data |= (0x0001 <<  4);	/* Stop on XOFF */
+	reg_data |= (0x0001 <<  0);	/* Enable TMAC */
+
+	MSP85x0_GE_WRITE((MSP85x0_GE_TMAC_CONFIG_1 + (port_num << MAC_PORT_OFFSET)), reg_data);
+	udelay(30);
+
+	/* Destination Address drop bit */
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_RMAC_CONFIG_2 + (port_num << MAC_PORT_OFFSET));
+        reg_data |= 0x109;        /* DA_DROP bit and pause */
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_CONFIG_2 + (port_num << MAC_PORT_OFFSET)), reg_data);
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_LINK_CONFIG + (port_num << MAC_PORT_OFFSET)), 0x3);
+#ifdef MSP85x0_GE_JUMBO_FRAMES
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_MAX_FRAME_LEN + (port_num << MAC_PORT_OFFSET)), 0x4000);
+#endif
+	/* Start the Rx activity */
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_RMAC_CONFIG_1 + (port_num << MAC_PORT_OFFSET));
+	reg_data |= (0x0001 << 14);	/* Preamble check enable */	
+	reg_data |= (0x0001 << 13);	/* VLAN tag aware */		
+	reg_data |= (0x0003 << 10);	/* in-range length checking */	
+	reg_data |= (0x0001 <<  8);	/* Max frame discard */		
+	reg_data |= (0x0001 <<  7);	/* Max frame check enable */	
+	reg_data |= (0x0001 <<  6);	/* Min frame discard */		
+	reg_data |= (0x0001 <<  5);	/* Min frame check enable */	
+	reg_data |= (0x0001 <<  4);	/* CRC discard */		
+	reg_data |= (0x0001 <<  3);	/* CRC check enable */		
+	reg_data |= (0x0001 <<  1);	/* reserved */
+	reg_data |= (0x0001 <<  0);	/* RMAC Enable */
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_CONFIG_1 + (port_num << MAC_PORT_OFFSET)), reg_data);
+	udelay(30);
+	return 0;
+}
+
+static int trtg_block_enable(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int port_num = msp85x0_ge_eth->port_num;
+	unsigned int reg_data;
+
+	/*
+	 * Step 3:  TRTG block enable
+	 */
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_TRTG_CONFIG + (port_num << TRTG2_PORT_OFFSET));
+	reg_data &= ~1;
+        MSP85x0_GE_WRITE((MSP85x0_GE_TRTG_CONFIG + (port_num << TRTG2_PORT_OFFSET)), reg_data);
+
+        reg_data = PKT_PAD_BYTES(2);
+        MSP85x0_GE_WRITE((MSP85x0_GE_TRTG_BYTE_OFFSET_0 + (port_num << TRTG2_PORT_OFFSET)), reg_data);
+        MSP85x0_GE_WRITE((MSP85x0_GE_TRTG_BYTE_OFFSET_1 + (port_num << TRTG2_PORT_OFFSET)), reg_data);   
+	mdelay(5);
+
+	/* Priority */
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_TRTG_PRIORITY_CHKSUM + (port_num << TRTG2_PORT_OFFSET));
+	reg_data &= ~(0x00f00000);
+	reg_data |= (14 << 8);
+	MSP85x0_GE_WRITE((MSP85x0_GE_TRTG_PRIORITY_CHKSUM + (port_num << TRTG2_PORT_OFFSET)), reg_data);
+
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_TRTG_CONFIG + (port_num << TRTG2_PORT_OFFSET));
+	reg_data |= 0x0001;
+	MSP85x0_GE_WRITE((MSP85x0_GE_TRTG_CONFIG + (port_num << TRTG2_PORT_OFFSET)), reg_data);
+	return 0;
+}
+
+
+static int enable_tx_and_rx_interrupts(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int port_num = msp85x0_ge_eth->port_num;
+	unsigned int reg_data;
+
+	if (config_done == 0) {
+		/* XD_OOD_INTSMSG = 0x61, XD_INTSMSG    = 0x62
+		   XD_RX_INTSMSG  = 0x60, XD_TX_INTSMSG = 0x60  */
+                MSP85x0_GE_WRITE(MSP85x0_GE_CPIF2_INT_MSG_ADDR0,(RM9150_GCIC_BASE + RM9150_GCIC_INTMSG) >> 4);
+                reg_data = 0x61626060;
+                MSP85x0_GE_WRITE(MSP85x0_GE_CPIF2_SET_VECTOR_MSG0, reg_data);
+                reg_data = MSP85x0_GE_READ(MSP85x0_GE_CPIF2_INT_VECOTR_MODE0);
+                reg_data |= 0x1;
+                MSP85x0_GE_WRITE(MSP85x0_GE_CPIF2_INT_VECOTR_MODE0, reg_data);
+	}
+
+	/*
+	 * Enable the Interrupts for Rx 
+	 */
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_INTR_XDMA_IE);
+	reg_data |= (RX_INT << (port_num * XDMA_CHANNEL_OFFSET));
+	MSP85x0_GE_WRITE(MSP85x0_GE_INTR_XDMA_IE, reg_data);
+
+	return 0;
+}
+
+
+static int get_ring_count(unsigned int count)
+{
+	unsigned int ring_size;
+	switch(count)
+	{
+		case 1:
+			ring_size=0;break;
+		case 2:
+			ring_size=1;break;
+		case 4:
+			ring_size=2;break;
+		case 8:
+			ring_size=3;break;
+		case 16:
+			ring_size=4;break;
+		default:
+			ring_size=0;break;
+	}
+	return ring_size;
+}
+
+static int get_rx_buff_size(unsigned int size)
+{
+	unsigned int buff_size;
+	switch(size)
+	{
+		case 1:
+			buff_size=0;break;
+		case 2:
+			buff_size=1;break;
+		case 4:
+			buff_size=2;break;
+		case 8:
+			buff_size=3;break;
+		case 16:
+			buff_size=4;break;
+		case 32:
+			buff_size=5;break;
+		default:
+			buff_size=0;break;
+	}
+	return buff_size;
+}
+
+static int xdma_config(struct net_device *netdev)
+{
+	volatile unsigned long reg_data;
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	int port_num = msp85x0_ge_eth->port_num;
+	unsigned int count = 0,rx_ring,tx_ring;
+
+	if (config_done == 0) {
+		reg_data = MSP85x0_GE_READ(MSP85x0_GE_XDMA_CONFIG);
+		reg_data &= ~(0x80000000);      /* clear reset */
+		reg_data |= (0x1 << 29);	/* sparse tx descriptor spacing */
+		reg_data |= (0x1 << 28);	/* sparse rx descriptor spacing */
+                /* No support for coherency.  Has to be cleared */
+		reg_data &= ~(0x8000); /* Disable the write back */ 
+                reg_data &=~(0x1E00000);
+		MSP85x0_GE_WRITE(MSP85x0_GE_XDMA_CONFIG, reg_data);
+	}
+
+	msp85x0_ge_eth->tx_threshold = 0;
+	msp85x0_ge_eth->rx_threshold = 0;
+
+        /* We need to write the descriptors for Tx and Rx */
+        MSP85x0_GE_WRITE((MSP85x0_GE_CHANNEL0_TX_DESC + (port_num << XDMA_PORT_OFFSET)),
+                       (unsigned long) msp85x0_ge_eth->tx_dma);
+        MSP85x0_GE_WRITE((MSP85x0_GE_CHANNEL0_RX_DESC + (port_num << XDMA_PORT_OFFSET)),
+                       (unsigned long) msp85x0_ge_eth->rx_dma);
+
+        /* IR register for the XDMA */
+        reg_data = MSP85x0_GE_READ(MSP85x0_GE_GDI_INTERRUPT_ENABLE + (port_num << XDMA_PORT_OFFSET));
+        reg_data |= 0xF006C000; /* No Rx_OOD */
+        MSP85x0_GE_WRITE((MSP85x0_GE_GDI_INTERRUPT_ENABLE + (port_num << XDMA_PORT_OFFSET)), reg_data);
+
+	tx_ring = get_ring_count(MSP85x0_GE_TX_QUEUE/64);
+	tx_ring = tx_ring << 27;
+	rx_ring = get_ring_count(MSP85x0_GE_RX_QUEUE/64);
+	rx_ring = rx_ring << 16;
+
+	// Should be written while XDMA in the reset
+        reg_data = MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_CONFIG + (port_num << XDMA_PORT_OFFSET));
+	reg_data &=~(7 << 27); 	// Clear Tx descriptor ring size
+	reg_data &=~(7 << 16); 	// Clear Rx descriptor ring size
+	reg_data |=(tx_ring | rx_ring);
+	reg_data |= 0x400;  	// Rx TCP Checksum
+        if(MSP85x0_GE_RX_BUFSIZE % 512)
+        {
+                printk(KERN_ERR"\n\r ERROR!! Invalid Rx buffer size.   ");
+                printk(KERN_ERR"\n\r         should be mulitple of 512.");
+                printk(KERN_ERR"\n\r Current size=0x%x",MSP85x0_GE_RX_BUFSIZE) ;
+        }
+	reg_data |= (get_rx_buff_size(MSP85x0_GE_RX_BUFSIZE/512) << 5);
+        MSP85x0_GE_WRITE((MSP85x0_GE_CHANNEL0_CONFIG + (port_num << XDMA_PORT_OFFSET)), reg_data);
+	// Rx desc iTH thershold for packet drop
+	reg_data=2;  // 0 ->4 , 1 -> 8, 2 -> 16, 3 -> 32 
+        MSP85x0_GE_WRITE((MSP85x0_GE_CHANNEL0_RX_DESC_PKT_DRP_THR + (port_num << XDMA_PORT_OFFSET)), reg_data);
+        MSP85x0_GE_WRITE((MSP85x0_GE_GDI_PASSPW_CONFIG + (port_num << XDMA_PORT_OFFSET)),0x101);
+
+	/* Start the Tx and Rx XDMA controller */
+        reg_data = MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_CONFIG + (port_num << XDMA_PORT_OFFSET));
+        reg_data &= ~(1 << 31);     /* Clear tx reset */
+        reg_data &= ~(1 << 20);     /* Clear rx reset */
+        MSP85x0_GE_WRITE((MSP85x0_GE_CHANNEL0_CONFIG + (port_num << XDMA_PORT_OFFSET)), reg_data);
+
+        /* Rx desc count */
+        count=msp85x0_ge_rx_task(netdev, msp85x0_ge_eth);
+        MSP85x0_GE_WRITE((MSP85x0_GE_CHANNEL0_RX_DMA_STS + (msp85x0_ge_eth->port_num << 9)),count);
+	msp85x0_ge_eth->rx_local_desc_count=count;	
+	udelay(30);
+	return 0;
+}
+
+
+/*
+ * Start the port. All the hardware specific configuration
+ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX
+ * go here
+ */
+static int msp85x0_ge_port_start(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	int port_num = msp85x0_ge_eth->port_num;
+
+	xdma_config(netdev);
+   	msp85x0_eth_setup_tx_rx_fifo(netdev);
+	trtg_block_enable(netdev);
+	start_tx_and_rx_activity(netdev);
+
+	msp85x0_ge_gmii_config(port_num);
+	enable_tx_and_rx_interrupts(netdev);
+
+	if (config_done == 0) {
+		config_done = 1;
+	}
+
+	return MSP85x0_OK;
+}
+/*
+ * Function to queue the packet for the Ethernet device
+ */
+static void msp85x0_ge_tx_queue(msp85x0_ge_port_info * msp85x0_ge_eth,
+				struct sk_buff * skb)
+{
+	struct device *device = &msp85x0_ge_device[msp85x0_ge_eth->port_num]->dev;
+	unsigned int curr_desc = msp85x0_ge_eth->tx_curr_desc_q;
+	volatile msp85x0_ge_tx_desc *tx_curr;
+	int port_num = msp85x0_ge_eth->port_num;
+	unsigned int pkts;
+
+	tx_curr = &(msp85x0_ge_eth->tx_desc_area[curr_desc]);
+
+	pkts=MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_TX_DMA_STS+ (port_num << XDMA_PORT_OFFSET)) & 0x3FF;
+	if(pkts < 1023)	
+	{
+		tx_curr->buffer_addr =dma_map_single(device, skb->data, skb_headlen(skb),
+			       DMA_TO_DEVICE);
+
+		msp85x0_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb;
+		tx_curr->buffer_len = skb_headlen(skb);
+
+		/* Last descriptor enables interrupt and changes ownership */
+		tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5);
+		
+   		DMA_CACHE_WBACK_INV((unsigned long)tx_curr,sizeof(msp85x0_ge_tx_desc));
+			
+        	/* Kick the XDMA to start the transfer from memory to the FIFO */
+        	MSP85x0_GE_WRITE((MSP85x0_GE_CHANNEL0_TX_DMA_STS + (port_num << XDMA_PORT_OFFSET)), 0x1);
+		/* Have the packet count updated */
+		increment_tx_pkt_count(port_num);
+		/* Current descriptor updated */
+		msp85x0_ge_eth->tx_curr_desc_q = (curr_desc + 1) % MSP85x0_GE_TX_QUEUE;
+
+		/* Prefetch the next descriptor */
+		prefetch((const void *)&msp85x0_ge_eth->tx_desc_area[msp85x0_ge_eth->tx_curr_desc_q]);
+	}
+
+}
+
+static int msp85x0_eth_set_mac_addr(struct net_device *dev)
+{
+   msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(dev);
+   unsigned int port = msp85x0_ge_eth->port_num;
+   unsigned char addr[6];
+   unsigned int i,retries=1000;
+  	
+   
+   memcpy(addr, dev->dev_addr, 6);
+   
+   /* TMAC address */
+   MSP85x0_GE_WRITE(MSP85x0_GE_TMAC_STATION_HI + (port<<12),
+                  (addr[5] << 8) | addr[4]);
+   MSP85x0_GE_WRITE(MSP85x0_GE_TMAC_STATION_MID + (port<<12),
+                  (addr[3] << 8) | addr[2]);
+   MSP85x0_GE_WRITE(MSP85x0_GE_TMAC_STATION_LOW + (port<<12),
+                  (addr[1] << 8) | addr[0]);
+
+   /* RMAC address */
+   MSP85x0_GE_WRITE(MSP85x0_GE_RMAC_STATION_HI + (port<<12),
+                  (addr[5] << 8) | addr[4]);
+   MSP85x0_GE_WRITE(MSP85x0_GE_RMAC_STATION_MID + (port<<12),
+                  (addr[3] << 8) | addr[2]);
+   MSP85x0_GE_WRITE(MSP85x0_GE_RMAC_STATION_LOW + (port<<12),
+                  (addr[1] << 8) | addr[0]);
+
+   for (i=0; i<8; i++)
+   {
+      /* select address filter */
+      MSP85x0_GE_WRITE(MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_2 + (port<<12), i);
+      
+      /* accept on match */
+      MSP85x0_GE_WRITE(MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_0 + (port<<12), 0x9);
+      
+      /* exact match */
+      MSP85x0_GE_WRITE(MSP85x0_GE_AFX_EXACT_MATCH_LOW + (port<<12),
+                     (addr[1] << 8) | addr[0]);
+      MSP85x0_GE_WRITE(MSP85x0_GE_AFX_EXACT_MATCH_MID + (port<<12),
+                     (addr[3] << 8) | addr[2]);
+      MSP85x0_GE_WRITE(MSP85x0_GE_AFX_EXACT_MATCH_HIGH + (port<<12),
+                     (addr[5] << 8) | addr[4]);
+
+      /* set VLAN id to 0 */
+      MSP85x0_GE_WRITE(MSP85x0_GE_AFX_EXACT_MATCH_VID + (port<<12), 0);
+      
+      /* update address filter */
+      MSP85x0_GE_WRITE(MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_3 + (port<<12), 1);
+      while (retries)
+      {
+	if(!(MSP85x0_GE_READ(MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_3 + (port<<12)) & 1))
+	{
+		break;
+	}
+	mdelay(1);
+	retries--;
+      }
+      if(!retries)
+      {
+      	 printk("\n\r Unable to update the filters ");
+      	 return MSP85x0_ERROR;
+      }
+    }	
+ 	return MSP85x0_OK; 
+}
+static int msp85x0_eth_setup_tx_ring(struct net_device *dev)
+{
+   msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(dev);
+   unsigned int port_num = msp85x0_ge_eth->port_num,retval;
+
+   /* Allocate the Tx ring now */
+   msp85x0_ge_eth->tx_ring_skbs = 0;
+   msp85x0_ge_eth->tx_ring_size = MSP85x0_GE_TX_QUEUE;
+
+   /* Allocate space in the SRAM for the descriptors */
+
+   msp85x0_ge_eth->tx_desc_area = (msp85x0_ge_tx_desc *)
+  		(msp85x0_ge_sram + MSP85x0_TX_RING_BYTES * port_num);
+   msp85x0_ge_eth->tx_desc_area_size =
+	     msp85x0_ge_eth->tx_ring_size * sizeof(msp85x0_ge_tx_desc);
+
+   msp85x0_ge_eth->tx_dma = MSP85x0_SRAM_BASE + MSP85x0_TX_RING_BYTES * port_num;
+   GE_DBG("tx_dma=0x%x\n",(unsigned int)msp85x0_ge_eth->tx_dma);
+   GE_DBG("tx_desc_area=0x%x\n",(unsigned int )msp85x0_ge_eth->tx_desc_area);
+
+   if (!msp85x0_ge_eth->tx_desc_area) 
+   {
+   	printk(KERN_ERR"%s: Cannot allocate Tx Ring (size %d bytes) for port %d \n",dev->name, MSP85x0_TX_RING_BYTES, port_num);
+	return MSP85x0_ERROR;
+   }
+
+   memset((void *)msp85x0_ge_eth->tx_desc_area, 0, msp85x0_ge_eth->tx_desc_area_size);
+	
+   /* Now initialize the Tx descriptor ring */
+   retval=msp85x0_ge_init_tx_desc_ring(msp85x0_ge_eth,msp85x0_ge_eth->tx_ring_size,
+	   (unsigned long) msp85x0_ge_eth->tx_desc_area,
+	   (unsigned long) msp85x0_ge_eth->tx_dma);
+ 
+   DMA_CACHE_WBACK_INV((unsigned long)msp85x0_ge_eth->tx_desc_area,msp85x0_ge_eth->tx_desc_area_size);
+
+   if(retval!=MSP85x0_OK)
+   {
+	printk("\n\r Error initializing descriptor ...");
+	return MSP85x0_ERROR;		
+   }
+   return retval;
+}
+
+static int msp85x0_eth_setup_rx_ring(struct net_device *dev)
+{
+   msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(dev);
+   unsigned int port_num = msp85x0_ge_eth->port_num;
+
+
+   /* Allocate the Rx ring now */
+   msp85x0_ge_eth->rx_ring_size = MSP85x0_GE_RX_QUEUE;
+   msp85x0_ge_eth->rx_ring_skbs = 0;
+  
+   msp85x0_ge_eth->rx_desc_area =
+                (msp85x0_ge_rx_desc *)(msp85x0_ge_sram + 0x4000 + MSP85x0_RX_RING_BYTES * port_num);
+   msp85x0_ge_eth->rx_dma = MSP85x0_SRAM_BASE + 0x4000 + MSP85x0_RX_RING_BYTES * port_num;
+
+   msp85x0_ge_eth->rx_desc_area_size =
+	     msp85x0_ge_eth->rx_ring_size * sizeof(msp85x0_ge_rx_desc);
+
+   GE_DBG("rx_dma=0x%p\n", (void *)msp85x0_ge_eth->rx_dma);
+   GE_DBG("rx_desc_area=0x%p\n",(void *)msp85x0_ge_eth->rx_desc_area);
+
+   if (!msp85x0_ge_eth->rx_desc_area) {
+	printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n",
+	       dev->name, MSP85x0_RX_RING_BYTES);
+	printk(KERN_ERR "%s: Freeing previously allocated TX queues...",
+	       dev->name);
+	return MSP85x0_ERROR;
+   }
+   memset((void *)msp85x0_ge_eth->rx_desc_area, 0, msp85x0_ge_eth->rx_desc_area_size);
+
+   /* Now initialize the Rx ring */
+   if ((msp85x0_ge_init_rx_desc_ring
+       (msp85x0_ge_eth, msp85x0_ge_eth->rx_ring_size, MSP85x0_GE_RX_BUFSIZE,
+      (unsigned long) msp85x0_ge_eth->rx_desc_area, 0,
+      (unsigned long) msp85x0_ge_eth->rx_dma)) == 0)
+   {	
+       panic("%s: Error initializing RX Ring\n", dev->name);
+	return MSP85x0_ERROR;
+   }
+  DMA_CACHE_WBACK_INV((unsigned long)msp85x0_ge_eth->rx_desc_area,msp85x0_ge_eth->rx_desc_area_size);
+
+   return MSP85x0_OK;
+}
+
+static int msp85x0_eth_setup_tx_rx_fifo(struct net_device *dev)
+{
+   	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(dev);
+   	unsigned int port = msp85x0_ge_eth->port_num;
+
+	unsigned int reg_data,reg_data1;
+
+        /* Enable RX FIFO 0 and 8 */
+	// RX FIFO
+        reg_data = MSP85x0_GE_READ(MSP85x0_GE_SDQPF_RXFIFO_0 + (port * SQDPF_RX_PORT_OFFSET));
+        reg_data |= 0x100000;
+	MSP85x0_GE_WRITE(MSP85x0_GE_SDQPF_RXFIFO_0 + (port * SQDPF_RX_PORT_OFFSET), reg_data);
+        /*
+         * BAV2,BAV and DAV settings for the Rx FIFO
+	 *
+   	 * The recommendation for RxFIFO is to minimize DAV_TH, minimize BAV_TH, and set BAV2_TH to its min.
+         * DAV_TH min = 2.
+         * BAV_TH min = 2.
+         * BAV2_TH min = BAV_TH min + 3 = 2+3 = 5.
+	 */
+        reg_data = 0x00500802;
+        MSP85x0_GE_WRITE(MSP85x0_GE_SDQPF_RX_THRLD_0 + (port * SQDPF_RX_PORT_OFFSET), reg_data);
+
+        reg_data = MSP85x0_GE_READ(MSP85x0_GE_SDQPF_RXFIFO_0 + (port * SQDPF_RX_PORT_OFFSET));
+	reg_data = 0x00260000;
+        reg_data |=(port << 7);
+        reg_data |=(port << 8);
+        MSP85x0_GE_WRITE(MSP85x0_GE_SDQPF_RXFIFO_0 + (port * SQDPF_RX_PORT_OFFSET), reg_data);
+
+	// TX FIFO
+        reg_data = MSP85x0_GE_READ(MSP85x0_GE_SDQPF_TXFIFO_0 + (port * SQDPF_TX_PORT_OFFSET));
+        reg_data |= 0x100000;
+        MSP85x0_GE_WRITE(MSP85x0_GE_SDQPF_TXFIFO_0 + (port * SQDPF_TX_PORT_OFFSET), reg_data);
+        /*
+         *  BAV2, BAV and DAV settings for the Tx FIFO
+         *
+         *  The recommendation for TxFIFO is to maximize DAV_TH, minimize BAV_TH, 
+         *  and set BAV2_TH to its min.
+         *  DAV_TH max = SIZE-3.  So for 4KB physical buffer this is (128 - 3) = 125.
+         *  BAV_TH min = 2.
+         *  BAV2_TH min = BAV_TH min + 3 = 2+3 = 5.
+	 */
+
+        reg_data1 = 0x0050087D;
+        MSP85x0_GE_WRITE(MSP85x0_GE_SDQPF_TX_THRLD_0 + (port * SQDPF_TX_PORT_OFFSET), reg_data1);
+
+        reg_data = MSP85x0_GE_READ(MSP85x0_GE_SDQPF_TXFIFO_0 + (port * SQDPF_TX_PORT_OFFSET));
+	reg_data = 0x220000;
+	reg_data |=(port << 7);
+        MSP85x0_GE_WRITE(MSP85x0_GE_SDQPF_TXFIFO_0 + (port * SQDPF_TX_PORT_OFFSET), reg_data);
+	return MSP85x0_OK;
+}
+
+
+static int msp85x0_ge_eth_open(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int port_num = msp85x0_ge_eth->port_num;
+	unsigned long reg_data;
+	unsigned int phy_reg;
+	int err = 0;
+
+	int tbi_mode;
+	if(config_done == 0){
+		reg_data = MSP85x0_GE_READ(MSP85x0_GE_TSB_CTRL_0);
+		tbi_mode =(reg_data & 0x700) >> 8;
+	
+		if(!tbi_mode)
+		{	
+			reg_data &=~(0x700);
+			MSP85x0_GE_WRITE(MSP85x0_GE_TSB_CTRL_0,reg_data);
+		}
+	}
+
+	/* Stop the Rx activity */
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_RMAC_CONFIG_1 + (port_num << MAC_PORT_OFFSET));
+	reg_data &= ~(0x00000001);
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_CONFIG_1 + (port_num << MAC_PORT_OFFSET)), reg_data);
+
+        /* Clear the port interrupts */
+        MSP85x0_GE_WRITE((MSP85x0_GE_CHANNEL0_INTERRUPT +
+                        (port_num << 9)), 0xf006c002);
+	MSP85x0_GE_WRITE((MSP85x0_GE_CHANNEL0_INTERRUPT +
+                        (port_num << 9)), 0);
+	if (config_done == 0) {
+	        MSP85x0_GE_WRITE(MSP85x0_GE_INTR_XDMA_CORE_A, 0xffffffff);
+	}
+	/* Set MAC address */
+   	if(msp85x0_eth_set_mac_addr(netdev)==MSP85x0_ERROR)
+	{
+		printk(KERN_ERR"\n\r Unable to update the AFX filters");
+		return MSP85x0_ERROR;
+	}
+	/* Setup Tx Ring */
+   	if(msp85x0_eth_setup_tx_ring(netdev)==MSP85x0_ERROR)
+   	{
+		printk(KERN_ERR"\n\r Unable to setup tx ring "); 
+		return MSP85x0_ERROR;
+   	}
+	/* Setup Rx Ring */	
+   	if(msp85x0_eth_setup_rx_ring(netdev)==MSP85x0_ERROR)
+   	{
+		printk(KERN_ERR"\n\r Unable to setup rx ring "); 
+		return MSP85x0_ERROR; 	
+   	}
+	/* Port Init - (Stop Tx and Rx XDMA Channels for the port)*/
+	if (config_done == 0)
+		msp85x0_port_init(netdev, msp85x0_ge_eth);
+
+	/* Fill the Rx ring with the SKBs */
+	msp85x0_ge_port_start(netdev);
+
+	/*
+	 * Check if Interrupt Coalescing needs to be turned on. The
+	 * values specified in the register is multiplied by
+	 * (8 x 64 nanoseconds) to determine when an interrupt should
+	 * be sent to the CPU.
+	 */
+	if (MSP85x0_GE_TX_COAL) {
+		msp85x0_ge_eth->tx_int_coal =
+		    msp85x0_ge_tx_coal(port_num);
+	}
+
+	err = titan_ge_mdio_read(port_num,TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
+	if (err == TITAN_GE_MDIO_ERROR) {
+		printk(KERN_ERR
+		       "Could not read PHY control register 0x11 \n");
+		return MSP85x0_ERROR;
+	}
+	if (!(phy_reg & 0x0400)) {
+		netif_carrier_off(netdev);
+		netif_stop_queue(netdev);
+		return MSP85x0_ERROR;
+	} else {
+		netif_carrier_on(netdev);
+		netif_start_queue(netdev);
+	}
+
+	return MSP85x0_OK;
+}
+
+
+/*
+ * Queue the packet for Tx. Currently no support for zero copy,
+ * checksum offload and Scatter Gather. The chip does support
+ * Scatter Gather only. But, that wont help here since zero copy
+ * requires support for Tx checksumming also.
+ */
+int msp85x0_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned long flags;
+	struct net_device_stats *stats;
+
+	stats = &msp85x0_ge_eth->stats;
+	spin_lock_irqsave(&msp85x0_ge_eth->lock, flags);
+
+	if (msp85x0_ge_eth->tx_threshold > TX_THRESHOLD) {
+		msp85x0_ge_eth->tx_threshold = 0;
+		msp85x0_ge_free_tx_queue(netdev);
+	}
+	else
+		msp85x0_ge_eth->tx_threshold++;
+
+
+	if ((MSP85x0_GE_TX_QUEUE - msp85x0_ge_eth->tx_ring_skbs) <=
+	    (skb_shinfo(skb)->nr_frags + 1)) {
+	printk("\n\r tx fragments = %d",skb_shinfo(skb)->nr_frags); 
+		netif_stop_queue(netdev);
+		spin_unlock_irqrestore(&msp85x0_ge_eth->lock, flags);
+		printk(KERN_ERR "Tx OOD \n");
+		return 1;
+	}
+
+	msp85x0_ge_tx_queue(msp85x0_ge_eth, skb);
+	msp85x0_ge_eth->tx_ring_skbs++;
+
+	stats->tx_bytes += skb->len;
+	stats->tx_packets++;
+
+	spin_unlock_irqrestore(&msp85x0_ge_eth->lock, flags);
+	netdev->trans_start = jiffies;
+	return 0;
+}
+
+/*
+ * Actually does the Rx. Rx side checksumming supported.
+ */
+static int msp85x0_ge_rx(struct net_device *netdev, int port_num,
+			msp85x0_ge_port_info * msp85x0_ge_eth,
+		       msp85x0_ge_packet * packet)
+{
+	int rx_curr_desc, rx_used_desc;
+	volatile msp85x0_ge_rx_desc *rx_desc;
+
+	rx_curr_desc = msp85x0_ge_eth->rx_curr_desc_q;
+	rx_used_desc = msp85x0_ge_eth->rx_used_desc_q;
+	port_num     = msp85x0_ge_eth->port_num;
+
+	rx_desc = &(msp85x0_ge_eth->rx_desc_area[rx_curr_desc]);
+
+	packet->skb = msp85x0_ge_eth->rx_skb[rx_curr_desc];
+	packet->len = (rx_desc->cmd_sts & 0x7fff);
+
+	/*
+	 * At this point, we dont know if the checksumming
+	 * actually helps relieve CPU. So, keep it for
+	 * port 0 only
+	 */
+	packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16);
+	packet->cmd_sts = rx_desc->cmd_sts;
+
+	if((rx_curr_desc + 1) == MSP85x0_GE_RX_QUEUE)
+		msp85x0_ge_eth->rx_curr_desc_q =0;
+	else
+		msp85x0_ge_eth->rx_curr_desc_q = (rx_curr_desc + 1);
+	msp85x0_ge_eth->rx_ring_skbs--;
+	msp85x0_ge_eth->rx_local_desc_count--;
+
+	/* Prefetch the next descriptor */
+	prefetch((const void *)
+	       &msp85x0_ge_eth->rx_desc_area[msp85x0_ge_eth->rx_curr_desc_q]);
+
+	return MSP85x0_OK;
+}
+
+/*
+ * Free the Tx queue of the used SKBs
+ */
+static int msp85x0_ge_free_tx_queue(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	int pkts,port_num = msp85x0_ge_eth->port_num;
+	int tx_desc_used;
+	struct sk_buff *skb;
+
+	/* Take the lock */
+	pkts=get_tx_pkt_count(port_num);
+	while(pkts)
+	{
+		pkts--;
+		tx_desc_used = msp85x0_ge_eth->tx_used_desc_q;
+
+		/* return right away */
+		if (tx_desc_used == msp85x0_ge_eth->tx_curr_desc_q)
+			break;
+	
+		skb = msp85x0_ge_eth->tx_skb[tx_desc_used];
+		dev_kfree_skb_irq(skb);
+		msp85x0_ge_eth->tx_skb[tx_desc_used] = NULL;
+
+		if((tx_desc_used + 1) == MSP85x0_GE_TX_QUEUE)
+			msp85x0_ge_eth->tx_used_desc_q=0;
+		else
+			msp85x0_ge_eth->tx_used_desc_q=tx_desc_used + 1;
+
+		if (msp85x0_ge_eth->tx_ring_skbs > 0)
+		{
+			msp85x0_ge_eth->tx_ring_skbs--;
+			decrement_tx_pkt_count(port_num);
+		}
+	}
+	return MSP85x0_OK;
+}
+
+/*
+ * Threshold beyond which we do the cleaning of
+ * Tx queue and new allocation for the Rx
+ * queue
+ */
+/*
+ * Receive the packets and send it to the kernel.
+ */
+
+
+static int msp85x0_ge_receive_queue(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int port_num = msp85x0_ge_eth->port_num;
+	msp85x0_ge_packet packet;
+	struct net_device_stats *stats;
+	struct sk_buff *skb;
+	unsigned long received_packets = 0;
+	unsigned int ack;
+	int max=-1;
+
+	unsigned int rx_dma_desc_count;
+	unsigned int total_desc_recvd;
+
+	rx_dma_desc_count=MSP85x0_GE_READ(MSP85x0_GE_CHANNEL0_RX_DMA_STS + (port_num << 9));		
+	if(msp85x0_ge_eth->rx_local_desc_count == rx_dma_desc_count)
+	{
+		return MSP85x0_ERROR;
+	}
+	if(rx_dma_desc_count > msp85x0_ge_eth->rx_local_desc_count)
+	{
+		printk(KERN_ERR"\n\r The DMA and S/W counter are not in SYNC !!");
+		return MSP85x0_ERROR;
+	}
+	total_desc_recvd=msp85x0_ge_eth->rx_local_desc_count - rx_dma_desc_count;
+	max=total_desc_recvd;
+
+	oom_flag=0;
+	stats = &msp85x0_ge_eth->stats;
+	while ((max--) && 
+	       (msp85x0_ge_rx(netdev, port_num, msp85x0_ge_eth, &packet) == MSP85x0_OK))
+ 	{	
+		skb = (struct sk_buff *) packet.skb;
+		if(!skb)
+		{
+			printk(KERN_ERR"\n\r Null SKB !!! ");
+			break;
+		}
+
+		msp85x0_ge_eth->rx_work_limit--;
+
+		received_packets++;
+
+		if (msp85x0_ge_eth->rx_threshold > RX_THRESHOLD) {
+			ack=msp85x0_ge_rx_task(netdev, msp85x0_ge_eth);
+		        MSP85x0_GE_WRITE((MSP85x0_GE_CHANNEL0_RX_DMA_STS + (msp85x0_ge_eth->port_num << 9)),ack);
+			msp85x0_ge_eth->rx_local_desc_count +=ack;	
+			if(!oom_flag){
+				msp85x0_ge_eth->rx_threshold = 0;
+			}
+		} else
+			msp85x0_ge_eth->rx_threshold++;
+
+		if (packet.cmd_sts & (MSP85x0_GE_RX_PERR | MSP85x0_GE_RX_OVERFLOW_ERROR | MSP85x0_GE_RX_TRUNC | MSP85x0_GE_RX_CRC_ERROR))
+		{
+			if(packet.cmd_sts & MSP85x0_GE_RX_OVERFLOW_ERROR)
+				stats->rx_over_errors++; 
+			else if(packet.cmd_sts & MSP85x0_GE_RX_TRUNC)
+				stats->rx_frame_errors++;
+			else
+				stats->rx_errors++;
+			dev_kfree_skb_any(skb);
+			continue;
+		}
+
+                if(!(packet.cmd_sts & MSP85x0_GE_RX_STP))
+                {
+                        stats->rx_dropped++;
+                        dev_kfree_skb_any(skb);
+                        continue;
+                }
+ 
+
+		/*
+		 * Increment data pointer by two since thats where
+		 * the MAC starts
+		 */
+		skb_reserve(skb, 2);
+		/*
+		 * Either support fast path or slow path. Decision
+		 * making can really slow down the performance. The
+		 * idea is to cut down the number of checks and improve
+		 * the fastpath.
+		 */
+		skb_put(skb, packet.len - 2);
+
+		skb->protocol = eth_type_trans(skb, netdev);
+
+		if(netif_receive_skb(skb)==NET_RX_DROP)
+		{
+			stats->rx_dropped++;
+		}
+		else
+		{
+			stats->rx_packets++;
+			stats->rx_bytes += packet.len;
+		}
+		if (!msp85x0_ge_eth->rx_work_limit || (oom_flag==1))
+		{
+			break;
+		}
+	}
+	return received_packets;
+}
+
+/*
+ * Main function to handle the polling for Rx side NAPI.
+ * Receive interrupts have been disabled at this point.
+ * The poll schedules the transmit followed by receive.
+ */
+static int msp85x0_ge_poll(struct net_device *netdev, int *budget)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	int port_num = msp85x0_ge_eth->port_num;
+	int work_done = 0;
+	unsigned long flags, status;	
+
+	msp85x0_ge_eth->rx_work_limit = *budget;
+	if ((int)msp85x0_ge_eth->rx_work_limit > netdev->quota)
+		msp85x0_ge_eth->rx_work_limit = netdev->quota;
+
+	do {
+		/* Ack the Rx interrupts */
+		clear_xdma_interrupts(port_num,RX_INT);
+		work_done += msp85x0_ge_receive_queue(netdev);
+		/* Out of quota and there is work to be done */
+		if((oom_flag == 1) || (msp85x0_ge_eth->rx_work_limit <= 0))
+		{
+			*budget -= work_done;
+			netdev->quota -= work_done;
+			return 1;
+		}
+		status = MSP85x0_GE_READ(MSP85x0_GE_INTR_XDMA_CORE_A);
+	}
+	while (status & (RX_INT << (XDMA_CHANNEL_OFFSET * port_num)));	
+
+	/* If we are here, then no more interrupts to process */
+	/*
+	 * No more packets on the poll list. Turn the interrupts
+	 * back on and we should be able to catch the new
+	 * packets in the interrupt handler
+	 */
+	spin_lock_irqsave(&msp85x0_ge_eth->lock,flags);
+	if (!work_done)
+		work_done = 1;
+
+	*budget -= work_done;
+	netdev->quota -= work_done;
+
+	/* Remove us from the poll list */
+	netif_rx_complete(netdev);
+
+	/* Re-enable interrupts */
+	msp85x0_ge_enable_rx_int(port_num);
+	spin_unlock_irqrestore(&msp85x0_ge_eth->lock,flags);
+	return 0;
+}
+
+/*
+ * Close the network device
+ */
+int msp85x0_ge_stop(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+
+	spin_lock_irq(&(msp85x0_ge_eth->lock));
+	msp85x0_ge_eth_stop(netdev);
+	free_irq(netdev->irq, netdev);
+	spin_unlock_irq(&msp85x0_ge_eth->lock);
+	return MSP85x0_OK;
+}
+
+/* Don't Re-Initialize the port, Just start from where it stops */ 
+static int msp85x0_ge_eth_reopen(struct net_device *netdev)	
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int reg_data,irq;
+	int retval;
+
+        irq = MSP85x0_ETH_PORT_IRQ;
+
+	retval = request_irq(irq, INTERRUPT_HANDLER,
+		     SA_INTERRUPT | SA_SAMPLE_RANDOM | SA_SHIRQ, netdev->name, netdev);
+
+	if (retval != 0) {
+		printk(KERN_ERR "Cannot assign IRQ number to MSP85x0 GE \n");
+		return -1;
+	}
+
+	netdev->irq = irq;
+	printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, msp85x0_ge_eth->port_num);
+
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_INTR_XDMA_IE);
+	reg_data |=(RX_INT << (msp85x0_ge_eth->port_num * 16));
+	MSP85x0_GE_WRITE(MSP85x0_GE_INTR_XDMA_IE,reg_data);
+
+	netif_start_queue(netdev);	
+	msp85x0_bringup_sequence(msp85x0_ge_eth->port_num);
+	return 0;
+}
+
+/*
+ * Actually does the stop of the Ethernet device
+ */
+static void msp85x0_ge_eth_stop(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int reg_data;
+
+	/* Tell Kernel to release this interface */
+	netif_stop_queue(netdev);
+	/* Disable the Tx and Rx Interrupts for the port*/
+	reg_data=MSP85x0_GE_READ(MSP85x0_GE_INTR_XDMA_IE);
+	reg_data &=~(0x3 << (msp85x0_ge_eth->port_num * 16));
+	MSP85x0_GE_WRITE(MSP85x0_GE_INTR_XDMA_IE,reg_data);
+	/* set the open function to re-open */
+	/* This to work around to solve the msp85x0 shutdown and bringup sequence */
+	netdev->open=msp85x0_ge_eth_reopen;
+	msp85x0_reset_sequence(msp85x0_ge_eth->port_num);
+}
+
+/*
+ * Update the MAC address. Note that we have to write the
+ * address in three station registers, 16 bits each. And this
+ * has to be done for TMAC and RMAC
+ */
+static void msp85x0_ge_update_mac_address(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+	unsigned int port_num = msp85x0_ge_eth->port_num;
+	u8 p_addr[6];
+
+	memcpy(msp85x0_ge_eth->port_mac_addr, netdev->dev_addr, 6);
+	memcpy(p_addr, netdev->dev_addr, 6);
+
+	/* Update the Address Filtering Match tables */
+	msp85x0_ge_update_afx(msp85x0_ge_eth);
+
+	printk("Station MAC : %d %d %d %d %d %d  \n",
+		p_addr[5], p_addr[4], p_addr[3],
+		p_addr[2], p_addr[1], p_addr[0]);
+
+	/* Set the MAC address here for TMAC and RMAC */
+	MSP85x0_GE_WRITE((MSP85x0_GE_TMAC_STATION_HI + (port_num << MAC_PORT_OFFSET)),
+		       ((p_addr[5] << 8) | p_addr[4]));
+	MSP85x0_GE_WRITE((MSP85x0_GE_TMAC_STATION_MID + (port_num << MAC_PORT_OFFSET)),
+		       ((p_addr[3] << 8) | p_addr[2]));
+	MSP85x0_GE_WRITE((MSP85x0_GE_TMAC_STATION_LOW + (port_num << MAC_PORT_OFFSET)),
+		       ((p_addr[1] << 8) | p_addr[0]));
+
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_STATION_HI + (port_num << MAC_PORT_OFFSET)),
+		       ((p_addr[5] << 8) | p_addr[4]));
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_STATION_MID + (port_num << MAC_PORT_OFFSET)),
+		       ((p_addr[3] << 8) | p_addr[2]));
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_STATION_LOW + (port_num << MAC_PORT_OFFSET)),
+		       ((p_addr[1] << 8) | p_addr[0]));
+}
+
+/*
+ * Set the MAC address of the Ethernet device
+ */
+static int msp85x0_ge_set_mac_address(struct net_device *dev, void *addr)
+{
+	msp85x0_ge_port_info *tp = netdev_priv(dev);
+	struct sockaddr *sa = addr;
+
+	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+
+	spin_lock_irq(&tp->lock);
+	msp85x0_ge_update_mac_address(dev);
+	spin_unlock_irq(&tp->lock);
+
+	return 0;
+}
+
+/*
+ * Get the Ethernet device stats
+ */
+static struct net_device_stats *msp85x0_ge_get_stats(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth = netdev_priv(netdev);
+
+	return &msp85x0_ge_eth->stats;
+}
+
+/*
+ * Initialize the Rx descriptor ring for the MSP85x0 Ge
+ */
+static int msp85x0_ge_init_rx_desc_ring(msp85x0_ge_port_info * msp85x0_eth_port,
+				      int rx_desc_num,
+				      int rx_buff_size,
+				      unsigned long rx_desc_base_addr,
+				      unsigned long rx_buff_base_addr,
+				      unsigned long rx_dma)
+{
+	volatile msp85x0_ge_rx_desc *rx_desc;
+	unsigned long buffer_addr;
+	int index;
+	unsigned long msp85x0_ge_rx_desc_bus = rx_dma;
+
+	buffer_addr = rx_buff_base_addr;
+	rx_desc = (msp85x0_ge_rx_desc *) rx_desc_base_addr;
+
+	/* Check alignment */
+	if (rx_buff_base_addr & 0xF)
+		return 0;
+
+	/* Check Rx buffer size */
+	if ((rx_buff_size < 8) || (rx_buff_size > MSP85x0_GE_MAX_RX_BUFFER))
+		return 0;
+
+	/* Initialize the Rx desc ring */
+	for (index = 0; index < rx_desc_num; index++) {
+		msp85x0_ge_rx_desc_bus += sizeof(msp85x0_ge_rx_desc);
+		rx_desc[index].cmd_sts = 0;
+		rx_desc[index].buffer_addr = 0;
+		msp85x0_eth_port->rx_skb[index] = NULL;
+		buffer_addr += rx_buff_size;
+	}
+
+	msp85x0_eth_port->rx_curr_desc_q = 0;
+	msp85x0_eth_port->rx_used_desc_q = 0;
+
+	msp85x0_eth_port->rx_desc_area = (msp85x0_ge_rx_desc *) rx_desc_base_addr;
+	msp85x0_eth_port->rx_desc_area_size =
+	    rx_desc_num * sizeof(msp85x0_ge_rx_desc);
+
+	msp85x0_eth_port->rx_dma = rx_dma;
+
+	return MSP85x0_OK;
+}
+
+/*
+ * Initialize the Tx descriptor ring. Descriptors in the SRAM
+ */
+static int msp85x0_ge_init_tx_desc_ring(msp85x0_ge_port_info * msp85x0_ge_eth,
+				      int tx_desc_num,
+				      unsigned long tx_desc_base_addr,
+				      unsigned long tx_dma)
+{
+	msp85x0_ge_tx_desc *tx_desc;
+	int index;
+	unsigned long msp85x0_ge_tx_desc_bus = tx_dma;
+
+	if (tx_desc_base_addr & 0xF)
+	{
+		printk(KERN_ERR"\n\r Descriptor Base is not 16 byte aligned !!=0x%lx",tx_desc_base_addr);
+		return 0;
+	}
+
+	tx_desc = (msp85x0_ge_tx_desc *) tx_desc_base_addr;
+
+	for (index = 0; index < tx_desc_num; index++) {
+		msp85x0_ge_eth->tx_dma_array[index] =
+		    (dma_addr_t) msp85x0_ge_tx_desc_bus;
+		msp85x0_ge_tx_desc_bus += sizeof(msp85x0_ge_tx_desc);
+		tx_desc[index].cmd_sts = 0x0000;
+		tx_desc[index].buffer_len = 0;
+		tx_desc[index].buffer_addr = 0x00000000;
+		msp85x0_ge_eth->tx_skb[index] = NULL;
+	}
+
+	msp85x0_ge_eth->tx_curr_desc_q = 0;
+	msp85x0_ge_eth->tx_used_desc_q = 0;
+
+	msp85x0_ge_eth->tx_desc_area = (msp85x0_ge_tx_desc *) tx_desc_base_addr;
+	msp85x0_ge_eth->tx_desc_area_size =
+	    tx_desc_num * sizeof(msp85x0_ge_tx_desc);
+
+	msp85x0_ge_eth->tx_dma = tx_dma;
+	return MSP85x0_OK;
+}
+
+/*
+ * Initialize the device as an Ethernet device
+ */
+static void __init msp85x0_ge_probe(struct net_device *netdev)
+{
+	msp85x0_ge_port_info *msp85x0_ge_eth;
+	unsigned int port = port_number;
+
+	ether_setup(netdev);
+
+	netdev->open = msp85x0_ge_open;
+	netdev->stop = msp85x0_ge_stop;
+	netdev->hard_start_xmit = msp85x0_ge_start_xmit;
+	netdev->get_stats = msp85x0_ge_get_stats;
+	netdev->set_multicast_list = msp85x0_ge_set_multi;
+	netdev->set_mac_address = msp85x0_ge_set_mac_address;
+
+	/* Tx timeout */
+	netdev->tx_timeout = msp85x0_ge_tx_timeout;
+	netdev->watchdog_timeo = 2 * HZ;
+
+	/* Set these to very high values */
+	netdev->poll = msp85x0_ge_poll;
+	netdev->weight = 64;
+
+	netdev->tx_queue_len = MSP85x0_GE_TX_QUEUE;
+	netdev->base_addr = 0;
+
+	netdev->change_mtu = msp85x0_ge_change_mtu;
+
+	msp85x0_ge_eth = netdev_priv(netdev);
+	/* Allocation of memory for the driver structures */
+
+	msp85x0_ge_eth->port_num = port;
+
+	/* Configure the Tx timeout handler */
+	INIT_WORK(&msp85x0_ge_eth->tx_timeout_task,
+		  (void (*)(void *)) msp85x0_ge_tx_timeout_task, netdev);
+	/* we're going to reset, so assume we have no link for now */
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+	spin_lock_init(&msp85x0_ge_eth->lock);
+
+	/*
+	 * Set MAC addresses: we assume that PMON correctly sets
+	 * up MAC addresses
+	 */
+	netdev->dev_addr[0] = 
+	  	MSP85x0_GE_READ((MSP85x0_GE_TMAC_STATION_LOW + 
+			       (port << MAC_PORT_OFFSET))) & 0xff;
+	netdev->dev_addr[1] = 
+		MSP85x0_GE_READ((MSP85x0_GE_TMAC_STATION_LOW + 
+			       (port << MAC_PORT_OFFSET))) >> 8;
+	netdev->dev_addr[2] = 
+		MSP85x0_GE_READ((MSP85x0_GE_TMAC_STATION_MID + 
+			       (port << MAC_PORT_OFFSET))) & 0xff;
+	netdev->dev_addr[3] = 
+		MSP85x0_GE_READ((MSP85x0_GE_TMAC_STATION_MID + 
+			       (port << MAC_PORT_OFFSET))) >> 8;
+	netdev->dev_addr[4] = 
+		MSP85x0_GE_READ((MSP85x0_GE_TMAC_STATION_HI + 
+			       (port << MAC_PORT_OFFSET))) & 0xff;
+	netdev->dev_addr[5] = 
+		MSP85x0_GE_READ((MSP85x0_GE_TMAC_STATION_HI + 
+			       (port << MAC_PORT_OFFSET))) >> 8;
+
+	printk(KERN_NOTICE
+	       "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       netdev->name, port, netdev->dev_addr[0],
+	       netdev->dev_addr[1], netdev->dev_addr[2],
+	       netdev->dev_addr[3], netdev->dev_addr[4],
+	       netdev->dev_addr[5]);
+
+	printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n");
+
+	return;
+}
+
+/*
+ * Reset the Ethernet port
+ */
+static void msp85x0_ge_port_reset(unsigned int port_num)
+{
+	unsigned int reg_data;
+	unsigned int retries=1000;
+	/* Stop the Tx port activity */
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_TMAC_CONFIG_1 +
+				(port_num << MAC_PORT_OFFSET));
+	reg_data &= ~(0x0001);
+	MSP85x0_GE_WRITE((MSP85x0_GE_TMAC_CONFIG_1 +
+			(port_num << MAC_PORT_OFFSET)), reg_data);
+
+	/* Wait till TMAC is brought down. */
+        reg_data = MSP85x0_GE_READ(MSP85x0_GE_TMAC_CONFIG_1 + 
+                                (port_num << MAC_PORT_OFFSET));
+        while((reg_data & 0x8000) && retries){
+		retries--;
+		udelay(30);
+                reg_data = MSP85x0_GE_READ(MSP85x0_GE_TMAC_CONFIG_1 +
+				(port_num << MAC_PORT_OFFSET));
+        }
+	if(!retries)
+	{
+		printk(KERN_ERR "Unable to stop the Tx MAC for Port %d",port_num);
+	}
+	/* Stop the Rx port activity */
+	retries=1000;
+	reg_data = MSP85x0_GE_READ(MSP85x0_GE_RMAC_CONFIG_1 +
+				(port_num << MAC_PORT_OFFSET));
+	reg_data &= ~(0x0001);
+	MSP85x0_GE_WRITE((MSP85x0_GE_RMAC_CONFIG_1 +
+			(port_num << MAC_PORT_OFFSET)), reg_data);
+
+	/* Wait till all packets received and RMAC brought down. */
+        reg_data = MSP85x0_GE_READ(MSP85x0_GE_RMAC_CONFIG_1 +
+                                (port_num << MAC_PORT_OFFSET));
+        while((reg_data & 0x8000) && retries){
+		retries--;
+		udelay(30);
+                reg_data = MSP85x0_GE_READ(MSP85x0_GE_RMAC_CONFIG_1 +
+                                (port_num << MAC_PORT_OFFSET));
+        }
+	if(!retries)
+	{
+		printk(KERN_ERR "Unable to stop the Rx MAC for Port %d",port_num);
+	}
+	return;
+}
+
+/*
+ * Coalescing for the Tx path
+ */
+static unsigned int msp85x0_ge_tx_coal(int port)
+{
+	unsigned int delay;
+	delay = (MSP85x0_GE_TX_COAL << 16) | MSP85x0_GE_RX_COAL;
+
+	MSP85x0_GE_WRITE(MSP85x0_GE_INT_COALESCING + (port * 4), delay);
+        MSP85x0_GE_WRITE(MSP85x0_GE_INT_COALESCING + (port * 4), delay);
+	return delay;
+}
+
+/*
+ * Register the MSP85x0 GE with the kernel
+ */
+static int __init msp85x0_ge_init_module(void)
+{
+	unsigned int version, device,regval;
+	int i,rc;
+
+	printk(KERN_NOTICE"PMC-Sierra MSP85x0 10/100/1000 Ethernet Driver \n");
+
+	msp85x0_ge_sram=(unsigned int)IOMAP(MSP85x0_SRAM_BASE,MSP85x0_SRAM_SIZE);
+	if (!msp85x0_ge_sram) {
+		printk(KERN_ERR"Mapping MSP85x0 SRAM failed\n");
+		return -ENOMEM;
+	}
+	
+	regval = MSP85x0_GE_READ(MSP85x0_GE_DEVICE_ID);
+	version= GET_GE_VERSION(regval);
+	device = GET_GE_ID(regval);
+
+	printk(KERN_NOTICE "Device Id : %x,  Version : %x \n", device, version);
+
+	for (port_number = 0; port_number < NO_PORTS; port_number++) {
+		i=port_number;
+		msp85x0_eth[i] = alloc_netdev(sizeof(struct _eth_port_ctrl),"eth%d",msp85x0_ge_probe);
+		if(!msp85x0_eth[i])
+			return -ENOMEM;
+
+		if((rc = register_netdev(msp85x0_eth[i])))
+		{
+      			printk(KERN_ERR "msp85x0_eth: error %i registering device \"%s\"\n",
+				rc, msp85x0_eth[i]->name);
+         		free_netdev(msp85x0_eth[i]);
+         		return -ENODEV;
+		
+		}
+
+	}
+	msp85x0_reset_sequence(0);
+	msp85x0_reset_sequence(1);
+	msp85x0_ge_xdma_reset();			
+   	spin_lock_init(&msp85x0_lock);
+	return 0;
+}
+
+/*
+ * Unregister the MSP85x0 GE from the kernel
+ */
+static void __exit msp85x0_ge_cleanup_module(void)
+{
+	int i;
+
+	for (i = 0; i < NO_PORTS; i++) 
+	{
+		if (msp85x0_eth[i]) 
+		{
+			unregister_netdev(msp85x0_eth[i]);
+			free_netdev(msp85x0_eth[i]);
+		}
+	}
+
+	iounmap((void *)msp85x0_ge_sram);
+}
+
+MODULE_AUTHOR("PMC Sierra Inc <thotakir@pmc-sierra.com>");
+MODULE_DESCRIPTION("MSP85x0 GE Ethernet driver");
+MODULE_LICENSE("GPL");
+
+module_init(msp85x0_ge_init_module);
+module_exit(msp85x0_ge_cleanup_module);
+
diff -Naur a/drivers/net/msp85x0_ge.h b/drivers/net/msp85x0_ge.h
--- a/drivers/net/msp85x0_ge.h	1969-12-31 16:00:00.000000000 -0800
+++ b/drivers/net/msp85x0_ge.h	2006-06-23 15:26:10.000000000 -0700
@@ -0,0 +1,452 @@
+#ifndef _MSP85x0_GE_H_
+#define _MSP85x0_GE_H_
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <asm/byteorder.h>
+
+#include <asm/pmc_sequoia.h>
+
+/*
+ * These functions should be later moved to a more generic location since there
+ * will be others accessing it also
+ */
+
+// MSP85x0_GE_BASE and MSP85x0_GE_SIZE are defined in asm/pmc_sequoia.h
+
+#ifndef msec_delay
+#define msec_delay(x)   do { if(in_interrupt()) { \
+				/* Don't mdelay in interrupt context! */ \
+				BUG(); \
+			} else { \
+				set_current_state(TASK_UNINTERRUPTIBLE); \
+				schedule_timeout((x * HZ)/1000); \
+			} } while(0)
+#endif
+#define MSP85x0_GE_PORT_0
+
+#define MSP85x0_SRAM_BASE         RM9150_SRAM_BASE
+#define MSP85x0_SRAM_SIZE         RM9150_SRAM_SIZE
+
+extern unsigned long titan_ge_sram;
+
+/*
+ * We may need these constants
+ */
+#define MSP85x0_BIT0    0x00000001
+#define MSP85x0_BIT1    0x00000002
+#define MSP85x0_BIT2    0x00000004
+#define MSP85x0_BIT3    0x00000008
+#define MSP85x0_BIT4    0x00000010
+#define MSP85x0_BIT5    0x00000020
+#define MSP85x0_BIT6    0x00000040
+#define MSP85x0_BIT7    0x00000080
+#define MSP85x0_BIT8    0x00000100
+#define MSP85x0_BIT9    0x00000200
+#define MSP85x0_BIT10   0x00000400
+#define MSP85x0_BIT11   0x00000800
+#define MSP85x0_BIT12   0x00001000
+#define MSP85x0_BIT13   0x00002000
+#define MSP85x0_BIT14   0x00004000
+#define MSP85x0_BIT15   0x00008000
+#define MSP85x0_BIT16   0x00010000
+#define MSP85x0_BIT17   0x00020000
+#define MSP85x0_BIT18   0x00040000
+#define MSP85x0_BIT19   0x00080000
+#define MSP85x0_BIT20   0x00100000
+#define MSP85x0_BIT21   0x00200000
+#define MSP85x0_BIT22   0x00400000
+#define MSP85x0_BIT23   0x00800000
+#define MSP85x0_BIT24   0x01000000
+#define MSP85x0_BIT25   0x02000000
+#define MSP85x0_BIT26   0x04000000
+#define MSP85x0_BIT27   0x08000000
+#define MSP85x0_BIT28   0x10000000
+#define MSP85x0_BIT29   0x20000000
+#define MSP85x0_BIT30   0x40000000
+#define MSP85x0_BIT31   0x80000000
+
+/* Flow Control */
+#define	MSP85x0_GE_FC_NONE	0x0
+#define	MSP85x0_GE_FC_FULL	0x1
+#define	MSP85x0_GE_FC_TX_PAUSE	0x2
+#define	MSP85x0_GE_FC_RX_PAUSE	0x3
+
+/* Duplex Settings */
+#define	MSP85x0_GE_FULL_DUPLEX	0x1
+#define	MSP85x0_GE_HALF_DUPLEX	0x2
+
+/* Speed settings */
+#define	MSP85x0_GE_SPEED_1000	0x1
+#define	MSP85x0_GE_SPEED_100	0x2
+#define	MSP85x0_GE_SPEED_10	0x3
+
+/* Debugging info only */
+#undef MSP85x0_DEBUG
+
+/* Keep the rings in the Titan's SSRAM */
+#define MSP85x0_RX_RING_IN_SRAM
+
+#ifdef CONFIG_MIPS64
+#define	MSP85x0_GE_IE_MASK	0xfffffffffb001b64
+#define	MSP85x0_GE_IE_STATUS	0xfffffffffb001b60
+#else
+#define	MSP85x0_GE_IE_MASK	0xfb001b64
+#define	MSP85x0_GE_IE_STATUS	0xfb001b60
+#endif
+
+/* Support for Jumbo Frames */
+#undef MSP85x0_GE_JUMBO_FRAMES
+//#define MSP85x0_GE_JUMBO_FRAMES
+
+/* Rx buffer size */
+#ifdef MSP85x0_GE_JUMBO_FRAMES
+#define	MSP85x0_GE_RX_BUFSIZE	(16 * 1024) 
+#else
+#define	MSP85x0_GE_RX_BUFSIZE	2048  
+#endif
+
+/*
+ * Tx and Rx Interrupt Coalescing parameter. These values are
+ * for 1 Ghz processor. Rx coalescing can be taken care of
+ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing
+ * is not adaptive. Hence, these values need to be adjusted
+ * based on load, CPU speed etc.
+ */
+#define	MSP85x0_GE_RX_COAL	10
+#define	MSP85x0_GE_TX_COAL	200
+
+#if defined(__BIG_ENDIAN)
+
+/* Define the Rx descriptor */
+
+typedef struct eth_rx_desc {
+	u32     reserved;	/* Unused 		*/
+	u32     buffer_addr;	/* CPU buffer address 	*/
+	u32	cmd_sts;	/* Command and Status	*/
+	u32	buffer;		/* XDMA buffer address	*/
+} msp85x0_ge_rx_desc;
+
+/* Define the Tx descriptor */
+typedef struct eth_tx_desc {
+	u16     cmd_sts;	/* Command, Status and Buffer count */
+	u16	buffer_len;	/* Length of the buffer	*/
+	u32     buffer_addr;	/* Physical address of the buffer */
+} msp85x0_ge_tx_desc;
+
+#elif defined(__LITTLE_ENDIAN)
+
+/* Define the Rx descriptor */
+typedef struct eth_rx_desc {
+        u32     buffer_addr;    /* CPU buffer address   */
+        u32     reserved;       /* Unused               */
+        u32     buffer;         /* XDMA buffer address  */
+        u32     cmd_sts;        /* Command and Status   */	
+} msp85x0_ge_rx_desc;
+
+/* Define the Tx descriptor */
+typedef struct eth_tx_desc {
+	u32     buffer_addr;	/* Physical address of the buffer */
+	u16     buffer_len;     /* Length of the buffer */
+	u16     cmd_sts;        /* Command, Status and Buffer count */
+} msp85x0_ge_tx_desc;
+#endif
+
+/* Default Tx Queue Size */
+#define MSP85x0_GE_TX_QUEUE     256
+#define MSP85x0_TX_RING_BYTES	(MSP85x0_GE_TX_QUEUE * sizeof(struct eth_tx_desc))
+
+/* Default Rx Queue Size */
+#define	MSP85x0_GE_RX_QUEUE	256
+#define MSP85x0_RX_RING_BYTES	(MSP85x0_GE_RX_QUEUE * sizeof(struct eth_rx_desc))
+
+/* Packet Structure */
+typedef struct _pkt_info {
+	unsigned int           len;
+	unsigned int            cmd_sts;
+	unsigned int            buffer;
+	struct sk_buff          *skb;
+	unsigned int		checksum;
+} msp85x0_ge_packet;
+
+
+#define	PHYS_CNT	3
+
+/* Titan Port specific data structure */
+typedef struct _eth_port_ctrl {
+	unsigned int		port_num;
+	u8			port_mac_addr[6];
+
+	/* Rx descriptor pointers */
+	int 			rx_curr_desc_q, rx_used_desc_q;
+
+	/* Tx descriptor pointers */
+	int 			tx_curr_desc_q, tx_used_desc_q;
+
+	/* Rx descriptor area */
+	volatile msp85x0_ge_rx_desc	*rx_desc_area;
+	unsigned int			rx_desc_area_size;
+	struct sk_buff*			rx_skb[MSP85x0_GE_RX_QUEUE];
+
+	/* Tx Descriptor area */
+	volatile msp85x0_ge_tx_desc	*tx_desc_area;
+	unsigned int                    tx_desc_area_size;
+	struct sk_buff*                 tx_skb[MSP85x0_GE_TX_QUEUE];
+
+	/* Timeout task */
+	struct work_struct		tx_timeout_task;
+
+	/* DMA structures and handles */
+	dma_addr_t			tx_dma;
+	dma_addr_t			rx_dma;
+	dma_addr_t			tx_dma_array[MSP85x0_GE_TX_QUEUE];
+
+	/* Device lock */
+	spinlock_t			lock;
+
+	unsigned int			tx_ring_skbs;
+	unsigned int			rx_ring_size;
+	unsigned int			tx_ring_size;
+	unsigned int			rx_ring_skbs;
+
+	struct net_device_stats		stats;
+
+	/* Tx and Rx coalescing */
+	unsigned long			rx_int_coal;
+	unsigned long			tx_int_coal;
+
+	/* Threshold for replenishing the Rx and Tx rings */
+	unsigned int			tx_threshold;
+	unsigned int			rx_threshold;
+
+	/* NAPI work limit */
+	int				rx_work_limit;
+	unsigned int 			rx_local_desc_count;
+
+} msp85x0_ge_port_info;
+
+/* Titan specific constants */
+#define	MSP85x0_ETH_PORT_IRQ		5
+
+/* Max Rx buffer */
+#define	MSP85x0_GE_MAX_RX_BUFFER		65536
+
+/* Tx and Rx Error */
+#define	MSP85x0_GE_ERROR
+
+/* Rx Descriptor Command and Status */
+
+#define	MSP85x0_GE_RX_CRC_ERROR		MSP85x0_BIT27	/* crc error */
+#define	MSP85x0_GE_RX_OVERFLOW_ERROR	MSP85x0_BIT15	/* overflow */
+#define MSP85x0_GE_RX_BUFFER_OWNED	MSP85x0_BIT21	/* buffer ownership */
+#define	MSP85x0_GE_RX_STP			MSP85x0_BIT31	/* start of packet */
+#define	MSP85x0_GE_RX_BAM			MSP85x0_BIT30	/* broadcast address match */
+#define MSP85x0_GE_RX_PAM			MSP85x0_BIT28	/* physical address match */
+#define MSP85x0_GE_RX_LAFM		MSP85x0_BIT29	/* logical address filter match */
+#define MSP85x0_GE_RX_VLAN		MSP85x0_BIT26	/* virtual lans */
+#define MSP85x0_GE_RX_PERR		MSP85x0_BIT19	/* packet error */
+#define MSP85x0_GE_RX_TRUNC		MSP85x0_BIT20	/* packet size greater than 32 buffers */
+
+/* Tx Descriptor Command */
+#define	MSP85x0_GE_TX_BUFFER_OWNED	MSP85x0_BIT5	/* buffer ownership */
+#define	MSP85x0_GE_TX_ENABLE_INTERRUPT	MSP85x0_BIT15	/* Interrupt Enable */
+
+/* Return Status */
+#define	MSP85x0_OK	0x1	/* Good Status */
+#define	MSP85x0_ERROR	0x2	/* Error Status */
+
+/* MIB specific register offset */
+#define MSP85x0_GE_MSTATX_STATS_BASE_LOW       0x0800  /* MSTATX COUNTL[15:0] */
+#define MSP85x0_GE_MSTATX_STATS_BASE_MID       0x0804  /* MSTATX COUNTM[15:0] */
+#define MSP85x0_GE_MSTATX_STATS_BASE_HI        0x0808  /* MSTATX COUNTH[7:0] */
+#define MSP85x0_GE_MSTATX_CONTROL              0x0828  /* MSTATX Control */
+#define MSP85x0_GE_MSTATX_VARIABLE_SELECT      0x082C  /* MSTATX Variable Select */
+
+/* MIB counter offsets, add to the MSP85x0_GE_MSTATX_STATS_BASE_XXX */
+#define MSP85x0_GE_MSTATX_RXFRAMESOK                   0x0040
+#define MSP85x0_GE_MSTATX_RXOCTETSOK                   0x0050
+#define MSP85x0_GE_MSTATX_RXFRAMES                     0x0060
+#define MSP85x0_GE_MSTATX_RXOCTETS                     0x0070
+#define MSP85x0_GE_MSTATX_RXUNICASTFRAMESOK            0x0080
+#define MSP85x0_GE_MSTATX_RXBROADCASTFRAMESOK          0x0090
+#define MSP85x0_GE_MSTATX_RXMULTICASTFRAMESOK          0x00A0
+#define MSP85x0_GE_MSTATX_RXTAGGEDFRAMESOK             0x00B0
+#define MSP85x0_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK    0x00C0
+#define MSP85x0_GE_MSTATX_RXMACCONTROLFRAMESOK         0x00D0
+#define MSP85x0_GE_MSTATX_RXFCSERROR                   0x00E0
+#define MSP85x0_GE_MSTATX_RXALIGNMENTERROR             0x00F0
+#define MSP85x0_GE_MSTATX_RXSYMBOLERROR                0x0100
+#define MSP85x0_GE_MSTATX_RXLAYER1ERROR                0x0110
+#define MSP85x0_GE_MSTATX_RXINRANGELENGTHERROR         0x0120
+#define MSP85x0_GE_MSTATX_RXLONGLENGTHERROR            0x0130
+#define MSP85x0_GE_MSTATX_RXLONGLENGTHCRCERROR         0x0140
+#define MSP85x0_GE_MSTATX_RXSHORTLENGTHERROR           0x0150
+#define MSP85x0_GE_MSTATX_RXSHORTLLENGTHCRCERROR       0x0160
+#define MSP85x0_GE_MSTATX_RXFRAMES64OCTETS             0x0170
+#define MSP85x0_GE_MSTATX_RXFRAMES65TO127OCTETS        0x0180
+#define MSP85x0_GE_MSTATX_RXFRAMES128TO255OCTETS       0x0190
+#define MSP85x0_GE_MSTATX_RXFRAMES256TO511OCTETS       0x01A0
+#define MSP85x0_GE_MSTATX_RXFRAMES512TO1023OCTETS      0x01B0
+#define MSP85x0_GE_MSTATX_RXFRAMES1024TO1518OCTETS     0x01C0
+#define MSP85x0_GE_MSTATX_RXFRAMES1519TOMAXSIZE        0x01D0
+#define MSP85x0_GE_MSTATX_RXSTATIONADDRESSFILTERED     0x01E0
+#define MSP85x0_GE_MSTATX_RXVARIABLE                   0x01F0
+#define MSP85x0_GE_MSTATX_GENERICADDRESSFILTERED       0x0200
+#define MSP85x0_GE_MSTATX_UNICASTFILTERED              0x0210
+#define MSP85x0_GE_MSTATX_MULTICASTFILTERED            0x0220
+#define MSP85x0_GE_MSTATX_BROADCASTFILTERED            0x0230
+#define MSP85x0_GE_MSTATX_HASHFILTERED                 0x0240
+#define MSP85x0_GE_MSTATX_TXFRAMESOK                   0x0250
+#define MSP85x0_GE_MSTATX_TXOCTETSOK                   0x0260
+#define MSP85x0_GE_MSTATX_TXOCTETS                     0x0270
+#define MSP85x0_GE_MSTATX_TXTAGGEDFRAMESOK             0x0280
+#define MSP85x0_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK    0x0290
+#define MSP85x0_GE_MSTATX_TXFCSERROR                   0x02A0
+#define MSP85x0_GE_MSTATX_TXSHORTLENGTHERROR           0x02B0
+#define MSP85x0_GE_MSTATX_TXLONGLENGTHERROR            0x02C0
+#define MSP85x0_GE_MSTATX_TXSYSTEMERROR                0x02D0
+#define MSP85x0_GE_MSTATX_TXMACERROR                   0x02E0
+#define MSP85x0_GE_MSTATX_TXCARRIERSENSEERROR          0x02F0
+#define MSP85x0_GE_MSTATX_TXSQETESTERROR               0x0300
+#define MSP85x0_GE_MSTATX_TXUNICASTFRAMESOK            0x0310
+#define MSP85x0_GE_MSTATX_TXBROADCASTFRAMESOK          0x0320
+#define MSP85x0_GE_MSTATX_TXMULTICASTFRAMESOK          0x0330
+#define MSP85x0_GE_MSTATX_TXUNICASTFRAMESATTEMPTED     0x0340
+#define MSP85x0_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED   0x0350
+#define MSP85x0_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED   0x0360
+#define MSP85x0_GE_MSTATX_TXFRAMES64OCTETS             0x0370
+#define MSP85x0_GE_MSTATX_TXFRAMES65TO127OCTETS        0x0380
+#define MSP85x0_GE_MSTATX_TXFRAMES128TO255OCTETS       0x0390
+#define MSP85x0_GE_MSTATX_TXFRAMES256TO511OCTETS       0x03A0
+#define MSP85x0_GE_MSTATX_TXFRAMES512TO1023OCTETS      0x03B0
+#define MSP85x0_GE_MSTATX_TXFRAMES1024TO1518OCTETS     0x03C0
+#define MSP85x0_GE_MSTATX_TXFRAMES1519TOMAXSIZE        0x03D0
+#define MSP85x0_GE_MSTATX_TXVARIABLE                   0x03E0
+#define MSP85x0_GE_MSTATX_RXSYSTEMERROR                0x03F0
+#define MSP85x0_GE_MSTATX_SINGLECOLLISION              0x0400
+#define MSP85x0_GE_MSTATX_MULTIPLECOLLISION            0x0410
+#define MSP85x0_GE_MSTATX_DEFERREDXMISSIONS            0x0420
+#define MSP85x0_GE_MSTATX_LATECOLLISIONS               0x0430
+#define MSP85x0_GE_MSTATX_ABORTEDDUETOXSCOLLS          0x0440
+
+
+/* Interrupt specific defines */
+#define MSP85x0_GE_DEVICE_ID         0x0000  /* Device ID */
+#define MSP85x0_GE_RESET             0x0008  /* Reset reg */
+#define MSP85x0_GE_TSB_CTRL_0        0x0010  /* TSB Control reg 0 */
+#define MSP85x0_GE_CPIF2_GU0         0x0014  /* CPIF2 General Use 0 */
+#define MSP85x0_GE_CPIF2_GENERAL_USE3	0x0020
+#define MSP85x0_GE_INTR_GRP0_STATUS  0x0024  /* General Interrupt Group 0 Status */
+#define MSP85x0_GE_INTR_XDMA_CORE_A  0x002C  /* XDMA Channel Interrupt Status, Core A*/
+#define MSP85x0_GE_CPIF2_SET_VECTOR_MSG0	0x0044
+#define MSP85x0_GE_CPIF2_INT_MSG_ADDR0	0x0060
+#define MSP85x0_GE_CPIF2_INT_VECOTR_MODE0	0x0080
+#define MSP85x0_GE_INTR_XDMA_IE      0x0084  /* XDMA Channel Interrupt Enable */
+#define MSP85x0_GE_SDQPF_ECC_INTR    0x280C  /* SDQPF ECC Interrupt Status */
+
+#define MSP85x0_GE_SDQPF_RXFIFO_CTL  0x2828  /* SDQPF RxFifo Control and Interrupt Enb*/
+#define MSP85x0_GE_SDQPF_RXFIFO_INTR 0x282C  /* SDQPF RxFifo Interrupt Status */
+#define MSP85x0_GE_SDQPF_RXFIFO_0    0x2840  /* SDQPF RxFIFO Config */
+#define MSP85x0_GE_SDQPF_RX_THRLD_0  0x2844
+#define MSP85x0_GE_SDQPF_RXFIFO_8    0x28A0  /* SDQPF RxFIFO Config */
+#define MSP85x0_GE_SDQPF_RX_THRLD_8  0x28A4
+
+#define MSP85x0_GE_SDQPF_TXFIFO_CTL  0x2928  /* SDQPF TxFifo Control and Interrupt Enb*/
+#define MSP85x0_GE_SDQPF_TXFIFO_INTR 0x292C  /* SDQPF TxFifo Interrupt Status */
+#define MSP85x0_GE_SDQPF_TXFIFO_0    0x2940  /* SDQPF TxFIFO Enable */
+#define MSP85x0_GE_SDQPF_TX_THRLD_0  0x2944  /* SDQPF TxFIFO Enable */
+#define MSP85x0_GE_SDQPF_TXFIFO_1    0x294C  /* SDQPF TxFIFO Enable */
+#define MSP85x0_GE_SDQPF_TX_THRLD_1  0x2950  /* SDQPF TxFIFO Enable */
+
+#define MSP85x0_GE_XDMA_CONFIG       0x3000  /* XDMA Global Configuration */
+#define MSP85x0_GE_XDMA_INTR_SUMMARY 0x3010  /* XDMA Interrupt Summary */
+#define MSP85x0_GE_XDMA_BUFADDRPRE   0x3018  /* XDMA Buffer Address Prefix */
+#define MSP85x0_GE_XDMA_DESCADDRPRE  0x301C  /* XDMA Descriptor Address Prefix */
+#define MSP85x0_GE_XDMA_PORTWEIGHT   0x302C  /* XDMA Port Weight Configuration */
+
+#define MSP85x0_GE_CPIF2_CPXCISR     0x002C
+#define MSP85x0_GE_CPIF2_CPGIG0SR    0x0024
+#define MSP85x0_GE_INTR_GRP0_STATUS  0x0024	
+
+/* Rx MAC defines */
+#define MSP85x0_GE_RMAC_CONFIG_1               0x1200  /* RMAC Configuration 1 */
+#define MSP85x0_GE_RMAC_CONFIG_2               0x1204  /* RMAC Configuration 2 */
+#define MSP85x0_GE_RMAC_MAX_FRAME_LEN          0x1208  /* RMAC Max Frame Length */
+#define MSP85x0_GE_RMAC_STATION_HI             0x120C  /* Rx Station Address High */
+#define MSP85x0_GE_RMAC_STATION_MID            0x1210  /* Rx Station Address Middle */
+#define MSP85x0_GE_RMAC_STATION_LOW            0x1214  /* Rx Station Address Low */
+#define MSP85x0_GE_RMAC_LINK_CONFIG            0x1218  /* RMAC Link Configuration */
+
+/* Tx MAC defines */
+#define MSP85x0_GE_TMAC_CONFIG_1               0x1240  /* TMAC Configuration 1 */
+#define MSP85x0_GE_TMAC_CONFIG_2               0x1244  /* TMAC Configuration 2 */
+#define MSP85x0_GE_TMAC_IPG                    0x1248  /* TMAC Inter-Packet Gap */
+#define MSP85x0_GE_TMAC_STATION_HI             0x124C  /* Tx Station Address High */
+#define MSP85x0_GE_TMAC_STATION_MID            0x1250  /* Tx Station Address Middle */
+#define MSP85x0_GE_TMAC_STATION_LOW            0x1254  /* Tx Station Address Low */
+#define MSP85x0_GE_TMAC_MAX_FRAME_LEN          0x1258  /* TMAC Max Frame Length */
+#define MSP85x0_GE_TMAC_MIN_FRAME_LEN          0x125C  /* TMAC Min Frame Length */
+#define MSP85x0_GE_TMAC_PAUSE_FRAME_TIME       0x1260  /* TMAC Pause Frame Time */
+#define MSP85x0_GE_TMAC_PAUSE_FRAME_INTERVAL   0x1264  /* TMAC Pause Frame Interval */
+
+#define MSP85x0_GE_L1RPP_CONFIG_STS	     0x128C	
+#define MSP85x0_GE_RTIF_CONFIG		     0x12CC
+
+#define MSP85x0_GE_L1TPP_CONFIG 		     0x1300
+/* GMII register */
+#define MSP85x0_GE_GMII_INTERRUPT_STATUS       0x1348  /* GMII Interrupt Status */
+#define MSP85x0_GE_GMII_CONFIG_GENERAL         0x134C  /* GMII Configuration General */
+#define MSP85x0_GE_GMII_CONFIG_MODE            0x1350  /* GMII Configuration Mode */
+
+/* Tx and Rx XDMA defines */
+
+#define MSP85x0_GE_GXDMA_INT_STS		     0x3008
+#define MSP85x0_GE_GXDMA0_DESC_PREFETCH_CNT    0x305C
+
+#define MSP85x0_GE_INT_COALESCING              0x3030 /* Interrupt Coalescing */
+#define MSP85x0_GE_GDI_PASSPW_CONFIG           0x303C /* Channel 0 XDMA config */
+#define MSP85x0_GE_CHANNEL0_CONFIG             0x3040 /* Channel 0 XDMA config */
+#define MSP85x0_GE_CHANNEL0_TX_DMA_STS	     0x3044 /* Channel 0 Tx DMA Status */	
+#define MSP85x0_GE_CHANNEL0_RX_DMA_STS	     0x3048 /* Channel 0 Rx DMA Status */
+#define MSP85x0_GE_CHANNEL0_INTERRUPT          0x304c /* Channel 0 Interrupt Status */
+#define MSP85x0_GE_GDI_INTERRUPT_ENABLE        0x3050 /* IE for the GDI Errors */
+#define MSP85x0_GE_CHANNEL0_PACKET             0x3060 /* Channel 0 Packet count */
+#define MSP85x0_GE_CHANNEL0_BYTE               0x3064 /* Channel 0 Byte count */
+#define MSP85x0_GE_CHANNEL0_TX_DESC            0x3054 /* Channel 0 Tx first desc */
+#define MSP85x0_GE_CHANNEL0_RX_DESC            0x3058 /* Channel 0 Rx first desc */
+#define MSP85x0_GE_CHANNEL0_RX_DESC_PKT_DRP_THR	0x3074
+
+#define MSP85x0_GE_TRTG2_INTERRUPT_IND	     0x100C
+#define MSP85x0_GE_TRTG_PRIORITY_CHKSUM	     0x1038
+#define MSP85x0_GE_TRTG_BYTE_OFFSET_0	     0x103C
+#define MSP85x0_GE_TRTG_BYTE_OFFSET_1	     0x1040
+
+/* AFX (Address Filter Exact) register offsets for Slice 0 */
+#define MSP85x0_GE_AFX_EXACT_MATCH_LOW         0x1100  /* AFX Exact Match Address Low*/
+#define MSP85x0_GE_AFX_EXACT_MATCH_MID         0x1104  /* AFX Exact Match Address Mid*/
+#define MSP85x0_GE_AFX_EXACT_MATCH_HIGH        0x1108  /* AFX Exact Match Address Hi */
+#define MSP85x0_GE_AFX_EXACT_MATCH_VID         0x110C  /* AFX Exact Match VID */
+
+#define MSP85x0_GE_AFX_MULTICAST_HASH_LOW      0x1118  /* AFX Multicast HASH Low */
+#define MSP85x0_GE_AFX_MULTICAST_HASH_MIDLOW   0x111c  /* AFX Multicast HASH MidLow */
+#define MSP85x0_GE_AFX_MULTICAST_HASH_MIDHI    0x1120  /* AFX Multicast HASH MidHi*/
+#define MSP85x0_GE_AFX_MULTICAST_HASH_HI       0x1124  /* AFX Multicast HASH Hi */
+#define MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_0     0x1158  /* AFX Address Filter Ctrl 0 */
+#define MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_1     0x115C  /* AFX Address Filter Ctrl 1 */
+#define MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_2     0x1160  /* AFX Address Filter Ctrl 2 */
+#define MSP85x0_GE_AFX_ADDRS_FILTER_CTRL_3     0x1164  /* AFX Address Filter Ctrl 2 */
+/* Traffic Groomer block */
+#define        MSP85x0_GE_TRTG_CONFIG	     0x1000  /* TRTG Config */
+
+
+#define XDMA_TMAC_RESET  0x80000000
+#define XDMA_TMAC_ENABLE (~(0xC0000000))
+
+#define XDMA_RMAC_RESET  0x00100000
+#define XDMA_RMAC_ENABLE (~(0x00180000))
+#endif 				/* _MSP85x0_GE_H_ */
+
diff -Naur a/drivers/net/titan_mdio.c b/drivers/net/titan_mdio.c
--- a/drivers/net/titan_mdio.c	2005-07-11 11:28:10.000000000 -0700
+++ b/drivers/net/titan_mdio.c	2006-06-22 11:48:21.000000000 -0700
@@ -41,6 +41,17 @@
 /*
  * Titan MDIO and SCMB registers
  */
+#ifdef CONFIG_PMC_SEQUOIA
+
+#define TITAN_GE_SCMB_CONTROL                0x0400  /* SCMB Control */
+#define TITAN_GE_SCMB_CLKA                   0x0404  /* SCMB Clock A */
+#define TITAN_GE_MDIO_COMMAND                0x0410  /* MDIO Command */
+#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS    0x0414  /* MDIO Device and Port addrs */
+#define TITAN_GE_MDIO_DATA                   0x0418  /* MDIO Data */
+#define TITAN_GE_MDIO_INTERRUPTS             0x041C  /* MDIO Interrupts */
+
+#else // CONFIG_PMC_SEQUOIA
+
 #define TITAN_GE_SCMB_CONTROL                0x01c0  /* SCMB Control */
 #define TITAN_GE_SCMB_CLKA	             0x01c4  /* SCMB Clock A */
 #define TITAN_GE_MDIO_COMMAND                0x01d0  /* MDIO Command */
@@ -48,6 +59,8 @@
 #define TITAN_GE_MDIO_DATA                   0x01d8  /* MDIO Data */
 #define TITAN_GE_MDIO_INTERRUPTS             0x01dC  /* MDIO Interrupts */
 
+#endif //CONFIG_PMC_SEQUOIA
+
 /*
  * Function to poll the MDIO
  */
@@ -132,6 +145,10 @@
 	volatile unsigned long	val;
 	int retries = 0;
 
+#ifdef CONFIG_PMC_SEQUOIA
+        dev_addr++;
+#endif
+
 	/* Setup the PHY device */
 
 again:
@@ -181,6 +198,10 @@
 {
 	volatile unsigned long	val;
 
+#ifdef CONFIG_PMC_SEQUOIA
+        dev_addr++;
+#endif
+
 	if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
 		return TITAN_GE_MDIO_ERROR;
 
diff -Naur a/drivers/net/titan_mdio.h b/drivers/net/titan_mdio.h
--- a/drivers/net/titan_mdio.h	2005-07-11 11:28:10.000000000 -0700
+++ b/drivers/net/titan_mdio.h	2006-06-22 11:48:21.000000000 -0700
@@ -7,8 +7,13 @@
 #include <linux/netdevice.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
+#ifdef CONFIG_PMC_YOSEMITE
 #include "titan_ge.h"
+#else
+#include "msp85x0_ge.h"
+#endif
 
+extern unsigned long titan_ge_base;
 
 #define	TITAN_GE_MDIO_ERROR	(-9000)
 #define	TITAN_GE_MDIO_GOOD	0

^ permalink raw reply

* Re: [patch 2/6] [Network namespace] Network device sharing by view
From: Eric W. Biederman @ 2006-06-26 20:37 UTC (permalink / raw)
  To: Herbert Poetzl
  Cc: Daniel Lezcano, Andrey Savochkin, linux-kernel, netdev, serue,
	haveblue, clg, Andrew Morton, dev, devel, sam, viro,
	Alexey Kuznetsov
In-Reply-To: <20060626200225.GA5330@MAIL.13thfloor.at>

Herbert Poetzl <herbert@13thfloor.at> writes:

> On Mon, Jun 26, 2006 at 01:35:15PM -0600, Eric W. Biederman wrote:
>> Herbert Poetzl <herbert@13thfloor.at> writes:
>> 
>
> yes, but you will not be able to apply policy on
> the parent, restricting the child networking in a
> proper way without jumping through hoops ...

?  I don't understand where you are coming from.
There is no restriction on where you can apply policy.

>> I really do not believe we have a hotpath issue, if this
>> is implemented properly. Benchmarks of course need to be taken,
>> to prove this.
>
> I'm fine with proper testing and good numbers here
> but until then, I can only consider it a prototype

We are taking the first steps to get this all sorted out.
I think what we have is more than a prototype but less then
the final implementation.  Call it the very first draft version.

>> There are only two places a sane implementation should show issues.
>> - When the access to a pointer goes through a pointer to find
>>   that global variable.
>> - When doing a lookup in a hash table we need to look at an additional
>>   field to verify a hash match.  Because having a completely separate
>>   hash table is likely too expensive.
>> 
>> If that can be shown to really slow down packets on the hot path I am
>> willing to consider other possibilities. Until then I think we are on
>> path to the simplest and most powerful version of building a network
>> namespace usable by containers.
>
> keep in mind that you actually have three kinds
> of network traffic on a typical host/guest system:
>
>  - traffic between unit and outside
>    - host traffic should be quite minimal
>    - guest traffic will be quite high
>
>  - traffic between host and guest
>    probably minimal too (only for shared services)
>
>  - traffic between guests
>    can be as high (or even higher) than the
>    outbound traffic, just think web guest and
>    database guest

Interesting.

>> The routing between network namespaces does have the potential to be
>> more expensive than just a packet trivially coming off the wire into a
>> socket.
>
> IMHO the routing between network namespaces should
> not require more than the current local traffic
> does (i.e. you should be able to achieve loopback
> speed within an insignificant tolerance) and not
> nearly the time required for on-wire stuff ...

That assumes on the wire stuff is noticeably slower.
You can achieve over 1GB/s on some networks.

But I agree that the cost should resemble the current
loopback device.  I have seen nothing that suggests
it is not.

>> However that is fundamentally from a lack of hardware. If the
>> rest works smarter filters in the drivers should enable to remove the
>> cost.
>> 
>> Basically it is just a matter of:
>> if (dest_mac == my_mac1) it is for device 1.
>> If (dest_mac == my_mac2) it is for device 2.
>> etc.
>
> hmm, so you plan on providing a different MAC for
> each guest? how should that be handled from the
> user PoV? you cannot simply make up MACs as you
> go, and, depending on the network card, operation
> in promisc mode might be slower than for a given
> set (maybe only one) MAC, no?

The speed is a factor certainly.  As for making up
macs.  There is a local assignment bit that you can set.
With that set it is just a matter of using a decent random
number generator.  The kernel already does this is some places.

>> At a small count of macs it is trivial to understand it will go
>> fast for a larger count of macs it only works with a good data
>> structure.  We don't hit any extra cache lines of the packet,
>> and the above test can be collapsed with other routing lookup tests.
>
> well, I'm absolutely not against flexibility or
> full virtualization, but the proposed 'routing'
> on the host effectively doubles the time the
> packet spends in the network stack(s), so I can
> not believe that this approach would not add
> (significant) overhead to the hot path ...

It might, but I am pretty certain it won't double
the cost, as you don't do 2 full network stack traversals.
And even at a full doubling I doubt it will affect bandwith
or latency very much.  If it does we have a lot more to optimize
in the network stack than just this code.

Eric

^ permalink raw reply

* [PATCH Round 2 2/2] Core network changes to support network event notification.
From: Steve Wise @ 2006-06-26 20:36 UTC (permalink / raw)
  To: davem; +Cc: netdev
In-Reply-To: <20060626203638.19083.71231.stgit@stevo-desktop>


This patch adds netevent and netlink calls for neighbour change, route
add/del, and routing redirect events.

TBD: 
	PMTU change netevent and netlink calls.
	netlink call for redirect events.
---

 include/linux/rtnetlink.h |    2 ++
 net/core/Makefile         |    2 +-
 net/core/neighbour.c      |   37 ++++++++++++++++++++++++++++++-------
 net/ipv4/fib_semantics.c  |    9 +++++++++
 net/ipv4/route.c          |   16 ++++++++++++++++
 net/ipv6/route.c          |   22 ++++++++++++++++++++++
 6 files changed, 80 insertions(+), 8 deletions(-)

diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index df0cdd4..14f5622 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -42,6 +42,8 @@ #define RTM_NEWNEIGH	RTM_NEWNEIGH
 #define RTM_DELNEIGH	RTM_DELNEIGH
 	RTM_GETNEIGH,
 #define RTM_GETNEIGH	RTM_GETNEIGH
+	RTM_CHGNEIGH,
+#define RTM_CHGNEIGH	RTM_CHGNEIGH
 
 	RTM_NEWRULE	= 32,
 #define RTM_NEWRULE	RTM_NEWRULE
diff --git a/net/core/Makefile b/net/core/Makefile
index e9bd246..2645ba4 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -7,7 +7,7 @@ obj-y := sock.o request_sock.o skbuff.o 
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 
-obj-y		     += dev.o ethtool.o dev_mcast.o dst.o \
+obj-y		     += dev.o ethtool.o dev_mcast.o dst.o netevent.o \
 			neighbour.o rtnetlink.o utils.o link_watch.o filter.o
 
 obj-$(CONFIG_XFRM) += flow.o
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 50a8c73..7b67da8 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -30,9 +30,11 @@ #include <linux/times.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
 #include <net/sock.h>
+#include <net/netevent.h>
 #include <linux/rtnetlink.h>
 #include <linux/random.h>
 #include <linux/string.h>
+#include <linux/notifier.h>
 
 #define NEIGH_DEBUG 1
 
@@ -59,6 +61,7 @@ static void neigh_app_notify(struct neig
 #endif
 static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
 void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
+static void rtm_neigh_change(struct neighbour *n);
 
 static struct neigh_table *neigh_tables;
 #ifdef CONFIG_PROC_FS
@@ -755,6 +758,7 @@ #endif
 			neigh->nud_state = NUD_STALE;
 			neigh->updated = jiffies;
 			neigh_suspect(neigh);
+			notify = 1;
 		}
 	} else if (state & NUD_DELAY) {
 		if (time_before_eq(now, 
@@ -763,6 +767,7 @@ #endif
 			neigh->nud_state = NUD_REACHABLE;
 			neigh->updated = jiffies;
 			neigh_connect(neigh);
+			notify = 1;
 			next = neigh->confirmed + neigh->parms->reachable_time;
 		} else {
 			NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
@@ -820,6 +825,8 @@ #endif
 out:
 		write_unlock(&neigh->lock);
 	}
+	if (notify)
+		rtm_neigh_change(neigh);
 
 #ifdef CONFIG_ARPD
 	if (notify && neigh->parms->app_probes)
@@ -927,9 +934,7 @@ int neigh_update(struct neighbour *neigh
 {
 	u8 old;
 	int err;
-#ifdef CONFIG_ARPD
 	int notify = 0;
-#endif
 	struct net_device *dev;
 	int update_isrouter = 0;
 
@@ -949,9 +954,7 @@ #endif
 			neigh_suspect(neigh);
 		neigh->nud_state = new;
 		err = 0;
-#ifdef CONFIG_ARPD
 		notify = old & NUD_VALID;
-#endif
 		goto out;
 	}
 
@@ -1023,9 +1026,7 @@ #endif
 		if (!(new & NUD_CONNECTED))
 			neigh->confirmed = jiffies -
 				      (neigh->parms->base_reachable_time << 1);
-#ifdef CONFIG_ARPD
 		notify = 1;
-#endif
 	}
 	if (new == old)
 		goto out;
@@ -1056,7 +1057,11 @@ out:
 			(neigh->flags | NTF_ROUTER) :
 			(neigh->flags & ~NTF_ROUTER);
 	}
+
 	write_unlock_bh(&neigh->lock);
+
+	if (notify)
+		rtm_neigh_change(neigh);
 #ifdef CONFIG_ARPD
 	if (notify && neigh->parms->app_probes)
 		neigh_app_notify(neigh);
@@ -2370,9 +2375,27 @@ static void neigh_app_notify(struct neig
 	NETLINK_CB(skb).dst_group  = RTNLGRP_NEIGH;
 	netlink_broadcast(rtnl, skb, 0, RTNLGRP_NEIGH, GFP_ATOMIC);
 }
-
 #endif /* CONFIG_ARPD */
 
+static void rtm_neigh_change(struct neighbour *n)
+{
+	struct nlmsghdr *nlh;
+	int size = NLMSG_SPACE(sizeof(struct ndmsg) + 256);
+	struct sk_buff *skb = alloc_skb(size, GFP_ATOMIC);
+
+	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n);
+	if (!skb)
+		return;
+
+	if (neigh_fill_info(skb, n, 0, 0, RTM_CHGNEIGH, 0) < 0) {
+		kfree_skb(skb);
+		return;
+	}
+	nlh			   = (struct nlmsghdr *)skb->data;
+	NETLINK_CB(skb).dst_group  = RTNLGRP_NEIGH;
+	netlink_broadcast(rtnl, skb, 0, RTNLGRP_NEIGH, GFP_ATOMIC);
+}
+
 #ifdef CONFIG_SYSCTL
 
 static struct neigh_sysctl_table {
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 0f4145b..197c365 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -45,6 +45,7 @@ #include <net/tcp.h>
 #include <net/sock.h>
 #include <net/ip_fib.h>
 #include <net/ip_mp_alg.h>
+#include <net/netevent.h>
 
 #include "fib_lookup.h"
 
@@ -280,6 +281,14 @@ void rtmsg_fib(int event, u32 key, struc
 	struct sk_buff *skb;
 	u32 pid = req ? req->pid : n->nlmsg_pid;
 	int size = NLMSG_SPACE(sizeof(struct rtmsg)+256);
+	struct netevent_route_info nri;
+	int netevent;
+
+	nri.family = AF_INET;
+	nri.data = &fa->fa_info;
+	netevent = event == RTM_NEWROUTE ? NETEVENT_ROUTE_ADD 
+					 : NETEVENT_ROUTE_DEL;
+	call_netevent_notifiers(netevent, &nri);
 
 	skb = alloc_skb(size, GFP_KERNEL);
 	if (!skb)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index cc9423d..a20c320 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -105,6 +105,7 @@ #include <net/tcp.h>
 #include <net/icmp.h>
 #include <net/xfrm.h>
 #include <net/ip_mp_alg.h>
+#include <net/netevent.h>
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
 #endif
@@ -1112,6 +1113,19 @@ static void rt_del(unsigned hash, struct
 	spin_unlock_bh(rt_hash_lock_addr(hash));
 }
 
+static void rtm_redirect(struct rtable *old, struct rtable *new)
+{
+	struct netevent_redirect netevent;
+	netevent.old = &old->u.dst;
+	netevent.new = &new->u.dst;
+	struct sk_buff *skb;
+
+	/* notify netevent subscribers */
+	call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
+
+	/* TBD...post NETLINK msg */
+}
+
 void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
 		    u32 saddr, struct net_device *dev)
 {
@@ -1211,6 +1225,8 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
 					rt_drop(rt);
 					goto do_next;
 				}
+				
+				rtm_redirect(rth, rt);
 
 				rt_del(hash, rth);
 				if (!rt_intern_hash(hash, rt, &rt))
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 8a77793..ff523fb 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -908,6 +908,7 @@ int ip6_route_add(struct in6_rtmsg *rtms
 	struct net_device *dev = NULL;
 	struct inet6_dev *idev = NULL;
 	int addr_type;
+	struct netevent_route_info nri;
 
 	rta = (struct rtattr **) _rtattr;
 
@@ -1086,6 +1087,9 @@ install_route:
 		rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
 	rt->u.dst.dev = dev;
 	rt->rt6i_idev = idev;
+	nri.family = AF_INET6;
+	nri.data = rt;
+	call_netevent_notifiers(NETEVENT_ROUTE_ADD, &nri);
 	return ip6_ins_rt(rt, nlh, _rtattr, req);
 
 out:
@@ -1117,6 +1121,7 @@ static int ip6_route_del(struct in6_rtms
 	struct fib6_node *fn;
 	struct rt6_info *rt;
 	int err = -ESRCH;
+	struct netevent_route_info nri;
 
 	read_lock_bh(&rt6_lock);
 
@@ -1138,6 +1143,10 @@ static int ip6_route_del(struct in6_rtms
 				continue;
 			dst_hold(&rt->u.dst);
 			read_unlock_bh(&rt6_lock);
+			
+			nri.family = AF_INET6;
+			nri.data = rt;
+			call_netevent_notifiers(NETEVENT_ROUTE_DEL, &nri);
 
 			return ip6_del_rt(rt, nlh, _rtattr, req);
 		}
@@ -1147,6 +1156,17 @@ static int ip6_route_del(struct in6_rtms
 	return err;
 }
 
+static void rtm_redirect(struct rt6_info *old, struct rt6_info *new)
+{
+	struct netevent_redirect netevent;
+
+	netevent.old = &old->u.dst;
+	netevent.new = &new->u.dst;
+	call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
+
+	/* TBD...post NETLINK msg */
+}
+
 /*
  *	Handle redirects
  */
@@ -1253,6 +1273,8 @@ restart:
 	if (ip6_ins_rt(nrt, NULL, NULL, NULL))
 		goto out;
 
+	rtm_redirect(rt, nrt);
+
 	if (rt->rt6i_flags&RTF_CACHE) {
 		ip6_del_rt(rt, NULL, NULL, NULL);
 		return;

^ permalink raw reply related

* [PATCH Round 2 1/2] Network Event Notifier Mechanism.
From: Steve Wise @ 2006-06-26 20:36 UTC (permalink / raw)
  To: davem; +Cc: netdev
In-Reply-To: <20060626203638.19083.71231.stgit@stevo-desktop>


This patch uses notifier blocks to implement a network event
notifier mechanism.

Clients register their callback function by calling
register_netevent_notifier() like this:

static struct notifier_block nb = {
        .notifier_call = my_callback_func
};

...

register_netevent_notifier(&nb);
---

 include/net/netevent.h |   49 +++++++++++++++++++++++++++++++++++
 net/core/netevent.c    |   67 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 116 insertions(+), 0 deletions(-)

diff --git a/include/net/netevent.h b/include/net/netevent.h
new file mode 100644
index 0000000..22214c8
--- /dev/null
+++ b/include/net/netevent.h
@@ -0,0 +1,49 @@
+#ifndef _NET_EVENT_H
+#define _NET_EVENT_H
+
+/*
+ *	Generic netevent notifiers
+ *
+ *	Authors:
+ *      Tom Tucker              <tom@opengridcomputing.com>
+ *
+ * 	Changes:
+ */
+
+#ifdef __KERNEL__
+
+#include <net/dst.h>
+
+/* 
+ * Generic route info structure.
+ *
+ * Family	  Data ptr type
+ * --------------------------------
+ * AF_INET 	- struct fib_info *
+ * AF_INET6	- struct rt6_info *
+ * AF_DECnet	- struct dn_route *
+ */
+struct netevent_route_info {
+	u16 family;
+	void *data;	
+};
+
+struct netevent_redirect {
+	struct dst_entry *old;
+	struct dst_entry *new;
+};
+
+enum netevent_notif_type {
+	NETEVENT_NEIGH_UPDATE = 1, /* arg is struct neighbour ptr */
+	NETEVENT_ROUTE_ADD,   	   /* arg is struct netevent_route_info ptr */
+	NETEVENT_ROUTE_DEL,   	   /* arg is struct netevent_route_info ptr */
+	NETEVENT_PMTU_UPDATE,	   /* arg is struct dst_entry ptr */
+	NETEVENT_REDIRECT,	   /* arg is struct netevent_redirect ptr */
+};
+
+extern int register_netevent_notifier(struct notifier_block *nb);
+extern int unregister_netevent_notifier(struct notifier_block *nb);
+extern int call_netevent_notifiers(unsigned long val, void *v);
+
+#endif
+#endif
diff --git a/net/core/netevent.c b/net/core/netevent.c
new file mode 100644
index 0000000..8f3e0a6
--- /dev/null
+++ b/net/core/netevent.c
@@ -0,0 +1,67 @@
+/*
+ *	Network event notifiers
+ *
+ *	Authors:
+ *      Tom Tucker             <tom@opengridcomputing.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.
+ *
+ *	Fixes:
+ */
+
+#include <linux/rtnetlink.h>
+#include <linux/notifier.h>
+
+static ATOMIC_NOTIFIER_HEAD(netevent_notif_chain);
+
+/**
+ *	register_netevent_notifier - register a netevent notifier block
+ *	@nb: notifier
+ *
+ *	Register a notifier to be called when a netevent occurs.
+ *	The notifier passed is linked into the kernel structures and must
+ *	not be reused until it has been unregistered. A negative errno code
+ *	is returned on a failure.
+ */
+int register_netevent_notifier(struct notifier_block *nb)
+{
+	int err;
+
+	err = atomic_notifier_chain_register(&netevent_notif_chain, nb);
+	return err;
+}
+
+/**
+ *	netevent_unregister_notifier - unregister a netevent notifier block
+ *	@nb: notifier
+ *
+ *	Unregister a notifier previously registered by
+ *	register_neigh_notifier(). The notifier is unlinked into the
+ *	kernel structures and may then be reused. A negative errno code
+ *	is returned on a failure.
+ */
+
+int unregister_netevent_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&netevent_notif_chain, nb);
+}
+
+/**
+ *	call_netevent_notifiers - call all netevent notifier blocks
+ *      @val: value passed unmodified to notifier function
+ *      @v:   pointer passed unmodified to notifier function
+ *
+ *	Call all neighbour notifier blocks.  Parameters and return value
+ *	are as for notifier_call_chain().
+ */
+
+int call_netevent_notifiers(unsigned long val, void *v)
+{
+	return atomic_notifier_call_chain(&netevent_notif_chain, val, v);
+}
+
+EXPORT_SYMBOL_GPL(register_netevent_notifier);
+EXPORT_SYMBOL_GPL(unregister_netevent_notifier);

^ permalink raw reply related

* [PATCH Round 2 0/2][RFC] Network Event Notifier Mechanism
From: Steve Wise @ 2006-06-26 20:36 UTC (permalink / raw)
  To: davem; +Cc: netdev


Round 2 Changes:

- cleaned up event structures per review feedback.
- began integration with netlink (see neighbour changes in patch 2).
- added IPv6 support.

STILL TODO:

- PMTU events/netlink
- Redirect netlink (need to define a new netlink message for this).

Questions:

- this patch is enabling some of the functionality that was under
  CONFIG_ARPD.  Should I remove the CONFIG_ARPD stuff, leave it as-is
  or what?

- what about support for other afs?  Should I hook AF_DECnet?  IPX? Or is
  AF_INET and AF_INET6 sufficient?

- I added a new RTM type in rtnetlink.h for neighbour change netlink
  messages.  I suspect I did it wrong...


------

This patch implements a mechanism that allows interested clients to
register for notification of certain network events. The intended use
is to allow RDMA devices (linux/drivers/infiniband) to be notified of
neighbour updates, ICMP redirects, path MTU changes, and route changes.

The reason these devices need update events is because they typically
cache this information in hardware and need to be notified when this
information has been updated.

The key events of interest are:

- neighbour mac address change 
- routing redirect (the next hop neighbour changes for a dst_entry)
- path mtu change (the patch mtu for a dst_entry changes).
- route add/deletes

NOTE: Network events are also passed up to user space via netlink.

We would like to get this or similar functionality included in 2.6.19
and request comments.

This patchset consists of 2 patches:

1) New files implementing the Network Event Notifier
2) Core network changes to generate network event notifications

Signed-off-by: Tom Tucker <tom@opengridcomputing.com>
Signed-off-by: Steve Wise <swise@opengridcomputing.com>

^ permalink raw reply

* Re: [patch 1/4] Network namespaces: cleanup of dev_base list use
From: Andrey Savochkin @ 2006-06-26 20:14 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: dlezcano, linux-kernel, netdev, serue, haveblue, clg,
	Andrew Morton, dev, herbert, devel, sam, viro, Alexey Kuznetsov
In-Reply-To: <m1u067ubm8.fsf@ebiederm.dsl.xmission.com>

Eric,

On Mon, Jun 26, 2006 at 10:26:23AM -0600, Eric W. Biederman wrote:
> Andrey Savochkin <saw@swsoft.com> writes:
> 
> > On Mon, Jun 26, 2006 at 09:13:52AM -0600, Eric W. Biederman wrote:
> >> 
> >> There is another topic for discussion in this patch as well.
> >> How much of the context should be implicit and how much
> >> should be explicit.
> >> 
> >> If the changes from netchannels had already been implemented, and all of
> >> the network processing was happening in a process context then I would
> >> trivially agree that implicit would be the way to go.
> >
> 
[snip]
> It is a big enough problem that I don't think we want to gate on
> that development but we need to be ready to take advantage of it when
> it happens.

Well, ok, implicit namespace reference will take advantage of it
if it happens.

> 
> >> However short of always having code always execute in the proper
> >> context I'm not comfortable with implicit parameters to functions.
> >> Not that this the contents of this patch should address this but the
> >> later patches should.
> >
> > We just have too many layers in networking code, and FIB/routing
> > illustrates it well.
> 
> I don't follow this comment.  How does a lot of layers affect
> the choice of implicit or explicit parameters?  If you are maintaining
> a patch outside the kernel I could see how there could be a win for
> touching the least amount of code possible but for merged code that
> you only have to go through once I don't see how the number of layers
> affects things.

I agree that implicit vs explicit parameters is a topic for discussion.
>From what you see from my patch, I vote for implicit ones in this case :)

I was talking about layers because they imply changing more code,
and usually imply adding more parameters to functions and passing these
additional parameters to next layers.
In "routing" code it goes from routing entry points, to routing cache, to
general FIB functions, to table-specific code (FIB hash).

These additional parameters bloat the code to some extent.
Sometimes it's possible to save here and there by fetching the parameter
(namespace pointer) indirectly from structures you already have at hand,
but it can't be done universally.

One of the properties of implicit argument which I especially like
is that both input and output paths are absolutely symmetric in how
the namespace pointer is extracted.

> 
> As I recall for most of the FIB/routing code once you have removed
> the global variable accesses and introduce namespace checks in
> the hash table (because allocating hash tables at runtime isn't sane)
> the rest of the code was agnostic about what was going on.  So I think
> you have touched everything that needs touching.  So I don't see
> a code size or complexity argument there.

	Andrey

^ permalink raw reply

* Re: [patch 3/4] Network namespaces: IPv4 FIB/routing in namespaces
From: Herbert Poetzl @ 2006-06-26 20:05 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Andrey Savochkin, linux-kernel, netdev, serue, haveblue, clg,
	Andrew Morton, dev, devel, sam, ebiederm, viro
In-Reply-To: <449FF5AE.2040201@fr.ibm.com>

On Mon, Jun 26, 2006 at 04:56:46PM +0200, Daniel Lezcano wrote:
> Andrey Savochkin wrote:
> >Structures related to IPv4 rounting (FIB and routing cache)
> >are made per-namespace.
> 
> How do you handle ICMP_REDIRECT ?

and btw. how do you handle the beloved 'ping'
(i.e. ICMP_ECHO_REQUEST/REPLY for and from
guests?

best,
Herbert


^ permalink raw reply

* Re: [patch 2/6] [Network namespace] Network device sharing by view
From: Herbert Poetzl @ 2006-06-26 20:02 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Daniel Lezcano, Andrey Savochkin, linux-kernel, netdev, serue,
	haveblue, clg, Andrew Morton, dev, devel, sam, viro,
	Alexey Kuznetsov
In-Reply-To: <m1u067r9qk.fsf@ebiederm.dsl.xmission.com>

On Mon, Jun 26, 2006 at 01:35:15PM -0600, Eric W. Biederman wrote:
> Herbert Poetzl <herbert@13thfloor.at> writes:
> 
> > On Mon, Jun 26, 2006 at 10:40:59AM -0600, Eric W. Biederman wrote:
> >> Daniel Lezcano <dlezcano@fr.ibm.com> writes:
> >> 
> >> >> Then you lose the ability for each namespace to have its own
> >> >> routing entries. Which implies that you'll have difficulties with
> >> >> devices that should exist and be visible in one namespace only
> >> >> (like tunnels), as they require IP addresses and route.
> >> >
> >> > I mean instead of having the route tables private to the namespace, the
> > routes
> >> > have the information to which namespace they are associated.
> >> 
> >> Is this an implementation difference or is this a user visible
> >> difference? As an implementation difference this is sensible, as it is
> >> pretty insane to allocate hash tables at run time.
> >>
> >> As a user visible difference that affects semantics of the operations
> >> this is not something we want to do.
> >
> > well, I guess there are even more options here, for
> > example I'd like to propose the following idea, which
> > might be a viable solution for the policy/isolation
> > problem, with the actual overhead on the setup part
> > not the hot pathes for packet and connection handling
> >
> > we could use the multiple routing tables to provide
> > a single routing table for each guest, which could
> > be used inside the guest to add arbitrary routes, but
> > would allow to keep the 'main' policy on the host, by
> > selecting the proper table based on IPs and guest tags
> >
> > similar we could allow to have a separate iptables
> > chain for each guest (or several chains), which are
> > once again directed by the host system (applying the
> > required prolicy) which can be managed and configured
> > via normal iptable interfaces (both on the guest and
> > host) but actually provide at least to layers
> 
> I have real concerns about the complexity of the route you
> have described.
> 
> > note: this does not work for hierarchical network
> > contexts, but I do not see that the yet proposed
> > implementations would do, so I do not think that
> > is of concern here ...
> 
> Well we are hierarchical in the sense that a parent
> can have a different network namespace then a child.
> So recursive containers work fine.  So this is like
> the uts namespace or the ipc namespace rather than
> like the pid namespace.

yes, but you will not be able to apply policy on
the parent, restricting the child networking in a
proper way without jumping through hoops ...

> I really do not believe we have a hotpath issue, if this
> is implemented properly. Benchmarks of course need to be taken,
> to prove this.

I'm fine with proper testing and good numbers here
but until then, I can only consider it a prototype

> There are only two places a sane implementation should show issues.
> - When the access to a pointer goes through a pointer to find
>   that global variable.
> - When doing a lookup in a hash table we need to look at an additional
>   field to verify a hash match.  Because having a completely separate
>   hash table is likely too expensive.
> 
> If that can be shown to really slow down packets on the hot path I am
> willing to consider other possibilities. Until then I think we are on
> path to the simplest and most powerful version of building a network
> namespace usable by containers.

keep in mind that you actually have three kinds
of network traffic on a typical host/guest system:

 - traffic between unit and outside
   - host traffic should be quite minimal
   - guest traffic will be quite high

 - traffic between host and guest
   probably minimal too (only for shared services)

 - traffic between guests
   can be as high (or even higher) than the
   outbound traffic, just think web guest and
   database guest

> The routing between network namespaces does have the potential to be
> more expensive than just a packet trivially coming off the wire into a
> socket.

IMHO the routing between network namespaces should
not require more than the current local traffic
does (i.e. you should be able to achieve loopback
speed within an insignificant tolerance) and not
nearly the time required for on-wire stuff ...

> However that is fundamentally from a lack of hardware. If the
> rest works smarter filters in the drivers should enable to remove the
> cost.
> 
> Basically it is just a matter of:
> if (dest_mac == my_mac1) it is for device 1.
> If (dest_mac == my_mac2) it is for device 2.
> etc.

hmm, so you plan on providing a different MAC for
each guest? how should that be handled from the
user PoV? you cannot simply make up MACs as you
go, and, depending on the network card, operation
in promisc mode might be slower than for a given
set (maybe only one) MAC, no?

> At a small count of macs it is trivial to understand it will go
> fast for a larger count of macs it only works with a good data
> structure.  We don't hit any extra cache lines of the packet,
> and the above test can be collapsed with other routing lookup tests.

well, I'm absolutely not against flexibility or
full virtualization, but the proposed 'routing'
on the host effectively doubles the time the
packet spends in the network stack(s), so I can
not believe that this approach would not add
(significant) overhead to the hot path ...

best,
Herbert

> Eric

^ permalink raw reply

* Re: [patch 3/4] Network namespaces: IPv4 FIB/routing in namespaces
From: Andrey Savochkin @ 2006-06-26 19:39 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: linux-kernel, netdev, serue, haveblue, clg, Andrew Morton, dev,
	herbert, devel, sam, ebiederm, viro, Alexey Kuznetsov
In-Reply-To: <44A003CD.9050204@fr.ibm.com>

On Mon, Jun 26, 2006 at 05:57:01PM +0200, Daniel Lezcano wrote:
> Andrey Savochkin wrote:
> > On Mon, Jun 26, 2006 at 04:56:46PM +0200, Daniel Lezcano wrote:
> >>
> >>How do you handle ICMP_REDIRECT ?
> > 
> > 
> > Are you talking about routing cache entries created on incoming redirects?
> > Or outgoing redirects?
> > 
> 
> incoming redirects

They are inserted into routing cache with the current namespace tag, in
the same way as input routing cache entries.

	Andrey

^ permalink raw reply

* [PATCH] WAN: update info page for a bunch of my drivers
From: Krzysztof Halasa @ 2006-06-26 19:36 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

Updates generic HDLC info page address, I should have done it
long time ago.

Signed-off-by: Krzysztof Halasa <khc@pm.waw.pl>

--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -7,7 +7,7 @@
  * under the terms of version 2 of the GNU General Public License
  * as published by the Free Software Foundation.
  *
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
  *
  * Sources of information:
  *    Hitachi HD64570 SCA User's Manual
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -7,7 +7,7 @@
  * under the terms of version 2 of the GNU General Public License
  * as published by the Free Software Foundation.
  *
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
  *
  * Note: integrated CSU/DSU/DDS are not supported by this driver
  *
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -7,7 +7,7 @@
  * under the terms of version 2 of the GNU General Public License
  * as published by the Free Software Foundation.
  *
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
  *
  * Sources of information:
  *    Hitachi HD64572 SCA-II User's Manual

^ permalink raw reply

* Re: [patch 2/6] [Network namespace] Network device sharing by view
From: Eric W. Biederman @ 2006-06-26 19:35 UTC (permalink / raw)
  To: Herbert Poetzl
  Cc: Daniel Lezcano, Andrey Savochkin, linux-kernel, netdev, serue,
	haveblue, clg, Andrew Morton, dev, devel, sam, viro,
	Alexey Kuznetsov
In-Reply-To: <20060626183649.GB3368@MAIL.13thfloor.at>

Herbert Poetzl <herbert@13thfloor.at> writes:

> On Mon, Jun 26, 2006 at 10:40:59AM -0600, Eric W. Biederman wrote:
>> Daniel Lezcano <dlezcano@fr.ibm.com> writes:
>> 
>> >> Then you lose the ability for each namespace to have its own
>> >> routing entries. Which implies that you'll have difficulties with
>> >> devices that should exist and be visible in one namespace only
>> >> (like tunnels), as they require IP addresses and route.
>> >
>> > I mean instead of having the route tables private to the namespace, the
> routes
>> > have the information to which namespace they are associated.
>> 
>> Is this an implementation difference or is this a user visible
>> difference? As an implementation difference this is sensible, as it is
>> pretty insane to allocate hash tables at run time.
>>
>> As a user visible difference that affects semantics of the operations
>> this is not something we want to do.
>
> well, I guess there are even more options here, for
> example I'd like to propose the following idea, which
> might be a viable solution for the policy/isolation
> problem, with the actual overhead on the setup part
> not the hot pathes for packet and connection handling
>
> we could use the multiple routing tables to provide
> a single routing table for each guest, which could
> be used inside the guest to add arbitrary routes, but
> would allow to keep the 'main' policy on the host, by
> selecting the proper table based on IPs and guest tags
>
> similar we could allow to have a separate iptables
> chain for each guest (or several chains), which are
> once again directed by the host system (applying the
> required prolicy) which can be managed and configured
> via normal iptable interfaces (both on the guest and
> host) but actually provide at least to layers

I have real concerns about the complexity of the route you
have described.

> note: this does not work for hierarchical network
> contexts, but I do not see that the yet proposed
> implementations would do, so I do not think that
> is of concern here ...

Well we are hierarchical in the sense that a parent
can have a different network namespace then a child.
So recursive containers work fine.  So this is like
the uts namespace or the ipc namespace rather than
like the pid namespace.

I really do not believe we have a hotpath issue, if this
is implemented properly. Benchmarks of course need to be taken,
to prove this.

There are only two places a sane implementation should show issues.
- When the access to a pointer goes through a pointer to find
  that global variable.
- When doing a lookup in a hash table we need to look at an additional
  field to verify a hash match.  Because having a completely separate
  hash table is likely too expensive.

If that can be shown to really slow down packets on the hot path
I am willing to consider other possibilities.  Until then I think
we are on path to the simplest and most powerful version of building
a network namespace usable by containers.

The routing between network namespaces does have the potential to
be more expensive than just a packet trivially coming off the wire
into a socket.  However that is fundamentally from a lack of hardware.
If the rest works smarter filters in the drivers should enable to
remove the cost.

Basically it is just a matter of:
if (dest_mac == my_mac1) it is for device 1.
If (dest_mac == my_mac2) it is for device 2.
etc.

At a small count of macs it is trivial to understand it will go
fast for a larger count of macs it only works with a good data
structure.  We don't hit any extra cache lines of the packet,
and the above test can be collapsed with other routing lookup tests.

Eric


^ permalink raw reply

* Re: [patch 4/4] Network namespaces: playing and debugging
From: Andrey Savochkin @ 2006-06-26 19:34 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: linux-kernel, netdev, serue, haveblue, clg, Andrew Morton, dev,
	herbert, devel, sam, ebiederm, viro, Alexey Kuznetsov
In-Reply-To: <44A01995.20802@fr.ibm.com>

On Mon, Jun 26, 2006 at 07:29:57PM +0200, Daniel Lezcano wrote:
> >>>Do
> >>>	exec 7< /proc/net/net_ns
> >>>in your bash shell and you'll get a brand new network namespace.
> >>>There you can, for example, do
> >>>	ip link set lo up
> >>>	ip addr list
> >>>	ip addr add 1.2.3.4 dev lo
> >>>	ping -n 1.2.3.4
> >>>
> 
> Andrey,
> 
> I began to play with your patchset. I am able to connect to 127.0.0.1 
> from different namespaces. Is it the expected behavior ?
> Furthermore, I am not able to have several programs, running in 
> different namespaces, to bind to the same INADDR_ANY:port.
> 
> Will these features be included in the second patchset ?

Of course.
This patchset adds namespaces to routing code, which means that
you can define local IP addresses in each namespace independently.
But this first patchset doesn't include namespaces in socket lookup code.

	Andrey

^ 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