From kumba@gentoo.org Thu Mar  1 04:34:20 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 04:34:25 +0000 (GMT)
Received: from rwcrmhc14.comcast.net ([204.127.192.84]:12252 "EHLO
	rwcrmhc14.comcast.net") by ftp.linux-mips.org with ESMTP
	id S20037750AbXCAEeU (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 1 Mar 2007 04:34:20 +0000
Received: from [192.168.1.4] (c-68-34-70-207.hsd1.md.comcast.net[68.34.70.207])
          by comcast.net (rwcrmhc14) with ESMTP
          id <20070301043335m1400hmpkre>; Thu, 1 Mar 2007 04:33:35 +0000
Message-ID: <45E6578F.9060407@gentoo.org>
Date:	Wed, 28 Feb 2007 23:33:19 -0500
From:	Kumba <kumba@gentoo.org>
User-Agent: Thunderbird 2.0b2 (Windows/20070116)
MIME-Version: 1.0
To:	Linux MIPS List <linux-mips@linux-mips.org>
Subject: Re: IP32 prom crashes due to __pa() funkiness
References: <45D8B070.7070405@gentoo.org>
In-Reply-To: <45D8B070.7070405@gentoo.org>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <kumba@gentoo.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14293
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: kumba@gentoo.org
Precedence: bulk
X-list: linux-mips

Kumba wrote:
> 
> Initially, booting a straight git checkout on an IP32 will cause it to 
> prom crash, usually somewhere in between init_bootmem() and 
> init_bootmem_core().  I bisected git to trace this back to one of the 
> inital __pa() introduction patches from commit d4df6d4 (get ride of 
> CPHYSADDR()).  It actually appears that the actual commit that broke 
> things was 620a480 (Make __pa() aware of XKPHYS/CKSEG0 address mix for 
> 64 bit kernels).
> 
> The [short-term] fix highlighted by Ilya is to make __pa() 
> unconditionally be defined to "((unsigned long)(x) < CKSEG0 ? 
> PAGE_OFFSET : CKSEG0)"; Discovered by building IP32 with 
> CONFIG_BUILD_ELF64=n.
> 
> Normally, this shouldn't be possible, as CONFIG_BUILD_ELF64=n was 
> originally only allowed by using the old o64 hack, which has 
> subsequently died and been replaced with the newer -msym32 form.  As far 
> as I know, CONFIG_BUILD_ELF64 is apparently supposed to be removed at 
> some point in the future, since I believe it existed only for quirky 
> 64bit-in-32bit kernels for IP22 and more commonly, IP32.  From 2.6.17 
> onwards, I've been building IP32 kernels with CONFIG_BUILD_ELF64=y and 
> using gcc-4, and haven't had problems up until now.
> 
> Anyways, I'm not sure if this is an IP32-specific oddity or not 
> (probably is), but it needs the define highlighted above to work 
> properly.  Plain PAGE_OFFSET won't work for these machines.  Given the 
> same trick os -msym32 is used for the rare IP22 64bit kernel, I would 
> not be surprised if the same problem and fix both occur and work for 
> those machines as well.  Something to maybe test later, I suppose.
> 
> But for now, anyone got thoughts as to a sane workaround for this?  
> Perhaps some conditional tweaks in mach-ip32/*.h files somewheres, would 
> it be simpler to just switch to:
> 
> #if defined(CONFIG_64BIT) && (!defined(CONFIG_BUILD_ELF64) || 
> defined(CONFIG_SGI_IP32))
> 
> (assuming that IP22 doesn't need it; I'll find out later)

"Re-verify range to target, One ping only."


So, anyone got thoughts on this?

I've actually built and booted an SGI IP32 kernel using this logic in 
include/asm-mips/page.h, Line 135:

#if defined(CONFIG_64BIT) && (!defined(CONFIG_BUILD_ELF64) || 
(defined(CONFIG_SGI_IP32) || defined(CONFIG_SGI_IP22)))



--Kumba

-- 
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands 
do them because they must, while the eyes of the great are elsewhere."  --Elrond

From riamae@gmail.com Thu Mar  1 04:34:49 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 04:34:53 +0000 (GMT)
Received: from nf-out-0910.google.com ([64.233.182.187]:49797 "EHLO
	nf-out-0910.google.com") by ftp.linux-mips.org with ESMTP
	id S20038845AbXCAEea (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 1 Mar 2007 04:34:30 +0000
Received: by nf-out-0910.google.com with SMTP id l24so759371nfc
        for <linux-mips@linux-mips.org>; Wed, 28 Feb 2007 20:33:29 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:reply-to:to:subject:cc:in-reply-to:mime-version:content-type:references;
        b=hlns2RpgDa6MTh5+CfG44TH4djbtFn8B0ECJEal2xlb1+KeMtxTcOFaQEssIkBEulQc5hV8lz7ZB0rexBAgke0BkXC9NwxZMbbFjx1xhBDrygJDkL7bwUrruMjZizh91Bkdy/9TXYOMqqcFHvMxw3VA8GGwSyXKVw89BKfEUGIk=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:reply-to:to:subject:cc:in-reply-to:mime-version:content-type:references;
        b=hJIjKRI5hafqVUSt+648nFqeNBh8LJS8yTdzZnRjPI9pgQ9wvkRlubQ5K8MAGJk6wCfcPWgztczx9i+YQblpuQVMFwZ0SVZr1obIxoOvC0RMWcNF5uI66P0F+3iS8k/sZpBvWZx6zPPcHFnTO8l1loYY0pcRyieTIUkyE/Ywmwc=
Received: by 10.82.187.16 with SMTP id k16mr478891buf.1172723609104;
        Wed, 28 Feb 2007 20:33:29 -0800 (PST)
Received: by 10.82.152.14 with HTTP; Wed, 28 Feb 2007 20:33:29 -0800 (PST)
Message-ID: <d28769380702282033t13a918cdkd8baf084a2ea79a8@mail.gmail.com>
Date:	Thu, 1 Mar 2007 12:33:29 +0800
From:	dejo <riamae@gmail.com>
Reply-To: riamae@gmail.com
To:	"Ralf Baechle" <ralf@linux-mips.org>
Subject: Re: early_initcall replacement
Cc:	linux-mips@linux-mips.org
In-Reply-To: <20070228024756.GA23519@linux-mips.org>
MIME-Version: 1.0
Content-Type: multipart/alternative; 
	boundary="----=_Part_33195_47410.1172723609039"
References: <d28769380702271755u675241b3vb8b265120a2c70ca@mail.gmail.com>
	 <20070228024756.GA23519@linux-mips.org>
Return-Path: <riamae@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14294
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: riamae@gmail.com
Precedence: bulk
X-list: linux-mips

------=_Part_33195_47410.1172723609039
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Thank you for your reply, sir. I found out that there's already a
plat_mem_setup defined in vr41xx/common/init.c that's why I cannot rename
the function invoked by early_initcall to plat_mem_setup.

Actually, when I examined it further, I found out that using arch_initcall
works just fine except that the add_memory_region is not called before
everything else. It causes error because there's no memory region allotted.

I did this:
/*arch/mips/vr41xx/common/init.c */
void __init plat_mem_setup(void)
{
    vr41xx_calculate_clock_frequency();

    timer_init();
    iomem_resource_init();
            add_memory_region(0, 0x04000000, BOOT_MEM_RAM);
}

and it worked! But it's not good practice isn't it? I might ruin the other
vr41xx boards. Do you have any suggestions? Thank you.

ria mae


On 2/28/07, Ralf Baechle <ralf@linux-mips.org> wrote:
>
> On Wed, Feb 28, 2007 at 09:55:28AM +0800, dejo wrote:
>
> > Hello! I would like to ask what replaced early_initcall in the
> > 2.6.18.4kernel.
>
> What you need to change is
>
> o remove the early_initcall() line.
> o rename the function invoked by early_initcall to plat_mem_setup and
>    change its prototype to: "void __init plat_mem_setup(void)".
>
>   Ralf
>

------=_Part_33195_47410.1172723609039
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Thank you for your reply, sir. I found out that there&#39;s already a
plat_mem_setup defined in vr41xx/common/init.c that&#39;s why I cannot
rename the function invoked by early_initcall to plat_mem_setup.<br><br>Actually,
when I examined it further, I found out that using arch_initcall works
just fine except that the add_memory_region is not called before
everything else. It causes error because there&#39;s no memory region
allotted. <br><br>I did this:<br>/*arch/mips/vr41xx/common/init<div id="mb_2">.c */<span class="q"><br>void __init plat_mem_setup(void)<br></span>{<br>&nbsp;&nbsp;&nbsp; vr41xx_calculate_clock_frequency();<br><br>&nbsp;&nbsp;&nbsp; timer_init();<br>&nbsp;&nbsp;&nbsp; iomem_resource_init();
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add_memory_region(0, 0x04000000, BOOT_MEM_RAM);
<br>}<br><br>and it worked! But it&#39;s not good practice isn&#39;t it? I
might ruin the other vr41xx boards. Do you have any suggestions? Thank
you. <br><br>ria mae</div><br><br><div><span class="gmail_quote">On 2/28/07, <b class="gmail_sendername">Ralf Baechle</b> &lt;<a href="mailto:ralf@linux-mips.org">ralf@linux-mips.org</a>&gt; wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
On Wed, Feb 28, 2007 at 09:55:28AM +0800, dejo wrote:<br><br>&gt; Hello! I would like to ask what replaced early_initcall in the<br>&gt; 2.6.18.4kernel.<br><br>What you need to change is<br><br> o remove the early_initcall() line.
<br> o rename the function invoked by early_initcall to plat_mem_setup and<br>&nbsp;&nbsp; change its prototype to: &quot;void __init plat_mem_setup(void)&quot;.<br><br>&nbsp;&nbsp;Ralf<br></blockquote></div><br>

------=_Part_33195_47410.1172723609039--

From vagabon.xyz@gmail.com Thu Mar  1 09:40:20 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 09:40:25 +0000 (GMT)
Received: from qb-out-0506.google.com ([72.14.204.238]:64617 "EHLO
	qb-out-0506.google.com") by ftp.linux-mips.org with ESMTP
	id S20039230AbXCAJkU (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 1 Mar 2007 09:40:20 +0000
Received: by qb-out-0506.google.com with SMTP id e12so331123qba
        for <linux-mips@linux-mips.org>; Thu, 01 Mar 2007 01:39:18 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=qxorT7Qdq/auhwfhrNAmnMiemK6JWTnRASDei26Lsa2pF3M3NBTDhE7lBLdFmUyksaRjPaGVNztmEMi+VQel7iBnAXC/xlNeAJPGDLRTv7xZ7+y2RXwWrdPC0P/5rHmVhfdsH57cUUc2DXeB1LpMUkXvMrc4JlqNe+NmwizyIq4=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=YtGWX43mxixUhBLw6pNj1dli56pys95vfDucLR27hvP9aaM4Tz9OBrQZHB8ellWeKS85azYSM3PX7W4xIYZY4qz5xVqy0hphsiYBbED8Lt1Ot4s8gQELl+vuMb2FdILl16Ivb/ARKE4vCsKz9JHpk/xCuQ7SeWZJp8DgQhzj5jI=
Received: by 10.114.13.1 with SMTP id 1mr86193wam.1172741948570;
        Thu, 01 Mar 2007 01:39:08 -0800 (PST)
Received: by 10.114.136.11 with HTTP; Thu, 1 Mar 2007 01:39:08 -0800 (PST)
Message-ID: <cda58cb80703010139y3e5bbb8eqa4d25b75ba658a22@mail.gmail.com>
Date:	Thu, 1 Mar 2007 10:39:08 +0100
From:	"Franck Bui-Huu" <vagabon.xyz@gmail.com>
To:	Kumba <kumba@gentoo.org>
Subject: Re: IP32 prom crashes due to __pa() funkiness
Cc:	"Linux MIPS List" <linux-mips@linux-mips.org>
In-Reply-To: <45D8B070.7070405@gentoo.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
References: <45D8B070.7070405@gentoo.org>
Return-Path: <vagabon.xyz@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14295
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: vagabon.xyz@gmail.com
Precedence: bulk
X-list: linux-mips

Hi,

Kumba wrote:
>
> Initially, booting a straight git checkout on an IP32 will cause it to
> prom crash, usually somewhere in between init_bootmem() and
> init_bootmem_core().  I bisected git to trace this back to one of the
> inital __pa() introduction patches from commit d4df6d4 (get ride of
> CPHYSADDR()).  It actually appears that the actual commit that broke
> things was 620a480 (Make __pa() aware of XKPHYS/CKSEG0 address mix for
> 64 bit kernels).
>
> The [short-term] fix highlighted by Ilya is to make __pa()
> unconditionally be defined to "((unsigned long)(x) < CKSEG0 ?
> PAGE_OFFSET : CKSEG0)"; Discovered by building IP32 with
> CONFIG_BUILD_ELF64=n.
>

Well, it means that you previously used CONFIG_BUILD_ELF64=y (this
implied that PAGE_OFFSET is in XKPHYS) whereas your kernel has CKSEG
load address (symbols need PAGE_OFFSET in CKSEG for address
translation).

So the question is why can't you use CONFIG_BUILD_ELF64=n (and
reagarding the current definition of CONFIG_BUILD_ELF64).

> Normally, this shouldn't be possible, as CONFIG_BUILD_ELF64=n was
> originally only allowed by using the old o64 hack, which has
> subsequently died and been replaced with the newer -msym32 form.  As far
> as I know, CONFIG_BUILD_ELF64 is apparently supposed to be removed at
> some point in the future, since I believe it existed only for quirky

It makes me think that I posted a patch for that a couple of weeks ago:

http://marc.theaimsgroup.com/?l=linux-mips&m=117154480225936&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154480126802&w=2
http://marc.theaimsgroup.com/?l=linux-mips&m=117154587014827&w=2

Basically this patch removes CONFIG_BUILD_ELF64 and makes Kbuild to use
'-msym32' switch if you really need it. Kbuild makes its choice according
the load address of your kernel image.

Could you give it a try ? This patch was based on 2.6.20 but it should
apply fine on a 2.6.21-rc[12].
-- 
               Franck

From yoichi_yuasa@tripeaks.co.jp Thu Mar  1 13:51:50 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 13:51:56 +0000 (GMT)
Received: from mo31.po.2iij.net ([210.128.50.54]:30499 "EHLO mo31.po.2iij.net")
	by ftp.linux-mips.org with ESMTP id S20039214AbXCANvu (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 1 Mar 2007 13:51:50 +0000
Received: by mo.po.2iij.net (mo31) id l21DoTUQ067439; Thu, 1 Mar 2007 22:50:29 +0900 (JST)
Received: from localhost.localdomain (70.27.30.125.dy.iij4u.or.jp [125.30.27.70])
	by mbox.po.2iij.net (mbox32) id l21DoPRx060162
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT);
	Thu, 1 Mar 2007 22:50:26 +0900 (JST)
Date:	Thu, 1 Mar 2007 22:50:25 +0900
From:	Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	yoichi_yuasa@tripeaks.co.jp, linux-mips <linux-mips@linux-mips.org>
Subject: [PATCH][MIPS] update Cobalt reserved resource
Message-Id: <20070301225025.7612e583.yoichi_yuasa@tripeaks.co.jp>
Organization: TriPeaks Corporation
X-Mailer: Sylpheed version 1.0.6 (GTK+ 1.2.10; i486-pc-linux-gnu)
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Return-Path: <yoichi_yuasa@tripeaks.co.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14296
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: yoichi_yuasa@tripeaks.co.jp
Precedence: bulk
X-list: linux-mips

Hi Ralf,

This patch has removed unused timer resource.
Moreover, the name of reserved resources ware changed.

Yoichi

Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>

diff -pruN -X mips/Documentation/dontdiff mips-orig/arch/mips/cobalt/setup.c mips/arch/mips/cobalt/setup.c
--- mips-orig/arch/mips/cobalt/setup.c	2006-12-09 21:03:07.860183750 +0900
+++ mips/arch/mips/cobalt/setup.c	2006-12-09 21:44:28.215782000 +0900
@@ -79,37 +79,38 @@ static struct resource cobalt_io_resourc
 	.flags	= IORESOURCE_IO
 };
 
-static struct resource cobalt_io_resources[] = {
-	{
+/*
+ * Cobalt doesn't have PS/2 keyboard/mouse interfaces,
+ * keyboard conntroller is never used.
+ * Also PCI-ISA bridge DMA contoroller is never used.
+ */
+static struct resource cobalt_reserved_resources[] = {
+	{	/* dma1 */
 		.start	= 0x00,
 		.end	= 0x1f,
-		.name	= "dma1",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x40,
-		.end	= 0x5f,
-		.name	= "timer",
-		.flags	= IORESOURCE_BUSY
-	}, {
+		.name	= "reserved",
+		.flags	= IORESOURCE_BUSY | IORESOURCE_IO,
+	},
+	{	/* keyboard */
 		.start	= 0x60,
 		.end	= 0x6f,
-		.name	= "keyboard",
-		.flags	= IORESOURCE_BUSY
-	}, {
+		.name	= "reserved",
+		.flags	= IORESOURCE_BUSY | IORESOURCE_IO,
+	},
+	{	/* dma page reg */
 		.start	= 0x80,
 		.end	= 0x8f,
-		.name	= "dma page reg",
-		.flags	= IORESOURCE_BUSY
-	}, {
+		.name	= "reserved",
+		.flags	= IORESOURCE_BUSY | IORESOURCE_IO,
+	},
+	{	/* dma2 */
 		.start	= 0xc0,
 		.end	= 0xdf,
-		.name	= "dma2",
-		.flags	= IORESOURCE_BUSY
+		.name	= "reserved",
+		.flags	= IORESOURCE_BUSY | IORESOURCE_IO,
 	},
 };
 
-#define COBALT_IO_RESOURCES (sizeof(cobalt_io_resources)/sizeof(struct resource))
-
 static struct pci_controller cobalt_pci_controller = {
 	.pci_ops	= &gt64111_pci_ops,
 	.mem_resource	= &cobalt_mem_resource,
@@ -133,9 +134,9 @@ void __init plat_mem_setup(void)
 	/* I/O port resource must include LCD/buttons */
 	ioport_resource.end = 0x0fffffff;
 
-	/* request I/O space for devices used on all i[345]86 PCs */
-	for (i = 0; i < COBALT_IO_RESOURCES; i++)
-		request_resource(&ioport_resource, cobalt_io_resources + i);
+	/* These resources have been reserved by VIA SuperI/O chip. */
+	for (i = 0; i < ARRAY_SIZE(cobalt_reserved_resources); i++)
+		request_resource(&ioport_resource, cobalt_reserved_resources + i);
 
         /* Read the cobalt id register out of the PCI config space */
         PCI_CFG_SET(devfn, (VIA_COBALT_BRD_ID_REG & ~0x3));

From macro@linux-mips.org Thu Mar  1 13:57:22 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 13:57:27 +0000 (GMT)
Received: from pollux.ds.pg.gda.pl ([153.19.208.7]:45330 "EHLO
	pollux.ds.pg.gda.pl") by ftp.linux-mips.org with ESMTP
	id S20039427AbXCAN5W (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 1 Mar 2007 13:57:22 +0000
Received: from localhost (localhost [127.0.0.1])
	by pollux.ds.pg.gda.pl (Postfix) with ESMTP id 9DCE0E1CE0;
	Thu,  1 Mar 2007 14:56:37 +0100 (CET)
X-Virus-Scanned: by amavisd-new at pollux.ds.pg.gda.pl
Received: from pollux.ds.pg.gda.pl ([127.0.0.1])
	by localhost (pollux.ds.pg.gda.pl [127.0.0.1]) (amavisd-new, port 10024)
	with ESMTP id VsH9wdrS6dwq; Thu,  1 Mar 2007 14:56:37 +0100 (CET)
Received: from piorun.ds.pg.gda.pl (piorun.ds.pg.gda.pl [153.19.208.8])
	by pollux.ds.pg.gda.pl (Postfix) with ESMTP id 244F9E1C69;
	Thu,  1 Mar 2007 14:56:37 +0100 (CET)
Received: from blysk.ds.pg.gda.pl (macro@blysk.ds.pg.gda.pl [153.19.208.6])
	by piorun.ds.pg.gda.pl (8.13.8/8.13.8) with ESMTP id l21DukqM011264;
	Thu, 1 Mar 2007 14:56:46 +0100
Date:	Thu, 1 Mar 2007 13:56:42 +0000 (GMT)
From:	"Maciej W. Rozycki" <macro@linux-mips.org>
To:	Andrew Morton <akpm@osdl.org>, Antonino Daplas <adaplas@pol.net>
cc:	linux-mips@linux-mips.org, linux-kernel@vger.kernel.org,
	linux-fbdev-devel@linux-mips.org
Subject: [PATCH 2.6.21-rc2 #3] tgafb: TURBOchannel support
Message-ID: <Pine.LNX.4.64N.0703011319480.25556@blysk.ds.pg.gda.pl>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
X-Virus-Scanned: ClamAV 0.90/2689/Thu Mar  1 06:46:09 2007 on piorun.ds.pg.gda.pl
X-Virus-Status:	Clean
Return-Path: <macro@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14297
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: macro@linux-mips.org
Precedence: bulk
X-list: linux-mips

 This is support for the TC variations of the TGA boards (properly known 
as SFB+ or Smart Frame Buffer Plus boards).  The 8-plane SFB+ board uses 
the Bt459 RAMDAC (unlike its PCI TGA counterpart, which uses the Bt485), 
so bits have been added to support this chip as well.

Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
---

 This is a new version which applies against 2.6.21-rc2.  It includes a 
small update to the help text in Kconfig as well.  No functional changes.

 Please apply.

  Maciej

patch-mips-2.6.21-rc1-20070222-hx+-73
diff -up --recursive --new-file linux-mips-2.6.21-rc1-20070222.macro/drivers/video/Kconfig linux-mips-2.6.21-rc1-20070222/drivers/video/Kconfig
--- linux-mips-2.6.21-rc1-20070222.macro/drivers/video/Kconfig	2007-02-22 06:01:02.000000000 +0000
+++ linux-mips-2.6.21-rc1-20070222/drivers/video/Kconfig	2007-03-01 00:43:32.000000000 +0000
@@ -516,15 +516,25 @@ config FB_HP300
 	default y
 
 config FB_TGA
-	tristate "TGA framebuffer support"
-	depends on FB && ALPHA
+	tristate "TGA/SFB+ framebuffer support"
+	depends on FB && (ALPHA || TC)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	select BITREVERSE
-	help
-	  This is the frame buffer device driver for generic TGA graphic
-	  cards. Say Y if you have one of those.
+	---help---
+	  This is the frame buffer device driver for generic TGA and SFB+
+	  graphic cards.  These include DEC ZLXp-E1, -E2 and -E3 PCI cards,
+	  also known as PBXGA-A, -B and -C, and DEC ZLX-E1, -E2 and -E3
+	  TURBOchannel cards, also known as PMAGD-A, -B and -C.
+
+	  Due to hardware limitations ZLX-E2 and E3 cards are not supported
+	  for DECstation 5000/200 systems.  Additionally due to firmware
+	  limitations these cards may cause troubles with booting DECstation
+	  5000/240 and /260 systems, but are fully supported under Linux if
+	  you manage to get it going. ;-)
+
+	  Say Y if you have one of those.
 
 config FB_VESA
 	bool "VESA VGA graphics support"
diff -up --recursive --new-file linux-mips-2.6.21-rc1-20070222.macro/drivers/video/tgafb.c linux-mips-2.6.21-rc1-20070222/drivers/video/tgafb.c
--- linux-mips-2.6.21-rc1-20070222.macro/drivers/video/tgafb.c	2007-02-21 05:56:49.000000000 +0000
+++ linux-mips-2.6.21-rc1-20070222/drivers/video/tgafb.c	2007-03-01 00:32:46.000000000 +0000
@@ -5,27 +5,45 @@
  *	Copyright (C) 1997 Geert Uytterhoeven
  *	Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
  *	Copyright (C) 2002 Richard Henderson
+ *	Copyright (C) 2006 Maciej W. Rozycki
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License. See the file COPYING in the main directory of this archive for
  *  more details.
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
+#include <linux/bitrev.h>
 #include <linux/delay.h>
-#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
 #include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/selection.h>
-#include <linux/bitrev.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tc.h>
+
 #include <asm/io.h>
+
 #include <video/tgafb.h>
 
+#ifdef CONFIG_PCI
+#define TGA_BUS_PCI(dev) (dev->bus == &pci_bus_type)
+#else
+#define TGA_BUS_PCI(dev) 0
+#endif
+
+#ifdef CONFIG_TC
+#define TGA_BUS_TC(dev) (dev->bus == &tc_bus_type)
+#else
+#define TGA_BUS_TC(dev) 0
+#endif
+
 /*
  * Local functions.
  */
@@ -42,12 +60,16 @@ static void tgafb_imageblit(struct fb_in
 static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *);
 static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *);
 
-static int __devinit tgafb_pci_register(struct pci_dev *,
-					const struct pci_device_id *);
-static void __devexit tgafb_pci_unregister(struct pci_dev *);
+static int __devinit tgafb_register(struct device *dev);
+static void __devexit tgafb_unregister(struct device *dev);
+
+static const char *mode_option;
+static const char *mode_option_pci = "640x480@60";
+static const char *mode_option_tc = "1280x1024@72";
 
-static const char *mode_option = "640x480@60";
 
+static struct pci_driver tgafb_pci_driver;
+static struct tc_driver tgafb_tc_driver;
 
 /*
  *  Frame buffer operations
@@ -65,9 +87,13 @@ static struct fb_ops tgafb_ops = {
 };
 
 
+#ifdef CONFIG_PCI
 /*
  *  PCI registration operations
  */
+static int __devinit tgafb_pci_register(struct pci_dev *,
+					const struct pci_device_id *);
+static void __devexit tgafb_pci_unregister(struct pci_dev *);
 
 static struct pci_device_id const tgafb_pci_table[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA) },
@@ -75,13 +101,68 @@ static struct pci_device_id const tgafb_
 };
 MODULE_DEVICE_TABLE(pci, tgafb_pci_table);
 
-static struct pci_driver tgafb_driver = {
+static struct pci_driver tgafb_pci_driver = {
 	.name			= "tgafb",
 	.id_table		= tgafb_pci_table,
 	.probe			= tgafb_pci_register,
 	.remove			= __devexit_p(tgafb_pci_unregister),
 };
 
+static int __devinit
+tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	return tgafb_register(&pdev->dev);
+}
+
+static void __devexit
+tgafb_pci_unregister(struct pci_dev *pdev)
+{
+	tgafb_unregister(&pdev->dev);
+}
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_TC
+/*
+ *  TC registration operations
+ */
+static int __devinit tgafb_tc_register(struct device *);
+static int __devexit tgafb_tc_unregister(struct device *);
+
+static struct tc_device_id const tgafb_tc_table[] = {
+	{ "DEC     ", "PMAGD-AA" },
+	{ "DEC     ", "PMAGD   " },
+	{ }
+};
+MODULE_DEVICE_TABLE(tc, tgafb_tc_table);
+
+static struct tc_driver tgafb_tc_driver = {
+	.id_table		= tgafb_tc_table,
+	.driver			= {
+		.name		= "tgafb",
+		.bus		= &tc_bus_type,
+		.probe		= tgafb_tc_register,
+		.remove		= __devexit_p(tgafb_tc_unregister),
+	},
+};
+
+static int __devinit
+tgafb_tc_register(struct device *dev)
+{
+	int status = tgafb_register(dev);
+	if (!status)
+		get_device(dev);
+	return status;
+}
+
+static int __devexit
+tgafb_tc_unregister(struct device *dev)
+{
+	put_device(dev);
+	tgafb_unregister(dev);
+	return 0;
+}
+#endif /* CONFIG_TC */
+
 
 /**
  *      tgafb_check_var - Optional function.  Validates a var passed in.
@@ -132,10 +213,10 @@ static int
 tgafb_set_par(struct fb_info *info)
 {
 	static unsigned int const deep_presets[4] = {
-		0x00014000,
-		0x0001440d,
+		0x00004000,
+		0x0000440d,
 		0xffffffff,
-		0x0001441d
+		0x0000441d
 	};
 	static unsigned int const rasterop_presets[4] = {
 		0x00000003,
@@ -157,6 +238,8 @@ tgafb_set_par(struct fb_info *info)
 	};
 
 	struct tga_par *par = (struct tga_par *) info->par;
+	int tga_bus_pci = TGA_BUS_PCI(par->dev);
+	int tga_bus_tc = TGA_BUS_TC(par->dev);
 	u32 htimings, vtimings, pll_freq;
 	u8 tga_type;
 	int i;
@@ -221,7 +304,7 @@ tgafb_set_par(struct fb_info *info)
 	TGA_WRITE_REG(par, vtimings, TGA_VERT_REG);
 
 	/* Initalise RAMDAC. */
-	if (tga_type == TGA_TYPE_8PLANE) {
+	if (tga_type == TGA_TYPE_8PLANE && tga_bus_pci) {
 
 		/* Init BT485 RAMDAC registers.  */
 		BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0),
@@ -261,6 +344,38 @@ tgafb_set_par(struct fb_info *info)
 				      TGA_RAMDAC_REG);
 		}
 
+	} else if (tga_type == TGA_TYPE_8PLANE && tga_bus_tc) {
+
+		/* Init BT459 RAMDAC registers.  */
+		BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_0, 0x40);
+		BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_1, 0x00);
+		BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_2,
+			    (par->sync_on_green ? 0xc0 : 0x40));
+
+		BT459_WRITE(par, BT459_REG_ACC, BT459_CUR_CMD_REG, 0x00);
+
+		/* Fill the palette.  */
+		BT459_LOAD_ADDR(par, 0x0000);
+		TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
+
+#ifdef CONFIG_HW_CONSOLE
+		for (i = 0; i < 16; i++) {
+			int j = color_table[i];
+
+			TGA_WRITE_REG(par, default_red[j], TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, default_grn[j], TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, default_blu[j], TGA_RAMDAC_REG);
+		}
+		for (i = 0; i < 240 * 3; i += 4) {
+#else
+		for (i = 0; i < 256 * 3; i += 4) {
+#endif
+			TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+		}
+
 	} else { /* 24-plane or 24plusZ */
 
 		/* Init BT463 RAMDAC registers.  */
@@ -431,6 +546,8 @@ tgafb_setcolreg(unsigned regno, unsigned
 		unsigned transp, struct fb_info *info)
 {
 	struct tga_par *par = (struct tga_par *) info->par;
+	int tga_bus_pci = TGA_BUS_PCI(par->dev);
+	int tga_bus_tc = TGA_BUS_TC(par->dev);
 
 	if (regno > 255)
 		return 1;
@@ -438,12 +555,18 @@ tgafb_setcolreg(unsigned regno, unsigned
 	green >>= 8;
 	blue >>= 8;
 
-	if (par->tga_type == TGA_TYPE_8PLANE) {
+	if (par->tga_type == TGA_TYPE_8PLANE && tga_bus_pci) {
 		BT485_WRITE(par, regno, BT485_ADDR_PAL_WRITE);
 		TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
 		TGA_WRITE_REG(par, red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
 		TGA_WRITE_REG(par, green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
 		TGA_WRITE_REG(par, blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+	} else if (par->tga_type == TGA_TYPE_8PLANE && tga_bus_tc) {
+		BT459_LOAD_ADDR(par, regno);
+		TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
+		TGA_WRITE_REG(par, red, TGA_RAMDAC_REG);
+		TGA_WRITE_REG(par, green, TGA_RAMDAC_REG);
+		TGA_WRITE_REG(par, blue, TGA_RAMDAC_REG);
 	} else {
 		if (regno < 16) {
 			u32 value = (regno << 16) | (regno << 8) | regno;
@@ -1309,18 +1432,29 @@ static void
 tgafb_init_fix(struct fb_info *info)
 {
 	struct tga_par *par = (struct tga_par *)info->par;
+	int tga_bus_pci = TGA_BUS_PCI(par->dev);
+	int tga_bus_tc = TGA_BUS_TC(par->dev);
 	u8 tga_type = par->tga_type;
-	const char *tga_type_name;
+	const char *tga_type_name = NULL;
 
 	switch (tga_type) {
 	case TGA_TYPE_8PLANE:
-		tga_type_name = "Digital ZLXp-E1";
+		if (tga_bus_pci)
+			tga_type_name = "Digital ZLXp-E1";
+		if (tga_bus_tc)
+			tga_type_name = "Digital ZLX-E1";
 		break;
 	case TGA_TYPE_24PLANE:
-		tga_type_name = "Digital ZLXp-E2";
+		if (tga_bus_pci)
+			tga_type_name = "Digital ZLXp-E2";
+		if (tga_bus_tc)
+			tga_type_name = "Digital ZLX-E2";
 		break;
 	case TGA_TYPE_24PLUSZ:
-		tga_type_name = "Digital ZLXp-E3";
+		if (tga_bus_pci)
+			tga_type_name = "Digital ZLXp-E3";
+		if (tga_bus_tc)
+			tga_type_name = "Digital ZLX-E3";
 		break;
 	default:
 		tga_type_name = "Unknown";
@@ -1348,9 +1482,15 @@ tgafb_init_fix(struct fb_info *info)
 	info->fix.accel = FB_ACCEL_DEC_TGA;
 }
 
-static __devinit int
-tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit
+tgafb_register(struct device *dev)
 {
+	static const struct fb_videomode modedb_tc = {
+		/* 1280x1024 @ 72 Hz, 76.8 kHz hsync */
+		"1280x1024@72", 0, 1280, 1024, 7645, 224, 28, 33, 3, 160, 3,
+		FB_SYNC_ON_GREEN, FB_VMODE_NONINTERLACED
+	};
+
 	static unsigned int const fb_offset_presets[4] = {
 		TGA_8PLANE_FB_OFFSET,
 		TGA_24PLANE_FB_OFFSET,
@@ -1358,40 +1498,51 @@ tgafb_pci_register(struct pci_dev *pdev,
 		TGA_24PLUSZ_FB_OFFSET
 	};
 
+	const struct fb_videomode *modedb_tga = NULL;
+	resource_size_t bar0_start = 0, bar0_len = 0;
+	const char *mode_option_tga = NULL;
+	int tga_bus_pci = TGA_BUS_PCI(dev);
+	int tga_bus_tc = TGA_BUS_TC(dev);
+	unsigned int modedbsize_tga = 0;
 	void __iomem *mem_base;
-	unsigned long bar0_start, bar0_len;
 	struct fb_info *info;
 	struct tga_par *par;
 	u8 tga_type;
-	int ret;
+	int ret = 0;
 
 	/* Enable device in PCI config.  */
-	if (pci_enable_device(pdev)) {
+	if (tga_bus_pci && pci_enable_device(to_pci_dev(dev))) {
 		printk(KERN_ERR "tgafb: Cannot enable PCI device\n");
 		return -ENODEV;
 	}
 
 	/* Allocate the fb and par structures.  */
-	info = framebuffer_alloc(sizeof(struct tga_par), &pdev->dev);
+	info = framebuffer_alloc(sizeof(struct tga_par), dev);
 	if (!info) {
 		printk(KERN_ERR "tgafb: Cannot allocate memory\n");
 		return -ENOMEM;
 	}
 
 	par = info->par;
-	pci_set_drvdata(pdev, info);
+	dev_set_drvdata(dev, info);
 
 	/* Request the mem regions.  */
-	bar0_start = pci_resource_start(pdev, 0);
-	bar0_len = pci_resource_len(pdev, 0);
 	ret = -ENODEV;
+	if (tga_bus_pci) {
+		bar0_start = pci_resource_start(to_pci_dev(dev), 0);
+		bar0_len = pci_resource_len(to_pci_dev(dev), 0);
+	}
+	if (tga_bus_tc) {
+		bar0_start = to_tc_dev(dev)->resource.start;
+		bar0_len = to_tc_dev(dev)->resource.end - bar0_start + 1;
+	}
 	if (!request_mem_region (bar0_start, bar0_len, "tgafb")) {
 		printk(KERN_ERR "tgafb: cannot reserve FB region\n");
 		goto err0;
 	}
 
 	/* Map the framebuffer.  */
-	mem_base = ioremap(bar0_start, bar0_len);
+	mem_base = ioremap_nocache(bar0_start, bar0_len);
 	if (!mem_base) {
 		printk(KERN_ERR "tgafb: Cannot map MMIO\n");
 		goto err1;
@@ -1399,12 +1550,16 @@ tgafb_pci_register(struct pci_dev *pdev,
 
 	/* Grab info about the card.  */
 	tga_type = (readl(mem_base) >> 12) & 0x0f;
-	par->pdev = pdev;
+	par->dev = dev;
 	par->tga_mem_base = mem_base;
 	par->tga_fb_base = mem_base + fb_offset_presets[tga_type];
 	par->tga_regs_base = mem_base + TGA_REGS_OFFSET;
 	par->tga_type = tga_type;
-	pci_read_config_byte(pdev, PCI_REVISION_ID, &par->tga_chip_rev);
+	if (tga_bus_pci)
+		pci_read_config_byte(to_pci_dev(dev), PCI_REVISION_ID,
+				     &par->tga_chip_rev);
+	if (tga_bus_tc)
+		par->tga_chip_rev = TGA_READ_REG(par, TGA_START_REG) & 0xff;
 
 	/* Setup framebuffer.  */
 	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
@@ -1414,8 +1569,17 @@ tgafb_pci_register(struct pci_dev *pdev,
 	info->pseudo_palette = (void *)(par + 1);
 
 	/* This should give a reasonable default video mode.  */
-
-	ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL,
+	if (tga_bus_pci) {
+		mode_option_tga = mode_option_pci;
+	}
+	if (tga_bus_tc) {
+		mode_option_tga = mode_option_tc;
+		modedb_tga = &modedb_tc;
+		modedbsize_tga = 1;
+	}
+	ret = fb_find_mode(&info->var, info,
+			   mode_option ? mode_option : mode_option_tga,
+			   modedb_tga, modedbsize_tga, NULL,
 			   tga_type == TGA_TYPE_8PLANE ? 8 : 32);
 	if (ret == 0 || ret == 4) {
 		printk(KERN_ERR "tgafb: Could not find valid video mode\n");
@@ -1438,13 +1602,19 @@ tgafb_pci_register(struct pci_dev *pdev,
 		goto err1;
 	}
 
-	printk(KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
-	       par->tga_chip_rev);
-	printk(KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n",
-	       pdev->bus->number, PCI_SLOT(pdev->devfn),
-	       PCI_FUNC(pdev->devfn));
-	printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n",
-	       info->node, info->fix.id, bar0_start);
+	if (tga_bus_pci) {
+		pr_info("tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
+			par->tga_chip_rev);
+		pr_info("tgafb: at PCI bus %d, device %d, function %d\n",
+			to_pci_dev(dev)->bus->number,
+			PCI_SLOT(to_pci_dev(dev)->devfn),
+			PCI_FUNC(to_pci_dev(dev)->devfn));
+	}
+	if (tga_bus_tc)
+		pr_info("tgafb: SFB+ detected, rev=0x%02x\n",
+			par->tga_chip_rev);
+	pr_info("fb%d: %s frame buffer device at 0x%lx\n",
+		info->node, info->fix.id, (long)bar0_start);
 
 	return 0;
 
@@ -1458,25 +1628,39 @@ tgafb_pci_register(struct pci_dev *pdev,
 }
 
 static void __devexit
-tgafb_pci_unregister(struct pci_dev *pdev)
+tgafb_unregister(struct device *dev)
 {
-	struct fb_info *info = pci_get_drvdata(pdev);
-	struct tga_par *par = info->par;
+	resource_size_t bar0_start = 0, bar0_len = 0;
+	int tga_bus_pci = TGA_BUS_PCI(dev);
+	int tga_bus_tc = TGA_BUS_TC(dev);
+	struct fb_info *info = NULL;
+	struct tga_par *par;
 
+	info = dev_get_drvdata(dev);
 	if (!info)
 		return;
+
+	par = info->par;
 	unregister_framebuffer(info);
 	fb_dealloc_cmap(&info->cmap);
 	iounmap(par->tga_mem_base);
-	release_mem_region(pci_resource_start(pdev, 0),
-			   pci_resource_len(pdev, 0));
+	if (tga_bus_pci) {
+		bar0_start = pci_resource_start(to_pci_dev(dev), 0);
+		bar0_len = pci_resource_len(to_pci_dev(dev), 0);
+	}
+	if (tga_bus_tc) {
+		bar0_start = to_tc_dev(dev)->resource.start;
+		bar0_len = to_tc_dev(dev)->resource.end - bar0_start + 1;
+	}
+	release_mem_region(bar0_start, bar0_len);
 	framebuffer_release(info);
 }
 
 static void __devexit
 tgafb_exit(void)
 {
-	pci_unregister_driver(&tgafb_driver);
+	tc_unregister_driver(&tgafb_tc_driver);
+	pci_unregister_driver(&tgafb_pci_driver);
 }
 
 #ifndef MODULE
@@ -1505,6 +1689,7 @@ tgafb_setup(char *arg)
 static int __devinit
 tgafb_init(void)
 {
+	int status;
 #ifndef MODULE
 	char *option = NULL;
 
@@ -1512,7 +1697,10 @@ tgafb_init(void)
 		return -ENODEV;
 	tgafb_setup(option);
 #endif
-	return pci_register_driver(&tgafb_driver);
+	status = pci_register_driver(&tgafb_pci_driver);
+	if (!status)
+		status = tc_register_driver(&tgafb_tc_driver);
+	return status;
 }
 
 /*
@@ -1522,5 +1710,5 @@ tgafb_init(void)
 module_init(tgafb_init);
 module_exit(tgafb_exit);
 
-MODULE_DESCRIPTION("framebuffer driver for TGA chipset");
+MODULE_DESCRIPTION("Framebuffer driver for TGA/SFB+ chipset");
 MODULE_LICENSE("GPL");
diff -up --recursive --new-file linux-mips-2.6.21-rc1-20070222.macro/include/video/tgafb.h linux-mips-2.6.21-rc1-20070222/include/video/tgafb.h
--- linux-mips-2.6.21-rc1-20070222.macro/include/video/tgafb.h	2004-12-05 05:57:54.000000000 +0000
+++ linux-mips-2.6.21-rc1-20070222/include/video/tgafb.h	2007-03-01 00:32:46.000000000 +0000
@@ -39,6 +39,7 @@
 #define	TGA_RASTEROP_REG		0x0034
 #define	TGA_PIXELSHIFT_REG		0x0038
 #define	TGA_DEEP_REG			0x0050
+#define	TGA_START_REG			0x0054
 #define	TGA_PIXELMASK_REG		0x005c
 #define	TGA_CURSOR_BASE_REG		0x0060
 #define	TGA_HORIZ_REG			0x0064
@@ -140,7 +141,7 @@
 
 
 /*
- * Useful defines for managing the BT463 on the 24-plane TGAs
+ * Useful defines for managing the BT463 on the 24-plane TGAs/SFB+s
  */
 
 #define	BT463_ADDR_LO		0x0
@@ -168,12 +169,35 @@
 #define	BT463_WINDOW_TYPE_BASE	0x0300
 
 /*
+ * Useful defines for managing the BT459 on the 8-plane SFB+s
+ */
+
+#define	BT459_ADDR_LO		0x0
+#define	BT459_ADDR_HI		0x1
+#define	BT459_REG_ACC		0x2
+#define	BT459_PALETTE		0x3
+
+#define	BT459_CUR_CLR_1		0x0181
+#define	BT459_CUR_CLR_2		0x0182
+#define	BT459_CUR_CLR_3		0x0183
+
+#define	BT459_CMD_REG_0		0x0201
+#define	BT459_CMD_REG_1		0x0202
+#define	BT459_CMD_REG_2		0x0203
+
+#define	BT459_READ_MASK		0x0204
+
+#define	BT459_BLINK_MASK	0x0206
+
+#define	BT459_CUR_CMD_REG	0x0300
+
+/*
  * The framebuffer driver private data.
  */
 
 struct tga_par {
-	/* PCI device.  */
-	struct pci_dev *pdev;
+	/* PCI/TC device.  */
+	struct device *dev;
 
 	/* Device dependent information.  */
 	void __iomem *tga_mem_base;
@@ -235,4 +259,21 @@ BT463_WRITE(struct tga_par *par, u32 m, 
 	TGA_WRITE_REG(par, m << 10 | v, TGA_RAMDAC_REG);
 }
 
+static inline void
+BT459_LOAD_ADDR(struct tga_par *par, u16 a)
+{
+	TGA_WRITE_REG(par, BT459_ADDR_LO << 2, TGA_RAMDAC_SETUP_REG);
+	TGA_WRITE_REG(par, a & 0xff, TGA_RAMDAC_REG);
+	TGA_WRITE_REG(par, BT459_ADDR_HI << 2, TGA_RAMDAC_SETUP_REG);
+	TGA_WRITE_REG(par, a >> 8, TGA_RAMDAC_REG);
+}
+
+static inline void
+BT459_WRITE(struct tga_par *par, u32 m, u16 a, u8 v)
+{
+	BT459_LOAD_ADDR(par, a);
+	TGA_WRITE_REG(par, m << 2, TGA_RAMDAC_SETUP_REG);
+	TGA_WRITE_REG(par, v, TGA_RAMDAC_REG);
+}
+
 #endif /* TGAFB_H */

From macro@linux-mips.org Thu Mar  1 13:57:51 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 13:57:55 +0000 (GMT)
Received: from pollux.ds.pg.gda.pl ([153.19.208.7]:62738 "EHLO
	pollux.ds.pg.gda.pl") by ftp.linux-mips.org with ESMTP
	id S20039435AbXCAN5r (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 1 Mar 2007 13:57:47 +0000
Received: from localhost (localhost [127.0.0.1])
	by pollux.ds.pg.gda.pl (Postfix) with ESMTP id E8727E1CD8;
	Thu,  1 Mar 2007 14:57:05 +0100 (CET)
X-Virus-Scanned: by amavisd-new at pollux.ds.pg.gda.pl
Received: from pollux.ds.pg.gda.pl ([127.0.0.1])
	by localhost (pollux.ds.pg.gda.pl [127.0.0.1]) (amavisd-new, port 10024)
	with ESMTP id W-xayQFJScnP; Thu,  1 Mar 2007 14:57:05 +0100 (CET)
Received: from piorun.ds.pg.gda.pl (piorun.ds.pg.gda.pl [153.19.208.8])
	by pollux.ds.pg.gda.pl (Postfix) with ESMTP id 5EE5AE1CDE;
	Thu,  1 Mar 2007 14:57:05 +0100 (CET)
Received: from blysk.ds.pg.gda.pl (macro@blysk.ds.pg.gda.pl [153.19.208.6])
	by piorun.ds.pg.gda.pl (8.13.8/8.13.8) with ESMTP id l21DvFZE011392;
	Thu, 1 Mar 2007 14:57:15 +0100
Date:	Thu, 1 Mar 2007 13:57:11 +0000 (GMT)
From:	"Maciej W. Rozycki" <macro@linux-mips.org>
To:	Andrew Morton <akpm@osdl.org>
cc:	linux-kernel@vger.kernel.org, linux-mips@linux-mips.org
Subject: [PATCH 2.6.21-rc2] dz: Remove struct pt_regs references
Message-ID: <Pine.LNX.4.64N.0703011326490.25556@blysk.ds.pg.gda.pl>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
X-Virus-Scanned: ClamAV 0.90/2689/Thu Mar  1 06:46:09 2007 on piorun.ds.pg.gda.pl
X-Virus-Status:	Clean
Return-Path: <macro@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14298
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: macro@linux-mips.org
Precedence: bulk
X-list: linux-mips

 Remove remaining references to saved registers now that 
uart_handle_sysrq_char() does not want them.

Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
---

 The driver does not build without this update.

 Please apply.

  Maciej

patch-mips-2.6.21-rc1-20070222-dz-pt_regs-0
diff -up --recursive --new-file linux-mips-2.6.21-rc1-20070222.macro/drivers/serial/dz.c linux-mips-2.6.21-rc1-20070222/drivers/serial/dz.c
--- linux-mips-2.6.21-rc1-20070222.macro/drivers/serial/dz.c	2007-02-05 16:38:50.000000000 +0000
+++ linux-mips-2.6.21-rc1-20070222/drivers/serial/dz.c	2007-03-01 01:36:56.000000000 +0000
@@ -170,8 +170,7 @@ static void dz_enable_ms(struct uart_por
  * This routine deals with inputs from any lines.
  * ------------------------------------------------------------
  */
-static inline void dz_receive_chars(struct dz_port *dport_in,
-				    struct pt_regs *regs)
+static inline void dz_receive_chars(struct dz_port *dport_in)
 {
 	struct dz_port *dport;
 	struct tty_struct *tty = NULL;
@@ -226,7 +225,7 @@ static inline void dz_receive_chars(stru
 			break;
 		}
 
-		if (uart_handle_sysrq_char(&dport->port, ch, regs))
+		if (uart_handle_sysrq_char(&dport->port, ch))
 			continue;
 
 		if ((status & dport->port.ignore_status_mask) == 0) {
@@ -332,7 +331,7 @@ static irqreturn_t dz_interrupt(int irq,
 	status = dz_in(dport, DZ_CSR);
 
 	if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE))
-		dz_receive_chars(dport, regs);
+		dz_receive_chars(dport);
 
 	if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE))
 		dz_transmit_chars(dport);
patch-mips-2.6.21-rc1-20070222-dz-pt_regs-0

From ralf@linux-mips.org Thu Mar  1 18:40:46 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 18:40:48 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:40932 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20039464AbXCASkq (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 1 Mar 2007 18:40:46 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l21IeiU6023583;
	Thu, 1 Mar 2007 18:40:44 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l21Iehbx023582;
	Thu, 1 Mar 2007 18:40:43 GMT
Date:	Thu, 1 Mar 2007 18:40:43 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Cc:	linux-mips <linux-mips@linux-mips.org>
Subject: Re: [PATCH][MIPS] update Cobalt reserved resource
Message-ID: <20070301184043.GA23522@linux-mips.org>
References: <20070301225025.7612e583.yoichi_yuasa@tripeaks.co.jp>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20070301225025.7612e583.yoichi_yuasa@tripeaks.co.jp>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14299
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Thu, Mar 01, 2007 at 10:50:25PM +0900, Yoichi Yuasa wrote:

> This patch has removed unused timer resource.
> Moreover, the name of reserved resources ware changed.

Thanks, applied.

  Ralf

From macro@linux-mips.org Thu Mar  1 18:56:08 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 18:56:13 +0000 (GMT)
Received: from pollux.ds.pg.gda.pl ([153.19.208.7]:40709 "EHLO
	pollux.ds.pg.gda.pl") by ftp.linux-mips.org with ESMTP
	id S20039439AbXCAS4I (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 1 Mar 2007 18:56:08 +0000
Received: from localhost (localhost [127.0.0.1])
	by pollux.ds.pg.gda.pl (Postfix) with ESMTP id 5C146E1CCD;
	Thu,  1 Mar 2007 19:55:23 +0100 (CET)
X-Virus-Scanned: by amavisd-new at pollux.ds.pg.gda.pl
Received: from pollux.ds.pg.gda.pl ([127.0.0.1])
	by localhost (pollux.ds.pg.gda.pl [127.0.0.1]) (amavisd-new, port 10024)
	with ESMTP id QkHssIO0Ez2m; Thu,  1 Mar 2007 19:55:23 +0100 (CET)
Received: from piorun.ds.pg.gda.pl (piorun.ds.pg.gda.pl [153.19.208.8])
	by pollux.ds.pg.gda.pl (Postfix) with ESMTP id E8D1BE1C69;
	Thu,  1 Mar 2007 19:55:22 +0100 (CET)
Received: from blysk.ds.pg.gda.pl (macro@blysk.ds.pg.gda.pl [153.19.208.6])
	by piorun.ds.pg.gda.pl (8.13.8/8.13.8) with ESMTP id l21Itbkh008692;
	Thu, 1 Mar 2007 19:55:37 +0100
Date:	Thu, 1 Mar 2007 18:55:30 +0000 (GMT)
From:	"Maciej W. Rozycki" <macro@linux-mips.org>
To:	Ralf Baechle <ralf@linux-mips.org>
cc:	linux-mips@linux-mips.org
Subject: Re: [MIPS] Untangle the rest of the prom_printf mess and convert to
 early printk
In-Reply-To: <S20039493AbXCASgj/20070301183639Z+38846@ftp.linux-mips.org>
Message-ID: <Pine.LNX.4.64N.0703011853230.25556@blysk.ds.pg.gda.pl>
References: <S20039493AbXCASgj/20070301183639Z+38846@ftp.linux-mips.org>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
X-Virus-Scanned: ClamAV 0.90/2690/Thu Mar  1 12:11:27 2007 on piorun.ds.pg.gda.pl
X-Virus-Status:	Clean
Return-Path: <macro@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14300
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: macro@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Thu, 1 Mar 2007, linux-mips@linux-mips.org wrote:

>  arch/mips/dec/prom/console.c             |   38 +--------

 Any particular reason for replacing an optimised version with this 
miserable contraption?

  Maciej

From ralf@linux-mips.org Thu Mar  1 19:10:21 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 19:10:22 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:57247 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20039452AbXCATKV (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 1 Mar 2007 19:10:21 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l21JAK1F024287;
	Thu, 1 Mar 2007 19:10:20 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l21JAJKL024286;
	Thu, 1 Mar 2007 19:10:19 GMT
Date:	Thu, 1 Mar 2007 19:10:19 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	"Maciej W. Rozycki" <macro@linux-mips.org>
Cc:	linux-mips@linux-mips.org
Subject: Re: [MIPS] Untangle the rest of the prom_printf mess and convert to early printk
Message-ID: <20070301191019.GA23843@linux-mips.org>
References: <S20039493AbXCASgj/20070301183639Z+38846@ftp.linux-mips.org> <Pine.LNX.4.64N.0703011853230.25556@blysk.ds.pg.gda.pl>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <Pine.LNX.4.64N.0703011853230.25556@blysk.ds.pg.gda.pl>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14301
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Thu, Mar 01, 2007 at 06:55:30PM +0000, Maciej W. Rozycki wrote:

> >  arch/mips/dec/prom/console.c             |   38 +--------
> 
>  Any particular reason for replacing an optimised version with this 
> miserable contraption?

I doubt anybody will notice when the first few lines of bootup messages
take a few cycles extra.  For the moment it did matter to get rid of
the impressive barbed wire fence made from several independant early
printk implementations and macros, functions and function pointers being
named prom_printf with no apparent pattern.

If you think the code really needs to be optimized as the next step, I
take patches.

  Ralf

From stjeanma@pmc-sierra.com Thu Mar  1 20:42:59 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 20:43:05 +0000 (GMT)
Received: from father.pmc-sierra.com ([216.241.224.13]:9387 "HELO
	father.pmc-sierra.bc.ca") by ftp.linux-mips.org with SMTP
	id S20039275AbXCAUm7 (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 1 Mar 2007 20:42:59 +0000
Received: (qmail 4577 invoked by uid 101); 1 Mar 2007 20:41:19 -0000
Received: from unknown (HELO pmxedge1.pmc-sierra.bc.ca) (216.241.226.183)
  by father.pmc-sierra.com with SMTP; 1 Mar 2007 20:41:19 -0000
Received: from pasqua.pmc-sierra.bc.ca (pasqua.pmc-sierra.bc.ca [134.87.183.161])
	by pmxedge1.pmc-sierra.bc.ca (8.13.4/8.12.7) with ESMTP id l21KfI9b003088
	for <linux-mips@linux-mips.org>; Thu, 1 Mar 2007 12:41:18 -0800
From:	Marc St-Jean <stjeanma@pmc-sierra.com>
Received: (from stjeanma@localhost)
	by pasqua.pmc-sierra.bc.ca (8.13.4/8.12.11) id l21KfHeh014921
	for linux-mips@linux-mips.org; Thu, 1 Mar 2007 14:41:17 -0600
Date:	Thu, 1 Mar 2007 14:41:17 -0600
Message-Id: <200703012041.l21KfHeh014921@pasqua.pmc-sierra.bc.ca>
To:	linux-mips@linux-mips.org
Subject: [PATCH 2/5] mips: PMC MSP71xx mips common
Return-Path: <stjeanma@pmc-sierra.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14302
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: stjeanma@pmc-sierra.com
Precedence: bulk
X-list: linux-mips

[PATCH 2/5] mips: PMC MSP71xx mips common

Patch to add mips common support for the PMC-Sierra
MSP71xx devices.

These 5 patches along with the previously posted serial patch
will boot the PMC-Sierra MSP7120 Residential Gateway board.

Thanks,
Marc

Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
---
Re-posting patch with recommended change:
Added CONFIG_NO_EXCEPT_FILL option and selected in PMC_MSP
to eliminate the .fill for exception handlers.
(arch/mips/Kconfig, arch/mips/kernel/head.S)

 arch/mips/Kconfig           |   87 ++++++++++++++++++++++
 arch/mips/Makefile          |   11 ++
 arch/mips/kernel/head.S     |    5 +
 arch/mips/kernel/traps.c    |    6 +
 include/asm-mips/bootinfo.h |   12 +++
 include/asm-mips/mipsregs.h |   30 +++++++
 include/asm-mips/regops.h   |  168 ++++++++++++++++++++++++++++++++++++++++++++
 include/asm-mips/war.h      |   11 ++
 8 files changed, 328 insertions(+), 2 deletions(-)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 5da6b0d..899c528 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -354,6 +354,7 @@ config MIPS_SIM
 	bool 'MIPS simulator (MIPSsim)'
 	select DMA_NONCOHERENT
 	select IRQ_CPU
+	select BOOT_RAW
 	select SYS_HAS_CPU_MIPS32_R1
 	select SYS_HAS_CPU_MIPS32_R2
 	select SYS_SUPPORTS_32BIT_KERNEL
@@ -504,6 +505,27 @@ config MACH_VR41XX
 	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
 	select GENERIC_HARDIRQS_NO__DO_IRQ
 
+config PMC_MSP
+	bool "PMC-Sierra MSP chipsets"
+	depends on EXPERIMENTAL
+	select DMA_NONCOHERENT
+	select SWAP_IO_SPACE
+	select NO_EXCEPT_FILL
+	select BOOT_RAW
+	select SYS_HAS_CPU_MIPS32_R1
+	select SYS_HAS_CPU_MIPS32_R2
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select SYS_SUPPORTS_BIG_ENDIAN
+	select SYS_SUPPORTS_KGDB
+	select IRQ_CPU
+	select SERIAL_8250
+	select SERIAL_8250_CONSOLE
+	help
+	  This adds support for the PMC-Sierra family of Multi-Service
+	  Processor System-On-A-Chips.  These parts include a number
+	  of integrated peripherals, interfaces and DSPs in addition to
+	  a variety of MIPS cores.
+
 config PMC_YOSEMITE
 	bool "PMC-Sierra Yosemite eval board"
 	select DMA_COHERENT
@@ -815,6 +837,55 @@ config TOSHIBA_RBTX4938
 
 endchoice
 
+choice
+	prompt "PMC-Sierra MSP SOC type"
+	depends on PMC_MSP
+
+config PMC_MSP4200_EVAL
+	bool "PMC-Sierra MSP4200 Eval Board"
+	select IRQ_MSP_SLP
+	select HW_HAS_PCI
+
+config PMC_MSP4200_GW
+	bool "PMC-Sierra MSP4200 VoIP Gateway"
+	select IRQ_MSP_SLP
+	select HW_HAS_PCI
+
+config PMC_MSP7120_EVAL
+	bool "PMC-Sierra MSP7120 Eval Board"
+	select SYS_SUPPORTS_MULTITHREADING
+	select IRQ_MSP_CIC
+	select HW_HAS_PCI
+	select MSP_USB
+
+config PMC_MSP7120_GW
+	bool "PMC-Sierra MSP7120 Residential Gateway"
+	select SYS_SUPPORTS_MULTITHREADING
+	select IRQ_MSP_CIC
+	select HW_HAS_PCI
+	select MSP_USB
+
+config PMC_MSP7120_FPGA
+	bool "PMC-Sierra MSP7120 FPGA"
+	select SYS_SUPPORTS_MULTITHREADING
+	select IRQ_MSP_CIC
+	select HW_HAS_PCI
+	select MSP_USB
+
+endchoice
+
+menu "Options for PMC-Sierra MSP chipsets"
+	depends on PMC_MSP
+
+config PMC_MSP_EMBEDDED_ROOTFS
+	bool "Root filesystem embedded in kernel image"
+	select MTD
+	select MTD_BLOCK
+	select MTD_PMC_MSP_RAMROOT
+	select MTD_RAM
+
+endmenu
+
 source "arch/mips/ddb5xxx/Kconfig"
 source "arch/mips/gt64120/ev64120/Kconfig"
 source "arch/mips/jazz/Kconfig"
@@ -879,6 +950,9 @@ config ARC
 config ARCH_MAY_HAVE_PC_FDC
 	bool
 
+config BOOT_RAW
+	bool
+
 config DMA_COHERENT
 	bool
 
@@ -924,6 +998,9 @@ config MIPS_DISABLE_OBSOLETE_IDE
 
 config GENERIC_ISA_DMA_SUPPORT_BROKEN
 	bool
+	
+config NO_EXCEPT_FILL
+	bool
 
 #
 # Endianess selection.  Sufficiently obscure so many users don't know what to
@@ -971,6 +1048,15 @@ config IRQ_CPU_RM9K
 config IRQ_MV64340
 	bool
 
+config IRQ_MSP_SLP
+	bool
+
+config IRQ_MSP_CIC
+	bool
+
+config MSP_USB
+	bool
+
 config DDB5XXX_COMMON
 	bool
 	select SYS_SUPPORTS_KGDB
@@ -1086,6 +1172,7 @@ config MIPS_L1_CACHE_SHIFT
 	int
 	default "4" if MACH_DECSTATION || SNI_RM
 	default "7" if SGI_IP27
+	default "4" if PMC_MSP4200_EVAL
 	default "5"
 
 config HAVE_STD_PC_SERIAL_PORT
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 92bca6a..1c38332 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -360,6 +360,14 @@ core-$(CONFIG_MOMENCO_OCELOT_C)	+= arch/mips/momentum/ocelot_c/
 load-$(CONFIG_MOMENCO_OCELOT_C)	+= 0xffffffff80100000
 
 #
+# PMC-Sierra MSP SOCs
+#
+core-$(CONFIG_PMC_MSP)		+= arch/mips/pmc-sierra/msp71xx/
+cflags-$(CONFIG_PMC_MSP)	+= -Iinclude/asm-mips/pmc-sierra/msp71xx \
+					-mno-branch-likely
+load-$(CONFIG_PMC_MSP)		+= 0xffffffff80100000
+
+#
 # PMC-Sierra Yosemite
 #
 core-$(CONFIG_PMC_YOSEMITE)	+= arch/mips/pmc-sierra/yosemite/
@@ -619,7 +627,8 @@ JIFFIES			= jiffies_64
 endif
 
 AFLAGS		+= $(cflags-y)
-CFLAGS		+= $(cflags-y)
+CFLAGS		+= $(cflags-y) \
+			-D"VMLINUX_LOAD_ADDRESS=$(load-y)"
 
 LDFLAGS			+= -m $(ld-emul)
 
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 6f57ca4..27366f6 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/threads.h>
 
+#include <asm/addrspace.h>
 #include <asm/asm.h>
 #include <asm/asmmacro.h>
 #include <asm/irqflags.h>
@@ -129,16 +130,18 @@
 #endif
 	.endm
 
+#ifndef CONFIG_NO_EXCEPT_FILL
 	/*
 	 * Reserved space for exception handlers.
 	 * Necessary for machines which link their kernels at KSEG0.
 	 */
 	.fill	0x400
+#endif
 
 EXPORT(stext)					# used for profiling
 EXPORT(_stext)
 
-#ifdef CONFIG_MIPS_SIM
+#ifdef CONFIG_BOOT_RAW
 	/*
 	 * Give us a fighting chance of running if execution beings at the
 	 * kernel load address.  This is needed because this platform does
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 18f56a9..2c812c2 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -70,6 +70,7 @@ extern asmlinkage void handle_reserved(void);
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
 	struct mips_fpu_struct *ctx, int has_fpu);
 
+void (*board_watchpoint_handler)(struct pt_regs *regs);
 void (*board_be_init)(void);
 int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
 void (*board_nmi_handler_setup)(void);
@@ -860,6 +861,11 @@ asmlinkage void do_mdmx(struct pt_regs *regs)
 
 asmlinkage void do_watch(struct pt_regs *regs)
 {
+	if (board_watchpoint_handler) {
+		(*board_watchpoint_handler)(regs);
+		return;
+	}
+	
 	/*
 	 * We use the watch exception where available to detect stack
 	 * overflows.
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index c7c945b..7fc52c7 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -213,6 +213,18 @@
 #define MACH_GROUP_NEC_EMMA2RH 25	/* NEC EMMA2RH (was 23)		*/
 #define  MACH_NEC_MARKEINS	0	/* NEC EMMA2RH Mark-eins	*/
 
+/*
+ * Valid machtype for group PMC-MSP
+ */
+#define MACH_GROUP_MSP         26	/* PMC-Sierra MSP boards/CPUs    */
+#define MACH_MSP4200_EVAL       0	/* PMC-Sierra MSP4200 Evaluation board */
+#define MACH_MSP4200_GW         1	/* PMC-Sierra MSP4200 Gateway demo board */
+#define MACH_MSP4200_FPGA       2	/* PMC-Sierra MSP4200 Emulation board */
+#define MACH_MSP7120_EVAL       3	/* PMC-Sierra MSP7120 Evaluation board */
+#define MACH_MSP7120_GW         4	/* PMC-Sierra MSP7120 Residential Gateway board */
+#define MACH_MSP7120_FPGA       5	/* PMC-Sierra MSP7120 Emulation board */
+#define MACH_MSP_OTHER        255	/* PMC-Sierra unknown board type */
+
 #define CL_SIZE			COMMAND_LINE_SIZE
 
 const char *get_system_type(void);
diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h
index 9985cb7..bd683b6 100644
--- a/include/asm-mips/mipsregs.h
+++ b/include/asm-mips/mipsregs.h
@@ -15,6 +15,7 @@
 
 #include <linux/linkage.h>
 #include <asm/hazards.h>
+#include <asm/war.h>
 
 /*
  * The following macros are especially useful for __asm__
@@ -1292,10 +1293,39 @@ static inline void tlb_probe(void)
 
 static inline void tlb_read(void)
 {
+#if MIPS34K_MISSED_ITLB_WAR
+	int res = 0;
+
+	__asm__ __volatile__(
+	"	.set	push						\n"
+	"	.set	noreorder					\n"
+	"	.set	noat						\n"
+	"	.set	mips32r2					\n"
+	"	.word	0x41610001		# dvpe $1		\n"
+	"	move	%0, $1						\n"
+	"	ehb							\n"
+	"	.set	pop						\n"
+	: "=r" (res));
+
+	instruction_hazard();
+#endif
+
 	__asm__ __volatile__(
 		".set noreorder\n\t"
 		"tlbr\n\t"
 		".set reorder");
+
+#if MIPS34K_MISSED_ITLB_WAR
+	if ((res & _ULCAST_(1)))
+		__asm__ __volatile__(
+		"	.set	push						\n"
+		"	.set	noreorder					\n"
+		"	.set	noat						\n"
+		"	.set	mips32r2					\n"
+		"	.word	0x41600021		# evpe			\n"
+		"	ehb							\n"
+		"	.set	pop						\n");
+#endif
 }
 
 static inline void tlb_write_indexed(void)
diff --git a/include/asm-mips/war.h b/include/asm-mips/war.h
index 13a3502..74c08e6 100644
--- a/include/asm-mips/war.h
+++ b/include/asm-mips/war.h
@@ -196,6 +196,14 @@
 #endif
 
 /*
+ * 34K core erratum: "Problems Executing the TLBR Instruction"
+ */
+#if defined(CONFIG_PMC_MSP7120_EVAL) || defined(CONFIG_PMC_MSP7120_GW) || \
+	defined(CONFIG_PMC_MSP7120_FPGA)
+#define MIPS34K_MISSED_ITLB_WAR		1
+#endif
+
+/*
  * Workarounds default to off
  */
 #ifndef ICACHE_REFILLS_WORKAROUND_WAR
@@ -234,5 +242,8 @@
 #ifndef R10000_LLSC_WAR
 #define R10000_LLSC_WAR			0
 #endif
+#ifndef MIPS34K_MISSED_ITLB_WAR
+#define MIPS34K_MISSED_ITLB_WAR		0
+#endif
 
 #endif /* _ASM_WAR_H */
diff --git a/include/asm-mips/regops.h b/include/asm-mips/regops.h
new file mode 100644
index 0000000..fbfc940
--- /dev/null
+++ b/include/asm-mips/regops.h
@@ -0,0 +1,168 @@
+/*
+ * $Id: regops.h,v 1.2 2006/05/08 22:00:34 ramsayji Exp $
+ *
+ * VPE/SMP-safe functions to access registers.  They use ll/sc instructions, so
+ * it is your responsibility to ensure these are available on your platform
+ * before including this file.
+ *
+ * In addition, there is a bug on the R10000 chips which has a workaround.  If
+ * you are affected by this bug, make sure to define the symbol
+ * 'R10000_LLSC_WAR' to be non-zero.  If you are using this header from within
+ * linux, you may include <asm/war.h> before including this file to have this
+ * defined appropriately for you.
+ *
+ * Copyright 2005 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
+ *  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF USE,
+ *  DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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., 675
+ *  Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_REGOPS_H__
+#define __ASM_REGOPS_H__
+
+#ifndef R10000_LLSC_WAR
+#define R10000_LLSC_WAR 0
+#endif
+
+#if R10000_LLSC_WAR == 1
+#define __beqz	"beqzl	"
+#else
+#define __beqz	"beqz	"
+#endif
+
+#ifndef _LINUX_TYPES_H
+typedef unsigned int uint32_t;
+#endif
+
+/*
+ * Sets all the masked bits to the corresponding value bits
+ */
+static inline void set_value_reg32( volatile uint32_t * const addr,
+					uint32_t const mask,
+					uint32_t const value )
+{
+	uint32_t temp;
+
+	__asm__ __volatile__(
+	"	.set	mips3				\n"
+	"1:	ll	%0, %1	# set_value_reg32	\n"
+	"	and	%0, %2				\n"
+	"	or	%0, %3				\n"
+	"	sc	%0, %1				\n"
+	"	"__beqz"%0, 1b				\n"
+	"	.set	mips0				\n"
+	: "=&r" (temp), "=m" (*addr)
+	: "ir" (~mask), "ir" (value), "m" (*addr) );
+}
+
+/*
+ * Sets all the masked bits to '1'
+ */
+static inline void set_reg32( volatile uint32_t * const addr,
+				uint32_t const mask )
+{
+	uint32_t temp;
+
+	__asm__ __volatile__(
+	"	.set	mips3				\n"
+	"1:	ll	%0, %1		# set_reg32	\n"
+	"	or	%0, %2				\n"
+	"	sc	%0, %1				\n"
+	"	"__beqz"%0, 1b				\n"
+	"	.set	mips0				\n"
+	: "=&r" (temp), "=m" (*addr)
+	: "ir" (mask), "m" (*addr) );
+}
+
+/*
+ * Sets all the masked bits to '0'
+ */
+static inline void clear_reg32( volatile uint32_t * const addr,
+				uint32_t const mask )
+{
+	uint32_t temp;
+
+	__asm__ __volatile__(
+	"	.set	mips3				\n"
+	"1:	ll	%0, %1		# clear_reg32	\n"
+	"	and	%0, %2				\n"
+	"	sc	%0, %1				\n"
+	"	"__beqz"%0, 1b				\n"
+	"	.set	mips0				\n"
+	: "=&r" (temp), "=m" (*addr)
+	: "ir" (~mask), "m" (*addr) );
+}
+
+/*
+ * Toggles all masked bits from '0' to '1' and '1' to '0'
+ */
+static inline void toggle_reg32( volatile uint32_t * const addr,
+				uint32_t const mask )
+{
+	uint32_t temp;
+
+	__asm__ __volatile__(
+	"	.set	mips3				\n"
+	"1:	ll	%0, %1		# toggle_reg32	\n"
+	"	xor	%0, %2				\n"
+	"	sc	%0, %1				\n"
+	"	"__beqz"%0, 1b				\n"
+	"	.set	mips0				\n"
+	: "=&r" (temp), "=m" (*addr)
+	: "ir" (mask), "m" (*addr) );
+}
+
+/* For special strange cases only:
+ *
+ * If you need custom processing within a ll/sc loop, use the following macros
+ * VERY CAREFULLY:
+ *
+ *   uint32_t tmp;                      <-- Define a variable to hold the data
+ *
+ *   custom_reg32_start(address, tmp);	<-- Reads the address and puts the value
+ *						in the 'tmp' variable given
+ *
+ *	< From here on out, you are (basicly) atomic, so don't do anything too
+ *	< fancy!
+ *	< Also, this code may loop if the end of this block fails to write
+ *	< everything back safely due do the other CPU, so do NOT do anything
+ *	< with side-effects!
+ *
+ *   custom_reg32_stop(address, tmp);	<-- Writes back 'tmp' safely. 
+ *
+ */
+#define custom_reg32_read(address, tmp)				\
+	__asm__ __volatile__(					\
+	"	.set	mips3				\n"	\
+	"1:	ll	%0, %1	#custom_reg32_read	\n"	\
+	"	.set	mips0				\n"	\
+	: "=r" (tmp), "=m" (*address)				\
+	: "m" (*address) )
+
+#define custom_reg32_write(address, tmp)			\
+	__asm__ __volatile__(					\
+	"	.set	mips3				\n"	\
+	"	sc	%0, %1	#custom_reg32_write	\n"	\
+	"	"__beqz"%0, 1b				\n"	\
+	"	.set	mips0				\n"	\
+	: "=&r" (tmp), "=m" (*address)				\
+	: "0" (tmp), "m" (*address) )
+
+#endif  /* __ASM_REGOPS_H__ */

From dale@farnsworth.org Thu Mar  1 23:32:54 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 23:32:58 +0000 (GMT)
Received: from xyzzy.farnsworth.org ([65.39.95.219]:49419 "HELO farnsworth.org")
	by ftp.linux-mips.org with SMTP id S20039468AbXCAXcy (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 1 Mar 2007 23:32:54 +0000
Received: (qmail 20181 invoked by uid 1000); 1 Mar 2007 16:31:48 -0700
From:	"Dale Farnsworth" <dale@farnsworth.org>
Date:	Thu, 1 Mar 2007 16:31:48 -0700
To:	Jeff Garzik <jgarzik@pobox.com>
Cc:	linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
	linux-mips@linux-mips.org, Ralf Baechle <ralf@linux-mips.org>
Subject: [PATCH 1/2] mv643xx_eth: move mac_addr inside mv643xx_eth_platform_data
Message-ID: <20070301233148.GA19550@xyzzy.farnsworth.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
User-Agent: Mutt/1.5.13 (2006-08-11)
Return-Path: <dale@farnsworth.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14303
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: dale@farnsworth.org
Precedence: bulk
X-list: linux-mips

The information contained within platform_data should be self-contained.
Replace the pointer to a MAC address with the actual MAC address in
struct mv643xx_eth_platform_data.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>

---

Replaced explicit mac address comparison with a call to is_valid_ether_addr(),
as suggested by Stephen Hemminger <shemminger@linux-foundation.org>.

 arch/mips/momentum/jaguar_atx/platform.c |   20 ++++----------------
 arch/mips/momentum/ocelot_3/platform.c   |   20 ++++----------------
 arch/mips/momentum/ocelot_c/platform.c   |   12 ++----------
 drivers/net/mv643xx_eth.c                |    2 +-
 include/linux/mv643xx.h                  |    2 +-
 5 files changed, 12 insertions(+), 44 deletions(-)

Index: b/drivers/net/mv643xx_eth.c
===================================================================
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1380,7 +1380,7 @@ static int mv643xx_eth_probe(struct plat
 
 	pd = pdev->dev.platform_data;
 	if (pd) {
-		if (pd->mac_addr)
+		if (is_valid_ether_addr(pd->mac_addr))
 			memcpy(dev->dev_addr, pd->mac_addr, 6);
 
 		if (pd->phy_addr || pd->force_phy_addr)
Index: b/include/linux/mv643xx.h
===================================================================
--- a/include/linux/mv643xx.h
+++ b/include/linux/mv643xx.h
@@ -1289,7 +1289,6 @@ struct mv64xxx_i2c_pdata {
 #define MV643XX_ETH_NAME	"mv643xx_eth"
 
 struct mv643xx_eth_platform_data {
-	char		*mac_addr;	/* pointer to mac address */
 	u16		force_phy_addr;	/* force override if phy_addr == 0 */
 	u16		phy_addr;
 
@@ -1304,6 +1303,7 @@ struct mv643xx_eth_platform_data {
 	u32		tx_sram_size;
 	u32		rx_sram_addr;
 	u32		rx_sram_size;
+	u8		mac_addr[6];	/* mac address if non-zero*/
 };
 
 #endif /* __ASM_MV643XX_H */
Index: b/arch/mips/momentum/jaguar_atx/platform.c
===================================================================
--- a/arch/mips/momentum/jaguar_atx/platform.c
+++ b/arch/mips/momentum/jaguar_atx/platform.c
@@ -47,11 +47,7 @@ static struct resource mv64x60_eth0_reso
 	},
 };
 
-static char eth0_mac_addr[ETH_ALEN];
-
 static struct mv643xx_eth_platform_data eth0_pd = {
-	.mac_addr	= eth0_mac_addr,
-
 	.tx_sram_addr	= MV_SRAM_BASE_ETH0,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
@@ -80,11 +76,7 @@ static struct resource mv64x60_eth1_reso
 	},
 };
 
-static char eth1_mac_addr[ETH_ALEN];
-
 static struct mv643xx_eth_platform_data eth1_pd = {
-	.mac_addr	= eth1_mac_addr,
-
 	.tx_sram_addr	= MV_SRAM_BASE_ETH1,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
@@ -113,11 +105,7 @@ static struct resource mv64x60_eth2_reso
 	},
 };
 
-static char eth2_mac_addr[ETH_ALEN];
-
-static struct mv643xx_eth_platform_data eth2_pd = {
-	.mac_addr	= eth2_mac_addr,
-};
+static struct mv643xx_eth_platform_data eth2_pd;
 
 static struct platform_device eth2_device = {
 	.name		= MV643XX_ETH_NAME,
@@ -200,9 +188,9 @@ static int __init mv643xx_eth_add_pds(vo
 	int ret;
 
 	get_mac(mac);
-	eth_mac_add(eth0_mac_addr, mac, 0);
-	eth_mac_add(eth1_mac_addr, mac, 1);
-	eth_mac_add(eth2_mac_addr, mac, 2);
+	eth_mac_add(eth0_pd.mac_addr, mac, 0);
+	eth_mac_add(eth1_pd.mac_addr, mac, 1);
+	eth_mac_add(eth2_pd.mac_addr, mac, 2);
 	ret = platform_add_devices(mv643xx_eth_pd_devs,
 			ARRAY_SIZE(mv643xx_eth_pd_devs));
 
Index: b/arch/mips/momentum/ocelot_3/platform.c
===================================================================
--- a/arch/mips/momentum/ocelot_3/platform.c
+++ b/arch/mips/momentum/ocelot_3/platform.c
@@ -47,11 +47,7 @@ static struct resource mv64x60_eth0_reso
 	},
 };
 
-static char eth0_mac_addr[ETH_ALEN];
-
 static struct mv643xx_eth_platform_data eth0_pd = {
-	.mac_addr	= eth0_mac_addr,
-
 	.tx_sram_addr	= MV_SRAM_BASE_ETH0,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
@@ -80,11 +76,7 @@ static struct resource mv64x60_eth1_reso
 	},
 };
 
-static char eth1_mac_addr[ETH_ALEN];
-
 static struct mv643xx_eth_platform_data eth1_pd = {
-	.mac_addr	= eth1_mac_addr,
-
 	.tx_sram_addr	= MV_SRAM_BASE_ETH1,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
@@ -113,11 +105,7 @@ static struct resource mv64x60_eth2_reso
 	},
 };
 
-static char eth2_mac_addr[ETH_ALEN];
-
-static struct mv643xx_eth_platform_data eth2_pd = {
-	.mac_addr	= eth2_mac_addr,
-};
+static struct mv643xx_eth_platform_data eth2_pd;
 
 static struct platform_device eth2_device = {
 	.name		= MV643XX_ETH_NAME,
@@ -200,9 +188,9 @@ static int __init mv643xx_eth_add_pds(vo
 	int ret;
 
 	get_mac(mac);
-	eth_mac_add(eth0_mac_addr, mac, 0);
-	eth_mac_add(eth1_mac_addr, mac, 1);
-	eth_mac_add(eth2_mac_addr, mac, 2);
+	eth_mac_add(eth0_pd.mac_addr, mac, 0);
+	eth_mac_add(eth1_pd.mac_addr, mac, 1);
+	eth_mac_add(eth2_pd.mac_addr, mac, 2);
 	ret = platform_add_devices(mv643xx_eth_pd_devs,
 			ARRAY_SIZE(mv643xx_eth_pd_devs));
 
Index: b/arch/mips/momentum/ocelot_c/platform.c
===================================================================
--- a/arch/mips/momentum/ocelot_c/platform.c
+++ b/arch/mips/momentum/ocelot_c/platform.c
@@ -46,11 +46,7 @@ static struct resource mv64x60_eth0_reso
 	},
 };
 
-static char eth0_mac_addr[ETH_ALEN];
-
 static struct mv643xx_eth_platform_data eth0_pd = {
-	.mac_addr	= eth0_mac_addr,
-
 	.tx_sram_addr	= MV_SRAM_BASE_ETH0,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
@@ -79,11 +75,7 @@ static struct resource mv64x60_eth1_reso
 	},
 };
 
-static char eth1_mac_addr[ETH_ALEN];
-
 static struct mv643xx_eth_platform_data eth1_pd = {
-	.mac_addr	= eth1_mac_addr,
-
 	.tx_sram_addr	= MV_SRAM_BASE_ETH1,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
@@ -174,8 +166,8 @@ static int __init mv643xx_eth_add_pds(vo
 	int ret;
 
 	get_mac(mac);
-	eth_mac_add(eth0_mac_addr, mac, 0);
-	eth_mac_add(eth1_mac_addr, mac, 1);
+	eth_mac_add(eth0_pd.mac_addr, mac, 0);
+	eth_mac_add(eth1_pd.mac_addr, mac, 1);
 	ret = platform_add_devices(mv643xx_eth_pd_devs,
 			ARRAY_SIZE(mv643xx_eth_pd_devs));
 

From dale@farnsworth.org Thu Mar  1 23:33:27 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 23:33:31 +0000 (GMT)
Received: from xyzzy.farnsworth.org ([65.39.95.219]:53771 "HELO farnsworth.org")
	by ftp.linux-mips.org with SMTP id S20039480AbXCAXd1 (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 1 Mar 2007 23:33:27 +0000
Received: (qmail 20364 invoked by uid 1000); 1 Mar 2007 16:33:24 -0700
From:	"Dale Farnsworth" <dale@farnsworth.org>
Date:	Thu, 1 Mar 2007 16:33:24 -0700
To:	Jeff Garzik <jgarzik@pobox.com>
Cc:	linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
	linux-mips@linux-mips.org, Ralf Baechle <ralf@linux-mips.org>
Subject: [PATCH 2/2] mv643xx_eth: Place explicit port number in mv643xx_eth_platform_data
Message-ID: <20070301233324.GA20193@xyzzy.farnsworth.org>
References: <20070301233148.GA19550@xyzzy.farnsworth.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20070301233148.GA19550@xyzzy.farnsworth.org>
User-Agent: Mutt/1.5.13 (2006-08-11)
Return-Path: <dale@farnsworth.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14304
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: dale@farnsworth.org
Precedence: bulk
X-list: linux-mips

We were using the platform_device.id field to identify which ethernet
port is used for mv643xx_eth device.  This is not generally correct.
It will be incorrect, for example, if a hardware platform uses a single
port but not the first port.  Here, we add an explicit port_number field
to struct mv643xx_eth_platform_data.

This makes the mv643xx_eth_platform_data structure required, but that
isn't an issue since all users currently provide it already.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>

---

 arch/mips/momentum/jaguar_atx/platform.c  |    8 ++
 arch/mips/momentum/ocelot_3/platform.c    |    8 ++
 arch/mips/momentum/ocelot_c/platform.c    |    4 +
 arch/powerpc/platforms/chrp/pegasos_eth.c |    2 
 arch/ppc/syslib/mv64x60.c                 |   12 +++-
 drivers/net/mv643xx_eth.c                 |   59 ++++++++++----------
 include/linux/mv643xx.h                   |    1 
 7 files changed, 62 insertions(+), 32 deletions(-)

diff --git a/arch/mips/momentum/jaguar_atx/platform.c b/arch/mips/momentum/jaguar_atx/platform.c
index 035ea51..003d3ee 100644
Index: b/arch/mips/momentum/jaguar_atx/platform.c
===================================================================
--- a/arch/mips/momentum/jaguar_atx/platform.c
+++ b/arch/mips/momentum/jaguar_atx/platform.c
@@ -48,6 +48,8 @@ static struct resource mv64x60_eth0_reso
 };
 
 static struct mv643xx_eth_platform_data eth0_pd = {
+	.port_number	= 0,
+
 	.tx_sram_addr	= MV_SRAM_BASE_ETH0,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
@@ -77,6 +79,8 @@ static struct resource mv64x60_eth1_reso
 };
 
 static struct mv643xx_eth_platform_data eth1_pd = {
+	.port_number	= 1,
+
 	.tx_sram_addr	= MV_SRAM_BASE_ETH1,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
@@ -105,7 +109,9 @@ static struct resource mv64x60_eth2_reso
 	},
 };
 
-static struct mv643xx_eth_platform_data eth2_pd;
+static struct mv643xx_eth_platform_data eth2_pd = {
+	.port_number	= 2,
+};
 
 static struct platform_device eth2_device = {
 	.name		= MV643XX_ETH_NAME,
Index: b/arch/mips/momentum/ocelot_3/platform.c
===================================================================
--- a/arch/mips/momentum/ocelot_3/platform.c
+++ b/arch/mips/momentum/ocelot_3/platform.c
@@ -48,6 +48,8 @@ static struct resource mv64x60_eth0_reso
 };
 
 static struct mv643xx_eth_platform_data eth0_pd = {
+	.port_number	= 0,
+
 	.tx_sram_addr	= MV_SRAM_BASE_ETH0,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
@@ -77,6 +79,8 @@ static struct resource mv64x60_eth1_reso
 };
 
 static struct mv643xx_eth_platform_data eth1_pd = {
+	.port_number	= 1,
+
 	.tx_sram_addr	= MV_SRAM_BASE_ETH1,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
@@ -105,7 +109,9 @@ static struct resource mv64x60_eth2_reso
 	},
 };
 
-static struct mv643xx_eth_platform_data eth2_pd;
+static struct mv643xx_eth_platform_data eth2_pd = {
+	.port_number	= 2,
+};
 
 static struct platform_device eth2_device = {
 	.name		= MV643XX_ETH_NAME,
Index: b/arch/mips/momentum/ocelot_c/platform.c
===================================================================
--- a/arch/mips/momentum/ocelot_c/platform.c
+++ b/arch/mips/momentum/ocelot_c/platform.c
@@ -47,6 +47,8 @@ static struct resource mv64x60_eth0_reso
 };
 
 static struct mv643xx_eth_platform_data eth0_pd = {
+	.port_number	= 0,
+
 	.tx_sram_addr	= MV_SRAM_BASE_ETH0,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
@@ -76,6 +78,8 @@ static struct resource mv64x60_eth1_reso
 };
 
 static struct mv643xx_eth_platform_data eth1_pd = {
+	.port_number	= 1,
+
 	.tx_sram_addr	= MV_SRAM_BASE_ETH1,
 	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
 	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
Index: b/arch/powerpc/platforms/chrp/pegasos_eth.c
===================================================================
--- a/arch/powerpc/platforms/chrp/pegasos_eth.c
+++ b/arch/powerpc/platforms/chrp/pegasos_eth.c
@@ -58,6 +58,7 @@ static struct resource mv643xx_eth0_reso
 
 
 static struct mv643xx_eth_platform_data eth0_pd = {
+	.port_number	= 0,
 	.tx_sram_addr = PEGASOS2_SRAM_BASE_ETH0,
 	.tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE,
 	.tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16,
@@ -87,6 +88,7 @@ static struct resource mv643xx_eth1_reso
 };
 
 static struct mv643xx_eth_platform_data eth1_pd = {
+	.port_number	= 1,
 	.tx_sram_addr = PEGASOS2_SRAM_BASE_ETH1,
 	.tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE,
 	.tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16,
Index: b/arch/ppc/syslib/mv64x60.c
===================================================================
--- a/arch/ppc/syslib/mv64x60.c
+++ b/arch/ppc/syslib/mv64x60.c
@@ -339,7 +339,9 @@ static struct resource mv64x60_eth0_reso
 	},
 };
 
-static struct mv643xx_eth_platform_data eth0_pd;
+static struct mv643xx_eth_platform_data eth0_pd = {
+	.port_number	= 0,
+};
 
 static struct platform_device eth0_device = {
 	.name		= MV643XX_ETH_NAME,
@@ -362,7 +364,9 @@ static struct resource mv64x60_eth1_reso
 	},
 };
 
-static struct mv643xx_eth_platform_data eth1_pd;
+static struct mv643xx_eth_platform_data eth1_pd = {
+	.port_number	= 1,
+};
 
 static struct platform_device eth1_device = {
 	.name		= MV643XX_ETH_NAME,
@@ -385,7 +389,9 @@ static struct resource mv64x60_eth2_reso
 	},
 };
 
-static struct mv643xx_eth_platform_data eth2_pd;
+static struct mv643xx_eth_platform_data eth2_pd = {
+	.port_number	= 2,
+};
 
 static struct platform_device eth2_device = {
 	.name		= MV643XX_ETH_NAME,
Index: b/drivers/net/mv643xx_eth.c
===================================================================
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1309,7 +1309,7 @@ static void mv643xx_init_ethtool_cmd(str
 static int mv643xx_eth_probe(struct platform_device *pdev)
 {
 	struct mv643xx_eth_platform_data *pd;
-	int port_num = pdev->id;
+	int port_num;
 	struct mv643xx_private *mp;
 	struct net_device *dev;
 	u8 *p;
@@ -1319,6 +1319,12 @@ static int mv643xx_eth_probe(struct plat
 	int duplex = DUPLEX_HALF;
 	int speed = 0;			/* default to auto-negotiation */
 
+	pd = pdev->dev.platform_data;
+	if (pd == NULL) {
+		printk(KERN_ERR "No mv643xx_eth_platform_data\n");
+		return -ENODEV;
+	}
+
 	dev = alloc_etherdev(sizeof(struct mv643xx_private));
 	if (!dev)
 		return -ENOMEM;
@@ -1331,8 +1337,6 @@ static int mv643xx_eth_probe(struct plat
 	BUG_ON(!res);
 	dev->irq = res->start;
 
-	mp->port_num = port_num;
-
 	dev->open = mv643xx_eth_open;
 	dev->stop = mv643xx_eth_stop;
 	dev->hard_start_xmit = mv643xx_eth_start_xmit;
@@ -1373,39 +1377,40 @@ static int mv643xx_eth_probe(struct plat
 
 	spin_lock_init(&mp->lock);
 
+	port_num = pd->port_number;
+
 	/* set default config values */
 	eth_port_uc_addr_get(dev, dev->dev_addr);
 	mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE;
 	mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE;
 
-	pd = pdev->dev.platform_data;
-	if (pd) {
-		if (is_valid_ether_addr(pd->mac_addr))
-			memcpy(dev->dev_addr, pd->mac_addr, 6);
-
-		if (pd->phy_addr || pd->force_phy_addr)
-			ethernet_phy_set(port_num, pd->phy_addr);
-
-		if (pd->rx_queue_size)
-			mp->rx_ring_size = pd->rx_queue_size;
-
-		if (pd->tx_queue_size)
-			mp->tx_ring_size = pd->tx_queue_size;
-
-		if (pd->tx_sram_size) {
-			mp->tx_sram_size = pd->tx_sram_size;
-			mp->tx_sram_addr = pd->tx_sram_addr;
-		}
+	if (is_valid_ether_addr(pd->mac_addr))
+		memcpy(dev->dev_addr, pd->mac_addr, 6);
 
-		if (pd->rx_sram_size) {
-			mp->rx_sram_size = pd->rx_sram_size;
-			mp->rx_sram_addr = pd->rx_sram_addr;
-		}
+	if (pd->phy_addr || pd->force_phy_addr)
+		ethernet_phy_set(port_num, pd->phy_addr);
+
+	if (pd->rx_queue_size)
+		mp->rx_ring_size = pd->rx_queue_size;
+
+	if (pd->tx_queue_size)
+		mp->tx_ring_size = pd->tx_queue_size;
+
+	if (pd->tx_sram_size) {
+		mp->tx_sram_size = pd->tx_sram_size;
+		mp->tx_sram_addr = pd->tx_sram_addr;
+	}
 
-		duplex = pd->duplex;
-		speed = pd->speed;
+	if (pd->rx_sram_size) {
+		mp->rx_sram_size = pd->rx_sram_size;
+		mp->rx_sram_addr = pd->rx_sram_addr;
 	}
 
+	duplex = pd->duplex;
+	speed = pd->speed;
+
+	mp->port_num = port_num;
+
 	/* Hook up MII support for ethtool */
 	mp->mii.dev = dev;
 	mp->mii.mdio_read = mv643xx_mdio_read;
Index: b/include/linux/mv643xx.h
===================================================================
--- a/include/linux/mv643xx.h
+++ b/include/linux/mv643xx.h
@@ -1289,6 +1289,7 @@ struct mv64xxx_i2c_pdata {
 #define MV643XX_ETH_NAME	"mv643xx_eth"
 
 struct mv643xx_eth_platform_data {
+	int		port_number;
 	u16		force_phy_addr;	/* force override if phy_addr == 0 */
 	u16		phy_addr;
 

From thomas.koeller@baslerweb.com Thu Mar  1 23:54:02 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 01 Mar 2007 23:54:08 +0000 (GMT)
Received: from mail04.hansenet.de ([213.191.73.12]:38353 "EHLO
	webmail.hansenet.de") by ftp.linux-mips.org with ESMTP
	id S20039480AbXCAXyC (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 1 Mar 2007 23:54:02 +0000
Received: from [80.171.15.212] (80.171.15.212) by webmail.hansenet.de (7.2.074) (authenticated as mbx20228207@koeller-hh.org)
        id 45CB2EBD00923740; Fri, 2 Mar 2007 00:50:09 +0100
Received: from localhost.koeller.dyndns.org (localhost.koeller.dyndns.org [127.0.0.1])
	by mail.koeller.dyndns.org (Postfix) with ESMTP id 187ED479E4;
	Fri,  2 Mar 2007 00:50:08 +0100 (CET)
From:	Thomas Koeller <thomas.koeller@baslerweb.com>
Date:	Fri, 2 Mar 2007 00:50:07 +0100
Subject: [PATCH] excite: Add image capturing driver
X-Length: 51609
X-UID:	11
To:	ralf@linux-mips.org
Cc:	linux-mips@linux-mips.org
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Message-Id: <200703020050.07717.thomas.koeller@baslerweb.com>
Return-Path: <thomas.koeller@baslerweb.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14305
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: thomas.koeller@baslerweb.com
Precedence: bulk
X-list: linux-mips

This is the excite's image capturing driver. As it does not fit in
any of the existing driver categories and is truly platform specific
(what good is a camera that cannot capture images?), it is included
in the platform.

Signed-off-by: Thomas Koeller <thomas.koeller@baslerweb.com>
---
 arch/mips/Kconfig                    |   11 +-
 arch/mips/basler/excite/Kconfig      |   29 +
 arch/mips/basler/excite/Makefile     |    3 +
 arch/mips/basler/excite/xicap.h      |   40 ++
 arch/mips/basler/excite/xicap_core.c |  472 ++++++++++++++
 arch/mips/basler/excite/xicap_gpi.c  | 1184 
++++++++++++++++++++++++++++++++++
 arch/mips/basler/excite/xicap_priv.h |   48 ++
 7 files changed, 1777 insertions(+), 10 deletions(-)
 create mode 100644 arch/mips/basler/excite/Kconfig
 create mode 100644 arch/mips/basler/excite/xicap.h
 create mode 100644 arch/mips/basler/excite/xicap_core.c
 create mode 100644 arch/mips/basler/excite/xicap_gpi.c
 create mode 100644 arch/mips/basler/excite/xicap_priv.h

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 3315a71..498b0b8 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -145,20 +145,11 @@ config BASLER_EXCITE
 	select SYS_SUPPORTS_64BIT_KERNEL
 	select SYS_SUPPORTS_BIG_ENDIAN
 	select SYS_SUPPORTS_KGDB
+	source "arch/mips/basler/excite/Kconfig"
 	help
 	  The eXcite is a smart camera platform manufactured by
 	  Basler Vision Technologies AG.
 
-config BASLER_EXCITE_PROTOTYPE
-	bool "Support for pre-release units"
-	depends on BASLER_EXCITE
-	default n
-	help
-	  Pre-series (prototype) units are different from later ones in
-	  some ways. Select this option if you have one of these. Please
-	  note that a kernel built with this option selected will not be
-	  able to run on normal units.
-
 config MIPS_COBALT
 	bool "Cobalt Server"
 	select DMA_NONCOHERENT
diff --git a/arch/mips/basler/excite/Kconfig b/arch/mips/basler/excite/Kconfig
new file mode 100644
index 0000000..3270815
--- /dev/null
+++ b/arch/mips/basler/excite/Kconfig
@@ -0,0 +1,29 @@
+config BASLER_EXCITE_PROTOTYPE
+	bool "Support for pre-release units"
+	depends on BASLER_EXCITE
+	default n
+	help
+	  Pre-series (prototype) units are different from later ones in
+	  some ways. Select this option if you have one of these. Please
+	  note that a kernel built with this option selected will not be
+	  able to run on normal units.
+
+config BASLER_EXCITE_XICAP
+	tristate "Image capturing driver"
+	depends on BASLER_EXCITE
+	default m
+	help
+	  Enable basic platform-specific support for frame capture devices.
+	  You do not want to disable this, because that would give you a
+	  camera incapable of capturing images, which is kind of pointless.
+	  This can also be compiled as a module, which will be named
+	  xicap_core.
+
+config BASLER_EXCITE_XICAP_GPI
+	tristate "Image capturing via GPI"
+	depends on BASLER_EXCITE_XICAP && GPI_RM9000
+	default m
+	help
+	  Image capturing driver for the GPI hardware found on RM9xxx
+	  chips manufactured by PMC-Sierra.
+
diff --git a/arch/mips/basler/excite/Makefile 
b/arch/mips/basler/excite/Makefile
index 519142c..1dd26a4 100644
--- a/arch/mips/basler/excite/Makefile
+++ b/arch/mips/basler/excite/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_BASLER_EXCITE)	+= excite_irq.o excite_prom.o 
excite_setup.o \
 
 obj-$(CONFIG_KGDB)		+= excite_dbg_io.o
 obj-m				+= excite_iodev.o
+
+obj-$(CONFIG_BASLER_EXCITE_XICAP)	+= xicap_core.o
+obj-$(CONFIG_BASLER_EXCITE_XICAP_GPI)	+= xicap_gpi.o
diff --git a/arch/mips/basler/excite/xicap.h b/arch/mips/basler/excite/xicap.h
new file mode 100644
index 0000000..6614bc4
--- /dev/null
+++ b/arch/mips/basler/excite/xicap.h
@@ -0,0 +1,40 @@
+#if ! defined(XICAP_H)
+#define XICAP_H
+
+#include <linux/ioctl.h>
+
+/* A buffer descriptor. */
+typedef struct {
+	void	*data;			/* data buffer */
+	size_t	size;			/* data buffer size */
+	void	*ctxt;			/* user-defined context pointer */
+} xicap_arg_qbuf_t;
+
+
+/*
+ * Result block passed back to user after operation completed.
+ * Todo: add time stamp field.
+ */
+typedef struct {
+	void		*data;		/* data buffer pointer */
+	void		*ctxt;		/* user context */
+	int		status;		/* buffer status, see below */
+} xicap_result_t;
+
+/* Returned buffer status values */
+#define XICAP_BUFSTAT_OK	0	/* normal return */
+#define XICAP_BUFSTAT_ABORTED	1	/* aborted by flush */
+#define XICAP_BUFSTAT_VMERR	2	/* buffer mapping error */
+
+
+
+/* Definitions for ioctl() */
+#define	XICAP_IOC_TYPE		0xbb	/* a random choice */
+
+/* Ready to grab next frame */
+#define XICAP_IOC_QBUF		_IOW(XICAP_IOC_TYPE, 0, xicap_arg_qbuf_t)
+#define XICAP_IOC_FLUSH		_IO(XICAP_IOC_TYPE, 1)
+
+#define XICAP_IOC_MAXNR		1
+
+#endif	/* ! defined(XICAP_H) */
diff --git a/arch/mips/basler/excite/xicap_core.c 
b/arch/mips/basler/excite/xicap_core.c
new file mode 100644
index 0000000..281a99c
--- /dev/null
+++ b/arch/mips/basler/excite/xicap_core.c
@@ -0,0 +1,472 @@
+/*
+ *  Copyright (C) 2004...2007 by Basler Vision Technologies AG
+ *  Author: Thomas Koeller <thomas.koeller@baslerweb.com>
+ *
+ *  This file contains basic support for image capturing on the
+ *  Basler eXcite intelligent camera platform, to be used by a
+ *  hardware-specific capturing driver.
+ */
+
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <asm/bitops.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+
+#include "xicap.h"
+#include "xicap_priv.h"
+
+
+
+/* Get device context from inode */
+#define cxi(__i__) container_of((__i__)->i_cdev, xicap_device_context_t, 
chardev)
+
+/* Get device context from file */
+#define cxf(__f__) ((xicap_device_context_t *) (__f__)->private_data)
+
+
+
+/* String constants */
+static const char xicap_name[] = "xicap";
+
+
+
+/* Data used for device number allocation */
+static dev_t devnum_base;
+static DECLARE_MUTEX(devnum_lock);
+static unsigned long devnum_bitmap = 0;
+
+#define MAX_DEVICES	(sizeof devnum_bitmap * 8)
+
+
+
+/* Function prototypes */
+static void xicap_device_release(struct class_device *);
+static long xicap_ioctl(struct file *, unsigned int, unsigned long);
+static unsigned int xicap_poll(struct file *, poll_table *);
+static ssize_t xicap_read(struct file *, char __user *, size_t, loff_t *);
+static int xicap_open(struct inode *, struct file *);
+static int xicap_release(struct inode *, struct file *);
+static int xicap_queue_buffer(xicap_device_context_t *,
+			      const xicap_arg_qbuf_t *);
+
+
+
+/* A class for xicap devices */
+static struct class xicap_class = {
+	.name		= (char *) xicap_name,
+	.release	= xicap_device_release,
+	.class_release	= NULL
+};
+
+
+
+/* The file operations vector */
+static struct file_operations xicap_fops = {
+	.unlocked_ioctl	= xicap_ioctl,
+	.read		= xicap_read,
+	.open		= xicap_open,
+	.release	= xicap_release,
+	.poll		= xicap_poll
+};
+
+
+
+struct xicap_devctxt {
+	struct class_device		classdev;
+	struct cdev			chardev;
+	const xicap_hw_driver_t *	hwdrv;
+	dev_t				devnum;
+	spinlock_t			compl_lock;
+	struct list_head		compl_queue;
+	atomic_t			opencnt;
+	wait_queue_head_t		wq;
+};
+
+
+
+/* A context for every class device */
+struct xicap_clsdev_ctxt {
+	xicap_hw_driver_t *	hwdrv;
+};
+
+
+
+/* Check for completed buffers */
+static inline int xicap_check_completed(xicap_device_context_t *dc)
+{
+	int r;
+	spin_lock(&dc->compl_lock);
+	r = !list_empty(&dc->compl_queue);
+	spin_unlock(&dc->compl_lock);
+	return r;
+}
+
+
+
+/* Retreive a completed buffer from the queue */
+static inline xicap_data_buffer_t *
+xicap_retreive_completed(xicap_device_context_t *dc)
+{
+	xicap_data_buffer_t * p;
+	spin_lock(&dc->compl_lock);
+	p = list_empty(&dc->compl_queue) ?
+		NULL : list_entry(dc->compl_queue.next, xicap_data_buffer_t,
+				  link);
+	if (p)
+		list_del(&p->link);
+	spin_unlock(&dc->compl_lock);
+	return p;
+}
+
+
+
+
+static long xicap_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+	int res = -ENOTTY;
+	union {
+		xicap_arg_qbuf_t qbuf;
+	} a;
+
+
+	if (unlikely(_IOC_TYPE(cmd) != XICAP_IOC_TYPE))
+		return -ENOTTY;
+
+	if ((_IOC_DIR(cmd) & _IOC_READ)
+	    && !access_ok(VERIFY_WRITE, arg, _IOC_SIZE(cmd)))
+		return -EFAULT;
+
+	if ((_IOC_DIR(cmd) & _IOC_WRITE)
+	    && !access_ok(VERIFY_READ, arg, _IOC_SIZE(cmd)))
+		return -EFAULT;
+
+	switch (cmd) {
+		case XICAP_IOC_QBUF:
+			if (_IOC_SIZE(XICAP_IOC_QBUF) != sizeof a.qbuf) {
+				res = -EINVAL;
+				break;
+			}
+			res = __copy_from_user(&a.qbuf, (void *) arg,
+					       sizeof a.qbuf) ?
+				-EINVAL : xicap_queue_buffer(cxf(f), &a.qbuf);
+			break;
+
+		case XICAP_IOC_FLUSH:
+			{
+				xicap_device_context_t * const dc = cxf(f);
+				res = dc->hwdrv->flush ?
+				      dc->hwdrv->flush(dc->classdev.dev) :
+				      -ENOTTY;
+			}
+			break;
+	}
+
+	return res;
+}
+
+
+
+static unsigned int xicap_poll(struct file *f, poll_table *tbl)
+{
+	xicap_device_context_t * const dc = cxf(f);
+	poll_wait(f, &dc->wq, tbl);
+	return POLLOUT | POLLWRNORM
+	       | (xicap_check_completed(dc) ? POLLIN | POLLRDNORM : 0);
+}
+
+
+
+static ssize_t xicap_read(struct file *f, char __user *buf, size_t len,
+			  loff_t *offs)
+{
+	int res;
+	xicap_device_context_t * const dc = cxf(f);
+	xicap_data_buffer_t *bd;
+	xicap_result_t dat;
+
+	if (unlikely(len != sizeof dat))
+		return -EINVAL;
+
+	if (unlikely(!access_ok(VERIFY_WRITE, buf, len)))
+		return -EFAULT;
+
+	if (f->f_flags & O_NONBLOCK) {
+		/* If nonblocking and no completed ops, return error status */
+		if (bd = xicap_retreive_completed(dc), !bd)
+			return -EAGAIN;
+	} else {
+		res = wait_event_interruptible(
+			dc->wq,
+			(bd = xicap_retreive_completed(dc), bd));
+		if (res)
+			return res;
+	}
+
+	if (dc->hwdrv->finish_buffer) {
+		const int i = dc->hwdrv->finish_buffer(dc->classdev.dev,
+						       bd->frmctxt);
+		if (i) {
+			kfree(bd);
+			return i;
+		}
+	}
+
+	dat.data = bd->uaddr;
+	dat.ctxt = bd->uctxt;
+	dat.status = bd->status;
+	__copy_to_user(buf, &dat, sizeof dat);
+	kfree(bd);
+
+	return sizeof dat;
+}
+
+
+
+static int xicap_open(struct inode *i, struct file *f)
+{
+	xicap_device_context_t * const dc = cxi(i);
+
+	/* Only one opener allowed */
+	if (atomic_dec_if_positive(&dc->opencnt) < 0)
+		return -EBUSY;
+
+	spin_lock_init(&dc->compl_lock);
+	INIT_LIST_HEAD(&dc->compl_queue);
+	init_waitqueue_head(&dc->wq);
+	f->private_data = cxi(i);
+	return dc->hwdrv->start(dc->classdev.dev);
+}
+
+
+
+static int xicap_release(struct inode *i, struct file *f)
+{
+	xicap_device_context_t * const dc = cxi(i);
+	dc->hwdrv->stop(dc->classdev.dev);
+
+	while (xicap_check_completed(dc))
+		kfree(xicap_retreive_completed(dc));
+
+	atomic_set(&dc->opencnt, 1);
+	return 0;
+}
+
+
+
+/* Device registration */
+xicap_device_context_t *
+xicap_device_register(struct device *dev, const xicap_hw_driver_t *hwdrv)
+{
+	int res = 0, devi = -1;
+
+	/* Set up a device context */
+	xicap_device_context_t * const dc =
+		(xicap_device_context_t *) kmalloc(sizeof *dc, GFP_KERNEL);
+	if (!dc) {
+		res = -ENOMEM;
+		goto ex;
+	}
+
+	memset(dc, 0, sizeof *dc);
+	cdev_init(&dc->chardev, &xicap_fops);
+	dc->chardev.owner = THIS_MODULE;
+	dc->classdev.dev = get_device(dev);
+	dc->hwdrv = hwdrv;
+	atomic_set(&dc->opencnt, 1);
+
+	/* Allocate a device number */
+	down(&devnum_lock);
+	if (unlikely(devnum_bitmap == ~0x0)) {
+		up(&devnum_lock);
+		res = -ENODEV;
+		goto ex;
+	}
+	devi = ffz(devnum_bitmap);
+	devnum_bitmap |= 0x1 << devi;
+	up(&devnum_lock);
+
+	/* Register the class device with its class */
+	dc->classdev.class = &xicap_class;
+	dc->classdev.devt = devi + devnum_base;
+	res = snprintf(dc->classdev.class_id, sizeof dc->classdev.class_id,
+		       "%s%u", xicap_name, devi)
+		< sizeof dc->classdev.class_id ? 0 : -ENAMETOOLONG;
+	if (!res)
+		res = class_device_register(&dc->classdev);
+	if (unlikely(res)) {
+		dc->classdev.class = NULL;
+		goto ex;
+	}
+
+	/* Register the character device */
+	res = cdev_add(&dc->chardev, devi + devnum_base, 1);
+
+ex:
+	if (res) {
+		if (dc->classdev.class)
+			class_device_unregister(&dc->classdev);
+		if (devi >= 0) {
+			down(&devnum_lock);
+			devnum_bitmap &= ~(0x1 << devi);
+			up(&devnum_lock);
+		}
+		if (dc) {
+			put_device(dc->classdev.dev);
+			kfree(dc);
+		}
+	} else {
+		dc->devnum = devi + devnum_base;
+	}
+
+	return res ? (xicap_device_context_t *) ERR_PTR(res) : dc;
+}
+
+
+
+/* Device unregistration */
+void xicap_device_unregister(xicap_device_context_t *dc)
+{
+	cdev_del(&dc->chardev);
+	class_device_unregister(&dc->classdev);
+	down(&devnum_lock);
+	devnum_base &= ~(0x1 << (dc->devnum - devnum_base));
+	up(&devnum_lock);
+}
+
+
+
+void xicap_frame_done(xicap_device_context_t *dc, xicap_data_buffer_t *bd)
+{
+	struct page **p;
+
+	for (p = bd->pages; p < bd->pages + bd->npages; p++)
+		page_cache_release(*p);
+
+	spin_lock(&dc->compl_lock);
+	list_add_tail(&bd->link, &dc->compl_queue);
+	spin_unlock(&dc->compl_lock);
+	wake_up_interruptible(&dc->wq);
+}
+
+
+
+static void xicap_device_release(struct class_device *cldev)
+{
+	xicap_device_context_t * const dc =
+		container_of(cldev, xicap_device_context_t, classdev);
+	put_device(dc->classdev.dev);
+	kfree(dc);
+}
+
+
+
+static int xicap_queue_buffer(xicap_device_context_t *dc,
+			      const xicap_arg_qbuf_t *arg)
+{
+	int res, npages;
+	xicap_data_buffer_t *bufdesc;
+
+	/* Check for buffer write permissions */
+	if (!access_ok(VERIFY_WRITE, arg->data, arg->size))
+		return -EFAULT;
+
+	npages = (PAGE_ALIGN((unsigned long ) arg->data + arg->size)
+		 - ((unsigned long ) arg->data & PAGE_MASK)) >> PAGE_SHIFT;
+
+	bufdesc = (xicap_data_buffer_t *)
+		kmalloc(sizeof *bufdesc + sizeof (struct page *) * npages,
+			GFP_KERNEL);
+	if (!bufdesc)
+		return -ENOMEM;
+
+	bufdesc->uctxt = arg->ctxt;
+	bufdesc->uaddr = arg->data;
+	bufdesc->size = arg->size;
+	bufdesc->npages = npages;
+
+	/* Get hold of the data buffer pages */
+	res = get_user_pages(current, current->mm, (unsigned long) arg->data,
+			     npages, 1, 0, bufdesc->pages, NULL);
+	if (res < 0) {
+		kfree(bufdesc);
+		return res;
+	}
+
+	bufdesc->frmctxt = dc->hwdrv->do_buffer(dc->classdev.dev, bufdesc);
+	if (IS_ERR(bufdesc->frmctxt))  {
+		int i;
+
+		for (i = 0; i < npages; i++)
+			put_page(bufdesc->pages[i]);
+		i = PTR_ERR(bufdesc->frmctxt);
+		kfree(bufdesc);
+		return i;
+	}
+
+	return 0;
+}
+
+
+
+static int __init xicap_init_module(void)
+{
+	int res;
+	static __initdata char
+		errfmt[] = KERN_ERR "%s: %s failed - error = %d\n",
+		clsreg[] = "class registration",
+		devalc[] = "device number allocation";
+
+	/* Register the xicap class */
+	res = class_register(&xicap_class);
+	if (unlikely(res)) {
+		printk(errfmt, xicap_class.name, clsreg, res);
+		return res;
+	}
+
+	/* Allocate a range of device numbers */
+	res = alloc_chrdev_region(&devnum_base, 0, MAX_DEVICES, xicap_name);
+	if (unlikely(res)) {
+		printk(errfmt, xicap_name, devalc, res);
+		class_unregister(&xicap_class);
+		return res;
+	}
+
+	return 0;
+}
+
+
+
+static void __exit xicap_cleanup_module(void)
+{
+	unregister_chrdev_region(devnum_base, MAX_DEVICES);
+	class_unregister(&xicap_class);
+}
+
+
+
+EXPORT_SYMBOL(xicap_device_register);
+EXPORT_SYMBOL(xicap_device_unregister);
+EXPORT_SYMBOL(xicap_frame_done);
+module_init(xicap_init_module);
+module_exit(xicap_cleanup_module);
+
+
+
+MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>");
+MODULE_DESCRIPTION("Basler eXcite frame capturing core driver");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/arch/mips/basler/excite/xicap_gpi.c 
b/arch/mips/basler/excite/xicap_gpi.c
new file mode 100644
index 0000000..29ac093
--- /dev/null
+++ b/arch/mips/basler/excite/xicap_gpi.c
@@ -0,0 +1,1184 @@
+/*
+ *  Copyright (C) 2004...2007 by Basler Vision Technologies AG
+ *  Author: Thomas Koeller <thomas.koeller@baslerweb.com>
+ *
+ *  This driver uses one of the GPI channels present on the
+ *  eXcite's RM9122 SoC to implement image data capturing.
+ */
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/moduleparam.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <asm/rm9k-ocd.h>
+#include <asm/page.h>
+#include <asm/semaphore.h>
+
+#include <rm9k_xicap.h>
+
+#include "xicap_priv.h"
+
+
+/* Module arguments */
+unsigned int min_packet_size = (32 * L1_CACHE_BYTES);
+module_param(min_packet_size, uint, 0644);
+
+
+
+/*
+ * Using vmap() to map the buffer led to problems that still
+ * have to be investigated. For now, use a workaround.
+ */
+#define VMAP_WORKAROUND			1
+
+
+
+#define PAGES_PER_FULL_PACKET		7
+#define MAX_PAGES_PER_PACKET		(PAGES_PER_FULL_PACKET + 1)
+#define FULL_PACKET_SIZE		(PAGE_SIZE * PAGES_PER_FULL_PACKET)
+#define ABSOLUTE_MIN_PACKET_SIZE	5
+#define MAX_PACKET_SIZE			32767
+#define DUMMY_PACKET_SIZE		min_packet_size
+
+
+
+/* DMA decriptor-related definitions */
+#define XDMA_RING_SIZE_CODE		3
+#define XDMA_DESC_RING_SIZE		(512 >> XDMA_RING_SIZE_CODE)
+#define XDMA_ENABLE_REGVAL		\
+	(0x80000000 | (XDMA_RING_SIZE_CODE << 16) | (3 << 5))
+
+
+/*
+ * I/O register access macros
+ * Do not use __raw_writeq() and __raw_readq(), these do not seem to work!
+ */
+#define io_writeq(__v__, __a__)	\
+	*(volatile unsigned long long *) (__a__) = (__v__)
+#define io_readq(__a__)		(*(volatile unsigned long long *) (__a__))
+#define io_readl(__a__)		__raw_readl((__a__))
+#define io_writel(__v__, __a__)	__raw_writel((__v__), (__a__))
+#define io_readb(__a__)		__raw_readb((__a__))
+#define io_writeb(__v__, __a__)	__raw_writeb((__v__), (__a__))
+
+
+
+typedef struct __pkt		packet_t;
+typedef struct __gpi_devctxt	xicap_gpi_device_context_t;
+
+
+/* Function prototypes */
+static int __init xicap_gpi_probe(struct device *);
+static int __exit xicap_gpi_remove(struct device *);
+static int xicap_gpi_start(struct device *);
+static void xicap_gpi_stop(struct device *);
+static int xicap_gpi_flush(struct device *);
+static xicap_frame_context_t * xicap_gpi_do_buffer(struct device *, 
xicap_data_buffer_t *);
+#if VMAP_WORKAROUND
+static int xicap_gpi_finish_buffer(struct device *, xicap_frame_context_t *);
+#endif
+static void xicap_gpi_run_pkt_queue(xicap_gpi_device_context_t *);
+static void xicap_gpi_start_data(xicap_gpi_device_context_t *);
+static void xicap_gpi_stop_data(xicap_gpi_device_context_t *);
+static void xicap_gpi_pkt_finish(struct work_struct *);
+static void xicap_gpi_flush_queue(struct list_head *, unsigned int);
+static irqreturn_t xicap_gpi_int_handler(int, void *);
+
+
+
+/* A common name for various objects */
+static const char xicap_gpi_name[] = "xicap_gpi";
+
+
+
+/* The driver struct */
+static struct device_driver xicap_gpi_driver = {
+	.name		= (char *) xicap_gpi_name,
+	.bus		= &platform_bus_type,
+	.owner		= THIS_MODULE,
+	.probe		= xicap_gpi_probe,
+	.remove		= __exit_p(xicap_gpi_remove),
+	.shutdown	= NULL,
+	.suspend	= NULL,
+	.resume		= NULL
+};
+
+
+
+static const xicap_hw_driver_t xicap_gpi_hwdrv = {
+	.start		= xicap_gpi_start,
+	.stop		= xicap_gpi_stop,
+	.do_buffer	= xicap_gpi_do_buffer,
+#if VMAP_WORKAROUND
+	.finish_buffer	= xicap_gpi_finish_buffer,
+#else
+	.finish_buffer	= NULL,
+#endif
+	.flush		= xicap_gpi_flush
+};
+
+
+
+/* A work queue for cleting packets */
+struct workqueue_struct *wq;
+
+
+
+/* A DMA buffer used to work around the RM9K GPI silicon bug */
+unsigned long dummy_dma_buffer;
+
+
+
+/* XDMA read descriptor */
+typedef struct {
+	u64	cpu_part;
+	u64	xdma_part;
+} xdmadesc_t;
+
+
+
+/* A context struct for every device */
+struct __gpi_devctxt {
+	struct semaphore		lock;
+	unsigned int			slice;
+	unsigned int			irq;
+	unsigned int			fifomem_start;
+	unsigned int			fifomem_size;
+
+	void __iomem *			regaddr_fifo_rx;
+	void __iomem *			regaddr_fifo_tx;
+	void __iomem *			regaddr_xdma;
+	void __iomem *			regaddr_pktproc;
+	void __iomem *			regaddr_fpga;
+	void __iomem *			dmadesc;
+
+	dma_addr_t			dmadesc_p;
+	atomic_t			desc_cnt;
+
+	struct list_head		frm_queue;
+	unsigned int			frm_cnt;
+	unsigned int			frm_ready_cnt;
+
+	/* Core driver context pointer */
+	xicap_device_context_t *	devctxt;
+
+	/*
+	 * The interrupt queue, where packes are queued for
+	 * processing at interrupt level.
+	 */
+	spinlock_t			int_queue_lock;
+	struct list_head		int_queue;
+	unsigned int			int_errflg;
+
+
+	/* The packet queue & related stuff */
+	struct list_head		pkt_queue;
+	unsigned int			pkt_page_i;
+
+
+	void __iomem *			curdesc;
+};
+
+
+
+struct __pkt {
+	union {
+		struct list_head	link;
+		struct work_struct	wrk;
+	}			link;
+	dma_addr_t		pgaddr[MAX_PAGES_PER_PACKET];
+	xicap_frame_context_t *	fctxt;
+	volatile const u64 *	desc2;
+	u16			copy_size;
+	u16			mapped_size;
+	u16			remain_size;
+	void *			copy_src;
+	struct page **		copy_pg;
+	unsigned int		copy_offs;
+	struct page **		page;
+	unsigned int 		ndirty;
+};
+
+
+
+#define PKTFLG_FIFO_OVERFLOW	0x01
+#define PKTFLG_DATA_ERROR	0x02
+#define PKTFLG_XDMA_ERROR	0x04
+#define PKTFLG_DESC_UNDERRUN	0x08
+
+
+
+
+struct xicap_frmctxt {
+	struct list_head		link;
+	struct device *			dev;
+	unsigned int			flags;
+	xicap_gpi_device_context_t *	dc;
+	int				status;
+	u16				fpga_data[5];
+	xicap_data_buffer_t *		buf;
+	atomic_t			npkts;
+	unsigned int 			total_pkts;
+	packet_t			pkts[0];
+};
+
+
+
+static inline xicap_data_buffer_t * xicap_gpi_delete_packet(packet_t *pkt)
+{
+	xicap_frame_context_t * const fctxt = pkt->fctxt;
+	xicap_data_buffer_t * res = NULL;
+
+	if (!atomic_dec_return(&fctxt->npkts)) {
+		res = fctxt->buf;
+		res->status = fctxt->status;
+#if !VMAP_WORKAROUND
+		kfree(fctxt);
+#endif
+	}
+
+	return res;
+}
+
+
+
+static inline const struct resource *
+xicap_gpi_get_resource(struct platform_device *d, unsigned long flags,
+		 const char *basename)
+{
+	const char fmt[] = "%s_%u";
+	char buf[80];
+
+	if (unlikely(snprintf(buf, sizeof buf, fmt, basename, d->id) >= sizeof buf))
+		return NULL;
+	return platform_get_resource_byname(d, flags, buf);
+}
+
+
+
+static inline void __iomem *
+xicap_gpi_map_regs(struct platform_device *d, const char *basename)
+{
+	void * result = NULL;
+	const struct resource * const r =
+		xicap_gpi_get_resource(d, IORESOURCE_MEM, basename);
+	if (likely(r))
+		result = ioremap_nocache(r->start, r->end + 1 - r->start);
+	return result;
+}
+
+
+
+/* No hotplugging on the platform bus - use __init */
+static int __init xicap_gpi_probe(struct device *dev)
+{
+	int res;
+	xicap_gpi_device_context_t *dc = NULL;
+	struct platform_device * pdv;
+	const struct resource * rsrc;
+
+	static char __initdata
+		rsrcname_gpi_slice[] = XICAP_RESOURCE_GPI_SLICE,
+		rsrcname_fifo_blk[] = XICAP_RESOURCE_FIFO_BLK,
+		rsrcname_irq[] = XICAP_RESOURCE_IRQ,
+		rsrcname_dmadesc[] = XICAP_RESOURCE_DMADESC,
+		rsrcname_fifo_rx[] = XICAP_RESOURCE_FIFO_RX,
+		rsrcname_fifo_tx[] = XICAP_RESOURCE_FIFO_TX,
+		rsrcname_xdma[] = XICAP_RESOURCE_XDMA,
+		rsrcname_pktproc[] = XICAP_RESOURCE_PKTPROC,
+		rsrcname_pkt_stream[] = XICAP_RESOURCE_PKT_STREAM;
+
+	/* Get the platform device. */
+	if (unlikely(dev->bus != &platform_bus_type)) {
+		res = -ENODEV;
+		goto errex;
+	}
+
+	pdv = to_platform_device(dev);
+
+	/* Create and set up the device context */
+	dc = (xicap_gpi_device_context_t *)
+	      kmalloc(sizeof (xicap_gpi_device_context_t), GFP_KERNEL);
+	if (!dc) {
+		res = -ENOMEM;
+		goto errex;
+	}
+	memset(dc, 0, sizeof *dc);
+	init_MUTEX(&dc->lock);
+
+	/* Evaluate resources */
+	res = -ENXIO;
+
+	rsrc = xicap_gpi_get_resource(pdv, 0, rsrcname_gpi_slice);
+	if (unlikely(!rsrc)) goto errex;
+	dc->slice = rsrc->start;
+
+	rsrc = xicap_gpi_get_resource(pdv, 0, rsrcname_fifo_blk);
+	if (unlikely(!rsrc)) goto errex;
+	dc->fifomem_start = rsrc->start;
+	dc->fifomem_size = rsrc->end + 1 - rsrc->start;
+
+	rsrc = xicap_gpi_get_resource(pdv, IORESOURCE_IRQ, rsrcname_irq);
+	if (unlikely(!rsrc)) goto errex;
+	dc->irq = rsrc->start;
+
+	rsrc = xicap_gpi_get_resource(pdv, IORESOURCE_MEM, rsrcname_dmadesc);
+	if (unlikely(!rsrc)) goto errex;
+	if (unlikely((rsrc->end + 1 - rsrc->start)
+	             < (XDMA_DESC_RING_SIZE * sizeof (xdmadesc_t))))
+		goto errex;
+	dc->dmadesc_p = (dma_addr_t) rsrc->start;
+	dc->dmadesc = ioremap_nocache(rsrc->start, rsrc->end + 1 - rsrc->start);
+
+	dc->regaddr_fifo_rx = xicap_gpi_map_regs(pdv, rsrcname_fifo_rx);
+	dc->regaddr_fifo_tx = xicap_gpi_map_regs(pdv, rsrcname_fifo_tx);
+	dc->regaddr_xdma = xicap_gpi_map_regs(pdv, rsrcname_xdma);
+	dc->regaddr_pktproc = xicap_gpi_map_regs(pdv, rsrcname_pktproc);
+	dc->regaddr_fpga = xicap_gpi_map_regs(pdv, rsrcname_pkt_stream);
+
+	if (unlikely(!dc->regaddr_fifo_rx || !dc->regaddr_fifo_tx
+	    || !dc->regaddr_xdma || !dc->regaddr_pktproc || !dc->regaddr_fpga
+	    || !dc->dmadesc))
+		goto errex;
+
+	/* Register the device with the core */
+	dc->devctxt = xicap_device_register(dev, &xicap_gpi_hwdrv);
+	res = IS_ERR(dc->devctxt) ? PTR_ERR(dc->devctxt) : 0;
+
+errex:
+	if (res) {
+		if (dc->regaddr_fifo_rx) iounmap(dc->regaddr_fifo_rx);
+		if (dc->regaddr_fifo_tx) iounmap(dc->regaddr_fifo_tx);
+		if (dc->regaddr_xdma) iounmap(dc->regaddr_xdma);
+		if (dc->regaddr_pktproc) iounmap(dc->regaddr_pktproc);
+		if (dc->regaddr_fpga) iounmap(dc->regaddr_fpga);
+		if (dc->dmadesc) iounmap(dc->dmadesc);
+		if (dc) kfree(dc);
+		dev_dbg("%s: %s failed, error = %d\n", xicap_gpi_name,
+			__func__, res);
+	} else {
+		dev->driver_data = dc;
+		dev_dbg("%s: Context at %p\n", xicap_gpi_name, dc);
+	}
+
+	return res;
+}
+
+
+
+static int __exit xicap_gpi_remove(struct device *dev)
+{
+	xicap_gpi_device_context_t * const dc =
+		(xicap_gpi_device_context_t *) dev->driver_data;
+
+	xicap_device_unregister(dc->devctxt);
+	kfree(dc);
+	dev->driver_data = NULL;
+	return 0;
+}
+
+
+
+static int xicap_gpi_start(struct device *dev)
+{
+	xicap_gpi_device_context_t * const dc =
+		(xicap_gpi_device_context_t *) dev->driver_data;
+	u32 reg;
+	int res;
+
+	/* Lock the device context */
+	down(&dc->lock);
+
+	/* Device context initialization */
+	INIT_LIST_HEAD(&dc->pkt_queue);
+	INIT_LIST_HEAD(&dc->frm_queue);
+	INIT_LIST_HEAD(&dc->int_queue);
+	spin_lock_init(&dc->int_queue_lock);
+	dc->int_errflg = 0;
+
+	lock_titan_regs();
+
+	/* Disable the slice status interrupts */
+	reg = titan_readl(0x0050) & ~(0x1f << (dc->slice * 5));
+	titan_writel(reg, 0x0050);
+
+	/* Disable the XDMA interrupts for this slice */
+	reg = titan_readl(0x0058) & ~(0xff << (dc->slice * 8));
+	titan_writel(reg, 0x0058);
+
+	unlock_titan_regs();
+
+	xicap_gpi_start_data(dc);
+
+	res = request_irq(dc->irq, xicap_gpi_int_handler,
+			  SA_SHIRQ, xicap_gpi_name, dc);
+	if (unlikely(res))
+		return res;
+
+	lock_titan_regs();
+
+	/* Enable the slice status interrupts */
+	reg = titan_readl(0x0050) | (0x2 << (dc->slice * 5));
+	titan_writel(reg, 0x0050);
+
+	/* Enable the XDMA data interrupt */
+	reg = 0xff << (dc->slice * 8);
+	titan_writel(reg, 0x0048);
+	titan_writel(reg, 0x004c);
+	reg = titan_readl(0x0058);
+	titan_writel(reg | (0x1 << (dc->slice * 8)), 0x0058);
+
+	unlock_titan_regs();
+
+	/* Release the device context and exit */
+	up(&dc->lock);
+	return 0;
+}
+
+
+
+static void xicap_gpi_start_data(xicap_gpi_device_context_t *dc)
+{
+	unsigned int i;
+
+	/* Reset all XDMA channels for this slice */
+	io_writel(0x80080000, dc->regaddr_xdma + 0x0000);
+	io_writel(0x80080000, dc->regaddr_xdma + 0x0040);
+	io_writel(0x80080000, dc->regaddr_xdma + 0x0080);
+	io_writel(0x80080000, dc->regaddr_xdma + 0x00c0);
+
+	/* Reset & enable the XDMA slice interrupts */
+	io_writel(0x80068002, dc->regaddr_xdma + 0x000c);
+	io_writel(0x00008002, dc->regaddr_xdma + 0x0010);
+
+	dc->pkt_page_i = 0;
+	dc->frm_ready_cnt = dc->frm_cnt = 0;
+
+	/* Set up the XDMA descriptor ring & enable the XDMA */
+	dc->curdesc = dc->dmadesc;
+	atomic_set(&dc->desc_cnt, XDMA_DESC_RING_SIZE);
+	io_writel(dc->dmadesc_p, dc->regaddr_xdma + 0x0018);
+	wmb();
+	memset(dc->dmadesc, 0, XDMA_DESC_RING_SIZE * sizeof (xdmadesc_t));
+	io_writel(XDMA_ENABLE_REGVAL, dc->regaddr_xdma + 0x0000);
+
+	/*
+	 * Enable the rx fifo we are going to use. Disable the
+	 * unused ones as well as the tx fifo.
+	 */
+	io_writel(0x00100000 | ((dc->fifomem_size) << 10)
+		  | dc->fifomem_start,
+		  dc->regaddr_fifo_rx + 0x0000);
+	wmb();
+	io_writel((10 << 20) | (10 << 10) | 128, dc->regaddr_fifo_rx
+		  + 0x0004);
+	io_writel(0x00100400, dc->regaddr_fifo_rx + 0x000c);
+	io_writel(0x00100400, dc->regaddr_fifo_rx + 0x0018);
+	io_writel(0x00100400, dc->regaddr_fifo_rx + 0x0024);
+	io_writel(0x00100400, dc->regaddr_fifo_tx + 0x0000);
+
+	/* Reset any pending interrupt, then enable fifo */
+	titan_writel(0xf << (dc->slice * 4), 0x482c);
+	wmb();
+	io_writel(0x00200000 | ((dc->fifomem_size) << 10)
+		  | dc->fifomem_start,
+		  dc->regaddr_fifo_rx + 0x0000);
+
+	/* Enable the packet processor */
+	io_writel(0x00000000, dc->regaddr_pktproc + 0x0000);
+	wmb();
+	io_writel(0x0000001f, dc->regaddr_pktproc + 0x0008);
+	io_writel(0x00000e08, dc->regaddr_pktproc + 0x0010);
+	io_writel(0x0000080f, dc->regaddr_pktproc + 0x0014);
+	io_writel(0x000003ff, dc->regaddr_pktproc + 0x0018);
+	io_writel(0x00000100, dc->regaddr_pktproc + 0x0038);
+	wmb();
+	io_writel(0x00000001, dc->regaddr_pktproc + 0x0000);
+
+	/* Disable address filtering */
+	io_writel(0x0, dc->regaddr_pktproc + 0x0120);
+	io_writel(0x2, dc->regaddr_pktproc + 0x0124);
+	for (i = 0; i < 8; i++) {
+		io_writel(  i, dc->regaddr_pktproc + 0x0128);
+		wmb();
+		io_writel(0x0, dc->regaddr_pktproc + 0x0100);
+		io_writel(0x0, dc->regaddr_pktproc + 0x0104);
+		io_writel(0x0, dc->regaddr_pktproc + 0x0108);
+		io_writel(0x0, dc->regaddr_pktproc + 0x010c);
+		wmb();
+	}
+
+	io_writel(0x1, dc->regaddr_pktproc + 0x012c);
+
+}
+
+
+
+static void xicap_gpi_stop_data(xicap_gpi_device_context_t *dc)
+{
+	/* Shut down the data transfer */
+	io_writeb(0x01, dc->regaddr_fpga + 0x000b);
+
+	/* Reset the XDMA channel */
+	io_writel(0x80080000, dc->regaddr_xdma + 0x0000);
+
+	/* Disable the FIFO */
+	io_writel(0x00100400, dc->regaddr_fifo_rx + 0x0000);
+
+	/* Disable the packet processor */
+	io_writel(0x00000000, dc->regaddr_pktproc + 0x0000);
+
+	dc->frm_ready_cnt = 0;
+	INIT_LIST_HEAD(&dc->frm_queue);
+}
+
+
+
+static void xicap_gpi_flush_queue(struct list_head *l, unsigned int stat)
+{
+	while (!list_empty(l)) {
+		packet_t * const pkt =
+			list_entry(l->next, packet_t, link.link);
+		xicap_gpi_device_context_t * const dc = pkt->fctxt->dc;
+		const dma_addr_t *pa = pkt->pgaddr;
+		xicap_data_buffer_t * buf;
+
+		list_del(&pkt->link.link);
+
+		while (pkt->mapped_size) {
+			size_t sz = pkt->mapped_size;
+			if (sz > PAGE_SIZE)
+				sz = PAGE_SIZE;
+			pkt->mapped_size -= sz;
+			dma_unmap_page(pkt->fctxt->dev, *pa++, sz,
+				       DMA_FROM_DEVICE);
+		}
+
+		if (pkt->copy_size) {
+			free_pages((unsigned long) pkt->copy_src,
+				   pkt->copy_size > PAGE_SIZE ? 1 : 0);
+			pkt->copy_size = 0;
+		}
+
+		buf = xicap_gpi_delete_packet(pkt);
+		if (buf) {
+			buf->status = stat;
+			xicap_frame_done(dc->devctxt, buf);
+		}
+	}
+}
+
+
+
+static void xicap_gpi_stop(struct device *dev)
+{
+	u32 reg;
+	LIST_HEAD(l);
+	xicap_gpi_device_context_t * const dc =
+		(xicap_gpi_device_context_t *) dev->driver_data;
+
+	lock_titan_regs();
+
+	/* Disable the slice status interrupts */
+	reg = titan_readl(0x0050) & ~(0x1f << (dc->slice * 5));
+	titan_writel(reg, 0x0050);
+
+	/* Disable the XDMA interrupts for this slice */
+	reg = titan_readl(0x0058) & ~(0xff << (dc->slice * 8));
+	titan_writel(reg, 0x0058);
+
+	unlock_titan_regs();
+	flush_workqueue(wq);
+	down(&dc->lock);
+	xicap_gpi_stop_data(dc);
+
+	/* Now clean up the packet & int queues */
+	spin_lock_irq(&dc->int_queue_lock);
+	list_splice_init(&dc->int_queue, &l);
+	spin_unlock_irq(&dc->int_queue_lock);
+	list_splice_init(&dc->pkt_queue, l.prev);
+	xicap_gpi_flush_queue(&l, ~0x0);
+	up(&dc->lock);
+
+	/* Detach interrupt handler */
+	free_irq(dc->irq, dc);
+}
+
+
+
+static int xicap_gpi_flush(struct device *dev)
+{
+	u32 reg;
+	xicap_gpi_device_context_t * const dc =
+		(xicap_gpi_device_context_t *) dev->driver_data;
+	LIST_HEAD(l);
+
+	lock_titan_regs();
+
+	/* Disable the slice status interrupts */
+	reg = titan_readl(0x0050) & ~(0x1f << (dc->slice * 5));
+	titan_writel(reg, 0x0050);
+
+	/* Disable the XDMA interrupts for this slice */
+	reg = titan_readl(0x0058) & ~(0xff << (dc->slice * 8));
+	titan_writel(reg, 0x0058);
+
+	unlock_titan_regs();
+
+	/* Now clean up the packet & int queues */
+	flush_workqueue(wq);
+	down(&dc->lock);
+	xicap_gpi_stop_data(dc);
+	spin_lock_irq(&dc->int_queue_lock);
+	list_splice_init(&dc->int_queue, &l);
+	spin_unlock_irq(&dc->int_queue_lock);
+	list_splice_init(&dc->pkt_queue, l.prev);
+	xicap_gpi_flush_queue(&l, XICAP_BUFSTAT_ABORTED);
+	xicap_gpi_start_data(dc);
+	up(&dc->lock);
+
+	lock_titan_regs();
+
+	/* Re-enable the slice status interrupts */
+	reg = titan_readl(0x0050) | (0x2 << (dc->slice * 5));
+	titan_writel(reg, 0x0050);
+
+	/* Re-enable the XDMA data interrupt */
+	reg = 0xff << (dc->slice * 8);
+	titan_writel(reg, 0x0048);
+	titan_writel(reg, 0x004c);
+	reg = titan_readl(0x0058);
+	wmb();
+	titan_writel(reg | (0x1 << (dc->slice * 8)), 0x0058);
+
+	unlock_titan_regs();
+
+	return 0;
+}
+
+
+
+static xicap_frame_context_t *
+xicap_gpi_do_buffer(struct device *dev, xicap_data_buffer_t *buf)
+{
+	unsigned long head_buf = 0, tail_buf = 0;
+	u16 head_size = 0, tail_size = 0, full_size = FULL_PACKET_SIZE;
+	u16 total_packets;
+	size_t sz = buf->size;
+	unsigned int full_packets = 0, head_order = 0, i, request_frame = 1;
+	const unsigned int boffs = (unsigned long) buf->uaddr & ~PAGE_MASK;
+	packet_t *pkt;
+	struct page ** pg;
+	LIST_HEAD(packets);
+	xicap_frame_context_t * fctxt;
+	xicap_gpi_device_context_t * const dc =
+		(xicap_gpi_device_context_t *) dev->driver_data;
+
+	if (unlikely(sz < ABSOLUTE_MIN_PACKET_SIZE))
+		return ERR_PTR(-EINVAL);
+
+	/*
+	 * If the buffer is not page aligned, the first part of it
+	 * (the 'head') is DMA'ed into a temporary buffer and later
+	 * copied to the user's buffer. The size of the head is chosen
+	 * so that the remaining part of the buffer is page aligned.
+	 */
+	if (boffs) {
+		head_size = PAGE_SIZE - boffs;
+		if (head_size < min_packet_size) {
+			head_size += PAGE_SIZE;
+			head_order = 1;
+		}
+		if (head_size > sz) {
+			head_size = sz;
+			head_order = (head_size > PAGE_SIZE) ? 1 : 0;
+		}
+		head_buf = __get_dma_pages(GFP_KERNEL, head_order);
+		if (!head_buf)
+			return ERR_PTR(-ENOMEM);
+
+		/* Compute the residual buffer size */
+		sz -= head_size;
+	}
+
+	/*
+	 * Now compute the number of full-sized packets, and the size
+	 * of the last ('tail') packet.
+	 */
+	if (sz) {
+		full_packets = sz / FULL_PACKET_SIZE;
+		tail_size = sz % FULL_PACKET_SIZE;
+	}
+
+	/*
+	 * If the tail packet is less than a page, it can be merged with
+	 * the previous one. This also covers the case where the size of
+	 * the tail packet is less than min_packet_size.
+	 */
+	if ((tail_size < PAGE_SIZE) && full_packets) {
+		full_packets--;
+		tail_size += FULL_PACKET_SIZE;
+	}
+
+	/*
+	 * The XDMA will pad the last packet to the next cache line
+	 * boundary, so in order to avoid writing beyond the user's
+	 * buffer, we need to use a temporary buffer if the tail packet
+	 * size is not an integer multiple of the cache line size.
+	 */
+	if (tail_size % L1_CACHE_BYTES) {
+		tail_buf = __get_dma_pages(GFP_KERNEL, 0);
+		if (unlikely(!tail_buf)) {
+			if (head_buf)
+				free_pages(head_buf, head_order);
+			return ERR_PTR(-ENOMEM);
+		}
+	}
+
+	/*
+	 * Now we know how many packets to process for the buffer, so we
+	 * can allocate a packet set. Add one extra dummy packet (silicon
+	 * bug workaround).
+	 */
+	total_packets =
+		full_packets + (head_size ? 1 : 0) + (tail_size ? 1 : 0) + 1;
+	fctxt = kmalloc(
+		sizeof (xicap_frame_context_t) + sizeof (packet_t) * total_packets,
+		GFP_KERNEL);
+	if (unlikely(!fctxt)) {
+		if (tail_buf)
+			free_pages(tail_buf, 0);
+		if (head_buf)
+			free_pages(head_buf, head_order);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	fctxt->buf = buf;
+	fctxt->dev = dev;
+	fctxt->flags = 0;
+	fctxt->status = XICAP_BUFSTAT_OK;
+	atomic_set(&fctxt->npkts, total_packets);
+	fctxt->total_pkts = total_packets;
+	pkt = &fctxt->pkts[0];
+	pg = buf->pages;
+	fctxt->dc = (xicap_gpi_device_context_t *) dev->driver_data;
+
+	/* Set up the head packet descriptor */
+	if (head_size) {
+		struct page * const p = virt_to_page((void *) head_buf);
+
+		pkt->page = pkt->copy_pg = pg;
+
+		if (head_order) {
+			pkt->pgaddr[0] = dma_map_page(dev, p, 0, PAGE_SIZE,
+						      DMA_FROM_DEVICE);
+			pkt->pgaddr[1] = dma_map_page(dev, p + 1, 0,
+						      head_size - PAGE_SIZE,
+						      DMA_FROM_DEVICE);
+			pkt->ndirty = 2;
+			pg += 2;
+		} else {
+			pkt->pgaddr[0] = dma_map_page(dev, p, 0, head_size,
+						      DMA_FROM_DEVICE);
+			pkt->ndirty = 1;
+			pg++;
+		}
+
+		pkt->copy_src = (void *) head_buf;
+		pkt->copy_offs = ((unsigned long)buf->uaddr & ~PAGE_MASK);
+		pkt->remain_size = pkt->mapped_size = pkt->copy_size = head_size;
+		pkt->fctxt = fctxt;
+		list_add_tail(&pkt->link.link, &packets);
+		pkt++;
+	}
+
+	/* Set up descriptors for all full-sized packets */
+	while (full_packets--) {
+		pkt->remain_size = pkt->mapped_size = FULL_PACKET_SIZE;
+		pkt->copy_size = 0;
+		pkt->page = pg;
+		pkt->ndirty = PAGES_PER_FULL_PACKET;
+
+		for (i = 0; i < PAGES_PER_FULL_PACKET; i++)
+			pkt->pgaddr[i] = dma_map_page(dev, *pg++, 0, PAGE_SIZE,
+						      DMA_FROM_DEVICE);
+
+		pkt->fctxt = fctxt;
+		list_add_tail(&pkt->link.link, &packets);
+		pkt++;
+	}
+
+	/* Set up the descriptor for the tail packet */
+	if (tail_size) {
+		const size_t cs = tail_size % PAGE_SIZE;
+
+		pkt->remain_size = pkt->mapped_size = tail_size;
+		pkt->page = pg;
+		pkt->ndirty = tail_size / PAGE_SIZE;
+
+		for (i = 0; i < pkt->ndirty; i++)
+			pkt->pgaddr[i] = dma_map_page(dev, *pg++, 0, PAGE_SIZE,
+						      DMA_FROM_DEVICE);
+
+		if (cs) {
+			if (tail_buf) {
+				struct page * const p =
+					virt_to_page((void *) tail_buf);
+				pkt->pgaddr[i] =
+					dma_map_page(dev, p, 0, cs,
+						     DMA_FROM_DEVICE);
+				pkt->copy_src = (void *) tail_buf;
+				pkt->copy_size = cs;
+				pkt->copy_pg = pg;
+				pkt->copy_offs = 0;
+			} else {
+				pkt->pgaddr[i] = dma_map_page(dev, *pg, 0, cs,
+							      DMA_FROM_DEVICE);
+				pkt->copy_size = 0;
+			}
+			pkt->ndirty++;
+		} else {
+			pkt->copy_size = 0;
+		}
+
+		pkt->fctxt = fctxt;
+		list_add_tail(&pkt->link.link, &packets);
+		pkt++;
+	}
+
+	/*
+	 * Set up the trailing dummy packet (silicon bug workaround).
+	 *
+	 * The XDMA does not generate an interrupt if the memory
+	 * controlled by the last DMA descriptor is filled with data
+	 * to the last byte. We work around this by adding a dummy packet
+	 * after each frame. This guarantees that there always is an
+	 * active DMA descriptor after the last one of the frame, and so
+	 * the XDMA will interrupt. The dummy packet size is chosen so that
+	 * the dummy buffer is not entirely filled and hence will always
+	 * generate an interrupt, too.
+	 */
+	pkt->remain_size = pkt->mapped_size = DUMMY_PACKET_SIZE;
+	pkt->page = NULL;
+	pkt->copy_size = 0;
+	pkt->ndirty = 0;
+
+	for (i = 0; i < DUMMY_PACKET_SIZE / PAGE_SIZE; i++)
+		pkt->pgaddr[i] =
+			dma_map_page(dev,
+				     virt_to_page((void *) dummy_dma_buffer),
+				     0, PAGE_SIZE, DMA_FROM_DEVICE);
+
+	pkt->pgaddr[i] =
+		dma_map_page(dev,
+			     virt_to_page((void *) dummy_dma_buffer),
+			     0, DUMMY_PACKET_SIZE % PAGE_SIZE,
+			     DMA_FROM_DEVICE);
+
+	pkt->fctxt = fctxt;
+	list_add_tail(&pkt->link.link, &packets);
+
+	/*
+	 * Set up data to send to the FPGA. The total number of packets
+	 * requested does _not_ include the dummy packet. If DUMMY_PACKET_SIZE
+	 * is not zero, a dummy packet is always sent.
+	 */
+	fctxt->fpga_data[0] = cpu_to_le16(fctxt->pkts[0].mapped_size);
+	fctxt->fpga_data[1] = cpu_to_le16(full_size);
+	fctxt->fpga_data[2] = cpu_to_le16((pkt - 1)->mapped_size);
+	fctxt->fpga_data[3] = cpu_to_le16(DUMMY_PACKET_SIZE);
+	fctxt->fpga_data[4] = cpu_to_le16(total_packets - 1);
+
+	down(&dc->lock);
+
+	/* Now enqueue all the packets in one step */
+	list_splice(&packets, dc->pkt_queue.prev);
+	if (!dc->frm_cnt++)
+		xicap_gpi_run_pkt_queue(dc);
+
+	dev_dbg("%s: created packet set %p\n"
+		"\thead size = %#06x, full size = %#06x, "
+		"tail size = %#06x, dummy size = %#06x\n"
+		"\ttotal packets = %u, active DMA descriptors = %u\n",
+		xicap_gpi_name, fctxt, head_size, full_size, tail_size,
+		DUMMY_PACKET_SIZE, total_packets,
+		io_readl(dc->regaddr_xdma + 0x0008));
+
+	/*
+	 * If less than two frames are currently pending, we can send
+	 * the frame parameters to the FPGA right away. Otherwise, we
+	 * need to queue the frame.
+	 */
+	if (dc->frm_ready_cnt++ > 1) {
+		list_add_tail(&fctxt->link, &dc->frm_queue);
+		request_frame = 0;
+	}
+
+	up(&dc->lock);
+
+	if (request_frame)
+		memcpy_toio(dc->regaddr_fpga, fctxt->fpga_data,
+			    sizeof fctxt->fpga_data);
+
+	return fctxt;
+}
+
+
+
+static void xicap_gpi_run_pkt_queue(xicap_gpi_device_context_t *dc)
+{
+	packet_t *pkt = list_empty(&dc->pkt_queue) ? NULL :
+			list_entry(dc->pkt_queue.next, packet_t, link.link);
+
+	while (pkt) {
+		int i;
+		size_t sz;
+
+		/* Stop, if no more free DMA descriptors */
+		if (0 > atomic_dec_if_positive(&dc->desc_cnt))
+			break;
+
+		i = dc->pkt_page_i++;
+
+		sz = pkt->remain_size;
+		if (sz > PAGE_SIZE)
+			sz = PAGE_SIZE;
+		pkt->remain_size -= sz;
+
+		/* Set up the DMA descriptor */
+		io_writeq(cpu_to_be64(pkt->pgaddr[i]), dc->curdesc);
+		if (i) {
+			io_writeq(cpu_to_be64(0x1ULL << 53), dc->curdesc + 8);
+		} else {
+			io_writeq(cpu_to_be64((0x1ULL << 63) | (0x1ULL << 53)),
+				  dc->curdesc + 8);
+			pkt->desc2 = dc->curdesc + 8;
+		}
+
+		dev_dbg("%s: Desc. %2u = %016Lx, %016Lx\n",
+			xicap_gpi_name,
+			(dc->curdesc - dc->dmadesc) / sizeof (xdmadesc_t),
+			(u64) pkt->pgaddr[i], pkt->desc2);
+
+		dc->curdesc += sizeof (xdmadesc_t);
+		if ((dc->curdesc - dc->dmadesc) >=
+		    (XDMA_DESC_RING_SIZE * sizeof (xdmadesc_t)))
+			dc->curdesc = dc->dmadesc;
+
+		/* Add the packet to the interrupt queue */
+		if (!pkt->remain_size) {
+			spin_lock_irq(&dc->int_queue_lock);
+			list_move_tail(&pkt->link.link, &dc->int_queue);
+			spin_unlock_irq(&dc->int_queue_lock);
+			dc->pkt_page_i = 0;
+			pkt = list_empty(&dc->pkt_queue) ? NULL :
+			      list_entry(dc->pkt_queue.next, packet_t,
+					 link.link);
+		}
+
+		io_writel(1, dc->regaddr_xdma + 0x0008);
+	}
+}
+
+
+#if VMAP_WORKAROUND
+static int
+xicap_gpi_finish_buffer(struct device *dev, xicap_frame_context_t *frmctxt)
+{
+	struct __pkt * const pkt_h = frmctxt->pkts,
+		     * const pkt_t = frmctxt->pkts + frmctxt->total_pkts - 2;
+
+	if (pkt_h->copy_size) {
+		__copy_to_user(frmctxt->buf->uaddr, pkt_h->copy_src,
+			       pkt_h->copy_size);
+		free_pages((unsigned long) pkt_h->copy_src,
+			   (pkt_h->copy_size > PAGE_SIZE) ? 1 : 0);
+	}
+
+	if (2 < frmctxt->total_pkts) {
+		if (pkt_t->copy_size) {
+			__copy_to_user(frmctxt->buf->uaddr + frmctxt->buf->size
+				       - pkt_t->copy_size,
+				       pkt_t->copy_src,
+				       pkt_t->copy_size);
+			free_pages((unsigned long) pkt_t->copy_src, 0);
+		}
+	}
+
+	kfree(frmctxt);
+	return 0;
+}
+#endif
+
+
+
+static void xicap_gpi_pkt_finish(struct work_struct *work)
+{
+	packet_t * const pkt = container_of(work, packet_t, link.wrk);
+	xicap_gpi_device_context_t * const dc =
+		(xicap_gpi_device_context_t *) pkt->fctxt->dev->driver_data;
+	const dma_addr_t *pa = pkt->pgaddr;
+	xicap_data_buffer_t * buf;
+
+	while (pkt->mapped_size) {
+		size_t sz = pkt->mapped_size;
+		if (sz > PAGE_SIZE)
+			sz = PAGE_SIZE;
+		pkt->mapped_size -= sz;
+		dma_unmap_page(pkt->fctxt->dev, *pa++, sz, DMA_FROM_DEVICE);
+	}
+
+#if !VMAP_WORKAROUND
+	if (pkt->copy_size) {
+		const unsigned int page_order =
+			(pkt->copy_size > PAGE_SIZE) ? 1 : 0;
+		void * const dst = vmap(pkt->copy_pg, 0x1 << page_order,
+					VM_MAP, PAGE_USERIO);
+
+		if (dst) {
+			memcpy(dst + pkt->copy_offs, pkt->copy_src,
+			       pkt->copy_size);
+			free_pages((unsigned long) pkt->copy_src, page_order);
+			vunmap(dst);
+		} else {
+			pkt->fctxt->status = XICAP_BUFSTAT_VMERR;
+		}
+	}
+#endif
+
+	while (pkt->ndirty--)
+		set_page_dirty_lock(*pkt->page++);
+
+	down(&dc->lock);
+	buf = xicap_gpi_delete_packet(pkt);
+	if (buf) {
+		xicap_frame_context_t *fctxt = NULL;
+		xicap_frame_done(dc->devctxt, buf);
+		dc->frm_cnt--;
+		if (dc->frm_ready_cnt-- > 2) {
+			fctxt = list_entry(dc->frm_queue.next,
+					  xicap_frame_context_t, link);
+			list_del(&fctxt->link);
+		}
+
+		if (fctxt)
+			memcpy_toio(dc->regaddr_fpga, fctxt->fpga_data,
+				    sizeof fctxt->fpga_data);
+	}
+
+	if (dc->frm_cnt)
+		xicap_gpi_run_pkt_queue(dc);
+	up(&dc->lock);
+}
+
+
+
+/* The interrupt handler */
+static irqreturn_t xicap_gpi_int_handler(int irq, void *arg)
+{
+	xicap_gpi_device_context_t * const dc =
+		(xicap_gpi_device_context_t *) arg;
+	u32 flg_dmadata, flg_slstat, flg_fofl, reg;
+
+	/* Check, if this interrupt is for us */
+	flg_dmadata = titan_readl(0x0048) & (0x1 << (dc->slice * 8));
+	flg_slstat = titan_readl(0x0040) & (0x1f << (dc->slice * 5));
+	flg_fofl = titan_readl(0x482c) & ((dc->slice * 4));
+	if (!(flg_dmadata | flg_slstat | flg_fofl))
+		return IRQ_NONE;	/* not our interrupt */
+
+	if (unlikely(flg_slstat)) {
+		reg = io_readl(dc->regaddr_pktproc + 0x000c) & 0x1f;
+		io_writel(reg, dc->regaddr_pktproc + 0x000c);
+		dc->int_errflg |= PKTFLG_DATA_ERROR;
+	}
+
+	if (unlikely(flg_fofl)) {
+		titan_writel(flg_fofl, 0x482c);
+		dc->int_errflg |= PKTFLG_FIFO_OVERFLOW;
+	}
+
+	reg = io_readl(dc->regaddr_xdma + 0x000c) & 0x00008002;
+	if (unlikely(reg)) {
+		io_writel(reg, dc->regaddr_xdma + 0x000c);
+		dc->int_errflg |= ((reg & 0x00008000) ? PKTFLG_XDMA_ERROR : 0)
+				  | ((reg & 0x00000002) ? PKTFLG_DESC_UNDERRUN : 0);
+	}
+
+	if (likely(flg_dmadata)) {
+		titan_writel(flg_dmadata, 0x0048);
+		spin_lock(&dc->int_queue_lock);
+		while (!list_empty(&dc->int_queue)) {
+			packet_t * const pkt = list_entry(dc->int_queue.next,
+							  packet_t, link.link);
+
+			/* If the packet is not completed yet, exit */
+			if (be64_to_cpu(*pkt->desc2) & (0x1ULL << 53))
+				break;
+			list_del(&pkt->link.link);
+
+			/* Release the DMA descriptors used by this packet */
+			atomic_add(PAGE_ALIGN(pkt->mapped_size) >> PAGE_SHIFT, &dc->desc_cnt);
+
+			/* All further processing is deferred to a worker thread */
+			INIT_WORK(&pkt->link.wrk, xicap_gpi_pkt_finish);
+			if(unlikely(!queue_work(wq, &pkt->link.wrk)))
+				panic("%s: worker thread error\n",
+				      xicap_gpi_name);
+		}
+		spin_unlock(&dc->int_queue_lock);
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+static int __init xicap_gpi_init_module(void)
+{
+	int res;
+	dummy_dma_buffer = __get_dma_pages(GFP_KERNEL, 0);
+	if (!dummy_dma_buffer)
+		return -ENOMEM;
+	wq = create_workqueue(xicap_gpi_name);
+	if (unlikely(!wq)) {
+		free_pages(dummy_dma_buffer, 0);
+		return -ENOMEM;
+	}
+	res = driver_register(&xicap_gpi_driver);
+	if (unlikely(res)) {
+		free_pages(dummy_dma_buffer, 0);
+		destroy_workqueue(wq);
+	}
+	return res;
+}
+
+
+
+static void __exit xicap_gpi_cleanup_module(void)
+{
+	driver_unregister(&xicap_gpi_driver);
+	destroy_workqueue(wq);
+	free_pages(dummy_dma_buffer, 0);
+}
+
+module_init(xicap_gpi_init_module);
+module_exit(xicap_gpi_cleanup_module);
+
+
+
+MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>");
+MODULE_DESCRIPTION("Basler eXcite frame capturing driver for gpi devices");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(min_packet_size, "Minimum data packet size");
diff --git a/arch/mips/basler/excite/xicap_priv.h 
b/arch/mips/basler/excite/xicap_priv.h
new file mode 100644
index 0000000..4149a7e
--- /dev/null
+++ b/arch/mips/basler/excite/xicap_priv.h
@@ -0,0 +1,48 @@
+#if ! defined(XICAP_PRIV_H)
+#define XICAP_PRIV_H
+
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+
+#include "xicap.h"
+
+
+
+typedef struct xicap_devctxt xicap_device_context_t;
+typedef struct xicap_frmctxt xicap_frame_context_t;
+
+
+
+/* A queue block for a data buffer */
+typedef struct {
+	struct list_head	link;
+	void __user *		uaddr;
+	size_t			size;
+	void *			uctxt;
+	xicap_frame_context_t *	frmctxt;
+	unsigned int		status;
+	unsigned int		npages;
+	struct page *		pages[0]; /* must be last element! */
+} xicap_data_buffer_t;
+
+
+
+/* Functions invoked by the core */
+typedef struct {
+	int			(*start)(struct device *);
+	void			(*stop)(struct device *);
+	xicap_frame_context_t *	(*do_buffer)(struct device *, xicap_data_buffer_t 
*);
+	int			(*finish_buffer)(struct device *, xicap_frame_context_t *);
+	int			(*flush)(struct device *);
+} xicap_hw_driver_t;
+
+
+
+/* Functions exported by the core */
+xicap_device_context_t *
+	xicap_device_register(struct device *, const xicap_hw_driver_t *);
+void xicap_device_unregister(xicap_device_context_t *);
+void xicap_frame_done(xicap_device_context_t *, xicap_data_buffer_t *);
+
+#endif	/* ! defined(XICAP_PRIV_H) */
-- 
1.5.0


From yoichi_yuasa@tripeaks.co.jp Fri Mar  2 03:44:07 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 03:44:12 +0000 (GMT)
Received: from mo31.po.2iij.net ([210.128.50.54]:30272 "EHLO mo31.po.2iij.net")
	by ftp.linux-mips.org with ESMTP id S20039480AbXCBDoH (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 2 Mar 2007 03:44:07 +0000
Received: by mo.po.2iij.net (mo31) id l223gbkx015239; Fri, 2 Mar 2007 12:42:37 +0900 (JST)
Received: from localhost.localdomain (65.126.232.202.bf.2iij.net [202.232.126.65])
	by mbox.po.2iij.net (mbox32) id l223gXYP031831
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT);
	Fri, 2 Mar 2007 12:42:35 +0900 (JST)
Date:	Fri, 2 Mar 2007 12:42:33 +0900
From:	Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	yoichi_yuasa@tripeaks.co.jp, linux-mips <linux-mips@linux-mips.org>
Subject: [PATCH][MIPS] fix Cobalt early printk
Message-Id: <20070302124233.6b9f2c67.yoichi_yuasa@tripeaks.co.jp>
Organization: TriPeaks Corporation
X-Mailer: Sylpheed version 1.0.4 (GTK+ 1.2.10; i386-pc-linux-gnu)
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Return-Path: <yoichi_yuasa@tripeaks.co.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14306
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: yoichi_yuasa@tripeaks.co.jp
Precedence: bulk
X-list: linux-mips

Hi Ralf,

This patch has fixed Cobalt early printk.

Yoichi

Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>

diff -pruN -X mips/Documentation/dontdiff mips-orig/arch/mips/Kconfig mips/arch/mips/Kconfig
--- mips-orig/arch/mips/Kconfig	2007-03-02 10:51:23.580547750 +0900
+++ mips/arch/mips/Kconfig	2007-03-02 12:35:15.292826000 +0900
@@ -167,6 +167,7 @@ config MIPS_COBALT
 	select IRQ_CPU
 	select MIPS_GT64111
 	select SYS_HAS_CPU_NEVADA
+	select SYS_HAS_EARLY_PRINTK
 	select SYS_SUPPORTS_32BIT_KERNEL
 	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
 	select SYS_SUPPORTS_LITTLE_ENDIAN
@@ -837,7 +838,6 @@ source "arch/mips/tx4927/Kconfig"
 source "arch/mips/tx4938/Kconfig"
 source "arch/mips/vr41xx/Kconfig"
 source "arch/mips/philips/pnx8550/common/Kconfig"
-source "arch/mips/cobalt/Kconfig"
 
 endmenu
 
diff -pruN -X mips/Documentation/dontdiff mips-orig/arch/mips/cobalt/Kconfig mips/arch/mips/cobalt/Kconfig
--- mips-orig/arch/mips/cobalt/Kconfig	2007-03-02 10:51:24.048577000 +0900
+++ mips/arch/mips/cobalt/Kconfig	1970-01-01 09:00:00.000000000 +0900
@@ -1,7 +0,0 @@
-config EARLY_PRINTK
-	bool "Early console support"
-	depends on MIPS_COBALT
-	help
-	  Provide early console support by direct access to the
-	  on board UART. The UART must have been previously
-	  initialised by the boot loader.
diff -pruN -X mips/Documentation/dontdiff mips-orig/arch/mips/cobalt/console.c mips/arch/mips/cobalt/console.c
--- mips-orig/arch/mips/cobalt/console.c	2007-03-02 10:51:24.068578250 +0900
+++ mips/arch/mips/cobalt/console.c	2007-03-02 11:27:01.184311000 +0900
@@ -9,11 +9,8 @@
 #include <asm/addrspace.h>
 #include <asm/mach-cobalt/cobalt.h>
 
-static void putchar(int c)
+void prom_putchar(char c)
 {
-	if(c == '\n')
-		putchar('\r');
-
 	while(!(COBALT_UART[UART_LSR] & UART_LSR_THRE))
 		;
 

From ralf@linux-mips.org Fri Mar  2 13:36:45 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 13:36:47 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:40632 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S28639872AbXCBNgp (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Mar 2007 13:36:45 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l22DajWO020078;
	Fri, 2 Mar 2007 13:36:45 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l22DaiNa020077;
	Fri, 2 Mar 2007 13:36:44 GMT
Date:	Fri, 2 Mar 2007 13:36:44 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Cc:	linux-mips <linux-mips@linux-mips.org>
Subject: Re: [PATCH][MIPS] fix Cobalt early printk
Message-ID: <20070302133644.GB19957@linux-mips.org>
References: <20070302124233.6b9f2c67.yoichi_yuasa@tripeaks.co.jp>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20070302124233.6b9f2c67.yoichi_yuasa@tripeaks.co.jp>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14307
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Fri, Mar 02, 2007 at 12:42:33PM +0900, Yoichi Yuasa wrote:

> This patch has fixed Cobalt early printk.

Applied.  Thanks,

  Ralf

From anemo@mba.ocn.ne.jp Fri Mar  2 14:25:33 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 14:25:38 +0000 (GMT)
Received: from mba.ocn.ne.jp ([210.190.142.172]:1264 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S28639868AbXCBOZd (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 2 Mar 2007 14:25:33 +0000
Received: from localhost (p2238-ipad211funabasi.chiba.ocn.ne.jp [58.91.158.238])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id 9857592E3; Fri,  2 Mar 2007 23:24:06 +0900 (JST)
Date:	Fri, 02 Mar 2007 23:24:07 +0900 (JST)
Message-Id: <20070302.232407.05600700.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org, netdev@vger.kernel.org, jeff@garzik.org,
	sshtylyov@ru.mvista.com
Subject: [PATCH 1/2] tc35815 driver update (part 1)
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14308
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

Current tc35815 driver is very obsolete and less maintained for a long
time.  Replace it with a new driver based on one from CELF patch
archive.  It was for 2.6.10 kernel so some adjustment and cleanup are
added. (remove config.h, SA_ to IRQF_ conversion, etc.)

Major advantages are:

* Independent of JMR3927.
  (Actually independent of MIPS, but AFAIK the chip is used only on
   MIPS platforms)
* TX4938 support.
* 64-bit proof.
* Asynchronous and on-demand auto negotiation.
* High performance on non-coherent architecture.
* ethtool support.
* Many bugfixes and cleanups.

And next patch add further improvements/bugfixes/cleanups.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
This is a patch against current linux-mips.org git-tree.

 drivers/net/Kconfig     |    3 
 drivers/net/tc35815.c   | 2070 +++++++++++++++++++++++++++++++---------------
 include/linux/pci_ids.h |    1 
 3 files changed, 1440 insertions(+), 634 deletions(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 9b0e9e8..8ba65d5 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1428,7 +1428,8 @@ config CS89x0
 
 config TC35815
 	tristate "TOSHIBA TC35815 Ethernet support"
-	depends on NET_PCI && PCI && TOSHIBA_JMR3927
+	depends on NET_PCI && PCI && MIPS
+	select MII
 
 config DGRS
 	tristate "Digi Intl. RightSwitch SE-X support"
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index e3a7e3c..0cf1f87 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1,35 +1,48 @@
-/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *                ahennessy@mvista.com
+/*
+ * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
  *
  * Based on skelton.c by Donald Becker.
- * Copyright (C) 2000-2001 Toshiba Corporation
  *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * This driver is a replacement of older and less maintained version.
+ * This is a header of the older version:
+ *	-----<snip>-----
+ *	Copyright 2001 MontaVista Software Inc.
+ *	Author: MontaVista Software, Inc.
+ *		ahennessy@mvista.com
+ *	Copyright (C) 2000-2001 Toshiba Corporation
+ *	static const char *version =
+ *		"tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+ *	-----<snip>-----
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
  *
- * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2005
+ * All Rights Reserved.
  *
- * 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.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  Revision History:
+ *	1.13	64-bit proof.
+ *	1.14	Do not round-up transmit length.
+ *	1.15	Define TC35815_DMA_SYNC_ONDEMAND, cleanup.
+ *	1.16	Fix free_page bug introduced in 1.15
+ *	1.17	Add mii/ethtool ioctl support.
+ *		Remove workaround for early TX4938.  Cleanup.
+ *	1.20	Kernel 2.6.
+ *	1.21	Fix receive packet length (omit CRC).
+ *		Call netif_carrier_on/netif_carrier_off.
+ *		Add kernel/module options (speed, duplex, doforce).
+ *		Do not try "force link mode" by default.
+ *		Reconfigure CAM on restarting.
+ *		Reset PHY on restarting.
+ *		Add workaround for 100MHalf HUB.
+ *	1.22	Minor fix.
+ *	1.23	Minor cleanup.
  */
 
-static const char *version =
-	"tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+#define DRV_VERSION	"1.23"
+static const char *version = "tc35815.c:v" DRV_VERSION "\n";
+#define MODNAME			"tc35815"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -40,6 +53,7 @@ static const char *version =
 #include <linux/in.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
@@ -47,36 +61,43 @@ static const char *version =
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
 #include <asm/io.h>
-#include <asm/dma.h>
 #include <asm/byteorder.h>
 
-/*
- * The name of the card. Is used for messages and in the requests for
- * io regions, irqs and dma channels
- */
-static const char* cardname = "TC35815CF";
-#define TC35815_PROC_ENTRY "net/tc35815"
-
-#define TC35815_MODULE_NAME "TC35815CF"
-#define TX_TIMEOUT (4*HZ)
-
 /* First, a few definitions that the brave might change. */
 
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef TC35815_DEBUG
-#define TC35815_DEBUG 1
-#endif
-static unsigned int tc35815_debug = TC35815_DEBUG;
-
 #define GATHER_TXINT	/* On-Demand Tx Interrupt */
+#define WORKAROUND_LOSTCAR
+#define WORKAROUND_100HALF_PROMISC
+
+typedef enum {
+	TC35815CF = 0,
+	TC35815_NWU,
+} board_t;
+
+/* indexed by board_t, above */
+static struct {
+	const char *name;
+} board_info[] __devinitdata = {
+	{ "TOSHIBA TC35815CF 10/100BaseTX" },
+	{ "TOSHIBA TC35815 with Wake on LAN" },
+};
+
+static struct pci_device_id tc35815_pci_tbl[] = {
+	{PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TC35815CF },
+	{PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TC35815_NWU },
+	{0,}
+};
+MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
 
-#define vtonocache(p)	KSEG1ADDR(virt_to_phys(p))
+/* see MODULE_PARM_DESC */
+static struct tc35815_options {
+	int speed;
+	int duplex;
+	int doforce;
+} options;
 
 /*
  * Registers
@@ -269,42 +290,6 @@ struct tc35815_regs {
 #define MD_CA_Wr               0x00000400 /* 1:Write 0:Read                  */
 
 
-/* MII register offsets */
-#define MII_CONTROL             0x0000
-#define MII_STATUS              0x0001
-#define MII_PHY_ID0             0x0002
-#define MII_PHY_ID1             0x0003
-#define MII_ANAR                0x0004
-#define MII_ANLPAR              0x0005
-#define MII_ANER                0x0006
-/* MII Control register bit definitions. */
-#define MIICNTL_FDX             0x0100
-#define MIICNTL_RST_AUTO        0x0200
-#define MIICNTL_ISOLATE         0x0400
-#define MIICNTL_PWRDWN          0x0800
-#define MIICNTL_AUTO            0x1000
-#define MIICNTL_SPEED           0x2000
-#define MIICNTL_LPBK            0x4000
-#define MIICNTL_RESET           0x8000
-/* MII Status register bit significance. */
-#define MIISTAT_EXT             0x0001
-#define MIISTAT_JAB             0x0002
-#define MIISTAT_LINK            0x0004
-#define MIISTAT_CAN_AUTO        0x0008
-#define MIISTAT_FAULT           0x0010
-#define MIISTAT_AUTO_DONE       0x0020
-#define MIISTAT_CAN_T           0x0800
-#define MIISTAT_CAN_T_FDX       0x1000
-#define MIISTAT_CAN_TX          0x2000
-#define MIISTAT_CAN_TX_FDX      0x4000
-#define MIISTAT_CAN_T4          0x8000
-/* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */
-#define MII_AN_TX_FDX           0x0100
-#define MII_AN_TX_HDX           0x0080
-#define MII_AN_10_FDX           0x0040
-#define MII_AN_10_HDX           0x0020
-
-
 /*
  * Descriptors
  */
@@ -352,18 +337,17 @@ struct BDesc {
 
 #ifdef NO_CHECK_CARRIER
 #define TX_CTL_CMD	(Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
-	Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
-	Tx_En)	/* maybe  0x7d01 */
+	Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
+	Tx_En)	/* maybe  0x7b01 */
 #else
 #define TX_CTL_CMD	(Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
-	Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
-	Tx_En)	/* maybe  0x7f01 */
+	Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
+	Tx_En)	/* maybe  0x7b01 */
 #endif
 #define RX_CTL_CMD	(Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
 	| Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn)	/* maybe 0x6f01 */
-
 #define INT_EN_CMD  (Int_NRAbtEn | \
-	 Int_DParDEn | Int_DParErrEn | \
+	Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \
 	Int_SSysErrEn  | Int_RMasAbtEn | Int_RTargAbtEn | \
 	Int_STargAbtEn | \
 	Int_BLExEn  | Int_FDAExEn) /* maybe 0xb7f*/
@@ -371,6 +355,8 @@ struct BDesc {
 /* Tuning parameters */
 #define DMA_BURST_SIZE	32
 #define TX_THRESHOLD	1024
+#define TX_THRESHOLD_MAX 1536       /* used threshold with packet max byte for low pci transfer ability.*/
+#define TX_THRESHOLD_KEEP_LIMIT 10  /* setting threshold max value when overrun error occured this count. */
 
 #define FD_PAGE_NUM 2
 #define FD_PAGE_ORDER 1
@@ -396,14 +382,23 @@ struct FrFD {
 };
 
 
-extern unsigned long tc_readl(volatile __u32 *addr);
-extern void tc_writel(unsigned long data, volatile __u32 *addr);
+#define tc_readl(addr)	readl(addr)
+#define tc_writel(d, addr)	writel(d, addr)
+
+#define TC35815_TX_TIMEOUT  ((400*HZ)/1000)
 
-dma_addr_t priv_dma_handle;
+/* Timer state engine. */
+enum tc35815_timer_state {
+	arbwait  = 0,	/* Waiting for auto negotiation to complete.          */
+	lupwait  = 1,	/* Auto-neg complete, awaiting link-up status.        */
+	ltrywait = 2,	/* Forcing try of all modes, from fastest to slowest. */
+	asleep   = 3,	/* Time inactive.                                     */
+	lcheck   = 4,	/* Check link status.                                 */
+};
 
 /* Information that need to be kept for each board. */
 struct tc35815_local {
-	struct net_device *next_module;
+	struct pci_dev *pci_dev;
 
 	/* statistics */
 	struct net_device_stats stats;
@@ -411,216 +406,318 @@ struct tc35815_local {
 		int max_tx_qlen;
 		int tx_ints;
 		int rx_ints;
+	        int tx_underrun;
 	} lstats;
 
-	int tbusy;
-	int option;
-#define TC35815_OPT_AUTO	0x00
-#define TC35815_OPT_10M	0x01
-#define TC35815_OPT_100M	0x02
-#define TC35815_OPT_FULLDUP	0x04
-	int linkspeed;	/* 10 or 100 */
+	/* Tx control lock.  This protects the transmit buffer ring
+	 * state along with the "tx full" state of the driver.  This
+	 * means all netif_queue flow control actions are protected
+	 * by this lock as well.
+	 */
+	spinlock_t lock;
+
+	int phy_addr;
 	int fullduplex;
+	unsigned short saved_lpa;
+	struct timer_list timer;
+	enum tc35815_timer_state timer_state; /* State of auto-neg timer. */
+	unsigned int timer_ticks;	/* Number of clicks at each state  */
 
 	/*
 	 * Transmitting: Batch Mode.
 	 *	1 BD in 1 TxFD.
 	 * Receiving: Packing Mode.
 	 *	1 circular FD for Free Buffer List.
-	 *	RX_BUG_PAGES BD in Free Buffer FD.
+	 *	RX_BUF_PAGES BD in Free Buffer FD.
 	 *	One Free Buffer BD has PAGE_SIZE data buffer.
 	 */
-        struct pci_dev *pdev;
-	dma_addr_t fd_buf_dma_handle;
-	void * fd_buf;	/* for TxFD, TxFD, FrFD */
+	void * fd_buf;	/* for TxFD, RxFD, FrFD */
+	dma_addr_t fd_buf_dma;
 	struct TxFD *tfd_base;
-	int tfd_start;
-	int tfd_end;
+	unsigned int tfd_start;
+	unsigned int tfd_end;
 	struct RxFD *rfd_base;
 	struct RxFD *rfd_limit;
 	struct RxFD *rfd_cur;
 	struct FrFD *fbl_ptr;
 	unsigned char fbl_curid;
-	dma_addr_t data_buf_dma_handle[RX_BUF_PAGES];
 	void * data_buf[RX_BUF_PAGES];		/* packing */
-	spinlock_t lock;
+	dma_addr_t data_buf_dma[RX_BUF_PAGES];		/* packing */
+
+	struct {
+		struct sk_buff *skb;
+		dma_addr_t skb_dma;
+	} tx_skbs[TX_FD_NUM];
+	struct mii_if_info mii;
+	unsigned short mii_id[2];
+	u32 msg_enable;
 };
 
-/* Index to functions, as function prototypes. */
+static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt)
+{
+	return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf);
+}
+static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
+{
+	return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma));
+}
+static inline dma_addr_t rxbuf_virt_to_bus(struct tc35815_local *lp, void *virt)
+{
+	int i;
+	for (i = 0; i < RX_BUF_PAGES; i++) {
+		if ((u8 *)virt >= (u8 *)lp->data_buf[i] &&
+		    (u8 *)virt < (u8 *)lp->data_buf[i] + PAGE_SIZE)
+			return lp->data_buf_dma[i] + ((u8 *)virt - (u8 *)lp->data_buf[i]);
+	}
+	return 0;
+}
+static inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
+{
+	int i;
+	for (i = 0; i < RX_BUF_PAGES; i++) {
+		if (bus >= lp->data_buf_dma[i] &&
+		    bus < lp->data_buf_dma[i] + PAGE_SIZE)
+			return (void *)((u8 *)lp->data_buf[i] +
+					(bus - lp->data_buf_dma[i]));
+	}
+	return NULL;
+}
 
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq);
+#define TC35815_DMA_SYNC_ONDEMAND
+static void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+	void *buf;
+	/* pci_map + pci_dma_sync will be more effective than
+	 * pci_alloc_consistent on some archs. */
+	if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL)
+		return NULL;
+	*dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE,
+				     PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(*dma_handle)) {
+		free_page((unsigned long)buf);
+		return NULL;
+	}
+	return buf;
+#else
+	return pci_alloc_consistent(hwdev, PAGE_SIZE, dma_handle);
+#endif
+}
+
+static void free_rxbuf_page(struct pci_dev *hwdev, void *buf, dma_addr_t dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+	pci_unmap_single(hwdev, dma_handle, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+	free_page((unsigned long)buf);
+#else
+	pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle);
+#endif
+}
+
+/* Index to functions, as function prototypes. */
 
 static int	tc35815_open(struct net_device *dev);
 static int	tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void     tc35815_tx_timeout(struct net_device *dev);
 static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
 static void	tc35815_rx(struct net_device *dev);
 static void	tc35815_txdone(struct net_device *dev);
 static int	tc35815_close(struct net_device *dev);
 static struct	net_device_stats *tc35815_get_stats(struct net_device *dev);
 static void	tc35815_set_multicast_list(struct net_device *dev);
+static void     tc35815_tx_timeout(struct net_device *dev);
+static int	tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops tc35815_ethtool_ops;
 
-static void 	tc35815_chip_reset(struct net_device *dev);
+/* Example routines you must write ;->. */
+static void 	tc35815_chip_reset(struct tc35815_regs *tr);
 static void 	tc35815_chip_init(struct net_device *dev);
+static void	tc35815_find_phy(struct net_device *dev);
 static void 	tc35815_phy_chip_init(struct net_device *dev);
 
-/* A list of all installed tc35815 devices. */
-static struct net_device *root_tc35815_dev = NULL;
+static void	panic_queues(struct net_device *dev);
 
-/*
- * PCI device identifiers for "new style" Linux PCI Device Drivers
- */
-static struct pci_device_id tc35815_pci_tbl[] = {
-    { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-    { 0, }
-};
-
-MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+					   struct ethtool_cmd *ep);
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location);
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+			  int val);
 
-int
-tc35815_probe(struct pci_dev *pdev,
-		const struct pci_device_id *ent)
+static void __devinit tc35815_init_dev_addr (struct net_device *dev)
 {
-	int err = 0;
-	int ret;
-	unsigned long pci_memaddr;
-	unsigned int pci_irq_line;
-
-	printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device);
-
-	err = pci_enable_device(pdev);
-	if (err)
-		return err;
-
-        pci_memaddr = pci_resource_start (pdev, 1);
-
-        printk(KERN_INFO "    pci_memaddr=%#08lx  resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0));
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	int i;
 
-	if (!pci_memaddr) {
-		printk(KERN_WARNING "no PCI MEM resources, aborting\n");
-		ret = -ENODEV;
-		goto err_out;
-	}
-	pci_irq_line = pdev->irq;
-	/* irq disabled. */
-	if (pci_irq_line == 0) {
-		printk(KERN_WARNING "no PCI irq, aborting\n");
-		ret = -ENODEV;
-		goto err_out;
+	while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+		;
+	for (i = 0; i < 6; i += 2) {
+		unsigned short data;
+		tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
+		while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+			;
+		data = tc_readl(&tr->PROM_Data);
+		dev->dev_addr[i] = data & 0xff;
+		dev->dev_addr[i+1] = data >> 8;
 	}
-
-	ret =  tc35815_probe1(pdev, pci_memaddr, pci_irq_line);
-	if (ret)
-		goto err_out;
-
-	pci_set_master(pdev);
-
-	return 0;
-
-err_out:
-	pci_disable_device(pdev);
-	return ret;
 }
 
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq)
+static int __devinit tc35815_init_one (struct pci_dev *pdev,
+				       const struct pci_device_id *ent)
 {
-	static unsigned version_printed = 0;
-	int i, ret;
-	struct tc35815_local *lp;
-	struct tc35815_regs *tr;
+	void *ioaddr = NULL;
 	struct net_device *dev;
+	struct tc35815_local *lp;
+	int rc;
+	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+
+	static int printed_version;
+	if (!printed_version++) {
+		printk(version);
+		printk(KERN_DEBUG MODNAME ": speed:%d duplex:%d doforce:%d\n",
+		       options.speed, options.duplex, options.doforce);
+	}
 
-	/* Allocate a new 'dev' if needed. */
-	dev = alloc_etherdev(sizeof(struct tc35815_local));
-	if (dev == NULL)
-		return -ENOMEM;
+	if (!pdev->irq) {
+		printk (KERN_WARNING MODNAME ": no IRQ assigned (%s).\n",
+			pci_name(pdev));
+		return -ENODEV;
+	}
 
-	/*
-	 * alloc_etherdev allocs and zeros dev->priv
-	 */
+	/* dev zeroed in alloc_etherdev */
+	dev = alloc_etherdev (sizeof (*lp));
+	if (dev == NULL) {
+		printk (KERN_ERR MODNAME ": unable to alloc new ethernet\n");
+		return -ENOMEM;
+	}
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 	lp = dev->priv;
 
-	if (tc35815_debug  &&  version_printed++ == 0)
-		printk(KERN_DEBUG "%s", version);
+	/* enable device (incl. PCI PM wakeup), and bus-mastering */
+	rc = pci_enable_device (pdev);
+	if (rc)
+		goto err_out;
+
+	mmio_start = pci_resource_start (pdev, 1);
+	mmio_end = pci_resource_end (pdev, 1);
+	mmio_flags = pci_resource_flags (pdev, 1);
+	mmio_len = pci_resource_len (pdev, 1);
+
+	/* set this immediately, we need to know before
+	 * we talk to the chip directly */
 
-	/* Fill in the 'dev' fields. */
-	dev->irq = irq;
-	dev->base_addr = (unsigned long)ioremap(base_addr,
-						sizeof(struct tc35815_regs));
-	if (!dev->base_addr) {
-		ret = -ENOMEM;
+	/* make sure PCI base addr 1 is MMIO */
+	if (!(mmio_flags & IORESOURCE_MEM)) {
+		printk (KERN_ERR MODNAME ": region #1 not an MMIO resource, aborting\n");
+		rc = -ENODEV;
 		goto err_out;
 	}
-	tr = (struct tc35815_regs*)dev->base_addr;
 
-	tc35815_chip_reset(dev);
-
-	/* Retrieve and print the ethernet address. */
-	while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-		;
-	for (i = 0; i < 6; i += 2) {
-		unsigned short data;
-		tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
-		while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-			;
-		data = tc_readl(&tr->PROM_Data);
-		dev->dev_addr[i] = data & 0xff;
-		dev->dev_addr[i+1] = data >> 8;
+	/* check for weird/broken PCI region reporting */
+	if ((mmio_len < sizeof(struct tc35815_regs))) {
+		printk (KERN_ERR MODNAME ": Invalid PCI region size(s), aborting\n");
+		rc = -ENODEV;
+		goto err_out;
 	}
 
-	/* Initialize the device structure. */
-	lp->pdev = pdev;
-	lp->next_module = root_tc35815_dev;
-	root_tc35815_dev = dev;
+	rc = pci_request_regions (pdev, MODNAME);
+	if (rc)
+		goto err_out;
 
-	spin_lock_init(&lp->lock);
+	pci_set_master (pdev);
 
-	if (dev->mem_start > 0) {
-		lp->option = dev->mem_start;
-		if ((lp->option & TC35815_OPT_10M) &&
-		    (lp->option & TC35815_OPT_100M)) {
-			/* if both speed speficied, auto select. */
-			lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M);
-		}
+	/* ioremap MMIO region */
+	ioaddr = ioremap (mmio_start, mmio_len);
+	if (ioaddr == NULL) {
+		printk (KERN_ERR MODNAME ": cannot remap MMIO, aborting\n");
+		rc = -EIO;
+		goto err_out_free_res;
 	}
-	//XXX fixme
-        lp->option |= TC35815_OPT_10M;
-
-	/* do auto negotiation */
-	tc35815_phy_chip_init(dev);
 
-	dev->open		= tc35815_open;
-	dev->stop		= tc35815_close;
-	dev->tx_timeout         = tc35815_tx_timeout;
-	dev->watchdog_timeo     = TX_TIMEOUT;
-	dev->hard_start_xmit	= tc35815_send_packet;
-	dev->get_stats		= tc35815_get_stats;
+	/* Initialize the device structure. */
+	dev->open = tc35815_open;
+	dev->hard_start_xmit = tc35815_send_packet;
+	dev->stop = tc35815_close;
+	dev->get_stats = tc35815_get_stats;
 	dev->set_multicast_list = tc35815_set_multicast_list;
-	SET_MODULE_OWNER(dev);
-	SET_NETDEV_DEV(dev, &pdev->dev);
+	dev->do_ioctl = tc35815_ioctl;
+	dev->ethtool_ops = &tc35815_ethtool_ops;
+	dev->tx_timeout = tc35815_tx_timeout;
+	dev->watchdog_timeo = TC35815_TX_TIMEOUT;
 
-	ret = register_netdev(dev);
-	if (ret)
-		goto err_out_iounmap;
+	dev->irq = pdev->irq;
+	dev->base_addr = (unsigned long) ioaddr;
 
-	printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC",
-	       dev->name, cardname, base_addr, irq);
-	for (i = 0; i < 6; i++)
-		printk(" %2.2x", dev->dev_addr[i]);
-	printk("\n");
-	printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n",
-	       dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half");
+	/* dev->priv/lp zeroed and aligned in alloc_etherdev */
+	lp = dev->priv;
+	spin_lock_init(&lp->lock);
+	lp->pci_dev = pdev;
+
+	lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK;
+	pci_set_drvdata(pdev, dev);
+
+	/* Soft reset the chip. */
+	tc35815_chip_reset((struct tc35815_regs*)ioaddr);
+
+	/* Retrieve the ethernet address. */
+	tc35815_init_dev_addr(dev);
+
+	rc = register_netdev (dev);
+	if (rc)
+		goto err_out_unmap;
+
+	printk (KERN_INFO "%s: %s at 0x%lx, "
+		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+		"IRQ %d\n",
+		dev->name,
+		board_info[ent->driver_data].name,
+		dev->base_addr,
+		dev->dev_addr[0], dev->dev_addr[1],
+		dev->dev_addr[2], dev->dev_addr[3],
+		dev->dev_addr[4], dev->dev_addr[5],
+		dev->irq);
+
+	init_timer(&lp->timer);
+	lp->mii.dev = dev;
+	lp->mii.mdio_read = tc_mdio_read;
+	lp->mii.mdio_write = tc_mdio_write;
+	lp->mii.phy_id_mask = 0x1f;
+	lp->mii.reg_num_mask = 0x1f;
+	tc35815_find_phy(dev);
+	lp->mii.phy_id = lp->phy_addr;
+	lp->mii.full_duplex = 0;
+	lp->mii.force_media = 0;
 
 	return 0;
 
-err_out_iounmap:
-	iounmap((void *) dev->base_addr);
+err_out_unmap:
+	iounmap(ioaddr);
+err_out_free_res:
+	pci_release_regions (pdev);
 err_out:
-	free_netdev(dev);
-	return ret;
+	free_netdev (dev);
+	return rc;
 }
 
 
+static void __devexit tc35815_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	unsigned long mmio_addr;
+
+	mmio_addr = dev->base_addr;
+
+	unregister_netdev (dev);
+
+	if (mmio_addr) {
+		iounmap ((void __iomem *)mmio_addr);
+		pci_release_regions (pdev);
+	}
+
+	free_netdev (dev);
+
+	pci_set_drvdata (pdev, NULL);
+}
+
 static int
 tc35815_init_queues(struct net_device *dev)
 {
@@ -633,40 +730,36 @@ tc35815_init_queues(struct net_device *d
 		    sizeof(struct BDesc) * RX_BUF_PAGES +
 		    sizeof(struct FDesc) * RX_FD_NUM +
 		    sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) {
-			printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name);
+			printk("%s: Invalid Queue Size.\n", dev->name);
 			return -ENOMEM;
 		}
 
-		if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0)
+		if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0)
 			return -ENOMEM;
 		for (i = 0; i < RX_BUF_PAGES; i++) {
-			if ((lp->data_buf[i] = (void *)get_zeroed_page(GFP_KERNEL)) == 0) {
+			if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) {
 				while (--i >= 0) {
-					free_page((unsigned long)lp->data_buf[i]);
-					lp->data_buf[i] = 0;
+					free_rxbuf_page(lp->pci_dev,
+							lp->data_buf[i],
+							lp->data_buf_dma[i]);
+					lp->data_buf[i] = NULL;
 				}
-				free_page((unsigned long)lp->fd_buf);
-				lp->fd_buf = 0;
+				pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, lp->fd_buf, lp->fd_buf_dma);
+				lp->fd_buf = NULL;
 				return -ENOMEM;
 			}
-#ifdef __mips__
-			dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM);
-#endif
 		}
-#ifdef __mips__
-		dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
-#endif
+		printk(KERN_DEBUG "%s: FD buf %p DataBuf", dev->name, lp->fd_buf);
+		for (i = 0; i < RX_BUF_PAGES; i++) {
+			printk(" %p", lp->data_buf[i]);
+		}
+		printk("\n");
 	} else {
-		memset(lp->fd_buf, 0, PAGE_SIZE * FD_PAGE_NUM);
-#ifdef __mips__
-		dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
-#endif
+		for (i = 0; i < FD_PAGE_NUM; i++) {
+			clear_page((void *)((unsigned long)lp->fd_buf + i * PAGE_SIZE));
+		}
 	}
-#ifdef __mips__
-	fd_addr = (unsigned long)vtonocache(lp->fd_buf);
-#else
 	fd_addr = (unsigned long)lp->fd_buf;
-#endif
 
 	/* Free Descriptors (for Receive) */
 	lp->rfd_base = (struct RxFD *)fd_addr;
@@ -683,26 +776,28 @@ tc35815_init_queues(struct net_device *d
 	lp->tfd_base = (struct TxFD *)fd_addr;
 	fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
 	for (i = 0; i < TX_FD_NUM; i++) {
-		lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1]));
-		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+		lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1]));
+		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
 		lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
 	}
-	lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0]));
+	lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0]));
 	lp->tfd_start = 0;
 	lp->tfd_end = 0;
 
 	/* Buffer List (for Receive) */
 	lp->fbl_ptr = (struct FrFD *)fd_addr;
-	lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr));
+	lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr));
 	lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD);
 	for (i = 0; i < RX_BUF_PAGES; i++) {
-		lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i]));
+		lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(lp->data_buf_dma[i]);
 		/* BDID is index of FrFD.bd[] */
 		lp->fbl_ptr->bd[i].BDCtl =
 			cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE);
 	}
 	lp->fbl_curid = 0;
 
+	printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n",
+	       dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr);
 	return 0;
 }
 
@@ -713,11 +808,20 @@ tc35815_clear_queues(struct net_device *
 	int i;
 
 	for (i = 0; i < TX_FD_NUM; i++) {
-		struct sk_buff *skb = (struct sk_buff *)
-			le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
-		if (skb)
+		struct sk_buff *skb =
+			lp->tfd_base[i].fd.FDSystem != cpu_to_le32(0xffffffff) ?
+			lp->tx_skbs[le32_to_cpu(lp->tfd_base[i].fd.FDSystem)].skb : NULL;
+		if (lp->tx_skbs[i].skb != skb) {
+			printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+			panic_queues(dev);
+		}
+		if (skb) {
+			pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+			lp->tx_skbs[i].skb = NULL;
+			lp->tx_skbs[i].skb_dma = 0;
 			dev_kfree_skb_any(skb);
-		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+		}
+		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
 	}
 
 	tc35815_init_queues(dev);
@@ -731,28 +835,40 @@ tc35815_free_queues(struct net_device *d
 
 	if (lp->tfd_base) {
 		for (i = 0; i < TX_FD_NUM; i++) {
-			struct sk_buff *skb = (struct sk_buff *)
-				le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
-			if (skb)
-				dev_kfree_skb_any(skb);
-			lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+			struct sk_buff *skb =
+				lp->tfd_base[i].fd.FDSystem != cpu_to_le32(0xffffffff) ?
+				lp->tx_skbs[le32_to_cpu(lp->tfd_base[i].fd.FDSystem)].skb : NULL;
+			if (lp->tx_skbs[i].skb != skb) {
+				printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+				panic_queues(dev);
+			}
+			if (skb) {
+				dev_kfree_skb(skb);
+				pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+				lp->tx_skbs[i].skb = NULL;
+				lp->tx_skbs[i].skb_dma = 0;
+			}
+			lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
 		}
 	}
 
 	lp->rfd_base = NULL;
-	lp->rfd_base = NULL;
 	lp->rfd_limit = NULL;
 	lp->rfd_cur = NULL;
 	lp->fbl_ptr = NULL;
 
 	for (i = 0; i < RX_BUF_PAGES; i++) {
-		if (lp->data_buf[i])
-			free_page((unsigned long)lp->data_buf[i]);
-		lp->data_buf[i] = 0;
+		if (lp->data_buf[i]) {
+			free_rxbuf_page(lp->pci_dev,
+					lp->data_buf[i], lp->data_buf_dma[i]);
+			lp->data_buf[i] = NULL;
+		}
+	}
+	if (lp->fd_buf) {
+		pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM,
+				    lp->fd_buf, lp->fd_buf_dma);
+		lp->fd_buf = NULL;
 	}
-	if (lp->fd_buf)
-		__free_pages(lp->fd_buf, FD_PAGE_ORDER);
-	lp->fd_buf = NULL;
 }
 
 static void
@@ -815,7 +931,7 @@ panic_queues(struct net_device *dev)
 	struct tc35815_local *lp = dev->priv;
 	int i;
 
-	printk("TxFD base %p, start %d, end %d\n",
+	printk("TxFD base %p, start %u, end %u\n",
 	       lp->tfd_base, lp->tfd_start, lp->tfd_end);
 	printk("RxFD base %p limit %p cur %p\n",
 	       lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
@@ -830,30 +946,11 @@ panic_queues(struct net_device *dev)
 	panic("%s: Illegal queue state.", dev->name);
 }
 
-#if 0
-static void print_buf(char *add, int length)
-{
-	int i;
-	int len = length;
-
-	printk("print_buf(%08x)(%x)\n", (unsigned int) add,length);
-
-	if (len > 100)
-		len = 100;
-	for (i = 0; i < len; i++) {
-		printk(" %2.2X", (unsigned char) add[i]);
-		if (!(i % 16))
-			printk("\n");
-	}
-	printk("\n");
-}
-#endif
-
 static void print_eth(char *add)
 {
 	int i;
 
-	printk("print_eth(%08x)\n", (unsigned int) add);
+	printk("print_eth(%p)\n", add);
 	for (i = 0; i < 6; i++)
 		printk(" %2.2X", (unsigned char) add[i + 6]);
 	printk(" =>");
@@ -862,6 +959,73 @@ static void print_eth(char *add)
 	printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
 }
 
+static int tc35815_tx_full(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	return ((lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end);
+}
+
+static void tc35815_restart(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	int do_phy_reset = 1;
+	del_timer(&lp->timer);		/* Kill if running	*/
+
+	if (lp->mii_id[0] == 0x0016 && (lp->mii_id[1] & 0xfc00) == 0xf800) {
+		/* Resetting PHY cause problem on some chip... (SEEQ 80221) */
+		do_phy_reset = 0;
+	}
+	if (do_phy_reset) {
+		int timeout;
+		tc_mdio_write(dev, pid, MII_BMCR, BMCR_RESET);
+		timeout = 100;
+		while (--timeout) {
+			if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_RESET))
+				break;
+			udelay(1);
+		}
+		if (!timeout)
+			printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name);
+	}
+
+	tc35815_chip_reset(tr);
+	tc35815_clear_queues(dev);
+	tc35815_chip_init(dev);
+	/* Reconfigure CAM again since tc35815_chip_init() initialize it. */
+	tc35815_set_multicast_list(dev);
+}
+
+static void tc35815_tx_timeout(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+
+	printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+	       dev->name, tc_readl(&tr->Tx_Stat));
+
+	/* Try to restart the adaptor. */
+	spin_lock_irq(&lp->lock);
+	tc35815_restart(dev);
+	spin_unlock_irq(&lp->lock);
+
+	lp->stats.tx_errors++;
+
+	/* If we have space available to accept new transmit
+	 * requests, wake up the queueing layer.  This would
+	 * be the case if the chipset_init() call above just
+	 * flushes out the tx queue and empties it.
+	 *
+	 * If instead, the tx queue is retained then the
+	 * netif_wake_queue() call should be placed in the
+	 * TX completion interrupt handler of the driver instead
+	 * of here.
+	 */
+	if (!tc35815_tx_full(dev))
+		netif_wake_queue(dev);
+}
+
 /*
  * Open/initialize the board. This is called (in the current kernel)
  * sometime after booting when the 'ifconfig' program is run.
@@ -874,17 +1038,17 @@ static int
 tc35815_open(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
+
 	/*
 	 * This is used if the interrupt line can turned off (shared).
 	 * See 3c503.c for an example of selecting the IRQ at config-time.
 	 */
-
-	if (dev->irq == 0  ||
-	    request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, cardname, dev)) {
+	if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, dev->name, dev)) {
 		return -EAGAIN;
 	}
 
-	tc35815_chip_reset(dev);
+	del_timer(&lp->timer);		/* Kill if running	*/
+	tc35815_chip_reset((struct tc35815_regs*)dev->base_addr);
 
 	if (tc35815_init_queues(dev) != 0) {
 		free_irq(dev->irq, dev);
@@ -892,127 +1056,103 @@ tc35815_open(struct net_device *dev)
 	}
 
 	/* Reset the hardware here. Don't forget to set the station address. */
+	spin_lock_irq(&lp->lock);
 	tc35815_chip_init(dev);
+	spin_unlock_irq(&lp->lock);
 
-	lp->tbusy = 0;
+	/* We are now ready to accept transmit requeusts from
+	 * the queueing layer of the networking.
+	 */
 	netif_start_queue(dev);
 
 	return 0;
 }
 
-static void tc35815_tx_timeout(struct net_device *dev)
-{
-	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
-	unsigned long flags;
-
-	spin_lock_irqsave(&lp->lock, flags);
-	printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
-	       dev->name, tc_readl(&tr->Tx_Stat));
-	/* Try to restart the adaptor. */
-	tc35815_chip_reset(dev);
-	tc35815_clear_queues(dev);
-	tc35815_chip_init(dev);
-	lp->tbusy=0;
-	spin_unlock_irqrestore(&lp->lock, flags);
-	dev->trans_start = jiffies;
-	netif_wake_queue(dev);
-}
-
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
 static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
 	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	short length = skb->len;
+	struct TxFD *txfd;
 
-	if (netif_queue_stopped(dev)) {
-		/*
-		 * If we get here, some higher level has decided we are broken.
-		 * There should really be a "kick me" function call instead.
-		 */
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 5)
-			return 1;
-		printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
-		       dev->name, tc_readl(&tr->Tx_Stat));
-		/* Try to restart the adaptor. */
-		tc35815_chip_reset(dev);
-		tc35815_clear_queues(dev);
-		tc35815_chip_init(dev);
-		lp->tbusy=0;
-		dev->trans_start = jiffies;
-		netif_wake_queue(dev);
-	}
-
-	/*
-	 * Block a timer-based transmit from overlapping. This could better be
-	 * done with atomic_swap(1, lp->tbusy), but set_bit() works as well.
+	/* If some error occurs while trying to transmit this
+	 * packet, you should return '1' from this function.
+	 * In such a case you _may not_ do anything to the
+	 * SKB, it is still owned by the network queueing
+	 * layer when an error is returned.  This means you
+	 * may not modify any SKB fields, you may not free
+	 * the SKB, etc.
 	 */
-	if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) {
-		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
-		dev_kfree_skb_any(skb);
-	} else {
-		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-		unsigned char *buf = skb->data;
-		struct TxFD *txfd = &lp->tfd_base[lp->tfd_start];
-		unsigned long flags;
-		lp->stats.tx_bytes += skb->len;
-
-
-#ifdef __mips__
-		dma_cache_wback_inv((unsigned long)buf, length);
-#endif
-
-		spin_lock_irqsave(&lp->lock, flags);
-
-		/* failsafe... */
-		if (lp->tfd_start != lp->tfd_end)
-			tc35815_txdone(dev);
 
+	/* This is the most common case for modern hardware.
+	 * The spinlock protects this code from the TX complete
+	 * hardware interrupt handler.  Queue flow control is
+	 * thus managed under this lock as well.
+	 */
+	spin_lock_irq(&lp->lock);
 
-		txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf));
+	/*add to ring */
+	txfd = &lp->tfd_base[lp->tfd_start];
 
-		txfd->bd.BDCtl = cpu_to_le32(length);
-		txfd->fd.FDSystem = cpu_to_le32((__u32)skb);
-		txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
+	/* failsafe... */
+	if (lp->tfd_start != lp->tfd_end)
+		tc35815_txdone(dev);
 
-		if (lp->tfd_start == lp->tfd_end) {
-			/* Start DMA Transmitter. */
-			txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+	if (netif_msg_pktdata(lp))
+		print_eth(skb->data);
+	if (lp->tx_skbs[lp->tfd_start].skb) {
+		printk("%s: tx_skbs conflict.\n", dev->name);
+		panic_queues(dev);
+	}
+	lp->tx_skbs[lp->tfd_start].skb = skb;
+	lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+	txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma);
+	txfd->bd.BDCtl = cpu_to_le32(length);
+	txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start);
+	txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
+
+	if (lp->tfd_start == lp->tfd_end) {
+		/* Start DMA Transmitter. */
+		txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
 #ifdef GATHER_TXINT
-			txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+		txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
 #endif
-			if (tc35815_debug > 2) {
-				printk("%s: starting TxFD.\n", dev->name);
-				dump_txfd(txfd);
-				if (tc35815_debug > 3)
-					print_eth(buf);
-			}
-			tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
-		} else {
-			txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
-			if (tc35815_debug > 2) {
-				printk("%s: queueing TxFD.\n", dev->name);
-				dump_txfd(txfd);
-				if (tc35815_debug > 3)
-					print_eth(buf);
-			}
+		if (netif_msg_tx_queued(lp)) {
+			printk("%s: starting TxFD.\n", dev->name);
+			dump_txfd(txfd);
 		}
-		lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
+		tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
+	} else {
+		txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
+		if (netif_msg_tx_queued(lp)) {
+			printk("%s: queueing TxFD.\n", dev->name);
+			dump_txfd(txfd);
+		}
+	}
+	lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
 
-		dev->trans_start = jiffies;
+	dev->trans_start = jiffies;
 
-		if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) {
-			/* we can send another packet */
-			lp->tbusy = 0;
-			netif_start_queue(dev);
-		} else {
-			netif_stop_queue(dev);
-			if (tc35815_debug > 1)
-				printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
-		}
-		spin_unlock_irqrestore(&lp->lock, flags);
+	/* If we just used up the very last entry in the
+	 * TX ring on this device, tell the queueing
+	 * layer to send no more.
+	 */
+	if (tc35815_tx_full(dev)) {
+		if (netif_msg_tx_queued(lp))
+			printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
+		netif_stop_queue(dev);
 	}
 
+	/* When the TX completion hw interrupt arrives, this
+	 * is when the transmit statistics are updated.
+	 */
+
+	spin_unlock_irq(&lp->lock);
 	return 0;
 }
 
@@ -1023,7 +1163,6 @@ static void tc35815_fatal_error_interrup
 	static int count;
 	printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
 	       dev->name, status);
-
 	if (status & Int_IntPCI)
 		printk(" IntPCI");
 	if (status & Int_DmParErr)
@@ -1033,80 +1172,79 @@ static void tc35815_fatal_error_interrup
 	printk("\n");
 	if (count++ > 100)
 		panic("%s: Too many fatal errors.", dev->name);
-	printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname);
+	printk(KERN_WARNING "%s: Resetting ...\n", dev->name);
 	/* Try to restart the adaptor. */
-	tc35815_chip_reset(dev);
-	tc35815_clear_queues(dev);
-	tc35815_chip_init(dev);
+	tc35815_restart(dev);
+	return;
 }
 
 /*
  * The typical workload of the driver:
- *   Handle the network interface interrupts.
+ * Handle the network interface interrupts.
  */
 static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
 	struct tc35815_regs *tr;
 	struct tc35815_local *lp;
-	int status, boguscount = 0;
-	int handled = 0;
-
-	if (dev == NULL) {
-		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
-		return IRQ_NONE;
-	}
+	int status, handled = 0;
 
-	tr = (struct tc35815_regs*)dev->base_addr;
+	tr = (struct tc35815_regs *)dev->base_addr;
 	lp = dev->priv;
 
-	do {
-		status = tc_readl(&tr->Int_Src);
-		if (status == 0)
-			break;
-		handled = 1;
-		tc_writel(status, &tr->Int_Src);	/* write to clear */
+	spin_lock(&lp->lock);
+	status = tc_readl(&tr->Int_Src);
+	tc_writel(status, &tr->Int_Src);	/* write to clear */
 
-		/* Fatal errors... */
-		if (status & FATAL_ERROR_INT) {
-			tc35815_fatal_error_interrupt(dev, status);
-			break;
-		}
-		/* recoverable errors */
-		if (status & Int_IntFDAEx) {
-			/* disable FDAEx int. (until we make rooms...) */
-			tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
-			printk(KERN_WARNING
-			       "%s: Free Descriptor Area Exhausted (%#x).\n",
-			       dev->name, status);
-			lp->stats.rx_dropped++;
-		}
-		if (status & Int_IntBLEx) {
-			/* disable BLEx int. (until we make rooms...) */
-			tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
-			printk(KERN_WARNING
-			       "%s: Buffer List Exhausted (%#x).\n",
-			       dev->name, status);
-			lp->stats.rx_dropped++;
-		}
-		if (status & Int_IntExBD) {
-			printk(KERN_WARNING
-			       "%s: Excessive Buffer Descriptiors (%#x).\n",
-			       dev->name, status);
-			lp->stats.rx_length_errors++;
-		}
-		/* normal notification */
-		if (status & Int_IntMacRx) {
-			/* Got a packet(s). */
-			lp->lstats.rx_ints++;
-			tc35815_rx(dev);
-		}
-		if (status & Int_IntMacTx) {
-			lp->lstats.tx_ints++;
-			tc35815_txdone(dev);
-		}
-	} while (++boguscount < 20) ;
+	/* Fatal errors... */
+	if (status & FATAL_ERROR_INT) {
+		tc35815_fatal_error_interrupt(dev, status);
+		spin_unlock(&lp->lock);
+		return IRQ_HANDLED;
+	}
+	/* recoverable errors */
+	if (status & Int_IntFDAEx) {
+		/* disable FDAEx int. (until we make rooms...) */
+		tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
+		printk(KERN_WARNING
+		       "%s: Free Descriptor Area Exhausted (%#x).\n",
+		       dev->name, status);
+		lp->stats.rx_dropped++;
+		handled = 1;
+	}
+	if (status & Int_IntBLEx) {
+		/* disable BLEx int. (until we make rooms...) */
+		tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
+		printk(KERN_WARNING
+		       "%s: Buffer List Exhausted (%#x).\n",
+		       dev->name, status);
+		lp->stats.rx_dropped++;
+		handled = 1;
+	}
+	if (status & Int_IntExBD) {
+		printk(KERN_WARNING
+		       "%s: Excessive Buffer Descriptiors (%#x).\n",
+		       dev->name, status);
+		lp->stats.rx_length_errors++;
+		handled = 1;
+	}
 
+	/* normal notification */
+	if (status & Int_IntMacRx) {
+		/* Got a packet(s). */
+		lp->lstats.rx_ints++;
+		tc35815_rx(dev);
+		handled = 1;
+	}
+	if (status & Int_IntMacTx) {
+		/* Transmit complete. */
+		lp->lstats.tx_ints++;
+		tc35815_txdone(dev);
+		netif_wake_queue(dev);
+		handled = 1;
+	}
+	(void)tc_readl(&tr->Int_Src);	/* flush */
+	spin_unlock(&lp->lock);
 	return IRQ_RETVAL(handled);
 }
 
@@ -1115,7 +1253,7 @@ static void
 tc35815_rx(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
 	unsigned int fdctl;
 	int i;
 	int buf_free_count = 0;
@@ -1126,8 +1264,11 @@ tc35815_rx(struct net_device *dev)
 		int pkt_len = fdctl & FD_FDLength_MASK;
 		struct RxFD *next_rfd;
 		int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+#if (RX_CTL_CMD & Rx_StripCRC) == 0
+		pkt_len -= 4;
+#endif
 
-		if (tc35815_debug > 2)
+		if (netif_msg_rx_status(lp))
 			dump_rxfd(lp->rfd_cur);
 		if (status & Rx_Good) {
 			/* Malloc up new buffer. */
@@ -1135,8 +1276,6 @@ tc35815_rx(struct net_device *dev)
 			unsigned char *data;
 			int cur_bd, offset;
 
-			lp->stats.rx_bytes += pkt_len;
-
 			skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
 			if (skb == NULL) {
 				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
@@ -1155,25 +1294,30 @@ tc35815_rx(struct net_device *dev)
 			while (offset < pkt_len && cur_bd < bd_count) {
 				int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) &
 					BD_BuffLength_MASK;
-				void *rxbuf =
-					bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData));
-#ifdef __mips__
-				dma_cache_inv((unsigned long)rxbuf, len);
+				dma_addr_t dma = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData);
+				void *rxbuf = rxbuf_bus_to_virt(lp, dma);
+				if (offset + len > pkt_len)
+					len = pkt_len - offset;
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+				pci_dma_sync_single_for_cpu(lp->pci_dev,
+							    dma, len,
+							    PCI_DMA_FROMDEVICE);
 #endif
 				memcpy(data + offset, rxbuf, len);
 				offset += len;
 				cur_bd++;
 			}
-#if 0
-			print_buf(data,pkt_len);
-#endif
-			if (tc35815_debug > 3)
+			if (netif_msg_pktdata(lp))
 				print_eth(data);
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
+			dev->last_rx = jiffies;
 			lp->stats.rx_packets++;
+			lp->stats.rx_bytes += pkt_len;
 		} else {
 			lp->stats.rx_errors++;
+			printk(KERN_DEBUG "%s: Rx error (status %x)\n",
+			       dev->name, status & Rx_Stat_Mask);
 			/* WORKAROUND: LongErr and CRCErr means Overflow. */
 			if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
 				status &= ~(Rx_LongErr|Rx_CRCErr);
@@ -1210,7 +1354,7 @@ tc35815_rx(struct net_device *dev)
 						    PAGE_SIZE);
 				lp->fbl_curid =
 					(lp->fbl_curid + 1) % RX_BUF_PAGES;
-				if (tc35815_debug > 2) {
+				if (netif_msg_rx_status(lp)) {
 					printk("%s: Entering new FBD %d\n",
 					       dev->name, lp->fbl_curid);
 					dump_frfd(lp->fbl_ptr);
@@ -1220,10 +1364,7 @@ tc35815_rx(struct net_device *dev)
 		}
 
 		/* put RxFD back to controller */
-		next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext));
-#ifdef __mips__
-		next_rfd = (struct RxFD *)vtonocache(next_rfd);
-#endif
+		next_rfd = fd_bus_to_virt(lp, le32_to_cpu(lp->rfd_cur->fd.FDNext));
 		if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
 			printk("%s: RxFD FDNext invalid.\n", dev->name);
 			panic_queues(dev);
@@ -1265,9 +1406,12 @@ tc35815_check_tx_stat(struct net_device
 	if (status & Tx_TxColl_MASK)
 		lp->stats.collisions += status & Tx_TxColl_MASK;
 
+#ifdef WORKAROUND_LOSTCAR
 	/* WORKAROUND: ignore LostCrS in full duplex operation */
-	if (lp->fullduplex)
+	if ((lp->timer_state != asleep && lp->timer_state != lcheck)
+	    || lp->fullduplex)
 		status &= ~Tx_NCarr;
+#endif
 
 	if (!(status & TX_STA_ERR)) {
 		/* no error. */
@@ -1283,6 +1427,15 @@ tc35815_check_tx_stat(struct net_device
 	if (status & Tx_Under) {
 		lp->stats.tx_fifo_errors++;
 		msg = "Tx FIFO Underrun.";
+		if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) {
+		  lp->lstats.tx_underrun++;
+		  if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {
+		    struct tc35815_regs *tr =
+		      (struct tc35815_regs *)dev->base_addr;
+		    tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);
+		    msg = "Tx FIFO Underrun.Change Tx threshold to max.";
+		  }
+		}
 	}
 	if (status & Tx_Defer) {
 		lp->stats.tx_fifo_errors++;
@@ -1306,18 +1459,20 @@ tc35815_check_tx_stat(struct net_device
 		lp->stats.tx_heartbeat_errors++;
 		msg = "Signal Quality Error.";
 	}
-	if (msg)
+	if (msg && netif_msg_tx_err(lp))
 		printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
 }
 
+/* This handles TX complete events posted by the device
+ * via interrupts.
+ */
 static void
 tc35815_txdone(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
 	struct TxFD *txfd;
 	unsigned int fdctl;
-	int num_done = 0;
 
 	txfd = &lp->tfd_base[lp->tfd_end];
 	while (lp->tfd_start != lp->tfd_end &&
@@ -1326,22 +1481,30 @@ tc35815_txdone(struct net_device *dev)
 		struct sk_buff *skb;
 		unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
 
-		if (tc35815_debug > 2) {
+		if (netif_msg_tx_done(lp)) {
 			printk("%s: complete TxFD.\n", dev->name);
 			dump_txfd(txfd);
 		}
 		tc35815_check_tx_stat(dev, status);
 
-		skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem);
+		skb = le32_to_cpu(txfd->fd.FDSystem) != cpu_to_le32(0xffffffff) ?
+			lp->tx_skbs[le32_to_cpu(txfd->fd.FDSystem)].skb : NULL;
+		if (lp->tx_skbs[lp->tfd_end].skb != skb) {
+			printk("%s: tx_skbs mismatch.\n", dev->name);
+			panic_queues(dev);
+		}
 		if (skb) {
-			dev_kfree_skb_any(skb);
+			lp->stats.tx_bytes += skb->len;
+			pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE);
+			lp->tx_skbs[lp->tfd_end].skb = NULL;
+			lp->tx_skbs[lp->tfd_end].skb_dma = 0;
+			dev_kfree_skb_irq(skb);
 		}
-		txfd->fd.FDSystem = cpu_to_le32(0);
+		txfd->fd.FDSystem = cpu_to_le32(0xffffffff);
 
-		num_done++;
 		lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
 		txfd = &lp->tfd_base[lp->tfd_end];
-		if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) {
+		if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) {
 			printk("%s: TxFD FDNext invalid.\n", dev->name);
 			panic_queues(dev);
 		}
@@ -1367,21 +1530,23 @@ tc35815_txdone(struct net_device *dev)
 #ifdef GATHER_TXINT
 				txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
 #endif
-				if (tc35815_debug > 2) {
+				if (netif_msg_tx_queued(lp)) {
 					printk("%s: start TxFD on queue.\n",
 					       dev->name);
 					dump_txfd(txfd);
 				}
-				tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
+				tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
 			}
 			break;
 		}
 	}
 
-	if (num_done > 0 && lp->tbusy) {
-		lp->tbusy = 0;
-		netif_start_queue(dev);
-	}
+	/* If we had stopped the queue due to a "tx full"
+	 * condition, and space has now been made available,
+	 * wake up the queue.
+	 */
+	if (netif_queue_stopped(dev) && ! tc35815_tx_full(dev))
+		netif_wake_queue(dev);
 }
 
 /* The inverse routine to tc35815_open(). */
@@ -1389,18 +1554,18 @@ static int
 tc35815_close(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-
-	lp->tbusy = 1;
 	netif_stop_queue(dev);
 
 	/* Flush the Tx and disable Rx here. */
 
-	tc35815_chip_reset(dev);
+	del_timer(&lp->timer);		/* Kill if running	*/
+	tc35815_chip_reset((struct tc35815_regs*)dev->base_addr);
 	free_irq(dev->irq, dev);
 
 	tc35815_free_queues(dev);
 
 	return 0;
+
 }
 
 /*
@@ -1410,29 +1575,27 @@ tc35815_close(struct net_device *dev)
 static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-	unsigned long flags;
-
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
 	if (netif_running(dev)) {
-		spin_lock_irqsave(&lp->lock, flags);
 		/* Update the statistics from the device registers. */
 		lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);
-		spin_unlock_irqrestore(&lp->lock, flags);
 	}
 
 	return &lp->stats;
 }
 
-static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr)
+static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr)
 {
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
 	int cam_index = index * 6;
 	unsigned long cam_data;
 	unsigned long saved_addr;
 	saved_addr = tc_readl(&tr->CAM_Adr);
 
-	if (tc35815_debug > 1) {
+	if (netif_msg_hw(lp)) {
 		int i;
-		printk(KERN_DEBUG "%s: CAM %d:", cardname, index);
+		printk(KERN_DEBUG "%s: CAM %d:", MODNAME, index);
 		for (i = 0; i < 6; i++)
 			printk(" %02x", addr[i]);
 		printk("\n");
@@ -1459,14 +1622,6 @@ static void tc35815_set_cam_entry(struct
 		tc_writel(cam_data, &tr->CAM_Data);
 	}
 
-	if (tc35815_debug > 2) {
-		int i;
-		for (i = cam_index / 4; i < cam_index / 4 + 2; i++) {
-			tc_writel(i * 4, &tr->CAM_Adr);
-			printk("CAM 0x%x: %08lx",
-			       i * 4, tc_readl(&tr->CAM_Data));
-		}
-	}
 	tc_writel(saved_addr, &tr->CAM_Adr);
 }
 
@@ -1481,10 +1636,18 @@ static void tc35815_set_cam_entry(struct
 static void
 tc35815_set_multicast_list(struct net_device *dev)
 {
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
 
 	if (dev->flags&IFF_PROMISC)
 	{
+#ifdef WORKAROUND_100HALF_PROMISC
+		/* With some (all?) 100MHalf HUB, controller will hang
+		 * if we enabled promiscuous mode before linkup... */
+		struct tc35815_local *lp = dev->priv;
+		int pid = lp->phy_addr;
+		if (!(tc_mdio_read(dev, pid, MII_BMSR) & BMSR_LSTATUS))
+			return;
+#endif
 		/* Enable promiscuous mode */
 		tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
 	}
@@ -1506,7 +1669,7 @@ tc35815_set_multicast_list(struct net_de
 			if (!cur_addr)
 				break;
 			/* entry 0,1 is reserved. */
-			tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr);
+			tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr);
 			ena_bits |= CAM_Ena_Bit(i + 2);
 		}
 		tc_writel(ena_bits, &tr->CAM_Ena);
@@ -1518,122 +1681,735 @@ tc35815_set_multicast_list(struct net_de
 	}
 }
 
-static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr, int phy, int phy_reg)
+static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct tc35815_local *lp = dev->priv;
-	unsigned long data;
-	unsigned long flags;
+	strcpy(info->driver, MODNAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(lp->pci_dev));
+}
+
+static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct tc35815_local *lp = dev->priv;
+	spin_lock_irq(&lp->lock);
+	mii_ethtool_gset(&lp->mii, cmd);
+	spin_unlock_irq(&lp->lock);
+	return 0;
+}
+
+static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+#if 1	/* use our negotiation method... */
+	/* Verify the settings we care about. */
+	if (cmd->autoneg != AUTONEG_ENABLE &&
+	    cmd->autoneg != AUTONEG_DISABLE)
+		return -EINVAL;
+	if (cmd->autoneg == AUTONEG_DISABLE &&
+	    ((cmd->speed != SPEED_100 &&
+	      cmd->speed != SPEED_10) ||
+	     (cmd->duplex != DUPLEX_HALF &&
+	      cmd->duplex != DUPLEX_FULL)))
+		return -EINVAL;
+
+	/* Ok, do it to it. */
+	spin_lock_irq(&lp->lock);
+	del_timer(&lp->timer);
+	tc35815_start_auto_negotiation(dev, cmd);
+	spin_unlock_irq(&lp->lock);
+	rc = 0;
+#else
+	spin_lock_irq(&lp->lock);
+	rc = mii_ethtool_sset(&lp->mii, cmd);
+	spin_unlock_irq(&lp->lock);
+#endif
+	return rc;
+}
 
-	spin_lock_irqsave(&lp->lock, flags);
+static int tc35815_nway_reset(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+	spin_lock_irq(&lp->lock);
+	rc = mii_nway_restart(&lp->mii);
+	spin_unlock_irq(&lp->lock);
+	return rc;
+}
 
-	tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
+static u32 tc35815_get_link(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+	spin_lock_irq(&lp->lock);
+	rc = mii_link_ok(&lp->mii);
+	spin_unlock_irq(&lp->lock);
+	return rc;
+}
+
+static u32 tc35815_get_msglevel(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	return lp->msg_enable;
+}
+
+static void tc35815_set_msglevel(struct net_device *dev, u32 datum)
+{
+	struct tc35815_local *lp = dev->priv;
+	lp->msg_enable = datum;
+}
+
+static int tc35815_get_stats_count(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	return sizeof(lp->lstats) / sizeof(int);
+}
+
+static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
+{
+	struct tc35815_local *lp = dev->priv;
+	data[0] = lp->lstats.max_tx_qlen;
+	data[1] = lp->lstats.tx_ints;
+	data[2] = lp->lstats.rx_ints;
+	data[3] = lp->lstats.tx_underrun;
+}
+
+static struct {
+	const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+	{ "max_tx_qlen" },
+	{ "tx_ints" },
+	{ "rx_ints" },
+	{ "tx_underrun" },
+};
+
+static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+static struct ethtool_ops tc35815_ethtool_ops = {
+	.get_drvinfo		= tc35815_get_drvinfo,
+	.get_settings		= tc35815_get_settings,
+	.set_settings		= tc35815_set_settings,
+	.nway_reset		= tc35815_nway_reset,
+	.get_link		= tc35815_get_link,
+	.get_msglevel		= tc35815_get_msglevel,
+	.set_msglevel		= tc35815_set_msglevel,
+	.get_strings		= tc35815_get_strings,
+	.get_stats_count	= tc35815_get_stats_count,
+	.get_ethtool_stats	= tc35815_get_ethtool_stats,
+};
+
+static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	spin_lock_irq(&lp->lock);
+	rc = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
+	spin_unlock_irq(&lp->lock);
+
+	return rc;
+}
+
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	unsigned long data;
+	tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA);
 	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
 		;
 	data = tc_readl(&tr->MD_Data);
-	spin_unlock_irqrestore(&lp->lock, flags);
-	return data;
+	return data & 0xffff;
+}
+
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+			  int val)
+{
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	tc_writel(val, &tr->MD_Data);
+	tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA);
+	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+		;
 }
 
-static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg)
+/* Auto negotiation.  The scheme is very simple.  We have a timer routine
+ * that keeps watching the auto negotiation process as it progresses.
+ * The DP83840 is first told to start doing it's thing, we set up the time
+ * and place the timer state machine in it's initial state.
+ *
+ * Here the timer peeks at the DP83840 status registers at each click to see
+ * if the auto negotiation has completed, we assume here that the DP83840 PHY
+ * will time out at some point and just tell us what (didn't) happen.  For
+ * complete coverage we only allow so many of the ticks at this level to run,
+ * when this has expired we print a warning message and try another strategy.
+ * This "other" strategy is to force the interface into various speed/duplex
+ * configurations and we stop when we see a link-up condition before the
+ * maximum number of "peek" ticks have occurred.
+ *
+ * Once a valid link status has been detected we configure the BigMAC and
+ * the rest of the Happy Meal to speak the most efficient protocol we could
+ * get a clean link for.  The priority for link configurations, highest first
+ * is:
+ *                 100 Base-T Full Duplex
+ *                 100 Base-T Half Duplex
+ *                 10 Base-T Full Duplex
+ *                 10 Base-T Half Duplex
+ *
+ * We start a new timer now, after a successful auto negotiation status has
+ * been detected.  This timer just waits for the link-up bit to get set in
+ * the BMCR of the DP83840.  When this occurs we print a kernel log message
+ * describing the link type in use and the fact that it is up.
+ *
+ * If a fatal error of some sort is signalled and detected in the interrupt
+ * service routine, and the chip is reset, or the link is ifconfig'd down
+ * and then back up, this entire process repeats itself all over again.
+ */
+/* Note: Above comments are come from sunhme driver. */
+
+static int tc35815_try_next_permutation(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	unsigned long flags;
+	int pid = lp->phy_addr;
+	unsigned short bmcr;
 
-	spin_lock_irqsave(&lp->lock, flags);
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
 
-	tc_writel(d, &tr->MD_Data);
-	tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA);
-	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
-		;
-	spin_unlock_irqrestore(&lp->lock, flags);
+	/* Downgrade from full to half duplex.  Only possible via ethtool.  */
+	if (bmcr & BMCR_FULLDPLX) {
+		bmcr &= ~BMCR_FULLDPLX;
+		printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+		return 0;
+	}
+
+	/* Downgrade from 100 to 10. */
+	if (bmcr & BMCR_SPEED100) {
+		bmcr &= ~BMCR_SPEED100;
+		printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+		return 0;
+	}
+
+	/* We've tried everything. */
+	return -1;
 }
 
-static void tc35815_phy_chip_init(struct net_device *dev)
+static void
+tc35815_display_link_mode(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-	static int first = 1;
-	unsigned short ctl;
-
-	if (first) {
-		unsigned short id0, id1;
-		int count;
-		first = 0;
-
-		/* first data written to the PHY will be an ID number */
-		tc_phy_write(dev, 0, tr, 0, MII_CONTROL);	/* ID:0 */
-#if 0
-		tc_phy_write(dev, MIICNTL_RESET, tr, 0, MII_CONTROL);
-		printk(KERN_INFO "%s: Resetting PHY...", dev->name);
-		while (tc_phy_read(dev, tr, 0, MII_CONTROL) & MIICNTL_RESET)
-			;
-		printk("\n");
-		tc_phy_write(dev, MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0,
-			     MII_CONTROL);
+	int pid = lp->phy_addr;
+	unsigned short lpa, bmcr;
+	char *speed = "", *duplex = "";
+
+	lpa = tc_mdio_read(dev, pid, MII_LPA);
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+		speed = "100Mb/s";
+	else
+		speed = "10Mb/s";
+	if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+		duplex = "Full Duplex";
+	else
+		duplex = "Half Duplex";
+
+	if (netif_msg_link(lp))
+		printk(KERN_INFO "%s: Link is up at %s, %s.\n",
+		       dev->name, speed, duplex);
+	printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+	       dev->name,
+	       bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+}
+
+static void tc35815_display_forced_link_mode(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmcr;
+	char *speed = "", *duplex = "";
+
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	if (bmcr & BMCR_SPEED100)
+		speed = "100Mb/s";
+	else
+		speed = "10Mb/s";
+	if (bmcr & BMCR_FULLDPLX)
+		duplex = "Full Duplex.\n";
+	else
+		duplex = "Half Duplex.\n";
+
+	if (netif_msg_link(lp))
+		printk(KERN_INFO "%s: Link has been forced up at %s, %s",
+		       dev->name, speed, duplex);
+}
+
+static void tc35815_set_link_modes(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	int pid = lp->phy_addr;
+	unsigned short bmcr, lpa;
+
+	if (lp->timer_state == arbwait) {
+		printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+		       dev->name,
+		       tc_mdio_read(dev, pid, MII_BMCR),
+		       tc_mdio_read(dev, pid, MII_BMSR),
+		       tc_mdio_read(dev, pid, MII_LPA));
+		lpa = tc_mdio_read(dev, pid, MII_LPA);
+		if (!(lpa & (LPA_10HALF | LPA_10FULL |
+			     LPA_100HALF | LPA_100FULL))) {
+			/* fall back to 10HALF */
+			printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n",
+			       dev->name, lpa);
+			lpa = LPA_10HALF;
+		}
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+			lp->fullduplex = 1;
+		else
+			lp->fullduplex = 0;
+	} else {
+		/* Forcing a link mode. */
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		if (bmcr & BMCR_FULLDPLX)
+			lp->fullduplex = 1;
+		else
+			lp->fullduplex = 0;
+	}
+
+	tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl);
+	if (lp->fullduplex) {
+		tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+	} else {
+		tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl);
+	}
+	tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl);
+
+#ifdef WORKAROUND_LOSTCAR
+	/* WORKAROUND: enable LostCrS only if half duplex operation */
+	if (!lp->fullduplex)
+		tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl);
+#endif
+	lp->mii.full_duplex = lp->fullduplex;
+}
+
+static void tc35815_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmsr, bmcr, lpa;
+	int restart_timer = 0;
+
+	spin_lock_irq(&lp->lock);
+
+	lp->timer_ticks++;
+	switch (lp->timer_state) {
+	case arbwait:
+		/*
+		 * Only allow for 5 ticks, thats 10 seconds and much too
+		 * long to wait for arbitration to complete.
+		 */
+		/* TC35815 need more times... */
+		if (lp->timer_ticks >= 10) {
+			/* Enter force mode. */
+			if (!options.doforce) {
+				printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+				       " cable probblem?\n", dev->name);
+				/* Try to restart the adaptor. */
+				tc35815_restart(dev);
+				goto out;
+			}
+			printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+			       " trying force link mode\n", dev->name);
+			printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name,
+			       tc_mdio_read(dev, pid, MII_BMCR),
+			       tc_mdio_read(dev, pid, MII_BMSR));
+			bmcr = BMCR_SPEED100;
+			tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+			/*
+			 * OK, seems we need do disable the transceiver
+			 * for the first tick to make sure we get an
+			 * accurate link state at the second tick.
+			 */
+
+			lp->timer_state = ltrywait;
+			lp->timer_ticks = 0;
+			restart_timer = 1;
+		} else {
+			/* Anything interesting happen? */
+			bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+			if (bmsr & BMSR_ANEGCOMPLETE) {
+				/* Just what we've been waiting for... */
+				tc35815_set_link_modes(dev);
+
+				/*
+				 * Success, at least so far, advance our state
+				 * engine.
+				 */
+				lp->timer_state = lupwait;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case lupwait:
+		/*
+		 * Auto negotiation was successful and we are awaiting a
+		 * link up status.  I have decided to let this timer run
+		 * forever until some sort of error is signalled, reporting
+		 * a message to the user at 10 second intervals.
+		 */
+		bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+		if (bmsr & BMSR_LSTATUS) {
+			/*
+			 * Wheee, it's up, display the link mode in use and put
+			 * the timer to sleep.
+			 */
+			tc35815_display_link_mode(dev);
+			netif_carrier_on(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+			/* delayed promiscuous enabling */
+			if (dev->flags & IFF_PROMISC)
+				tc35815_set_multicast_list(dev);
+#endif
+#if 1
+			lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+			lp->timer_state = lcheck;
+			restart_timer = 1;
+#else
+			lp->timer_state = asleep;
+			restart_timer = 0;
 #endif
-		id0 = tc_phy_read(dev, tr, 0, MII_PHY_ID0);
-		id1 = tc_phy_read(dev, tr, 0, MII_PHY_ID1);
-		printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name,
-		       id0, id1);
-		if (lp->option & TC35815_OPT_10M) {
-			lp->linkspeed = 10;
-			lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
-		} else if (lp->option & TC35815_OPT_100M) {
-			lp->linkspeed = 100;
-			lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
 		} else {
-			/* auto negotiation */
-			unsigned long neg_result;
-			tc_phy_write(dev, MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL);
-			printk(KERN_INFO "%s: Auto Negotiation...", dev->name);
-			count = 0;
-			while (!(tc_phy_read(dev, tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) {
-				if (count++ > 5000) {
-					printk(" failed. Assume 10Mbps\n");
-					lp->linkspeed = 10;
-					lp->fullduplex = 0;
-					goto done;
+			if (lp->timer_ticks >= 10) {
+				printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
+				       "not completely up.\n", dev->name);
+				lp->timer_ticks = 0;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case ltrywait:
+		/*
+		 * Making the timeout here too long can make it take
+		 * annoyingly long to attempt all of the link mode
+		 * permutations, but then again this is essentially
+		 * error recovery code for the most part.
+		 */
+		bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		if (lp->timer_ticks == 1) {
+			/*
+			 * Re-enable transceiver, we'll re-enable the
+			 * transceiver next tick, then check link state
+			 * on the following tick.
+			 */
+			restart_timer = 1;
+			break;
+		}
+		if (lp->timer_ticks == 2) {
+			restart_timer = 1;
+			break;
+		}
+		if (bmsr & BMSR_LSTATUS) {
+			/* Force mode selection success. */
+			tc35815_display_forced_link_mode(dev);
+			netif_carrier_on(dev);
+			tc35815_set_link_modes(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+			/* delayed promiscuous enabling */
+			if (dev->flags & IFF_PROMISC)
+				tc35815_set_multicast_list(dev);
+#endif
+#if 1
+			lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+			lp->timer_state = lcheck;
+			restart_timer = 1;
+#else
+			lp->timer_state = asleep;
+			restart_timer = 0;
+#endif
+		} else {
+			if (lp->timer_ticks >= 4) { /* 6 seconds or so... */
+				int ret;
+
+				ret = tc35815_try_next_permutation(dev);
+				if (ret == -1) {
+					/*
+					 * Aieee, tried them all, reset the
+					 * chip and try all over again.
+					 */
+					printk(KERN_NOTICE "%s: Link down, "
+					       "cable problem?\n",
+					       dev->name);
+
+					/* Try to restart the adaptor. */
+					tc35815_restart(dev);
+					goto out;
 				}
-				if (count % 512 == 0)
-					printk(".");
-				mdelay(1);
+				lp->timer_ticks = 0;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case lcheck:
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		lpa = tc_mdio_read(dev, pid, MII_LPA);
+		if (bmcr & (BMCR_PDOWN | BMCR_ISOLATE | BMCR_RESET)) {
+			printk(KERN_ERR "%s: PHY down? (BMCR %x)\n", dev->name,
+			       bmcr);
+		} else if ((lp->saved_lpa ^ lpa) &
+			   (LPA_100FULL|LPA_100HALF|LPA_10FULL|LPA_10HALF)) {
+			printk(KERN_NOTICE "%s: link status changed"
+			       " (BMCR %x LPA %x->%x)\n", dev->name,
+			       bmcr, lp->saved_lpa, lpa);
+		} else {
+			/* go on */
+			restart_timer = 1;
+			break;
+		}
+		/* Try to restart the adaptor. */
+		tc35815_restart(dev);
+		goto out;
+
+	case asleep:
+	default:
+		/* Can't happens.... */
+		printk(KERN_ERR "%s: Aieee, link timer is asleep but we got "
+		       "one anyways!\n", dev->name);
+		restart_timer = 0;
+		lp->timer_ticks = 0;
+		lp->timer_state = asleep; /* foo on you */
+		break;
+	}
+
+	if (restart_timer) {
+		lp->timer.expires = jiffies + ((12 * HZ)/10); /* 1.2s */
+		add_timer(&lp->timer);
+	}
+out:
+	spin_unlock_irq(&lp->lock);
+}
+
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+					   struct ethtool_cmd *ep)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmsr, bmcr, advertize;
+	int timeout;
+
+	netif_carrier_off(dev);
+	bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	advertize = tc_mdio_read(dev, pid, MII_ADVERTISE);
+
+	if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+		if (options.speed || options.duplex) {
+			/* Advertise only specified configuration. */
+			advertize &= ~(ADVERTISE_10HALF |
+				       ADVERTISE_10FULL |
+				       ADVERTISE_100HALF |
+				       ADVERTISE_100FULL);
+			if (options.speed != 10) {
+				if (options.duplex != 1)
+					advertize |= ADVERTISE_100FULL;
+				if (options.duplex != 2)
+					advertize |= ADVERTISE_100HALF;
 			}
-			printk(" done.\n");
-			neg_result = tc_phy_read(dev, tr, 0, MII_ANLPAR);
-			if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX))
-				lp->linkspeed = 100;
+			if (options.speed != 100) {
+				if (options.duplex != 1)
+					advertize |= ADVERTISE_10FULL;
+				if (options.duplex != 2)
+					advertize |= ADVERTISE_10HALF;
+			}
+			if (options.speed == 100)
+				bmcr |= BMCR_SPEED100;
+			else if (options.speed == 10)
+				bmcr &= ~BMCR_SPEED100;
+			if (options.duplex == 2)
+				bmcr |= BMCR_FULLDPLX;
+			else if (options.duplex == 1)
+				bmcr &= ~BMCR_FULLDPLX;
+		} else {
+			/* Advertise everything we can support. */
+			if (bmsr & BMSR_10HALF)
+				advertize |= ADVERTISE_10HALF;
 			else
-				lp->linkspeed = 10;
-			if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX))
-				lp->fullduplex = 1;
+				advertize &= ~ADVERTISE_10HALF;
+			if (bmsr & BMSR_10FULL)
+				advertize |= ADVERTISE_10FULL;
 			else
-				lp->fullduplex = 0;
-		done:
-			;
+				advertize &= ~ADVERTISE_10FULL;
+			if (bmsr & BMSR_100HALF)
+				advertize |= ADVERTISE_100HALF;
+			else
+				advertize &= ~ADVERTISE_100HALF;
+			if (bmsr & BMSR_100FULL)
+				advertize |= ADVERTISE_100FULL;
+			else
+				advertize &= ~ADVERTISE_100FULL;
 		}
+
+		tc_mdio_write(dev, pid, MII_ADVERTISE, advertize);
+
+		/* Enable Auto-Negotiation, this is usually on already... */
+		bmcr |= BMCR_ANENABLE;
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+		/* Restart it to make sure it is going. */
+		bmcr |= BMCR_ANRESTART;
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+		printk(KERN_DEBUG "%s: ADVERTISE %x BMCR %x\n", dev->name, advertize, bmcr);
+
+		/* BMCR_ANRESTART self clears when the process has begun. */
+		timeout = 64;  /* More than enough. */
+		while (--timeout) {
+			bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+			if (!(bmcr & BMCR_ANRESTART))
+				break; /* got it. */
+			udelay(10);
+		}
+		if (!timeout) {
+			printk(KERN_ERR "%s: TC35815 would not start auto "
+			       "negotiation BMCR=0x%04x\n",
+			       dev->name, bmcr);
+			printk(KERN_NOTICE "%s: Performing force link "
+			       "detection.\n", dev->name);
+			goto force_link;
+		} else {
+			printk(KERN_DEBUG "%s: auto negotiation started.\n", dev->name);
+			lp->timer_state = arbwait;
+		}
+	} else {
+force_link:
+		/* Force the link up, trying first a particular mode.
+		 * Either we are here at the request of ethtool or
+		 * because the Happy Meal would not start to autoneg.
+		 */
+
+		/* Disable auto-negotiation in BMCR, enable the duplex and
+		 * speed setting, init the timer state machine, and fire it off.
+		 */
+		if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+			bmcr = BMCR_SPEED100;
+		} else {
+			if (ep->speed == SPEED_100)
+				bmcr = BMCR_SPEED100;
+			else
+				bmcr = 0;
+			if (ep->duplex == DUPLEX_FULL)
+				bmcr |= BMCR_FULLDPLX;
+		}
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+		/* OK, seems we need do disable the transceiver for the first
+		 * tick to make sure we get an accurate link state at the
+		 * second tick.
+		 */
+		lp->timer_state = ltrywait;
 	}
 
-	ctl = 0;
-	if (lp->linkspeed == 100)
-		ctl |= MIICNTL_SPEED;
-	if (lp->fullduplex)
-		ctl |= MIICNTL_FDX;
-	tc_phy_write(dev, ctl, tr, 0, MII_CONTROL);
+	del_timer(&lp->timer);
+	lp->timer_ticks = 0;
+	lp->timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */
+	lp->timer.data = (unsigned long) dev;
+	lp->timer.function = &tc35815_timer;
+	add_timer(&lp->timer);
+}
 
-	if (lp->fullduplex) {
-		tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+static void tc35815_find_phy(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short id0;
+
+	/* find MII phy */
+	for (pid = 31; pid >= 0; pid--) {
+		id0 = tc_mdio_read(dev, pid, MII_BMSR);
+		if (id0 != 0xffff && id0 != 0x0000 &&
+		    (id0 & BMSR_RESV) != (0xffff & BMSR_RESV) /* paranoia? */
+			) {
+			lp->phy_addr = pid;
+			break;
+		}
 	}
+	if (pid < 0) {
+		printk(KERN_ERR "%s: No MII Phy found.\n",
+		       dev->name);
+		lp->phy_addr = pid = 0;
+	}
+
+	lp->mii_id[0] = tc_mdio_read(dev, pid, MII_PHYSID1);
+	lp->mii_id[1] = tc_mdio_read(dev, pid, MII_PHYSID2);
+	if (netif_msg_hw(lp))
+		printk(KERN_INFO "%s: PHY(%02x) ID %04x %04x\n", dev->name,
+		       pid, lp->mii_id[0], lp->mii_id[1]);
 }
 
-static void tc35815_chip_reset(struct net_device *dev)
+static void tc35815_phy_chip_init(struct net_device *dev)
 {
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmcr;
+	struct ethtool_cmd ecmd, *ep;
+
+	/* dis-isolate if needed. */
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	if (bmcr & BMCR_ISOLATE) {
+		int count = 32;
+		printk(KERN_DEBUG "%s: unisolating...", dev->name);
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr & ~BMCR_ISOLATE);
+		while (--count) {
+			if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_ISOLATE))
+				break;
+			udelay(20);
+		}
+		printk(" %s.\n", count ? "done" : "failed");
+	}
+
+	if (options.speed && options.duplex) {
+		ecmd.autoneg = AUTONEG_DISABLE;
+		ecmd.speed = options.speed == 10 ? SPEED_10 : SPEED_100;
+		ecmd.duplex = options.duplex == 1 ? DUPLEX_HALF : DUPLEX_FULL;
+		ep = &ecmd;
+	} else {
+		ep = NULL;
+	}
+	tc35815_start_auto_negotiation(dev, ep);
+}
 
+static void tc35815_chip_reset(struct tc35815_regs *tr)
+{
+	int i;
 	/* reset the controller */
 	tc_writel(MAC_Reset, &tr->MAC_Ctl);
-	while (tc_readl(&tr->MAC_Ctl) & MAC_Reset)
-		;
-
+	udelay(4); /* 3200ns */
+	i = 0;
+	while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) {
+		if (i++ > 100) {
+			printk(KERN_ERR "%s: MAC reset failed.\n", MODNAME);
+			break;
+		}
+		mdelay(1);
+	}
 	tc_writel(0, &tr->MAC_Ctl);
 
 	/* initialize registers to default value */
@@ -1651,90 +2427,118 @@ static void tc35815_chip_reset(struct ne
 	tc_writel(0, &tr->CAM_Ena);
 	(void)tc_readl(&tr->Miss_Cnt);	/* Read to clear */
 
+	/* initialize internal SRAM */
+	tc_writel(DMA_TestMode, &tr->DMA_Ctl);
+	for (i = 0; i < 0x1000; i += 4) {
+		tc_writel(i, &tr->CAM_Adr);
+		tc_writel(0, &tr->CAM_Data);
+	}
+	tc_writel(0, &tr->DMA_Ctl);
 }
 
 static void tc35815_chip_init(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-	unsigned long flags;
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
 	unsigned long txctl = TX_CTL_CMD;
 
 	tc35815_phy_chip_init(dev);
 
 	/* load station address to CAM */
-	tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr);
+	tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr);
 
 	/* Enable CAM (broadcast and unicast) */
 	tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
 	tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
 
-	spin_lock_irqsave(&lp->lock, flags);
-
 	tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
-
 	tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize);	/* Packing */
 	tc_writel(0, &tr->TxPollCtr);	/* Batch mode */
 	tc_writel(TX_THRESHOLD, &tr->TxThrsh);
 	tc_writel(INT_EN_CMD, &tr->Int_En);
 
 	/* set queues */
-	tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas);
+	tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas);
 	tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
 		  &tr->FDA_Lim);
 	/*
 	 * Activation method:
-	 * First, enable eht MAC Transmitter and the DMA Receive circuits.
+	 * First, enable the MAC Transmitter and the DMA Receive circuits.
 	 * Then enable the DMA Transmitter and the MAC Receive circuits.
 	 */
-	tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr);	/* start DMA receiver */
+	tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr);	/* start DMA receiver */
 	tc_writel(RX_CTL_CMD, &tr->Rx_Ctl);	/* start MAC receiver */
+
 	/* start MAC transmitter */
+#ifdef WORKAROUND_LOSTCAR
 	/* WORKAROUND: ignore LostCrS in full duplex operation */
-	if (lp->fullduplex)
+	if ((lp->timer_state != asleep && lp->timer_state != lcheck) ||
+	    lp->fullduplex)
 		txctl = TX_CTL_CMD & ~Tx_EnLCarr;
+#endif
 #ifdef GATHER_TXINT
 	txctl &= ~Tx_EnComp;	/* disable global tx completion int. */
 #endif
 	tc_writel(txctl, &tr->Tx_Ctl);
-#if 0	/* No need to polling */
-	tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr);	/* start DMA transmitter */
-#endif
-	spin_unlock_irqrestore(&lp->lock, flags);
 }
 
-static struct pci_driver tc35815_driver = {
-	.name = TC35815_MODULE_NAME,
-	.probe = tc35815_probe,
-	.remove = NULL,
-	.id_table = tc35815_pci_tbl,
+static struct pci_driver tc35815_pci_driver = {
+	.name		= MODNAME,
+	.id_table	= tc35815_pci_tbl,
+	.probe		= tc35815_init_one,
+	.remove		= __devexit_p(tc35815_remove_one),
 };
 
+module_param_named(speed, options.speed, int, 0);
+MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps");
+module_param_named(duplex, options.duplex, int, 0);
+MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full");
+module_param_named(doforce, options.doforce, int, 0);
+MODULE_PARM_DESC(doforce, "try force link mode if auto-negotiation failed");
+
+#ifndef MODULE
+static int __init tc35815_setup(char *str)
+{
+	static struct {
+		char *name;
+		int *val;
+	} opts[] = {
+		{ "speed:", &options.speed },
+		{ "duplex:", &options.duplex },
+		{ "doforce:", &options.doforce },
+	};
+	int i;
+	char *p;
+	p = str;
+	while (p) {
+		for (i = 0; i < ARRAY_SIZE(opts); i++) {
+			int optlen = strlen(opts[i].name);
+			if (strncmp(p, opts[i].name, optlen) == 0) {
+				*opts[i].val = simple_strtol(p + optlen, NULL, 0);
+				break;
+			}
+		}
+		p = strchr(p, ',');
+		if (p)
+			p++;
+	}
+	return 1;
+}
+__setup("tc35815=", tc35815_setup);
+#endif
+
 static int __init tc35815_init_module(void)
 {
-	return pci_register_driver(&tc35815_driver);
+	return pci_register_driver(&tc35815_pci_driver);
 }
 
 static void __exit tc35815_cleanup_module(void)
 {
-	struct net_device *next_dev;
-
-	/*
-	 * TODO: implement a tc35815_driver.remove hook, and
-	 * move this code into that function.  Then, delete
-	 * all root_tc35815_dev list handling code.
-	 */
-	while (root_tc35815_dev) {
-		struct net_device *dev = root_tc35815_dev;
-		next_dev = ((struct tc35815_local *)dev->priv)->next_module;
-		iounmap((void *)(dev->base_addr));
-		unregister_netdev(dev);
-		free_netdev(dev);
-		root_tc35815_dev = next_dev;
-	}
-
-	pci_unregister_driver(&tc35815_driver);
+	pci_unregister_driver(&tc35815_pci_driver);
 }
 
 module_init(tc35815_init_module);
 module_exit(tc35815_cleanup_module);
+
+MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index e19e199..6a58784 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1459,6 +1459,7 @@
 
 #define PCI_VENDOR_ID_TOSHIBA_2		0x102f
 #define PCI_DEVICE_ID_TOSHIBA_TC35815CF	0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU	0x0031
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE	0x0105
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC	0x0108
 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3

From anemo@mba.ocn.ne.jp Fri Mar  2 14:26:01 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 14:26:06 +0000 (GMT)
Received: from mba.ocn.ne.jp ([210.190.142.172]:22772 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S28639872AbXCBOZp (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 2 Mar 2007 14:25:45 +0000
Received: from localhost (p2238-ipad211funabasi.chiba.ocn.ne.jp [58.91.158.238])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id 920EDB809; Fri,  2 Mar 2007 23:24:22 +0900 (JST)
Date:	Fri, 02 Mar 2007 23:24:23 +0900 (JST)
Message-Id: <20070302.232423.93208109.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org, netdev@vger.kernel.org, jeff@garzik.org,
	sshtylyov@ru.mvista.com
Subject: [PATCH 2/2] tc35815 driver update (part 2)
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14309
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

More updates for tc35815 driver, including:

* TX4939 support.
* NETPOLL support.
* NAPI support. (disabled by default)
* Reduce memcpy on receiving.
* PM support.
* Many cleanups and bugfixes.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
 drivers/net/tc35815.c   |  827 +++++++++++++++++++++++++++++++++++-----------
 include/linux/pci_ids.h |    1 
 2 files changed, 632 insertions(+), 196 deletions(-)

diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 0cf1f87..ec888db 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -38,9 +38,33 @@
  *		Add workaround for 100MHalf HUB.
  *	1.22	Minor fix.
  *	1.23	Minor cleanup.
+ *	1.24	Remove tc35815_setup since new stype option
+ *		("tc35815.speed=10", etc.) can be used for 2.6 kernel.
+ *	1.25	TX4939 support.
+ *	1.26	Minor cleanup.
+ *	1.27	Move TX4939 PCFG.SPEEDn control code out from this driver.
+ *		Cleanup init_dev_addr. (NETDEV_REGISTER event notifier
+ *		can overwrite dev_addr)
+ *		support ETHTOOL_GPERMADDR.
+ *	1.28	Minor cleanup.
+ *	1.29	support netpoll.
+ *	1.30	Minor cleanup.
+ *	1.31	NAPI support. (disabled by default)
+ *		Use DMA_RxAlign_2 if possible.
+ *		Do not use PackedBuffer.
+ *		Cleanup.
+ *	1.32	Fix free buffer management on non-PackedBuffer mode.
+ *	1.33	Fix netpoll build.
+ *	1.34	Fix netpoll locking.  "BH rule" for NAPI is not enough with
+ *		netpoll, hard_start_xmit might be called from irq context.
+ *		PM support.
  */
 
-#define DRV_VERSION	"1.23"
+#ifdef TC35815_NAPI
+#define DRV_VERSION	"1.34-NAPI"
+#else
+#define DRV_VERSION	"1.34"
+#endif
 static const char *version = "tc35815.c:v" DRV_VERSION "\n";
 #define MODNAME			"tc35815"
 
@@ -71,23 +95,27 @@ static const char *version = "tc35815.c:
 #define GATHER_TXINT	/* On-Demand Tx Interrupt */
 #define WORKAROUND_LOSTCAR
 #define WORKAROUND_100HALF_PROMISC
+/* #define TC35815_USE_PACKEDBUFFER */
 
 typedef enum {
 	TC35815CF = 0,
 	TC35815_NWU,
+	TC35815_TX4939,
 } board_t;
 
 /* indexed by board_t, above */
-static struct {
+static const struct {
 	const char *name;
 } board_info[] __devinitdata = {
 	{ "TOSHIBA TC35815CF 10/100BaseTX" },
 	{ "TOSHIBA TC35815 with Wake on LAN" },
+	{ "TOSHIBA TC35815/TX4939" },
 };
 
-static struct pci_device_id tc35815_pci_tbl[] = {
-	{PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TC35815CF },
-	{PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TC35815_NWU },
+static const struct pci_device_id tc35815_pci_tbl[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
+	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
+	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
 	{0,}
 };
 MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
@@ -140,6 +168,11 @@ struct tc35815_regs {
  * Bit assignments
  */
 /* DMA_Ctl bit asign ------------------------------------------------------- */
+#define DMA_RxAlign            0x00c00000 /* 1:Reception Alignment           */
+#define DMA_RxAlign_1          0x00400000
+#define DMA_RxAlign_2          0x00800000
+#define DMA_RxAlign_3          0x00c00000
+#define DMA_M66EnStat          0x00080000 /* 1:66MHz Enable State            */
 #define DMA_IntMask            0x00040000 /* 1:Interupt mask                 */
 #define DMA_SWIntReq           0x00020000 /* 1:Software Interrupt request    */
 #define DMA_TxWakeUp           0x00010000 /* 1:Transmit Wake Up              */
@@ -351,6 +384,8 @@ struct BDesc {
 	Int_SSysErrEn  | Int_RMasAbtEn | Int_RTargAbtEn | \
 	Int_STargAbtEn | \
 	Int_BLExEn  | Int_FDAExEn) /* maybe 0xb7f*/
+#define DMA_CTL_CMD	DMA_BURST_SIZE
+#define HAVE_DMA_RXALIGN(lp)	likely((lp)->boardtype != TC35815CF)
 
 /* Tuning parameters */
 #define DMA_BURST_SIZE	32
@@ -358,12 +393,28 @@ struct BDesc {
 #define TX_THRESHOLD_MAX 1536       /* used threshold with packet max byte for low pci transfer ability.*/
 #define TX_THRESHOLD_KEEP_LIMIT 10  /* setting threshold max value when overrun error occured this count. */
 
+/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */
+#ifdef TC35815_USE_PACKEDBUFFER
 #define FD_PAGE_NUM 2
-#define FD_PAGE_ORDER 1
-/* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */
-#define RX_BUF_PAGES	8	/* >= 2 */
+#define RX_BUF_NUM	8	/* >= 2 */
 #define RX_FD_NUM	250	/* >= 32 */
 #define TX_FD_NUM	128
+#define RX_BUF_SIZE	PAGE_SIZE
+#else /* TC35815_USE_PACKEDBUFFER */
+#define FD_PAGE_NUM 4
+#define RX_BUF_NUM	128	/* < 256 */
+#define RX_FD_NUM	256	/* >= 32 */
+#define TX_FD_NUM	128
+#if RX_CTL_CMD & Rx_LongEn
+#define RX_BUF_SIZE	PAGE_SIZE
+#elif RX_CTL_CMD & Rx_StripCRC
+#define RX_BUF_SIZE	ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */
+#else
+#define RX_BUF_SIZE	ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */
+#endif
+#endif /* TC35815_USE_PACKEDBUFFER */
+#define RX_FD_RESERVE	(2 / 2)	/* max 2 BD per RxFD */
+#define NAPI_WEIGHT	16
 
 struct TxFD {
 	struct FDesc fd;
@@ -378,14 +429,14 @@ struct RxFD {
 
 struct FrFD {
 	struct FDesc fd;
-	struct BDesc bd[RX_BUF_PAGES];
+	struct BDesc bd[RX_BUF_NUM];
 };
 
 
 #define tc_readl(addr)	readl(addr)
 #define tc_writel(d, addr)	writel(d, addr)
 
-#define TC35815_TX_TIMEOUT  ((400*HZ)/1000)
+#define TC35815_TX_TIMEOUT  msecs_to_jiffies(400)
 
 /* Timer state engine. */
 enum tc35815_timer_state {
@@ -426,10 +477,14 @@ struct tc35815_local {
 	/*
 	 * Transmitting: Batch Mode.
 	 *	1 BD in 1 TxFD.
-	 * Receiving: Packing Mode.
+	 * Receiving: Packing Mode. (TC35815_USE_PACKEDBUFFER)
 	 *	1 circular FD for Free Buffer List.
-	 *	RX_BUF_PAGES BD in Free Buffer FD.
+	 *	RX_BUF_NUM BD in Free Buffer FD.
 	 *	One Free Buffer BD has PAGE_SIZE data buffer.
+	 * Or Non-Packing Mode.
+	 *	1 circular FD for Free Buffer List.
+	 *	RX_BUF_NUM BD in Free Buffer FD.
+	 *	One Free Buffer BD has ETH_FRAME_LEN data buffer.
 	 */
 	void * fd_buf;	/* for TxFD, RxFD, FrFD */
 	dma_addr_t fd_buf_dma;
@@ -440,41 +495,42 @@ struct tc35815_local {
 	struct RxFD *rfd_limit;
 	struct RxFD *rfd_cur;
 	struct FrFD *fbl_ptr;
+#ifdef TC35815_USE_PACKEDBUFFER
 	unsigned char fbl_curid;
-	void * data_buf[RX_BUF_PAGES];		/* packing */
-	dma_addr_t data_buf_dma[RX_BUF_PAGES];		/* packing */
-
+	void * data_buf[RX_BUF_NUM];		/* packing */
+	dma_addr_t data_buf_dma[RX_BUF_NUM];
 	struct {
 		struct sk_buff *skb;
 		dma_addr_t skb_dma;
 	} tx_skbs[TX_FD_NUM];
+#else
+	unsigned int fbl_count;
+	struct {
+		struct sk_buff *skb;
+		dma_addr_t skb_dma;
+	} tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM];
+#endif
 	struct mii_if_info mii;
 	unsigned short mii_id[2];
 	u32 msg_enable;
+	board_t boardtype;
 };
 
 static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt)
 {
 	return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf);
 }
+#ifdef DEBUG
 static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
 {
 	return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma));
 }
-static inline dma_addr_t rxbuf_virt_to_bus(struct tc35815_local *lp, void *virt)
-{
-	int i;
-	for (i = 0; i < RX_BUF_PAGES; i++) {
-		if ((u8 *)virt >= (u8 *)lp->data_buf[i] &&
-		    (u8 *)virt < (u8 *)lp->data_buf[i] + PAGE_SIZE)
-			return lp->data_buf_dma[i] + ((u8 *)virt - (u8 *)lp->data_buf[i]);
-	}
-	return 0;
-}
+#endif
+#ifdef TC35815_USE_PACKEDBUFFER
 static inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
 {
 	int i;
-	for (i = 0; i < RX_BUF_PAGES; i++) {
+	for (i = 0; i < RX_BUF_NUM; i++) {
 		if (bus >= lp->data_buf_dma[i] &&
 		    bus < lp->data_buf_dma[i] + PAGE_SIZE)
 			return (void *)((u8 *)lp->data_buf[i] +
@@ -513,29 +569,67 @@ static void free_rxbuf_page(struct pci_d
 	pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle);
 #endif
 }
+#else /* TC35815_USE_PACKEDBUFFER */
+static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev,
+				       struct pci_dev *hwdev,
+				       dma_addr_t *dma_handle)
+{
+	struct sk_buff *skb;
+	skb = dev_alloc_skb(RX_BUF_SIZE);
+	if (!skb)
+		return NULL;
+	skb->dev = dev;
+	*dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE,
+				     PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(*dma_handle)) {
+		dev_kfree_skb_any(skb);
+		return NULL;
+	}
+	skb_reserve(skb, 2);	/* make IP header 4byte aligned */
+	return skb;
+}
+
+static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle)
+{
+	pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE,
+			 PCI_DMA_FROMDEVICE);
+	dev_kfree_skb_any(skb);
+}
+#endif /* TC35815_USE_PACKEDBUFFER */
 
 /* Index to functions, as function prototypes. */
 
 static int	tc35815_open(struct net_device *dev);
 static int	tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
+static irqreturn_t	tc35815_interrupt(int irq, void *dev_id);
+#ifdef TC35815_NAPI
+static int	tc35815_rx(struct net_device *dev, int limit);
+static int	tc35815_poll(struct net_device *dev, int *budget);
+#else
 static void	tc35815_rx(struct net_device *dev);
+#endif
 static void	tc35815_txdone(struct net_device *dev);
 static int	tc35815_close(struct net_device *dev);
 static struct	net_device_stats *tc35815_get_stats(struct net_device *dev);
 static void	tc35815_set_multicast_list(struct net_device *dev);
 static void     tc35815_tx_timeout(struct net_device *dev);
 static int	tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct ethtool_ops tc35815_ethtool_ops;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void	tc35815_poll_controller(struct net_device *dev);
+#endif
+static const struct ethtool_ops tc35815_ethtool_ops;
 
 /* Example routines you must write ;->. */
-static void 	tc35815_chip_reset(struct tc35815_regs *tr);
+static void 	tc35815_chip_reset(struct net_device *dev);
 static void 	tc35815_chip_init(struct net_device *dev);
 static void	tc35815_find_phy(struct net_device *dev);
 static void 	tc35815_phy_chip_init(struct net_device *dev);
 
+#ifdef DEBUG
 static void	panic_queues(struct net_device *dev);
+#endif
 
+static void tc35815_timer(unsigned long data);
 static void tc35815_start_auto_negotiation(struct net_device *dev,
 					   struct ethtool_cmd *ep);
 static int tc_mdio_read(struct net_device *dev, int phy_id, int location);
@@ -544,9 +638,11 @@ static void tc_mdio_write(struct net_dev
 
 static void __devinit tc35815_init_dev_addr (struct net_device *dev)
 {
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	int i;
 
+	/* dev_addr will be overwritten on NETDEV_REGISTER event */
 	while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
 		;
 	for (i = 0; i < 6; i += 2) {
@@ -563,7 +659,7 @@ static void __devinit tc35815_init_dev_a
 static int __devinit tc35815_init_one (struct pci_dev *pdev,
 				       const struct pci_device_id *ent)
 {
-	void *ioaddr = NULL;
+	void __iomem *ioaddr = NULL;
 	struct net_device *dev;
 	struct tc35815_local *lp;
 	int rc;
@@ -572,20 +668,20 @@ static int __devinit tc35815_init_one (s
 	static int printed_version;
 	if (!printed_version++) {
 		printk(version);
-		printk(KERN_DEBUG MODNAME ": speed:%d duplex:%d doforce:%d\n",
-		       options.speed, options.duplex, options.doforce);
+		dev_printk(KERN_DEBUG, &pdev->dev,
+			   "speed:%d duplex:%d doforce:%d\n",
+			   options.speed, options.duplex, options.doforce);
 	}
 
 	if (!pdev->irq) {
-		printk (KERN_WARNING MODNAME ": no IRQ assigned (%s).\n",
-			pci_name(pdev));
+		dev_warn(&pdev->dev, "no IRQ assigned.\n");
 		return -ENODEV;
 	}
 
 	/* dev zeroed in alloc_etherdev */
 	dev = alloc_etherdev (sizeof (*lp));
 	if (dev == NULL) {
-		printk (KERN_ERR MODNAME ": unable to alloc new ethernet\n");
+		dev_err(&pdev->dev, "unable to alloc new ethernet\n");
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
@@ -607,14 +703,14 @@ static int __devinit tc35815_init_one (s
 
 	/* make sure PCI base addr 1 is MMIO */
 	if (!(mmio_flags & IORESOURCE_MEM)) {
-		printk (KERN_ERR MODNAME ": region #1 not an MMIO resource, aborting\n");
+		dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
 		rc = -ENODEV;
 		goto err_out;
 	}
 
 	/* check for weird/broken PCI region reporting */
 	if ((mmio_len < sizeof(struct tc35815_regs))) {
-		printk (KERN_ERR MODNAME ": Invalid PCI region size(s), aborting\n");
+		dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
 		rc = -ENODEV;
 		goto err_out;
 	}
@@ -628,7 +724,7 @@ static int __devinit tc35815_init_one (s
 	/* ioremap MMIO region */
 	ioaddr = ioremap (mmio_start, mmio_len);
 	if (ioaddr == NULL) {
-		printk (KERN_ERR MODNAME ": cannot remap MMIO, aborting\n");
+		dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
 		rc = -EIO;
 		goto err_out_free_res;
 	}
@@ -643,6 +739,13 @@ static int __devinit tc35815_init_one (s
 	dev->ethtool_ops = &tc35815_ethtool_ops;
 	dev->tx_timeout = tc35815_tx_timeout;
 	dev->watchdog_timeo = TC35815_TX_TIMEOUT;
+#ifdef TC35815_NAPI
+	dev->poll = tc35815_poll;
+	dev->weight = NAPI_WEIGHT;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = tc35815_poll_controller;
+#endif
 
 	dev->irq = pdev->irq;
 	dev->base_addr = (unsigned long) ioaddr;
@@ -651,12 +754,13 @@ static int __devinit tc35815_init_one (s
 	lp = dev->priv;
 	spin_lock_init(&lp->lock);
 	lp->pci_dev = pdev;
+	lp->boardtype = ent->driver_data;
 
 	lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK;
 	pci_set_drvdata(pdev, dev);
 
 	/* Soft reset the chip. */
-	tc35815_chip_reset((struct tc35815_regs*)ioaddr);
+	tc35815_chip_reset(dev);
 
 	/* Retrieve the ethernet address. */
 	tc35815_init_dev_addr(dev);
@@ -665,7 +769,8 @@ static int __devinit tc35815_init_one (s
 	if (rc)
 		goto err_out_unmap;
 
-	printk (KERN_INFO "%s: %s at 0x%lx, "
+	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+	printk(KERN_INFO "%s: %s at 0x%lx, "
 		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
 		"IRQ %d\n",
 		dev->name,
@@ -676,7 +781,7 @@ static int __devinit tc35815_init_one (s
 		dev->dev_addr[4], dev->dev_addr[5],
 		dev->irq);
 
-	init_timer(&lp->timer);
+	setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev);
 	lp->mii.dev = dev;
 	lp->mii.mdio_read = tc_mdio_read;
 	lp->mii.mdio_write = tc_mdio_write;
@@ -726,17 +831,16 @@ tc35815_init_queues(struct net_device *d
 	unsigned long fd_addr;
 
 	if (!lp->fd_buf) {
-		if (sizeof(struct FDesc) +
-		    sizeof(struct BDesc) * RX_BUF_PAGES +
-		    sizeof(struct FDesc) * RX_FD_NUM +
-		    sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) {
-			printk("%s: Invalid Queue Size.\n", dev->name);
-			return -ENOMEM;
-		}
+		BUG_ON(sizeof(struct FDesc) +
+		       sizeof(struct BDesc) * RX_BUF_NUM +
+		       sizeof(struct FDesc) * RX_FD_NUM +
+		       sizeof(struct TxFD) * TX_FD_NUM >
+		       PAGE_SIZE * FD_PAGE_NUM);
 
 		if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0)
 			return -ENOMEM;
-		for (i = 0; i < RX_BUF_PAGES; i++) {
+		for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
 			if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) {
 				while (--i >= 0) {
 					free_rxbuf_page(lp->pci_dev,
@@ -744,15 +848,40 @@ tc35815_init_queues(struct net_device *d
 							lp->data_buf_dma[i]);
 					lp->data_buf[i] = NULL;
 				}
-				pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, lp->fd_buf, lp->fd_buf_dma);
+				pci_free_consistent(lp->pci_dev,
+						    PAGE_SIZE * FD_PAGE_NUM,
+						    lp->fd_buf,
+						    lp->fd_buf_dma);
+				lp->fd_buf = NULL;
+				return -ENOMEM;
+			}
+#else
+			lp->rx_skbs[i].skb =
+				alloc_rxbuf_skb(dev, lp->pci_dev,
+						&lp->rx_skbs[i].skb_dma);
+			if (!lp->rx_skbs[i].skb) {
+				while (--i >= 0) {
+					free_rxbuf_skb(lp->pci_dev,
+						       lp->rx_skbs[i].skb,
+						       lp->rx_skbs[i].skb_dma);
+					lp->rx_skbs[i].skb = NULL;
+				}
+				pci_free_consistent(lp->pci_dev,
+						    PAGE_SIZE * FD_PAGE_NUM,
+						    lp->fd_buf,
+						    lp->fd_buf_dma);
 				lp->fd_buf = NULL;
 				return -ENOMEM;
 			}
+#endif
 		}
-		printk(KERN_DEBUG "%s: FD buf %p DataBuf", dev->name, lp->fd_buf);
-		for (i = 0; i < RX_BUF_PAGES; i++) {
+		printk(KERN_DEBUG "%s: FD buf %p DataBuf",
+		       dev->name, lp->fd_buf);
+#ifdef TC35815_USE_PACKEDBUFFER
+		printk(" DataBuf");
+		for (i = 0; i < RX_BUF_NUM; i++)
 			printk(" %p", lp->data_buf[i]);
-		}
+#endif
 		printk("\n");
 	} else {
 		for (i = 0; i < FD_PAGE_NUM; i++) {
@@ -768,9 +897,7 @@ tc35815_init_queues(struct net_device *d
 		lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
 	}
 	lp->rfd_cur = lp->rfd_base;
-	lp->rfd_limit = (struct RxFD *)(fd_addr -
-					sizeof(struct FDesc) -
-					sizeof(struct BDesc) * 30);
+	lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1);
 
 	/* Transmit Descriptors */
 	lp->tfd_base = (struct TxFD *)fd_addr;
@@ -787,14 +914,46 @@ tc35815_init_queues(struct net_device *d
 	/* Buffer List (for Receive) */
 	lp->fbl_ptr = (struct FrFD *)fd_addr;
 	lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr));
-	lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD);
-	for (i = 0; i < RX_BUF_PAGES; i++) {
+	lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD);
+#ifndef TC35815_USE_PACKEDBUFFER
+	/*
+	 * move all allocated skbs to head of rx_skbs[] array.
+	 * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in
+	 * tc35815_rx() had failed.
+	 */
+	lp->fbl_count = 0;
+	for (i = 0; i < RX_BUF_NUM; i++) {
+		if (lp->rx_skbs[i].skb) {
+			if (i != lp->fbl_count) {
+				lp->rx_skbs[lp->fbl_count].skb =
+					lp->rx_skbs[i].skb;
+				lp->rx_skbs[lp->fbl_count].skb_dma =
+					lp->rx_skbs[i].skb_dma;
+			}
+			lp->fbl_count++;
+		}
+	}
+#endif
+	for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
 		lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(lp->data_buf_dma[i]);
+#else
+		if (i >= lp->fbl_count) {
+			lp->fbl_ptr->bd[i].BuffData = 0;
+			lp->fbl_ptr->bd[i].BDCtl = 0;
+			continue;
+		}
+		lp->fbl_ptr->bd[i].BuffData =
+			cpu_to_le32(lp->rx_skbs[i].skb_dma);
+#endif
 		/* BDID is index of FrFD.bd[] */
 		lp->fbl_ptr->bd[i].BDCtl =
-			cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE);
+			cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) |
+				    RX_BUF_SIZE);
 	}
+#ifdef TC35815_USE_PACKEDBUFFER
 	lp->fbl_curid = 0;
+#endif
 
 	printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n",
 	       dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr);
@@ -808,13 +967,18 @@ tc35815_clear_queues(struct net_device *
 	int i;
 
 	for (i = 0; i < TX_FD_NUM; i++) {
+		u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
 		struct sk_buff *skb =
-			lp->tfd_base[i].fd.FDSystem != cpu_to_le32(0xffffffff) ?
-			lp->tx_skbs[le32_to_cpu(lp->tfd_base[i].fd.FDSystem)].skb : NULL;
+			fdsystem != 0xffffffff ?
+			lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
 		if (lp->tx_skbs[i].skb != skb) {
 			printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
 			panic_queues(dev);
 		}
+#else
+		BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
 		if (skb) {
 			pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
 			lp->tx_skbs[i].skb = NULL;
@@ -835,13 +999,18 @@ tc35815_free_queues(struct net_device *d
 
 	if (lp->tfd_base) {
 		for (i = 0; i < TX_FD_NUM; i++) {
+			u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
 			struct sk_buff *skb =
-				lp->tfd_base[i].fd.FDSystem != cpu_to_le32(0xffffffff) ?
-				lp->tx_skbs[le32_to_cpu(lp->tfd_base[i].fd.FDSystem)].skb : NULL;
+				fdsystem != 0xffffffff ?
+				lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
 			if (lp->tx_skbs[i].skb != skb) {
 				printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
 				panic_queues(dev);
 			}
+#else
+			BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
 			if (skb) {
 				dev_kfree_skb(skb);
 				pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
@@ -857,12 +1026,20 @@ tc35815_free_queues(struct net_device *d
 	lp->rfd_cur = NULL;
 	lp->fbl_ptr = NULL;
 
-	for (i = 0; i < RX_BUF_PAGES; i++) {
+	for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
 		if (lp->data_buf[i]) {
 			free_rxbuf_page(lp->pci_dev,
 					lp->data_buf[i], lp->data_buf_dma[i]);
 			lp->data_buf[i] = NULL;
 		}
+#else
+		if (lp->rx_skbs[i].skb) {
+			free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb,
+				       lp->rx_skbs[i].skb_dma);
+			lp->rx_skbs[i].skb = NULL;
+		}
+#endif
 	}
 	if (lp->fd_buf) {
 		pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM,
@@ -908,6 +1085,7 @@ dump_rxfd(struct RxFD *fd)
 	return bd_count;
 }
 
+#if defined(DEBUG) || defined(TC35815_USE_PACKEDBUFFER)
 static void
 dump_frfd(struct FrFD *fd)
 {
@@ -918,13 +1096,15 @@ dump_frfd(struct FrFD *fd)
 	       le32_to_cpu(fd->fd.FDStat),
 	       le32_to_cpu(fd->fd.FDCtl));
 	printk("BD: ");
-	for (i = 0; i < RX_BUF_PAGES; i++)
+	for (i = 0; i < RX_BUF_NUM; i++)
 		printk(" %08x %08x",
 		       le32_to_cpu(fd->bd[i].BuffData),
 		       le32_to_cpu(fd->bd[i].BDCtl));
 	printk("\n");
 }
+#endif
 
+#ifdef DEBUG
 static void
 panic_queues(struct net_device *dev)
 {
@@ -945,6 +1125,7 @@ panic_queues(struct net_device *dev)
 	dump_frfd(lp->fbl_ptr);
 	panic("%s: Illegal queue state.", dev->name);
 }
+#endif
 
 static void print_eth(char *add)
 {
@@ -969,7 +1150,6 @@ static void tc35815_restart(struct net_d
 {
 	struct tc35815_local *lp = dev->priv;
 	int pid = lp->phy_addr;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
 	int do_phy_reset = 1;
 	del_timer(&lp->timer);		/* Kill if running	*/
 
@@ -990,7 +1170,7 @@ static void tc35815_restart(struct net_d
 			printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name);
 	}
 
-	tc35815_chip_reset(tr);
+	tc35815_chip_reset(dev);
 	tc35815_clear_queues(dev);
 	tc35815_chip_init(dev);
 	/* Reconfigure CAM again since tc35815_chip_init() initialize it. */
@@ -1000,7 +1180,8 @@ static void tc35815_restart(struct net_d
 static void tc35815_tx_timeout(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 
 	printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
 	       dev->name, tc_readl(&tr->Tx_Stat));
@@ -1048,7 +1229,7 @@ tc35815_open(struct net_device *dev)
 	}
 
 	del_timer(&lp->timer);		/* Kill if running	*/
-	tc35815_chip_reset((struct tc35815_regs*)dev->base_addr);
+	tc35815_chip_reset(dev);
 
 	if (tc35815_init_queues(dev) != 0) {
 		free_irq(dev->irq, dev);
@@ -1076,9 +1257,8 @@ tc35815_open(struct net_device *dev)
 static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
-	short length = skb->len;
 	struct TxFD *txfd;
+	unsigned long flags;
 
 	/* If some error occurs while trying to transmit this
 	 * packet, you should return '1' from this function.
@@ -1094,29 +1274,36 @@ static int tc35815_send_packet(struct sk
 	 * hardware interrupt handler.  Queue flow control is
 	 * thus managed under this lock as well.
 	 */
-	spin_lock_irq(&lp->lock);
+	spin_lock_irqsave(&lp->lock, flags);
 
-	/*add to ring */
-	txfd = &lp->tfd_base[lp->tfd_start];
-
-	/* failsafe... */
-	if (lp->tfd_start != lp->tfd_end)
+	/* failsafe... (handle txdone now if half of FDs are used) */
+	if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM >
+	    TX_FD_NUM / 2)
 		tc35815_txdone(dev);
 
 	if (netif_msg_pktdata(lp))
 		print_eth(skb->data);
+#ifdef DEBUG
 	if (lp->tx_skbs[lp->tfd_start].skb) {
 		printk("%s: tx_skbs conflict.\n", dev->name);
 		panic_queues(dev);
 	}
+#else
+	BUG_ON(lp->tx_skbs[lp->tfd_start].skb);
+#endif
 	lp->tx_skbs[lp->tfd_start].skb = skb;
 	lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+	/*add to ring */
+	txfd = &lp->tfd_base[lp->tfd_start];
 	txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma);
-	txfd->bd.BDCtl = cpu_to_le32(length);
+	txfd->bd.BDCtl = cpu_to_le32(skb->len);
 	txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start);
 	txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
 
 	if (lp->tfd_start == lp->tfd_end) {
+		struct tc35815_regs __iomem *tr =
+			(struct tc35815_regs __iomem *)dev->base_addr;
 		/* Start DMA Transmitter. */
 		txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
 #ifdef GATHER_TXINT
@@ -1152,13 +1339,13 @@ static int tc35815_send_packet(struct sk
 	 * is when the transmit statistics are updated.
 	 */
 
-	spin_unlock_irq(&lp->lock);
+	spin_unlock_irqrestore(&lp->lock, flags);
 	return 0;
 }
 
 #define FATAL_ERROR_INT \
 	(Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
-static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
+static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status)
 {
 	static int count;
 	printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
@@ -1175,32 +1362,23 @@ static void tc35815_fatal_error_interrup
 	printk(KERN_WARNING "%s: Resetting ...\n", dev->name);
 	/* Try to restart the adaptor. */
 	tc35815_restart(dev);
-	return;
 }
 
-/*
- * The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
+#ifdef TC35815_NAPI
+static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit)
+#else
+static int tc35815_do_interrupt(struct net_device *dev, u32 status)
+#endif
 {
-	struct net_device *dev = dev_id;
-	struct tc35815_regs *tr;
-	struct tc35815_local *lp;
-	int status, handled = 0;
-
-	tr = (struct tc35815_regs *)dev->base_addr;
-	lp = dev->priv;
-
-	spin_lock(&lp->lock);
-	status = tc_readl(&tr->Int_Src);
-	tc_writel(status, &tr->Int_Src);	/* write to clear */
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int ret = -1;
 
 	/* Fatal errors... */
 	if (status & FATAL_ERROR_INT) {
 		tc35815_fatal_error_interrupt(dev, status);
-		spin_unlock(&lp->lock);
-		return IRQ_HANDLED;
+		return 0;
 	}
 	/* recoverable errors */
 	if (status & Int_IntFDAEx) {
@@ -1210,7 +1388,7 @@ static irqreturn_t tc35815_interrupt(int
 		       "%s: Free Descriptor Area Exhausted (%#x).\n",
 		       dev->name, status);
 		lp->stats.rx_dropped++;
-		handled = 1;
+		ret = 0;
 	}
 	if (status & Int_IntBLEx) {
 		/* disable BLEx int. (until we make rooms...) */
@@ -1219,51 +1397,112 @@ static irqreturn_t tc35815_interrupt(int
 		       "%s: Buffer List Exhausted (%#x).\n",
 		       dev->name, status);
 		lp->stats.rx_dropped++;
-		handled = 1;
+		ret = 0;
 	}
 	if (status & Int_IntExBD) {
 		printk(KERN_WARNING
 		       "%s: Excessive Buffer Descriptiors (%#x).\n",
 		       dev->name, status);
 		lp->stats.rx_length_errors++;
-		handled = 1;
+		ret = 0;
 	}
 
 	/* normal notification */
 	if (status & Int_IntMacRx) {
 		/* Got a packet(s). */
-		lp->lstats.rx_ints++;
+#ifdef TC35815_NAPI
+		ret = tc35815_rx(dev, limit);
+#else
 		tc35815_rx(dev);
-		handled = 1;
+		ret = 0;
+#endif
+		lp->lstats.rx_ints++;
 	}
 	if (status & Int_IntMacTx) {
 		/* Transmit complete. */
 		lp->lstats.tx_ints++;
 		tc35815_txdone(dev);
 		netif_wake_queue(dev);
-		handled = 1;
+		ret = 0;
+	}
+	return ret;
+}
+
+/*
+ * The typical workload of the driver:
+ * Handle the network interface interrupts.
+ */
+static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+#ifdef TC35815_NAPI
+	u32 dmactl = tc_readl(&tr->DMA_Ctl);
+
+	if (!(dmactl & DMA_IntMask)) {
+		/* disable interrupts */
+		tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
+		if (netif_rx_schedule_prep(dev))
+			__netif_rx_schedule(dev);
+		else {
+			printk(KERN_ERR "%s: interrupt taken in poll\n",
+			       dev->name);
+			BUG();
+		}
+		(void)tc_readl(&tr->Int_Src);	/* flush */
+		return IRQ_HANDLED;
 	}
+	return IRQ_NONE;
+#else
+	struct tc35815_local *lp = dev->priv;
+	int handled;
+	u32 status;
+
+	spin_lock(&lp->lock);
+	status = tc_readl(&tr->Int_Src);
+	tc_writel(status, &tr->Int_Src);	/* write to clear */
+	handled = tc35815_do_interrupt(dev, status);
 	(void)tc_readl(&tr->Int_Src);	/* flush */
 	spin_unlock(&lp->lock);
-	return IRQ_RETVAL(handled);
+	return IRQ_RETVAL(handled >= 0);
+#endif /* TC35815_NAPI */
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void tc35815_poll_controller(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	tc35815_interrupt(dev->irq, dev);
+	enable_irq(dev->irq);
+}
+#endif
+
 /* We have a good packet(s), get it/them out of the buffers. */
+#ifdef TC35815_NAPI
+static int
+tc35815_rx(struct net_device *dev, int limit)
+#else
 static void
 tc35815_rx(struct net_device *dev)
+#endif
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
 	unsigned int fdctl;
 	int i;
 	int buf_free_count = 0;
 	int fd_free_count = 0;
+#ifdef TC35815_NAPI
+	int received = 0;
+#endif
 
 	while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
 		int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
 		int pkt_len = fdctl & FD_FDLength_MASK;
-		struct RxFD *next_rfd;
 		int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+#ifdef DEBUG
+		struct RxFD *next_rfd;
+#endif
 #if (RX_CTL_CMD & Rx_StripCRC) == 0
 		pkt_len -= 4;
 #endif
@@ -1271,11 +1510,19 @@ tc35815_rx(struct net_device *dev)
 		if (netif_msg_rx_status(lp))
 			dump_rxfd(lp->rfd_cur);
 		if (status & Rx_Good) {
-			/* Malloc up new buffer. */
 			struct sk_buff *skb;
 			unsigned char *data;
-			int cur_bd, offset;
+			int cur_bd;
+#ifdef TC35815_USE_PACKEDBUFFER
+			int offset;
+#endif
 
+#ifdef TC35815_NAPI
+			if (--limit < 0)
+				break;
+#endif
+#ifdef TC35815_USE_PACKEDBUFFER
+			BUG_ON(bd_count > 2);
 			skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
 			if (skb == NULL) {
 				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
@@ -1307,10 +1554,44 @@ tc35815_rx(struct net_device *dev)
 				offset += len;
 				cur_bd++;
 			}
+#else /* TC35815_USE_PACKEDBUFFER */
+			BUG_ON(bd_count > 1);
+			cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl)
+				  & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
+#ifdef DEBUG
+			if (cur_bd >= RX_BUF_NUM) {
+				printk("%s: invalid BDID.\n", dev->name);
+				panic_queues(dev);
+			}
+			BUG_ON(lp->rx_skbs[cur_bd].skb_dma !=
+			       (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3));
+			if (!lp->rx_skbs[cur_bd].skb) {
+				printk("%s: NULL skb.\n", dev->name);
+				panic_queues(dev);
+			}
+#else
+			BUG_ON(cur_bd >= RX_BUF_NUM);
+#endif
+			skb = lp->rx_skbs[cur_bd].skb;
+			prefetch(skb->data);
+			lp->rx_skbs[cur_bd].skb = NULL;
+			lp->fbl_count--;
+			pci_unmap_single(lp->pci_dev,
+					 lp->rx_skbs[cur_bd].skb_dma,
+					 RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			if (!HAVE_DMA_RXALIGN(lp))
+				memmove(skb->data, skb->data - 2, pkt_len);
+			data = skb_put(skb, pkt_len);
+#endif /* TC35815_USE_PACKEDBUFFER */
 			if (netif_msg_pktdata(lp))
 				print_eth(data);
 			skb->protocol = eth_type_trans(skb, dev);
+#ifdef TC35815_NAPI
+			netif_receive_skb(skb);
+			received++;
+#else
 			netif_rx(skb);
+#endif
 			dev->last_rx = jiffies;
 			lp->stats.rx_packets++;
 			lp->stats.rx_bytes += pkt_len;
@@ -1334,59 +1615,149 @@ tc35815_rx(struct net_device *dev)
 			int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
 			unsigned char id =
 				(bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
-			if (id >= RX_BUF_PAGES) {
+#ifdef DEBUG
+			if (id >= RX_BUF_NUM) {
 				printk("%s: invalid BDID.\n", dev->name);
 				panic_queues(dev);
 			}
+#else
+			BUG_ON(id >= RX_BUF_NUM);
+#endif
 			/* free old buffers */
-			while (lp->fbl_curid != id) {
-				bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl);
+#ifdef TC35815_USE_PACKEDBUFFER
+			while (lp->fbl_curid != id)
+#else
+			while (lp->fbl_count < RX_BUF_NUM)
+#endif
+			{
+#ifdef TC35815_USE_PACKEDBUFFER
+				unsigned char curid = lp->fbl_curid;
+#else
+				unsigned char curid =
+					(id + 1 + lp->fbl_count) % RX_BUF_NUM;
+#endif
+				struct BDesc *bd = &lp->fbl_ptr->bd[curid];
+#ifdef DEBUG
+				bdctl = le32_to_cpu(bd->BDCtl);
 				if (bdctl & BD_CownsBD) {
 					printk("%s: Freeing invalid BD.\n",
 					       dev->name);
 					panic_queues(dev);
 				}
+#endif
 				/* pass BD to controler */
+#ifndef TC35815_USE_PACKEDBUFFER
+				if (!lp->rx_skbs[curid].skb) {
+					lp->rx_skbs[curid].skb =
+						alloc_rxbuf_skb(dev,
+								lp->pci_dev,
+								&lp->rx_skbs[curid].skb_dma);
+					if (!lp->rx_skbs[curid].skb)
+						break; /* try on next reception */
+					bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma);
+				}
+#endif /* TC35815_USE_PACKEDBUFFER */
 				/* Note: BDLength was modified by chip. */
-				lp->fbl_ptr->bd[lp->fbl_curid].BDCtl =
-					cpu_to_le32(BD_CownsBD |
-						    (lp->fbl_curid << BD_RxBDID_SHIFT) |
-						    PAGE_SIZE);
-				lp->fbl_curid =
-					(lp->fbl_curid + 1) % RX_BUF_PAGES;
+				bd->BDCtl = cpu_to_le32(BD_CownsBD |
+							(curid << BD_RxBDID_SHIFT) |
+							RX_BUF_SIZE);
+#ifdef TC35815_USE_PACKEDBUFFER
+				lp->fbl_curid = (curid + 1) % RX_BUF_NUM;
 				if (netif_msg_rx_status(lp)) {
 					printk("%s: Entering new FBD %d\n",
 					       dev->name, lp->fbl_curid);
 					dump_frfd(lp->fbl_ptr);
 				}
+#else
+				lp->fbl_count++;
+#endif
 				buf_free_count++;
 			}
 		}
 
 		/* put RxFD back to controller */
-		next_rfd = fd_bus_to_virt(lp, le32_to_cpu(lp->rfd_cur->fd.FDNext));
+#ifdef DEBUG
+		next_rfd = fd_bus_to_virt(lp,
+					  le32_to_cpu(lp->rfd_cur->fd.FDNext));
 		if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
 			printk("%s: RxFD FDNext invalid.\n", dev->name);
 			panic_queues(dev);
 		}
+#endif
 		for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
 			/* pass FD to controler */
-			lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);	/* for debug */
+#ifdef DEBUG
+			lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);
+#else
+			lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL);
+#endif
 			lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
 			lp->rfd_cur++;
 			fd_free_count++;
 		}
-
-		lp->rfd_cur = next_rfd;
+		if (lp->rfd_cur > lp->rfd_limit)
+			lp->rfd_cur = lp->rfd_base;
+#ifdef DEBUG
+		if (lp->rfd_cur != next_rfd)
+			printk("rfd_cur = %p, next_rfd %p\n",
+			       lp->rfd_cur, next_rfd);
+#endif
 	}
 
 	/* re-enable BL/FDA Exhaust interrupts. */
 	if (fd_free_count) {
-		tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En);
+		struct tc35815_regs __iomem *tr =
+			(struct tc35815_regs __iomem *)dev->base_addr;
+		u32 en, en_old = tc_readl(&tr->Int_En);
+		en = en_old | Int_FDAExEn;
 		if (buf_free_count)
-			tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En);
+			en |= Int_BLExEn;
+		if (en != en_old)
+			tc_writel(en, &tr->Int_En);
 	}
+#ifdef TC35815_NAPI
+	return received;
+#endif
+}
+
+#ifdef TC35815_NAPI
+static int
+tc35815_poll(struct net_device *dev, int *budget)
+{
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int limit = min(*budget, dev->quota);
+	int received = 0, handled;
+	u32 status;
+
+	spin_lock(&lp->lock);
+	status = tc_readl(&tr->Int_Src);
+	do {
+		tc_writel(status, &tr->Int_Src);	/* write to clear */
+
+		handled = tc35815_do_interrupt(dev, status, limit);
+		if (handled >= 0) {
+			received += handled;
+			limit -= handled;
+			if (limit <= 0)
+				break;
+		}
+		status = tc_readl(&tr->Int_Src);
+	} while (status);
+	spin_unlock(&lp->lock);
+
+	dev->quota -= received;
+	*budget -= received;
+	if (limit <= 0)
+		return 1;
+
+	netif_rx_complete(dev);
+	/* enable interrupts */
+	tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
+	return 0;
 }
+#endif
 
 #ifdef NO_CHECK_CARRIER
 #define TX_STA_ERR	(Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr)
@@ -1406,12 +1777,17 @@ tc35815_check_tx_stat(struct net_device
 	if (status & Tx_TxColl_MASK)
 		lp->stats.collisions += status & Tx_TxColl_MASK;
 
+#ifndef NO_CHECK_CARRIER
+	/* TX4939 does not have NCarr */
+	if (lp->boardtype == TC35815_TX4939)
+		status &= ~Tx_NCarr;
 #ifdef WORKAROUND_LOSTCAR
 	/* WORKAROUND: ignore LostCrS in full duplex operation */
 	if ((lp->timer_state != asleep && lp->timer_state != lcheck)
 	    || lp->fullduplex)
 		status &= ~Tx_NCarr;
 #endif
+#endif
 
 	if (!(status & TX_STA_ERR)) {
 		/* no error. */
@@ -1428,13 +1804,13 @@ tc35815_check_tx_stat(struct net_device
 		lp->stats.tx_fifo_errors++;
 		msg = "Tx FIFO Underrun.";
 		if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) {
-		  lp->lstats.tx_underrun++;
-		  if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {
-		    struct tc35815_regs *tr =
-		      (struct tc35815_regs *)dev->base_addr;
-		    tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);
-		    msg = "Tx FIFO Underrun.Change Tx threshold to max.";
-		  }
+			lp->lstats.tx_underrun++;
+			if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {
+				struct tc35815_regs __iomem *tr =
+					(struct tc35815_regs __iomem *)dev->base_addr;
+				tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);
+				msg = "Tx FIFO Underrun.Change Tx threshold to max.";
+			}
 		}
 	}
 	if (status & Tx_Defer) {
@@ -1470,7 +1846,6 @@ static void
 tc35815_txdone(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
 	struct TxFD *txfd;
 	unsigned int fdctl;
 
@@ -1480,6 +1855,7 @@ tc35815_txdone(struct net_device *dev)
 		int status = le32_to_cpu(txfd->fd.FDStat);
 		struct sk_buff *skb;
 		unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
+		u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem);
 
 		if (netif_msg_tx_done(lp)) {
 			printk("%s: complete TxFD.\n", dev->name);
@@ -1487,39 +1863,53 @@ tc35815_txdone(struct net_device *dev)
 		}
 		tc35815_check_tx_stat(dev, status);
 
-		skb = le32_to_cpu(txfd->fd.FDSystem) != cpu_to_le32(0xffffffff) ?
-			lp->tx_skbs[le32_to_cpu(txfd->fd.FDSystem)].skb : NULL;
+		skb = fdsystem != 0xffffffff ?
+			lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
 		if (lp->tx_skbs[lp->tfd_end].skb != skb) {
 			printk("%s: tx_skbs mismatch.\n", dev->name);
 			panic_queues(dev);
 		}
+#else
+		BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb);
+#endif
 		if (skb) {
 			lp->stats.tx_bytes += skb->len;
 			pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE);
 			lp->tx_skbs[lp->tfd_end].skb = NULL;
 			lp->tx_skbs[lp->tfd_end].skb_dma = 0;
+#ifdef TC35815_NAPI
+			dev_kfree_skb_any(skb);
+#else
 			dev_kfree_skb_irq(skb);
+#endif
 		}
 		txfd->fd.FDSystem = cpu_to_le32(0xffffffff);
 
 		lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
 		txfd = &lp->tfd_base[lp->tfd_end];
+#ifdef DEBUG
 		if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) {
 			printk("%s: TxFD FDNext invalid.\n", dev->name);
 			panic_queues(dev);
 		}
+#endif
 		if (fdnext & FD_Next_EOL) {
 			/* DMA Transmitter has been stopping... */
 			if (lp->tfd_end != lp->tfd_start) {
+				struct tc35815_regs __iomem *tr =
+					(struct tc35815_regs __iomem *)dev->base_addr;
 				int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
 				struct TxFD* txhead = &lp->tfd_base[head];
 				int qlen = (lp->tfd_start + TX_FD_NUM
 					    - lp->tfd_end) % TX_FD_NUM;
 
+#ifdef DEBUG
 				if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
 					printk("%s: TxFD FDCtl invalid.\n", dev->name);
 					panic_queues(dev);
 				}
+#endif
 				/* log max queue length */
 				if (lp->lstats.max_tx_qlen < qlen)
 					lp->lstats.max_tx_qlen = qlen;
@@ -1559,7 +1949,7 @@ tc35815_close(struct net_device *dev)
 	/* Flush the Tx and disable Rx here. */
 
 	del_timer(&lp->timer);		/* Kill if running	*/
-	tc35815_chip_reset((struct tc35815_regs*)dev->base_addr);
+	tc35815_chip_reset(dev);
 	free_irq(dev->irq, dev);
 
 	tc35815_free_queues(dev);
@@ -1575,7 +1965,8 @@ tc35815_close(struct net_device *dev)
 static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	if (netif_running(dev)) {
 		/* Update the statistics from the device registers. */
 		lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);
@@ -1587,15 +1978,16 @@ static struct net_device_stats *tc35815_
 static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	int cam_index = index * 6;
-	unsigned long cam_data;
-	unsigned long saved_addr;
+	u32 cam_data;
+	u32 saved_addr;
 	saved_addr = tc_readl(&tr->CAM_Adr);
 
 	if (netif_msg_hw(lp)) {
 		int i;
-		printk(KERN_DEBUG "%s: CAM %d:", MODNAME, index);
+		printk(KERN_DEBUG "%s: CAM %d:", dev->name, index);
 		for (i = 0; i < 6; i++)
 			printk(" %02x", addr[i]);
 		printk("\n");
@@ -1636,7 +2028,8 @@ static void tc35815_set_cam_entry(struct
 static void
 tc35815_set_multicast_list(struct net_device *dev)
 {
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 
 	if (dev->flags&IFF_PROMISC)
 	{
@@ -1789,7 +2182,7 @@ static void tc35815_get_strings(struct n
 	memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
 }
 
-static struct ethtool_ops tc35815_ethtool_ops = {
+static const struct ethtool_ops tc35815_ethtool_ops = {
 	.get_drvinfo		= tc35815_get_drvinfo,
 	.get_settings		= tc35815_get_settings,
 	.set_settings		= tc35815_set_settings,
@@ -1800,6 +2193,7 @@ static struct ethtool_ops tc35815_ethtoo
 	.get_strings		= tc35815_get_strings,
 	.get_stats_count	= tc35815_get_stats_count,
 	.get_ethtool_stats	= tc35815_get_ethtool_stats,
+	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
 static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1819,8 +2213,9 @@ static int tc35815_ioctl(struct net_devi
 
 static int tc_mdio_read(struct net_device *dev, int phy_id, int location)
 {
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
-	unsigned long data;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	u32 data;
 	tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA);
 	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
 		;
@@ -1831,7 +2226,8 @@ static int tc_mdio_read(struct net_devic
 static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
 			  int val)
 {
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	tc_writel(val, &tr->MD_Data);
 	tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA);
 	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
@@ -1952,17 +2348,18 @@ static void tc35815_display_forced_link_
 static void tc35815_set_link_modes(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	int pid = lp->phy_addr;
 	unsigned short bmcr, lpa;
+	int speed;
 
 	if (lp->timer_state == arbwait) {
+		lpa = tc_mdio_read(dev, pid, MII_LPA);
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
 		printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
 		       dev->name,
-		       tc_mdio_read(dev, pid, MII_BMCR),
-		       tc_mdio_read(dev, pid, MII_BMSR),
-		       tc_mdio_read(dev, pid, MII_LPA));
-		lpa = tc_mdio_read(dev, pid, MII_LPA);
+		       bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
 		if (!(lpa & (LPA_10HALF | LPA_10FULL |
 			     LPA_100HALF | LPA_100FULL))) {
 			/* fall back to 10HALF */
@@ -1970,11 +2367,14 @@ static void tc35815_set_link_modes(struc
 			       dev->name, lpa);
 			lpa = LPA_10HALF;
 		}
-		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
 		if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
 			lp->fullduplex = 1;
 		else
 			lp->fullduplex = 0;
+		if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+			speed = 100;
+		else
+			speed = 10;
 	} else {
 		/* Forcing a link mode. */
 		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
@@ -1982,6 +2382,10 @@ static void tc35815_set_link_modes(struc
 			lp->fullduplex = 1;
 		else
 			lp->fullduplex = 0;
+		if (bmcr & BMCR_SPEED100)
+			speed = 100;
+		else
+			speed = 10;
 	}
 
 	tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl);
@@ -1992,10 +2396,17 @@ static void tc35815_set_link_modes(struc
 	}
 	tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl);
 
+	/* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */
+
+#ifndef NO_CHECK_CARRIER
+	/* TX4939 does not have EnLCarr */
+	if (lp->boardtype != TC35815_TX4939) {
 #ifdef WORKAROUND_LOSTCAR
-	/* WORKAROUND: enable LostCrS only if half duplex operation */
-	if (!lp->fullduplex)
-		tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl);
+		/* WORKAROUND: enable LostCrS only if half duplex operation */
+		if (!lp->fullduplex && lp->boardtype != TC35815_TX4939)
+			tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl);
+#endif
+	}
 #endif
 	lp->mii.full_duplex = lp->fullduplex;
 }
@@ -2201,7 +2612,7 @@ static void tc35815_timer(unsigned long
 	}
 
 	if (restart_timer) {
-		lp->timer.expires = jiffies + ((12 * HZ)/10); /* 1.2s */
+		lp->timer.expires = jiffies + msecs_to_jiffies(1200);
 		add_timer(&lp->timer);
 	}
 out:
@@ -2329,9 +2740,7 @@ force_link:
 
 	del_timer(&lp->timer);
 	lp->timer_ticks = 0;
-	lp->timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */
-	lp->timer.data = (unsigned long) dev;
-	lp->timer.function = &tc35815_timer;
+	lp->timer.expires = jiffies + msecs_to_jiffies(1200);
 	add_timer(&lp->timer);
 }
 
@@ -2396,8 +2805,10 @@ static void tc35815_phy_chip_init(struct
 	tc35815_start_auto_negotiation(dev, ep);
 }
 
-static void tc35815_chip_reset(struct tc35815_regs *tr)
+static void tc35815_chip_reset(struct net_device *dev)
 {
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	int i;
 	/* reset the controller */
 	tc_writel(MAC_Reset, &tr->MAC_Ctl);
@@ -2405,7 +2816,7 @@ static void tc35815_chip_reset(struct tc
 	i = 0;
 	while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) {
 		if (i++ > 100) {
-			printk(KERN_ERR "%s: MAC reset failed.\n", MODNAME);
+			printk(KERN_ERR "%s: MAC reset failed.\n", dev->name);
 			break;
 		}
 		mdelay(1);
@@ -2439,7 +2850,8 @@ static void tc35815_chip_reset(struct tc
 static void tc35815_chip_init(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	unsigned long txctl = TX_CTL_CMD;
 
 	tc35815_phy_chip_init(dev);
@@ -2451,8 +2863,16 @@ static void tc35815_chip_init(struct net
 	tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
 	tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
 
-	tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
+	/* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */
+	if (HAVE_DMA_RXALIGN(lp))
+		tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl);
+	else
+		tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
+#ifdef TC35815_USE_PACKEDBUFFER
 	tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize);	/* Packing */
+#else
+	tc_writel(ETH_ZLEN, &tr->RxFragSize);
+#endif
 	tc_writel(0, &tr->TxPollCtr);	/* Batch mode */
 	tc_writel(TX_THRESHOLD, &tr->TxThrsh);
 	tc_writel(INT_EN_CMD, &tr->Int_En);
@@ -2470,23 +2890,69 @@ static void tc35815_chip_init(struct net
 	tc_writel(RX_CTL_CMD, &tr->Rx_Ctl);	/* start MAC receiver */
 
 	/* start MAC transmitter */
+#ifndef NO_CHECK_CARRIER
+	/* TX4939 does not have EnLCarr */
+	if (lp->boardtype == TC35815_TX4939)
+		txctl &= ~Tx_EnLCarr;
 #ifdef WORKAROUND_LOSTCAR
 	/* WORKAROUND: ignore LostCrS in full duplex operation */
 	if ((lp->timer_state != asleep && lp->timer_state != lcheck) ||
 	    lp->fullduplex)
-		txctl = TX_CTL_CMD & ~Tx_EnLCarr;
+		txctl &= ~Tx_EnLCarr;
 #endif
+#endif /* !NO_CHECK_CARRIER */
 #ifdef GATHER_TXINT
 	txctl &= ~Tx_EnComp;	/* disable global tx completion int. */
 #endif
 	tc_writel(txctl, &tr->Tx_Ctl);
 }
 
+#ifdef CONFIG_PM
+static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct tc35815_local *lp = dev->priv;
+	unsigned long flags;
+
+	pci_save_state(pdev);
+	if (!netif_running(dev))
+		return 0;
+	netif_device_detach(dev);
+	spin_lock_irqsave(&lp->lock, flags);
+	del_timer(&lp->timer);		/* Kill if running	*/
+	tc35815_chip_reset(dev);
+	spin_unlock_irqrestore(&lp->lock, flags);
+	pci_set_power_state(pdev, PCI_D3hot);
+	return 0;
+}
+
+static int tc35815_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct tc35815_local *lp = dev->priv;
+	unsigned long flags;
+
+	pci_restore_state(pdev);
+	if (!netif_running(dev))
+		return 0;
+	pci_set_power_state(pdev, PCI_D0);
+	spin_lock_irqsave(&lp->lock, flags);
+	tc35815_restart(dev);
+	spin_unlock_irqrestore(&lp->lock, flags);
+	netif_device_attach(dev);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
 static struct pci_driver tc35815_pci_driver = {
 	.name		= MODNAME,
 	.id_table	= tc35815_pci_tbl,
 	.probe		= tc35815_init_one,
 	.remove		= __devexit_p(tc35815_remove_one),
+#ifdef CONFIG_PM
+	.suspend	= tc35815_suspend,
+	.resume		= tc35815_resume,
+#endif
 };
 
 module_param_named(speed, options.speed, int, 0);
@@ -2496,37 +2962,6 @@ MODULE_PARM_DESC(duplex, "0:auto, 1:half
 module_param_named(doforce, options.doforce, int, 0);
 MODULE_PARM_DESC(doforce, "try force link mode if auto-negotiation failed");
 
-#ifndef MODULE
-static int __init tc35815_setup(char *str)
-{
-	static struct {
-		char *name;
-		int *val;
-	} opts[] = {
-		{ "speed:", &options.speed },
-		{ "duplex:", &options.duplex },
-		{ "doforce:", &options.doforce },
-	};
-	int i;
-	char *p;
-	p = str;
-	while (p) {
-		for (i = 0; i < ARRAY_SIZE(opts); i++) {
-			int optlen = strlen(opts[i].name);
-			if (strncmp(p, opts[i].name, optlen) == 0) {
-				*opts[i].val = simple_strtol(p + optlen, NULL, 0);
-				break;
-			}
-		}
-		p = strchr(p, ',');
-		if (p)
-			p++;
-	}
-	return 1;
-}
-__setup("tc35815=", tc35815_setup);
-#endif
-
 static int __init tc35815_init_module(void)
 {
 	return pci_register_driver(&tc35815_pci_driver);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 6a58784..d87226b 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1460,6 +1460,7 @@
 #define PCI_VENDOR_ID_TOSHIBA_2		0x102f
 #define PCI_DEVICE_ID_TOSHIBA_TC35815CF	0x0030
 #define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU	0x0031
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939	0x0032
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE	0x0105
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC	0x0108
 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3

From anemo@mba.ocn.ne.jp Fri Mar  2 16:30:34 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 16:30:39 +0000 (GMT)
Received: from mba.ocn.ne.jp ([210.190.142.172]:23793 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S28573827AbXCBQae (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 2 Mar 2007 16:30:34 +0000
Received: from localhost (p2238-ipad211funabasi.chiba.ocn.ne.jp [58.91.158.238])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP id 769ECB7F8
	for <linux-mips@linux-mips.org>; Sat,  3 Mar 2007 01:29:13 +0900 (JST)
Date:	Sat, 03 Mar 2007 01:29:14 +0900 (JST)
Message-Id: <20070303.012914.15243240.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Subject: Re: fadvise on MIPS
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
In-Reply-To: <20070217.004812.03978264.anemo@mba.ocn.ne.jp>
	<20070217.004329.108739438.anemo@mba.ocn.ne.jp>
References: <20070217.004329.108739438.anemo@mba.ocn.ne.jp>
	<20070217.004812.03978264.anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14310
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

On Sat, 17 Feb 2007 00:43:29 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote:
> 1) unistd.h defines __NR_fadvise64 for all ABI but no
> __NR_fadvise64_64.  But sys_fadvise64_64 is used for all syscall
> entries.  For N64, sys_fadvise64 and sys_fadvise64_64 are same so no
> problem, but for other ABIs size of 'len' argument cause mismatch
> between kernel and libc.
> 
> 2) On O32, glibc pass a 'long long' argument by hi and lo words, but
> kernel needs padding word between 'fd' and 'offset' argument.
> 
> 3) On N32, glibc pass a 'long long' argument by hi and lo words, but
> kernel expects a single register value for 'long long' argument.
> 
> 4) __ARCH_WANT_SYS_FADVISE64 is defined in unistd.h but sys_fadvise64
> is not used.
> 
> What is preferred way to fix those issues?
> 
> It seems N64 do not need any fix.
> 
> For N32 and O32, kernel should be fixed anyway, but which syscall
> should be supported?  And whether kernel or libc should take care of
> 'long long' issue?

Then how about this absolutely untested patch?

diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 7c0b393..4d46b1d 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -596,7 +596,7 @@ einval:	li	v0, -EINVAL
 	sys	sys_remap_file_pages	5
 	sys	sys_set_tid_address	1
 	sys	sys_restart_syscall	0
-	sys	sys_fadvise64_64	7
+	sys	_sys_fadvise64		5
 	sys	sys_statfs64		3	/* 4255 */
 	sys	sys_fstatfs64		2
 	sys	sys_timer_create	3
@@ -647,7 +647,7 @@ einval:	li	v0, -EINVAL
 	sys	sys_ppoll		5
 	sys	sys_unshare		1
 	sys	sys_splice		4
-	sys	sys_sync_file_range	7	/* 4305 */
+	sys	_sys_sync_file_range	6	/* 4305 */
 	sys	sys_tee			4
 	sys	sys_vmsplice		4
 	sys	sys_move_pages		6
@@ -656,6 +656,7 @@ einval:	li	v0, -EINVAL
 	sys	sys_kexec_load		4
 	sys	sys_getcpu		3
 	sys	sys_epoll_pwait		6
+	sys	_sys_fadvise64_64	6
 	.endm
 
 	/* We pre-compute the number of _instruction_ bytes needed to
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index f17e31e..2013773 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -336,7 +336,7 @@ EXPORT(sysn32_call_table)
 	PTR	sys_set_tid_address
 	PTR	sys_restart_syscall
 	PTR	compat_sys_semtimedop			/* 6215 */
-	PTR	sys_fadvise64_64
+	PTR	_sys_fadvise64
 	PTR	compat_sys_statfs64
 	PTR	compat_sys_fstatfs64
 	PTR	sys_sendfile64
@@ -397,3 +397,4 @@ EXPORT(sysn32_call_table)
 	PTR	compat_sys_kexec_load
 	PTR	sys_getcpu
 	PTR	compat_sys_epoll_pwait
+	PTR	_sys_fadvise64_64
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 142c9b7..3cc443b 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -459,7 +459,7 @@ sys_call_table:
 	PTR	sys_remap_file_pages
 	PTR	sys_set_tid_address
 	PTR	sys_restart_syscall
-	PTR	sys_fadvise64_64
+	PTR	_sys_fadvise64
 	PTR	compat_sys_statfs64		/* 4255 */
 	PTR	compat_sys_fstatfs64
 	PTR	compat_sys_timer_create
@@ -519,4 +519,5 @@ sys_call_table:
 	PTR	compat_sys_kexec_load
 	PTR	sys_getcpu
 	PTR	compat_sys_epoll_pwait
+	PTR	_sys_fadvise64_64
 	.size	sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 26e1a7e..ab8af1c 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -435,3 +435,29 @@ int kernel_execve(const char *filename,
 
 	return -__v0;
 }
+
+#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_COMPAT)
+#ifdef __BIG_ENDIAN
+#define merge_64(r1,r2)	(((u64)(r1) << 32) + ((u32)(r2)))
+#else
+#define merge_64(r1,r2)	(((u64)(r2) << 32) + ((u32)(r1)))
+#endif
+asmlinkage long _sys_fadvise64_64(int fd, long a1, long a2, long a3, long a4,
+				  int advice)
+{
+	return sys_fadvise64_64(fd, merge_64(a1, a2), merge_64(a3, a4),
+				advice);
+}
+
+asmlinkage long _sys_fadvise64(int fd, long a1, long a2, size_t len, int advice)
+{
+	return sys_fadvise64_64(fd, merge_64(a1, a2), len, advice);
+}
+
+asmlinkage long _sys_sync_file_range(int fd, long a1, long a2, long a3, long a4,
+				     unsigned int flags)
+{
+	return sys_sync_file_range(fd, merge_64(a1, a2), merge_64(a3, a4),
+				   flags);
+}
+#endif
diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h
index 696cff3..bf3ff4a 100644
--- a/include/asm-mips/unistd.h
+++ b/include/asm-mips/unistd.h
@@ -334,6 +334,7 @@
 #define __NR_kexec_load			(__NR_Linux + 311)
 #define __NR_getcpu			(__NR_Linux + 312)
 #define __NR_epoll_pwait		(__NR_Linux + 313)
+#define __NR_fadvise64_64		(__NR_Linux + 314)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
@@ -918,6 +919,7 @@
 #define __NR_kexec_load			(__NR_Linux + 274)
 #define __NR_getcpu			(__NR_Linux + 275)
 #define __NR_epoll_pwait		(__NR_Linux + 276)
+#define __NR_fadvise64_64		(__NR_Linux + 277)
 
 /*
  * Offset of the last N32 flavoured syscall

From florian.fainelli@int-evry.fr Fri Mar  2 21:09:57 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 21:10:02 +0000 (GMT)
Received: from smtp-ext.int-evry.fr ([157.159.11.17]:63650 "EHLO
	smtp-ext.int-evry.fr") by ftp.linux-mips.org with ESMTP
	id S20039604AbXCBVJ5 (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Mar 2007 21:09:57 +0000
Received: from mini.int.alphacore.net (florian.maisel.int-evry.fr [157.159.41.36])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by smtp-ext.int-evry.fr (Postfix) with ESMTP id 1F6848D1691
	for <linux-mips@linux-mips.org>; Fri,  2 Mar 2007 22:09:04 +0100 (CET)
From:	Florian Fainelli <florian.fainelli@int-evry.fr>
To:	linux-mips@linux-mips.org
Subject: [PATCH 0/7] MTX-1 patches
Date:	Fri, 2 Mar 2007 22:07:20 +0100
User-Agent: KMail/1.9.6
MIME-Version: 1.0
Content-Type: text/plain;
  charset="utf-8"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Message-Id: <200703022207.20580.florian.fainelli@int-evry.fr>
Return-Path: <florian.fainelli@int-evry.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14311
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: florian.fainelli@int-evry.fr
Precedence: bulk
X-list: linux-mips

Hi Ralf,

This patch suite is used in the OpenWrt au1000-2.6 port, and working 
flawlessly on MTX-1 boards for months now. Most patches are not from me, but 
forward ported from the openembedded repository.

Patches are based on 2.6.19.2 and should apply fine with 2.6.20.
-- 
Regards, Florian

From florian.fainelli@int-evry.fr Fri Mar  2 21:10:26 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 21:10:29 +0000 (GMT)
Received: from smtp-ext.int-evry.fr ([157.159.11.17]:14728 "EHLO
	smtp-ext.int-evry.fr") by ftp.linux-mips.org with ESMTP
	id S20039606AbXCBVKB (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Mar 2007 21:10:01 +0000
Received: from mini.int.alphacore.net (florian.maisel.int-evry.fr [157.159.41.36])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by smtp-ext.int-evry.fr (Postfix) with ESMTP id F11F48D1693
	for <linux-mips@linux-mips.org>; Fri,  2 Mar 2007 22:09:08 +0100 (CET)
From:	Florian Fainelli <florian.fainelli@int-evry.fr>
To:	linux-mips@linux-mips.org
Subject: [PATCH 1/7] MTX-1 watchdog driver
Date:	Fri, 2 Mar 2007 22:07:26 +0100
User-Agent: KMail/1.9.6
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
  boundary="Boundary-00=_OIJ6FHfN7oBlxto"
Message-Id: <200703022207.26276.florian.fainelli@int-evry.fr>
Return-Path: <florian.fainelli@int-evry.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14312
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: florian.fainelli@int-evry.fr
Precedence: bulk
X-list: linux-mips

--Boundary-00=_OIJ6FHfN7oBlxto
Content-Type: text/plain;
  charset="utf-8"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

This patch is required if you want to use a MTX-1 board and do not see it 
being rebooted every 10 seconds.

Signed-off-by: Florian Fainelli <florian.fainelli@int-evry.fr>
--

--Boundary-00=_OIJ6FHfN7oBlxto
Content-Type: text/plain;
  charset="utf-8";
  name="004-mtx1_watchdog.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="004-mtx1_watchdog.patch"

diff -urN linux-2.6.16.7/drivers/char/watchdog/Kconfig linux-2.6.16.7.new/drivers/char/watchdog/Kconfig
--- linux-2.6.16.7/drivers/char/watchdog/Kconfig	2006-04-17 23:53:25.000000000 +0200
+++ linux-2.6.16.7.new/drivers/char/watchdog/Kconfig	2006-04-22 23:23:53.000000000 +0200
@@ -460,6 +460,14 @@
 	  timer expired and no process has written to /dev/watchdog during
 	  that time.
 
+config MTX1_WATCHDOG
+	tristate "MTX-1 Hardware Watchdog"
+	depends on WATCHDOG && MIPS_MTX1
+	help
+	  Hardware driver for the AccessCube MTX-1 watchdog. This is a
+	  watchdog timer that will reboot the machine after a 100 seconds
+	  timer expired.
+
 # S390 Architecture
 
 config ZVM_WATCHDOG
diff -urN linux-2.6.16.7/drivers/char/watchdog/Makefile linux-2.6.16.7.new/drivers/char/watchdog/Makefile
--- linux-2.6.16.7/drivers/char/watchdog/Makefile	2006-04-17 23:53:25.000000000 +0200
+++ linux-2.6.16.7.new/drivers/char/watchdog/Makefile	2006-04-22 23:21:18.000000000 +0200
@@ -65,6 +65,7 @@
 
 # MIPS Architecture
 obj-$(CONFIG_INDYDOG) += indydog.o
+obj-$(CONFIG_MTX1_WATCHDOG) += mtx-1_watchdog.o
 
 # S390 Architecture
 
diff -urN linux-2.6.16.7/drivers/char/watchdog/mtx-1_watchdog.c linux-2.6.16.7.new/drivers/char/watchdog/mtx-1_watchdog.c
--- linux-2.6.16.7/drivers/char/watchdog/mtx-1_watchdog.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.16.7.new/drivers/char/watchdog/mtx-1_watchdog.c	2006-04-22 23:20:53.000000000 +0200
@@ -0,0 +1,246 @@
+/*
+ *      Driver for the MTX-1 Watchdog.
+ *
+ *      (c) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved.
+ *                              http://www.4g-systems.biz
+ *
+ *      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.
+ *
+ *      Neither Michael Stickel nor 4G Systems admit liability nor provide
+ *      warranty for any of this software. This material is provided
+ *      "AS-IS" and at no charge.
+ *
+ *      (c) Copyright 2005    4G Systems <info@4g-systems.biz>
+ *
+ *      Release 0.01.
+ *
+ *      Author: Michael Stickel  michael.stickel@4g-systems.biz
+ *
+ *
+ *      The Watchdog is configured to reset the MTX-1
+ *      if it is not triggered for 100 seconds.
+ *      It should not be triggered more often than 1.6 seconds.
+ *
+ *      A timer triggers the watchdog every 5 seconds, until
+ *      it is opened for the first time. After the first open
+ *      it MUST be triggered every 2..95 seconds.
+ */
+#include <linux/autoconf.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/fs.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+#ifndef FALSE
+# define FALSE (0)
+#endif
+
+#ifndef TRUE
+# define TRUE (!FALSE)
+#endif
+
+
+//---------[ Hardware Functions ]-----------------
+
+static void mtx1_trigger_wd (void)
+{
+	/*
+	 * toggle GPIO2_15
+	 */
+
+	u32 tmp = au_readl(GPIO2_DIR);
+	tmp = (tmp & ~(1<<15)) | ((~tmp) & (1<<15));
+	au_writel (tmp, GPIO2_DIR);
+}
+
+static void mtx1_enable_wd (void)
+{
+	au_writel (au_readl(GPIO2_DIR) | (u32)(1<<15), GPIO2_DIR);
+}
+
+static void mtx1_disable_wd (void)
+{
+	au_writel (au_readl(GPIO2_DIR) & ~((u32)(1<<15)), GPIO2_DIR);
+}
+
+
+//---------[ Timer Functions ]-----------------
+
+static struct timer_list   wd_trigger_timer;
+static char                timer_is_running = FALSE;
+
+static void wd_timer_callback (unsigned long data)
+{
+	if (timer_is_running)
+		mod_timer (&wd_trigger_timer, jiffies + 5 * HZ);
+	mtx1_trigger_wd();
+}
+
+static void start_wd_timer (void)
+{
+	if (!timer_is_running) {
+		struct timer_list *t = &wd_trigger_timer;
+		
+		init_timer (t);
+		t->function = wd_timer_callback;
+		t->data     = (unsigned long)0L;
+		t->expires  = jiffies + 5 * HZ;   // 5 seconds.
+		add_timer (t);
+		timer_is_running = TRUE;
+	}
+}
+
+
+
+static void stop_wd_timer (void)
+{
+	if (timer_is_running) {
+		del_timer(&wd_trigger_timer);
+		timer_is_running = FALSE;
+	}
+}
+
+
+//---------[ File Functions ]-----------------
+
+static char restart_after_close;
+
+static int mtx1wd_open (struct inode *inode, struct file *file)
+{
+	if (MINOR(inode->i_rdev) != WATCHDOG_MINOR) return -ENODEV;
+	//MOD_INC_USE_COUNT;
+
+	// stop the timer, if it is running. It will not be
+	// started again, until the module is loaded again.
+	stop_wd_timer();
+
+	// sleep for 2 seconds, to ensure, that the wd is
+	// not triggered more often than every 2 seconds.
+	schedule_timeout (2 * HZ);
+
+	return 0;
+}
+
+
+static int mtx1wd_release (struct inode *inode, struct file *file) {
+	if (MINOR(inode->i_rdev)==WATCHDOG_MINOR) {
+	}
+	if (restart_after_close)
+		start_wd_timer();
+	//MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+static ssize_t mtx1wd_write (struct file *file, const char *buf, size_t count, loff_t *ppos) {
+
+	mtx1_trigger_wd ();
+
+	if (count > 0) {
+               char buffer[10];
+               int n = (count>9)?9:count;
+
+               if (copy_from_user (&buffer, buf, n))
+                       return -EFAULT;
+               buffer[n]=0;
+
+               if (count >= 4 && strncmp("auto", buffer, 4)==0)
+                       restart_after_close = 1;
+
+               else if (count >= 6 && strncmp("manual", buffer, 6)==0)
+                       restart_after_close = 0;
+
+               return n;
+	}
+
+	return 0;
+}
+
+static ssize_t mtx1wd_read (struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+       char * state = restart_after_close ? "auto\n" : "manual\n";
+       int n = strlen(state)+1;
+
+       if (file->f_pos >= n)
+               return 0;
+
+       if (count < n)
+               return -EINVAL;
+
+       if(copy_to_user(buf, state, n))
+               return -EFAULT;
+
+       file->f_pos += n;
+
+       return n;
+}
+
+static struct file_operations mtx1wd_fops = {
+	.owner = THIS_MODULE,
+	.read = mtx1wd_read,
+	.write = mtx1wd_write,
+	.open = mtx1wd_open,
+	.release = mtx1wd_release
+};
+
+
+static struct miscdevice mtx1wd_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&mtx1wd_fops
+};
+
+
+
+//---------[ Module Functions ]-----------------
+
+
+static int __init init_mtx1_watchdog(void)
+{
+	printk("MTX-1 watchdog driver\n");
+
+	misc_register(&mtx1wd_miscdev);
+	
+	restart_after_close = 0;
+
+	mtx1_enable_wd ();
+
+	//-- trigger it for the first time.
+	//-- We do not exactly know how long it has not been triggered.
+	mtx1_trigger_wd ();
+
+	// start a timer, that calls mtx1_trigger_wd every 5 seconds.
+	start_wd_timer();
+
+	return 0;
+}
+
+static void __exit exit_mtx1_watchdog(void) {
+
+	// stop the timer, if it is running.
+        stop_wd_timer();
+
+        misc_deregister(&mtx1wd_miscdev);
+
+        mtx1_disable_wd();
+}
+
+module_init(init_mtx1_watchdog);
+module_exit(exit_mtx1_watchdog);
+
+MODULE_AUTHOR("Michael Stickel");
+MODULE_DESCRIPTION("Driver for the MTX-1 watchdog");
+MODULE_LICENSE("GPL");

--Boundary-00=_OIJ6FHfN7oBlxto--

From florian.fainelli@int-evry.fr Fri Mar  2 21:10:52 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 21:10:59 +0000 (GMT)
Received: from smtp-ext.int-evry.fr ([157.159.11.17]:2215 "EHLO
	smtp-ext.int-evry.fr") by ftp.linux-mips.org with ESMTP
	id S20039614AbXCBVKK (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Mar 2007 21:10:10 +0000
Received: from mini.int.alphacore.net (florian.maisel.int-evry.fr [157.159.41.36])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by smtp-ext.int-evry.fr (Postfix) with ESMTP id EB8948D1694
	for <linux-mips@linux-mips.org>; Fri,  2 Mar 2007 22:09:17 +0100 (CET)
From:	Florian Fainelli <florian.fainelli@int-evry.fr>
To:	linux-mips@linux-mips.org
Subject: [PATCH 2/7] Au1000 eth : Link beat detection
Date:	Fri, 2 Mar 2007 22:07:35 +0100
User-Agent: KMail/1.9.6
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
  boundary="Boundary-00=_XIJ6FfcY7J8uNDy"
Message-Id: <200703022207.35218.florian.fainelli@int-evry.fr>
Return-Path: <florian.fainelli@int-evry.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14313
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: florian.fainelli@int-evry.fr
Precedence: bulk
X-list: linux-mips

--Boundary-00=_XIJ6FfcY7J8uNDy
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

This patch fixes the link beat detection when the cable is not plugged at 
startup. It is not MTX1 specific.

Signed-off-by: Florian Fainelli <florian.fainelli@int-evry.fr>
--

--Boundary-00=_XIJ6FfcY7J8uNDy
Content-Type: text/plain;
  charset="iso-8859-1";
  name="005-au1000_eth_link_beat.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="005-au1000_eth_link_beat.patch"

diff -urN linux-2.6.16.7/drivers/net/au1000_eth.c linux-2.6.16.7.new/drivers/net/au1000_eth.c
--- linux-2.6.16.7/drivers/net/au1000_eth.c	2006-04-17 23:53:25.000000000 +0200
+++ linux-2.6.16.7.new/drivers/net/au1000_eth.c	2006-04-23 01:42:48.000000000 +0200
@@ -12,6 +12,9 @@
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
  *
+ *         Bjoern Riemer 2004
+ *           riemer@fokus.fraunhofer.de or riemer@riemer-nt.de
+ *             // fixed the link beat detection with ioctls (SIOCGMIIPHY)
  * ########################################################################
  *
  *  This program is free software; you can distribute it and/or modify it
@@ -1672,6 +1675,10 @@
 	aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
 	control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE;
 #ifndef CONFIG_CPU_LITTLE_ENDIAN
+	/*riemer: fix for startup without cable */
+	if (!link)
+		dev->flags &= ~IFF_RUNNING;
+
 	control |= MAC_BIG_ENDIAN;
 #endif
 	if (link && (dev->if_port == IF_PORT_100BASEFX)) {

--Boundary-00=_XIJ6FfcY7J8uNDy--

From florian.fainelli@int-evry.fr Fri Mar  2 21:11:22 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 21:11:29 +0000 (GMT)
Received: from smtp-ext.int-evry.fr ([157.159.11.17]:7054 "EHLO
	smtp-ext.int-evry.fr") by ftp.linux-mips.org with ESMTP
	id S20039616AbXCBVKR (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Mar 2007 21:10:17 +0000
Received: from mini.int.alphacore.net (florian.maisel.int-evry.fr [157.159.41.36])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by smtp-ext.int-evry.fr (Postfix) with ESMTP id AD75C8D1695
	for <linux-mips@linux-mips.org>; Fri,  2 Mar 2007 22:09:24 +0100 (CET)
From:	Florian Fainelli <florian.fainelli@int-evry.fr>
To:	linux-mips@linux-mips.org
Subject: [PATCH 3/7] MTX1 setup : remove unneeded settings
Date:	Fri, 2 Mar 2007 22:07:41 +0100
User-Agent: KMail/1.9.6
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
  boundary="Boundary-00=_dIJ6FCkMyOVD+Uz"
Message-Id: <200703022207.41964.florian.fainelli@int-evry.fr>
Return-Path: <florian.fainelli@int-evry.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14314
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: florian.fainelli@int-evry.fr
Precedence: bulk
X-list: linux-mips

--Boundary-00=_dIJ6FCkMyOVD+Uz
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

This patch removes unnecessary settings at setup time.

Signed-off-by: Florian Fainelli <florian.fainelli@int-evry.fr>
--

--Boundary-00=_dIJ6FCkMyOVD+Uz
Content-Type: text/plain;
  charset="iso-8859-1";
  name="007-mtx1_sio2.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="007-mtx1_sio2.patch"

--- linux-2.6.16.7/arch/mips/au1000/mtx-1/board_setup.c	2006-04-17 23:53:25.000000000 +0200
+++ linux-2.6.16.7.new/arch/mips/au1000/mtx-1/board_setup.c	2006-04-23 14:35:42.000000000 +0200
@@ -71,9 +71,7 @@
 #endif
 
 	// initialize sys_pinfunc:
-	// disable second ethernet port (SYS_PF_NI2)
-	// set U3/GPIO23 to GPIO23 (SYS_PF_U3)
-	au_writel( SYS_PF_NI2 | SYS_PF_U3, SYS_PINFUNC );
+	au_writel( SYS_PF_NI2, SYS_PINFUNC );
 
 	// initialize GPIO
 	au_writel( 0xFFFFFFFF, SYS_TRIOUTCLR );

--Boundary-00=_dIJ6FCkMyOVD+Uz--

From florian.fainelli@int-evry.fr Fri Mar  2 21:11:52 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 21:11:55 +0000 (GMT)
Received: from smtp-ext.int-evry.fr ([157.159.11.17]:50596 "EHLO
	smtp-ext.int-evry.fr") by ftp.linux-mips.org with ESMTP
	id S20039618AbXCBVKX (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Mar 2007 21:10:23 +0000
Received: from mini.int.alphacore.net (florian.maisel.int-evry.fr [157.159.41.36])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by smtp-ext.int-evry.fr (Postfix) with ESMTP id E736A8D1696
	for <linux-mips@linux-mips.org>; Fri,  2 Mar 2007 22:09:30 +0100 (CET)
From:	Florian Fainelli <florian.fainelli@int-evry.fr>
To:	linux-mips@linux-mips.org
Subject: [PATCH 4/7] MTX1 isdel carbus ressources
Date:	Fri, 2 Mar 2007 22:07:48 +0100
User-Agent: KMail/1.9.6
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
  boundary="Boundary-00=_kIJ6Flu0c4KDnm/"
Message-Id: <200703022207.48159.florian.fainelli@int-evry.fr>
Return-Path: <florian.fainelli@int-evry.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14315
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: florian.fainelli@int-evry.fr
Precedence: bulk
X-list: linux-mips

--Boundary-00=_kIJ6Flu0c4KDnm/
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

This patch adds cardbus ressources for MTX1 boards which have a PCMCIA 
controller.

Signed-off-by: Florian Fainelli <florian.fainelli@int-evry.fr>
--

--Boundary-00=_kIJ6Flu0c4KDnm/
Content-Type: text/x-diff;
  charset="us-ascii";
  name="008-isdel_cardbus.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="008-isdel_cardbus.patch"

diff -urN linux-2.6.16.7/arch/mips/au1000/mtx-1/board_setup.c linux-2.6.16.7.new/arch/mips/au1000/mtx-1/board_setup.c
--- linux-2.6.16.7/arch/mips/au1000/mtx-1/board_setup.c	2006-04-23 14:39:21.000000000 +0200
+++ linux-2.6.16.7.new/arch/mips/au1000/mtx-1/board_setup.c	2006-04-23 14:39:03.000000000 +0200
@@ -44,6 +44,9 @@
 #include <asm/pgtable.h>
 #include <asm/mach-au1x00/au1000.h>
 
+extern int (*board_pci_idsel)(unsigned int devsel, int assert);
+int    mtx1_pci_idsel(unsigned int devsel, int assert);
+
 void board_reset (void)
 {
 	/* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
@@ -77,11 +80,37 @@
 	au_writel( 0xFFFFFFFF, SYS_TRIOUTCLR );
 	au_writel( 0x00000001, SYS_OUTPUTCLR ); // set M66EN (PCI 66MHz) to OFF
 	au_writel( 0x00000008, SYS_OUTPUTSET ); // set PCI CLKRUN# to OFF
+	au_writel( 0x00000002, SYS_OUTPUTSET ); // set EXT_IO3 ON
 	au_writel( 0x00000020, SYS_OUTPUTCLR ); // set eth PHY TX_ER to OFF
 
 	// enable LED and set it to green
 	au_writel( au_readl(GPIO2_DIR) | 0x1800, GPIO2_DIR );
 	au_writel( 0x18000800, GPIO2_OUTPUT );
 
+	board_pci_idsel = mtx1_pci_idsel;
+
 	printk("4G Systems MTX-1 Board\n");
 }
+
+int
+mtx1_pci_idsel(unsigned int devsel, int assert)
+{
+#define MTX_IDSEL_ONLY_0_AND_3 0
+#if MTX_IDSEL_ONLY_0_AND_3
+       if (devsel != 0 && devsel != 3) {
+               printk("*** not 0 or 3\n");
+               return 0;
+       }
+#endif
+
+       if (assert && devsel != 0) {
+               // supress signal to cardbus
+               au_writel( 0x00000002, SYS_OUTPUTCLR ); // set EXT_IO3 OFF
+       }
+       else {
+               au_writel( 0x00000002, SYS_OUTPUTSET ); // set EXT_IO3 ON
+       }
+       au_sync_udelay(1);
+       return 1;
+}
+
diff -urN linux-2.6.16.7/arch/mips/au1000/mtx-1/irqmap.c linux-2.6.16.7.new/arch/mips/au1000/mtx-1/irqmap.c
--- linux-2.6.16.7/arch/mips/au1000/mtx-1/irqmap.c	2006-04-23 14:40:54.000000000 +0200
+++ linux-2.6.16.7.new/arch/mips/au1000/mtx-1/irqmap.c	2006-04-23 14:40:12.000000000 +0200
@@ -48,7 +48,7 @@
 #include <asm/mach-au1x00/au1000.h>
 
 char irq_tab_alchemy[][5] __initdata = {
- [0] = { -1, INTA, INTB, INTX, INTX},   /* IDSEL 00 - AdapterA-Slot0 (top)    */
+ [0] = { -1, INTA, INTA, INTX, INTX},   /* IDSEL 00 - AdapterA-Slot0 (top)    */
  [1] = { -1, INTB, INTA, INTX, INTX},   /* IDSEL 01 - AdapterA-Slot1 (bottom) */
  [2] = { -1, INTC, INTD, INTX, INTX},   /* IDSEL 02 - AdapterB-Slot0 (top)    */
  [3] = { -1, INTD, INTC, INTX, INTX},   /* IDSEL 03 - AdapterB-Slot1 (bottom) */

--Boundary-00=_kIJ6Flu0c4KDnm/--

From florian.fainelli@int-evry.fr Fri Mar  2 21:12:18 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 21:12:24 +0000 (GMT)
Received: from smtp-ext.int-evry.fr ([157.159.11.17]:10670 "EHLO
	smtp-ext.int-evry.fr") by ftp.linux-mips.org with ESMTP
	id S20039605AbXCBVKh (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Mar 2007 21:10:37 +0000
Received: from mini.int.alphacore.net (florian.maisel.int-evry.fr [157.159.41.36])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by smtp-ext.int-evry.fr (Postfix) with ESMTP id 4C8B78D1691
	for <linux-mips@linux-mips.org>; Fri,  2 Mar 2007 22:09:44 +0100 (CET)
From:	Florian Fainelli <florian.fainelli@int-evry.fr>
To:	linux-mips@linux-mips.org
Subject: [PATCH 5/7] MTX1 clear PCI errors
Date:	Fri, 2 Mar 2007 22:08:01 +0100
User-Agent: KMail/1.9.6
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
  boundary="Boundary-00=_xIJ6FubBCfdGaI9"
Message-Id: <200703022208.01454.florian.fainelli@int-evry.fr>
Return-Path: <florian.fainelli@int-evry.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14316
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: florian.fainelli@int-evry.fr
Precedence: bulk
X-list: linux-mips

--Boundary-00=_xIJ6FubBCfdGaI9
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

This patch clears PCI errors after showing more debug informations.

Signed-off-by: Florian Fainelli <florian.fainelli@int-evry.fr>
-- 

--Boundary-00=_xIJ6FubBCfdGaI9
Content-Type: text/plain;
  charset="iso-8859-1";
  name="009-pci_clear_errors.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="009-pci_clear_errors.patch"

diff -urN linux-2.6.19/arch/mips/pci/ops-au1000.c linux-2.6.19.new/arch/mips/pci/ops-au1000.c
--- linux-2.6.19/arch/mips/pci/ops-au1000.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.new/arch/mips/pci/ops-au1000.c	2006-12-28 03:02:42.000000000 +0100
@@ -172,7 +172,11 @@
 		error = -1;
 		DBG("Au1x Master Abort\n");
 	} else if ((status >> 28) & 0xf) {
-		DBG("PCI ERR detected: status %x\n", status);
+		DBG("PCI ERR detected: device %d, status %x\n", device, ((status >> 28) & 0xf));
+		
+		/* clear errors */
+		au_writel(status & 0xf000ffff, Au1500_PCI_STATCMD);		
+
 		*data = 0xffffffff;
 		error = -1;
 	}

--Boundary-00=_xIJ6FubBCfdGaI9--

From florian.fainelli@int-evry.fr Fri Mar  2 21:12:48 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 21:12:54 +0000 (GMT)
Received: from smtp-ext.int-evry.fr ([157.159.11.17]:28083 "EHLO
	smtp-ext.int-evry.fr") by ftp.linux-mips.org with ESMTP
	id S20039622AbXCBVKl (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Mar 2007 21:10:41 +0000
Received: from mini.int.alphacore.net (florian.maisel.int-evry.fr [157.159.41.36])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by smtp-ext.int-evry.fr (Postfix) with ESMTP id 215FC8D1698
	for <linux-mips@linux-mips.org>; Fri,  2 Mar 2007 22:09:49 +0100 (CET)
From:	Florian Fainelli <florian.fainelli@int-evry.fr>
To:	linux-mips@linux-mips.org
Subject: [PATCH 6/7] I2C via MTX-1 GPIO lines
Date:	Fri, 2 Mar 2007 22:08:05 +0100
User-Agent: KMail/1.9.6
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
  boundary="Boundary-00=_2IJ6FD92LqAwZM/"
Message-Id: <200703022208.06018.florian.fainelli@int-evry.fr>
Return-Path: <florian.fainelli@int-evry.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14317
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: florian.fainelli@int-evry.fr
Precedence: bulk
X-list: linux-mips

--Boundary-00=_2IJ6FD92LqAwZM/
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

This patch adds support for an I2C bus using GPIO devices. It is preconfigured 
to use the MTX-1 GPIO lines dedicated to I2C.

Signed-off-by: Florian Fainelli <florian.fainelli@int-evry.fr>
-- 

--Boundary-00=_2IJ6FD92LqAwZM/
Content-Type: text/plain;
  charset="us-ascii";
  name="010-au100_gpio_i2c.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="010-au100_gpio_i2c.patch"

diff -urN linux-2.6.19/drivers/i2c/busses/Kconfig linux-2.6.19.new/drivers/i2c/busses/Kconfig
--- linux-2.6.19/drivers/i2c/busses/Kconfig	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.new/drivers/i2c/busses/Kconfig	2006-12-28 17:04:34.000000000 +0100
@@ -84,6 +84,17 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-au1550.
 
+config I2C_AU1X00GPIO
+	tristate "Au1x00 i2c using GPIO pins"
+	depends on I2C
+	select I2C_ALGOBIT
+	help
+	  If you say yest to this option, support will be included for the
+	  Au1x00 GPIO interface.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-au1x00gpio.
+
 config I2C_ELEKTOR
 	tristate "Elektor ISA card"
 	depends on I2C && ISA && BROKEN_ON_SMP
diff -urN linux-2.6.19/drivers/i2c/busses/Makefile linux-2.6.19.new/drivers/i2c/busses/Makefile
--- linux-2.6.19/drivers/i2c/busses/Makefile	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.new/drivers/i2c/busses/Makefile	2006-12-28 03:07:37.000000000 +0100
@@ -9,6 +9,7 @@
 obj-$(CONFIG_I2C_AMD756_S4882)	+= i2c-amd756-s4882.o
 obj-$(CONFIG_I2C_AMD8111)	+= i2c-amd8111.o
 obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o
+obj-$(CONFIG_I2C_AU1X00GPIO)	+= i2c-au1x00gpio.o
 obj-$(CONFIG_I2C_ELEKTOR)	+= i2c-elektor.o
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
 obj-$(CONFIG_I2C_I801)		+= i2c-i801.o
diff -urN linux-2.6.19/drivers/i2c/busses/i2c-au1x00gpio.c linux-2.6.19.new/drivers/i2c/busses/i2c-au1x00gpio.c
--- linux-2.6.19/drivers/i2c/busses/i2c-au1x00gpio.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.new/drivers/i2c/busses/i2c-au1x00gpio.c	2006-12-28 17:02:10.000000000 +0100
@@ -0,0 +1,406 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-au1x00gpio.c i2c-hw access for Au1x00 GPIO pins.                      */
+/* ------------------------------------------------------------------------- */
+/*   Copyright (C) 1995-2000 Michael Stickel
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
+/* ------------------------------------------------------------------------- */ 
+
+/* With some changes from Ky�stialkki <kmalkki@cc.hut.fi> and even
+   Frodo Looijaard <frodol@dds.nl>
+   Simon G. Vogl
+*/
+
+/* $Id: i2c-au1x00gpio.c,v 1.1.1.2 2004/01/22 15:35:47 br1 Exp $ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm-mips/mach-au1x00/au1000.h>
+#include <asm-mips/mach-au1x00/au1000_gpio.h>
+
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+struct i2c_au1x00gpio
+{
+	struct i2c_au1x00gpio *next;
+
+	short  scl_gpio;
+	short  sda_gpio;
+
+	unsigned long scl_mask;
+	unsigned long sda_mask;
+
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data bit_au1x00gpio_data;
+};
+
+static struct i2c_au1x00gpio *adapter_list;
+
+
+
+/* ----- global defines -----------------------------------------------	*/
+#define DEB(x)		/* should be reasonable open, close &c. 	*/
+#define DEB2(x) 	/* low level debugging - very slow 		*/
+#define DEBE(x)	x	/* error messages 				*/
+
+/* ----- printer port defines ------------------------------------------*/
+
+/* ----- local functions ----------------------------------------------	*/
+
+
+//-- Primary GPIO
+static void bit_au1x00gpio_setscl(void *data, int state)
+{
+  struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
+  if (state)
+    au_writel(adapter->scl_mask, SYS_TRIOUTCLR); // Disable Driver: Switch off Transistor => 1
+  else
+    au_writel(adapter->scl_mask, SYS_OUTPUTCLR); // Clear Output and switch on Transistor => 0
+}
+
+
+static void bit_au1x00gpio_setsda(void *data, int state)
+{
+  struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
+  if (state)
+    au_writel(adapter->sda_mask, SYS_TRIOUTCLR);
+  else
+    au_writel(adapter->sda_mask, SYS_OUTPUTCLR);
+}
+
+
+static int bit_au1x00gpio_getscl(void *data)
+{
+  struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
+  return (au_readl(SYS_PINSTATERD) & adapter->scl_mask) ? 1 : 0;
+}
+
+
+static int bit_au1x00gpio_getsda(void *data)
+{
+  struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
+  return (au_readl(SYS_PINSTATERD) & adapter->sda_mask) ? 1 : 0;
+}
+
+
+
+
+/*--
+ *-- Functions for accessing GPIO-2
+ *--
+ */
+static void bit_au1x00gpio2_setscl(void *data, int state)
+{
+  struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
+  if (state)
+    {
+      au_writel(au_readl(GPIO2_DIR) & ~adapter->scl_mask, GPIO2_DIR);
+    }
+  else
+    {
+      au_writel(au_readl(GPIO2_OUTPUT) & ~adapter->scl_mask, GPIO2_OUTPUT);
+      au_writel(au_readl(GPIO2_DIR) | adapter->scl_mask, GPIO2_DIR);
+    }
+}
+
+static void bit_au1x00gpio2_setsda(void *data, int state)
+{
+  struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
+  if (state)
+    {
+      au_writel(au_readl(GPIO2_DIR) & ~adapter->sda_mask, GPIO2_DIR);
+    }
+  else
+    {
+      au_writel(au_readl(GPIO2_OUTPUT) & ~adapter->sda_mask, GPIO2_OUTPUT);
+      au_writel(au_readl(GPIO2_DIR) | adapter->sda_mask, GPIO2_DIR);
+    }
+}
+
+static int bit_au1x00gpio2_getscl(void *data)
+{
+  struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
+  return (au_readl(GPIO2_PINSTATE) & adapter->scl_mask) ? 1 : 0;
+}
+
+static int bit_au1x00gpio2_getsda(void *data)
+{
+  struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
+  return (au_readl(GPIO2_PINSTATE) & adapter->sda_mask) ? 1 : 0;
+}
+
+
+
+static int check_i2c_au1x00gpio_adapter(struct i2c_au1x00gpio *adapter)
+{
+  int state = 0;
+
+  adapter->bit_au1x00gpio_data.setsda (adapter, 1);
+  adapter->bit_au1x00gpio_data.setscl (adapter, 1);
+
+  if (adapter->bit_au1x00gpio_data.getsda(adapter)==0)
+    {
+      printk ("i2c-au1x00gpio: sda line should read 1 but reads 0\n");
+      state = -1;
+    }
+  if (adapter->bit_au1x00gpio_data.getscl(adapter)==0)
+    {
+      printk ("i2c-au1x00gpio: scl line should read 1 but reads 0\n");
+      state = -1;
+    }
+
+
+  adapter->bit_au1x00gpio_data.setsda (adapter, 0);
+  adapter->bit_au1x00gpio_data.setscl (adapter, 0);
+
+  if (adapter->bit_au1x00gpio_data.getsda(adapter)==1)
+    {
+      printk ("i2c-au1x00gpio: sda line should read 0 but reads 1\n");
+      state = -1;
+    }
+  if (adapter->bit_au1x00gpio_data.getscl(adapter)==1)
+    {
+      printk ("i2c-au1x00gpio: scl line should read 0 but reads 1\n");
+      state = -1;
+    }
+
+  if (state==0)
+    printk ("i2c-au1x00gpio: adapter with scl=GPIO%d,sda=GPIO%d is working\n",
+	    adapter->scl_gpio, adapter->sda_gpio
+	    );
+  return state;
+}
+
+
+
+#if 0
+static int bit_au1x00gpio_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int bit_au1x00gpio_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void bit_au1x00gpio_inc_use(struct i2c_adapter *adap)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void bit_au1x00gpio_dec_use(struct i2c_adapter *adap)
+{
+	MOD_DEC_USE_COUNT;
+}
+#endif
+ 
+
+
+static struct i2c_algo_bit_data bit_au1x00gpio_data = {
+	.data = NULL,
+	.setsda = bit_au1x00gpio_setsda,
+	.setscl = bit_au1x00gpio_setscl,
+	.getsda = bit_au1x00gpio_getsda,
+	.getscl = bit_au1x00gpio_getscl,
+	.udelay = 80,
+	.timeout = HZ,
+}; 
+
+
+static struct i2c_adapter bit_au1x00gpio_ops = {
+        .owner          = THIS_MODULE,
+        .name           = "Au1x00 GPIO I2C adapter",
+        .id             = I2C_HW_B_AU1x00GPIO,
+};
+
+
+
+/*
+ * scl_gpio:
+ *   0..31 for primary GPIO's
+ *   200..215 for secondary GPIO's
+ *
+ * sda_gpio:
+ *   0..31 for primary GPIO's
+ *   200..215 for secondary GPIO's
+ *
+ * You can even mix primary and secondary GPIO's.
+ * E.g.:  i2c_au1x00gpio_create(4,206);
+ */
+
+static int i2c_au1x00gpio_create (int scl_gpio, int sda_gpio)
+{
+  if ((scl_gpio < 32 || (scl_gpio >= 200 && scl_gpio <= 215)) &&
+      (scl_gpio < 32 || (scl_gpio >= 200 && scl_gpio <= 215)))
+    {
+	struct i2c_au1x00gpio *adapter = kmalloc(sizeof(struct i2c_au1x00gpio),
+					  GFP_KERNEL);
+	if (!adapter) {
+		printk(KERN_ERR "i2c-au1x00-gpio: Unable to malloc.\n");
+		return -1;
+	}
+
+	printk(KERN_DEBUG "i2c-au1x00-gpio.o: attaching to SCL=GPIO%d, SDA=GPIO%d\n",
+	       scl_gpio, sda_gpio);
+
+	memset (adapter, 0, sizeof(struct i2c_au1x00gpio));
+
+	adapter->adapter = bit_au1x00gpio_ops;
+
+	adapter->adapter.algo_data = &adapter->bit_au1x00gpio_data;
+	adapter->bit_au1x00gpio_data = bit_au1x00gpio_data;
+	adapter->bit_au1x00gpio_data.data = adapter;
+
+	adapter->bit_au1x00gpio_data.data = adapter;
+
+	adapter->scl_gpio = scl_gpio;
+	adapter->sda_gpio = sda_gpio;
+
+        if (sda_gpio < 32)
+          {
+	    adapter->bit_au1x00gpio_data.setsda = bit_au1x00gpio_setsda;
+	    adapter->bit_au1x00gpio_data.getsda = bit_au1x00gpio_getsda;
+            adapter->sda_mask = 1<<sda_gpio;
+          }
+        else if (sda_gpio >= 200 && sda_gpio <= 215)
+          {
+	    adapter->bit_au1x00gpio_data.setsda = bit_au1x00gpio2_setsda;
+	    adapter->bit_au1x00gpio_data.getsda = bit_au1x00gpio2_getsda;
+            adapter->sda_mask = 1<<(sda_gpio-200);
+          }
+
+
+        if (scl_gpio < 32)
+          {
+	    adapter->bit_au1x00gpio_data.setscl = bit_au1x00gpio_setscl;
+	    adapter->bit_au1x00gpio_data.getscl = bit_au1x00gpio_getscl;
+            adapter->scl_mask = 1<<scl_gpio;
+          }
+        else if (scl_gpio >= 200 && scl_gpio <= 215)
+          {
+ 	    adapter->bit_au1x00gpio_data.setscl = bit_au1x00gpio2_setscl;
+	    adapter->bit_au1x00gpio_data.getscl = bit_au1x00gpio2_getscl;
+            adapter->scl_mask = 1<<(scl_gpio-200);
+          }
+
+	au_writel(0L, SYS_PININPUTEN);
+	if (check_i2c_au1x00gpio_adapter(adapter)==0)
+	  {
+	    adapter->bit_au1x00gpio_data.setsda (adapter, 1);
+	    adapter->bit_au1x00gpio_data.setscl (adapter, 1);
+
+	    if (i2c_bit_add_bus(&adapter->adapter) < 0)
+	      {
+		printk(KERN_ERR "i2c-au1x00-gpio: Unable to register with I2C.\n");
+		kfree(adapter);
+		return -1;		/* No good */
+	      }
+	    
+	    adapter->next = adapter_list;
+	    adapter_list = adapter;
+	    return 0;
+	  }
+    }
+  else
+    printk(KERN_ERR "i2c-au1x00-gpio: Invalid argument scl_gpio=%d, sda_gpio=%d.\n", scl_gpio, sda_gpio);
+  return -1;
+}
+
+
+
+static void i2c_au1x00gpio_delete (int scl_gpio, int sda_gpio)
+{
+	struct i2c_au1x00gpio *adapter, *prev = NULL;
+
+	for (adapter = adapter_list; adapter; adapter = adapter->next)
+	{
+		if (adapter->scl_gpio == scl_gpio &&
+		    adapter->sda_gpio == sda_gpio)
+		{
+			i2c_bit_del_bus(&adapter->adapter);
+			if (prev)
+				prev->next = adapter->next;
+			else
+				adapter_list = adapter->next;
+			kfree(adapter);
+			return;
+		}
+		prev = adapter;
+	}
+}
+
+
+
+
+
+#ifndef CONFIG_I2C_AU1X00GPIO_SCL
+#define CONFIG_I2C_AU1X00GPIO_SCL (210)
+#endif
+
+#ifndef CONFIG_I2C_AU1X00GPIO_SDA
+#define CONFIG_I2C_AU1X00GPIO_SDA (9)
+#endif
+
+static int au1x00gpiopin_scl = CONFIG_I2C_AU1X00GPIO_SCL;
+static int au1x00gpiopin_sda = CONFIG_I2C_AU1X00GPIO_SDA;
+
+
+
+static int __init i2c_bit_au1x00gpio_init(void)
+{
+  printk(KERN_INFO "i2c-au1x00gpio.o: i2c Au1x00 GPIO adapter module version\n");
+
+  if (i2c_au1x00gpio_create (au1x00gpiopin_scl, au1x00gpiopin_sda) == 0)
+    {
+      printk(KERN_INFO "i2c-au1x00gpio.o: registered I2C-Bus for GPIO%d,GPIO%d\n",
+            au1x00gpiopin_scl, au1x00gpiopin_sda
+            );
+      return 0;
+    }
+  printk(KERN_INFO "i2c-au1x00gpio.o: failed to register I2C-Bus for GPIO%d,GPIO%d\n",
+            au1x00gpiopin_scl, au1x00gpiopin_sda
+        );
+  return -1;
+}
+
+
+static void __exit i2c_bit_au1x00gpio_exit(void)
+{
+  i2c_au1x00gpio_delete (au1x00gpiopin_scl, au1x00gpiopin_sda);
+}
+
+module_param(au1x00gpiopin_scl, int, 0644);
+MODULE_PARM_DESC(au1x00gpiopin_scl, "GPIO pin number used for SCL pin.");
+
+module_param(au1x00gpiopin_sda, int, 0644);
+MODULE_PARM_DESC(au1x00gpiopin_sda, "GPIO pin number used for SDA pin.");
+
+MODULE_AUTHOR("Michael Stickel <michael@cubic.org>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for Au1x00 GPIO adapter.");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_bit_au1x00gpio_init);
+module_exit(i2c_bit_au1x00gpio_exit);
diff -urN linux-2.6.19/include/linux/i2c-id.h linux-2.6.19.new/include/linux/i2c-id.h
--- linux-2.6.19/include/linux/i2c-id.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.new/include/linux/i2c-id.h	2006-12-28 03:12:15.000000000 +0100
@@ -231,6 +231,9 @@
 /* --- Au1550 PSC adapters adapters					*/
 #define I2C_HW_AU1550_PSC	0x1b0000
 
+/* --- Au1x00 i2c GPIO adapter						*/
+#define I2C_HW_B_AU1x00GPIO 0x1b
+
 /* --- SMBus only adapters						*/
 #define I2C_HW_SMBUS_PIIX4	0x040000
 #define I2C_HW_SMBUS_ALI15X3	0x040001

--Boundary-00=_2IJ6FD92LqAwZM/--

From florian.fainelli@int-evry.fr Fri Mar  2 21:13:17 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 21:13:19 +0000 (GMT)
Received: from smtp-ext.int-evry.fr ([157.159.11.17]:28083 "EHLO
	smtp-ext.int-evry.fr") by ftp.linux-mips.org with ESMTP
	id S20039624AbXCBVKm (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Mar 2007 21:10:42 +0000
Received: from mini.int.alphacore.net (florian.maisel.int-evry.fr [157.159.41.36])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by smtp-ext.int-evry.fr (Postfix) with ESMTP id CE33B8D1693
	for <linux-mips@linux-mips.org>; Fri,  2 Mar 2007 22:09:54 +0100 (CET)
From:	Florian Fainelli <florian.fainelli@int-evry.fr>
To:	linux-mips@linux-mips.org
Subject: [PATCH 7/7] MTX1 LED driver
Date:	Fri, 2 Mar 2007 22:08:11 +0100
User-Agent: KMail/1.9.6
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
  boundary="Boundary-00=_7IJ6FRy2+eWtR+j"
Message-Id: <200703022208.11940.florian.fainelli@int-evry.fr>
Return-Path: <florian.fainelli@int-evry.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14318
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: florian.fainelli@int-evry.fr
Precedence: bulk
X-list: linux-mips

--Boundary-00=_7IJ6FRy2+eWtR+j
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

This patch adds support for controlling the LEDS on the MTX-1 board. It 
registers the power(green) and status(red) LEDs.

Signed-off-by: Florian Fainelli <florian.fainelli@int-evry.fr>
-- 

--Boundary-00=_7IJ6FRy2+eWtR+j
Content-Type: text/plain;
  charset="us-ascii";
  name="011-mtx1_leds.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="011-mtx1_leds.patch"

diff -urN linux-2.6.19.2/drivers/leds/Kconfig linux-2.6.19.2.new/drivers/leds/Kconfig
--- linux-2.6.19.2/drivers/leds/Kconfig	2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2.new/drivers/leds/Kconfig	2007-03-02 13:50:28.000000000 +0100
@@ -76,6 +76,13 @@
 	  This option enables support for the Soekris net4801 and net4826 error
 	  LED.
 
+config LEDS_MTX1
+	tristate "LED Support for MTX-1 boards"
+	depends on LEDS_CLASS && MIPS_MTX1
+	help
+	  This option enables support for the MTX-1 power and status LED.
+
+
 comment "LED Triggers"
 
 config LEDS_TRIGGERS
diff -urN linux-2.6.19.2/drivers/leds/Makefile linux-2.6.19.2.new/drivers/leds/Makefile
--- linux-2.6.19.2/drivers/leds/Makefile	2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2.new/drivers/leds/Makefile	2007-03-02 13:49:35.000000000 +0100
@@ -13,6 +13,7 @@
 obj-$(CONFIG_LEDS_S3C24XX)		+= leds-s3c24xx.o
 obj-$(CONFIG_LEDS_AMS_DELTA)		+= leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)		+= leds-net48xx.o
+obj-$(CONFIG_LEDS_MTX1)			+= leds-mtx1.o
 
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)	+= ledtrig-timer.o
diff -urN linux-2.6.19.2/drivers/leds/leds-mtx1.c linux-2.6.19.2.new/drivers/leds/leds-mtx1.c
--- linux-2.6.19.2/drivers/leds/leds-mtx1.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.2.new/drivers/leds/leds-mtx1.c	2007-03-02 13:49:08.000000000 +0100
@@ -0,0 +1,116 @@
+/*
+ * LED driver for MTX-1 boards
+ *
+ * Copyright 2007 Florian Fainelli <florian@openwrt.org>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <asm/mach-au1x00/au1000.h>
+
+static struct platform_device *pdev;
+
+static void mtx1_green_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
+{
+	/* The power LED cannot be controlled the same way as for the Status LED */
+	if (brightness) {
+        	au_writel( 0x18000800, GPIO2_OUTPUT );
+	} else {
+		au_writel( 0x18000000, GPIO2_OUTPUT);
+	}
+}
+
+static void mtx1_red_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
+{
+	/* We store GPIO address (originally address - 200) in the "flags" field*/
+	unsigned long pinmask = 1 << led_cdev->flags; 
+	if (brightness) {
+		au_writel((pinmask << 16) | pinmask, GPIO2_OUTPUT); 
+	} else { 
+		au_writel((pinmask << 16) | 0, GPIO2_OUTPUT);
+	}
+}
+
+static struct led_classdev mtx1_green_led = {
+	.name = "mtx1:green",
+	.brightness_set = mtx1_green_led_set,
+};
+
+static struct led_classdev mtx1_red_led = {
+	.name = "mtx1:red",
+	.flags = 12,
+	.brightness_set = mtx1_red_led_set,
+	.default_trigger = "ide-disk",
+};
+
+static int mtx1_leds_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = led_classdev_register(&pdev->dev, &mtx1_green_led);
+	if (ret < 0)
+		goto out;
+
+	ret = led_classdev_register(&pdev->dev, &mtx1_red_led);
+	if (ret < 0)
+		led_classdev_unregister(&mtx1_green_led);
+
+out:
+	return ret;
+}
+
+static int mtx1_leds_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&mtx1_green_led);
+	led_classdev_unregister(&mtx1_red_led);
+	return 0;
+}
+
+static struct platform_driver mtx1_leds_driver = {
+	.probe = mtx1_leds_probe,
+	.remove = mtx1_leds_remove,
+	.driver = {
+		.name = "mtx1-leds",
+	}
+};
+
+static int __init mtx1_leds_init(void)
+{
+	int ret;
+
+        ret = platform_driver_register(&mtx1_leds_driver);
+        if (ret < 0)
+                goto out;
+
+        pdev = platform_device_register_simple("mtx1-leds", -1, NULL, 0);
+        if (IS_ERR(pdev)) {
+                ret = PTR_ERR(pdev);
+                platform_driver_unregister(&mtx1_leds_driver);
+                goto out;
+        }
+
+out:
+        return ret;
+
+}
+		
+static void __exit mtx1_leds_exit(void)
+{
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&mtx1_leds_driver);
+}
+
+module_init(mtx1_leds_init);
+module_exit(mtx1_leds_exit);
+		
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
+MODULE_DESCRIPTION("MTX-1 LED driver");
+MODULE_LICENSE("GPL");

--Boundary-00=_7IJ6FRy2+eWtR+j--

From mbizon@freebox.fr Fri Mar  2 23:49:03 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Mar 2007 23:49:07 +0000 (GMT)
Received: from sakura.staff.proxad.net ([213.228.1.107]:14758 "EHLO
	sakura.staff.proxad.net") by ftp.linux-mips.org with ESMTP
	id S28640072AbXCBXtD (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Mar 2007 23:49:03 +0000
Received: from max by sakura.staff.proxad.net with local (Exim 3.36 #1 (Debian))
	id 1HNHRb-0000YW-00; Sat, 03 Mar 2007 00:45:47 +0100
Subject: Re: [PATCH 0/2] FLATMEM: allow memory to start at pfn != 0 [take
	#2]
From:	Maxime Bizon <mbizon@freebox.fr>
Reply-To: mbizon@freebox.fr
To:	Franck Bui-Huu <vagabon.xyz@gmail.com>
Cc:	ralf <ralf@linux-mips.org>, linux-mips <linux-mips@linux-mips.org>
In-Reply-To: <116841864595-git-send-email-fbuihuu@gmail.com>
References: <116841864595-git-send-email-fbuihuu@gmail.com>
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Organization: Freebox
Date:	Sat, 03 Mar 2007 00:45:47 +0100
Message-Id: <1172879147.964.65.camel@sakura.staff.proxad.net>
Mime-Version: 1.0
X-Mailer: Evolution 2.8.1 
Return-Path: <mbizon@freebox.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14319
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: mbizon@freebox.fr
Precedence: bulk
X-list: linux-mips


On Wed, 2007-01-10 at 09:44 +0100, Franck Bui-Huu wrote:

Hi Franck,

> Here's is the second attempt to make this works on your Malta board
> and all other boards that have some data reserved at the start of
> their memories. In these cases the first patchset assumed wrongly that

I was happy to try this patch on my 4Kec board with memory starting at
0x10000000 but it doesn't work.


Setting PHYS_OFFSET to 0, I get the expected "Wasting 2098176 bytes for
tracking 65568 unused pages" and everything works as usual.

Setting PHYS_OFFSET to 0x10000000, I get "Wasting 1024 bytes for
tracking 32 unused pages", but the kernel doesn't boot and crash in
init_bootmem_node().


Looking at phys_to_virt(), it looks like I also need to change
PAGE_OFFSET to 0x90000000 to get correct values. This makes the kernel
boot with a correct memory map, but userspace doesn't work anymore.

Just in case, I'm not using git head, but a 2.6.20 kernel with the 2
patches applied. Just tell me if you need complete dmesg.

Regards,

-- 
Maxime


From Marc_St-Jean@pmc-sierra.com Sat Mar  3 00:33:24 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 00:33:30 +0000 (GMT)
Received: from mother.pmc-sierra.com ([216.241.224.12]:5263 "HELO
	mother.pmc-sierra.bc.ca") by ftp.linux-mips.org with SMTP
	id S28640059AbXCCAdY (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Mar 2007 00:33:24 +0000
Received: (qmail 10696 invoked by uid 101); 3 Mar 2007 00:32:11 -0000
Received: from unknown (HELO pmxedge2.pmc-sierra.bc.ca) (216.241.226.184)
  by mother.pmc-sierra.com with SMTP; 3 Mar 2007 00:32:11 -0000
Received: from bby1exi01.pmc_nt.nt.pmc-sierra.bc.ca (bby1exi01.pmc-sierra.bc.ca [216.241.231.251])
	by pmxedge2.pmc-sierra.bc.ca (8.13.4/8.12.7) with ESMTP id l230WAnX003533;
	Fri, 2 Mar 2007 16:32:10 -0800
Received: by bby1exi01.pmc-sierra.bc.ca with Internet Mail Service (5.5.2657.72)
	id <FGCP2ZSS>; Fri, 2 Mar 2007 16:32:10 -0800
Message-ID: <45E8C1FA.3040708@pmc-sierra.com>
From:	Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH 1/5] mips: PMC MSP71xx core platform
Date:	Fri, 2 Mar 2007 16:31:54 -0800 
MIME-Version: 1.0
X-Mailer: Internet Mail Service (5.5.2657.72)
x-originalarrivaltime: 03 Mar 2007 00:31:59.0218 (UTC) FILETIME=[5AD42D20:01C75D2B]
user-agent: Thunderbird 1.5.0.10 (X11/20070221)
Content-Type: text/plain;
	charset="iso-8859-1"
Return-Path: <Marc_St-Jean@pmc-sierra.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14320
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: Marc_St-Jean@pmc-sierra.com
Precedence: bulk
X-list: linux-mips

Hi Ralf, thanks for taking the time to provide detailed feedback. I've
implemented your suggestions other than the few comments below.

Marc

Ralf Baechle wrote:
> On Fri, Feb 23, 2007 at 01:55:27PM -0600, Marc St-Jean wrote:

[...]

> diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c

[...]

>  > +void msp_cic_irq_dispatch(void)
>  > +{
>  > +     u32 pending;
>  > +     int intbase;
>  > +
>  > +     intbase = MSP_CIC_INTBASE;
>  > +     pending = *CIC_STS_REG & *CIC_VPE0_MSK_REG;
>  > +
>  > +     /* check for PER interrupt */
>  > +     if (pending == (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) {
>  > +             intbase = MSP_PER_INTBASE;
>  > +             pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
>  > +     }
>  > +
>  > +     /* check for spurious interrupt */
>  > +     if (pending == 0x00000000) {
>  > +             printk("Spurious %s interrupt? status %08x, mask %08x\n",
> 
> Again a KERN_* severity string please.
> 
> (Spurious interrupts may happen in many systems so I wonder if the printk
> is a good idea at all?)

Regarding the spurious interrupts, if it's not a big issue I'd prefer
to keep the output in there so they aren't hidden under production loads
with newly written drivers.

[...]

>  > diff --git a/arch/mips/pmc-sierra/msp71xx/msp_prom.c 
> b/arch/mips/pmc-sierra/msp71xx/msp_prom.c
[...]

>  > +
>  > +#include <linux/module.h>
>  > +#include <linux/kernel.h>
>  > +#include <linux/init.h>
>  > +#include <linux/string.h>
>  > +#include <linux/interrupt.h>
>  > +#include <linux/mm.h>
>  > +#ifdef CONFIG_CRAMFS
>  > +#include <linux/cramfs_fs.h>
>  > +#endif
>  > +#ifdef CONFIG_SQUASHFS
>  > +#include <linux/squashfs_fs.h>
>  > +#endif
> 
> Please remove the squashfs hook until it has not become part of the 
> standard
> kernel.

I can't think of a way to remove this short of defining our own magic
number for the super block. We can't drop squashfs support as some of
our customers have very constrained memory systems on their boards.

Since this is in our platform code and CONFIG_SQUASHFS won't be defined,
if a customer chooses not to apply the squashfs patch, the 2 #ifdef will
evaluate to false and the code won't be included. How is this causing
problems?

[...]

>  > +/* rootfs functions */
>  > +#ifdef CONFIG_MTD_PMC_MSP_RAMROOT
>  > +bool get_ramroot(void **start, unsigned long *size)
>  > +{
>  > +     extern char _end[];
>  > +    
>  > +     /* Check for start following the end of the kernel */
>  > +     void *check_start = (void *)_end;
>  > +
>  > +     /* Check for supported rootfs types */
>  > +#ifdef CONFIG_CRAMFS
>  > +     if (*(__u32 *)check_start == CRAMFS_MAGIC) {
>  > +             /* Get CRAMFS size */
>  > +             *start = check_start;
>  > +             *size = PAGE_ALIGN(
>  > +                     ((struct cramfs_super *)check_start)->size);
>  > +            
>  > +             return true;
>  > +     }
>  > +#endif
>  > +#ifdef CONFIG_SQUASHFS
> 
> Please remove the squashfs hook until it has not become part of the 
> standard
> kernel.

Please see my comment above.


>  > +     if (*((unsigned int *)check_start) == SQUASHFS_MAGIC) {
>  > +             /* Get SQUASHFS size */
>  > +             *start = check_start;
>  > +             *size = PAGE_ALIGN(
>  > +                     ((struct squashfs_super_block 
> *)check_start)->bytes_used);
>  > +            
>  > +             return true;
>  > +     }
>  > +#endif
>  > +
>  > +     return false;
>  > +}

[...]

>  > diff --git a/arch/mips/pmc-sierra/msp71xx/msp_setup.c 
> b/arch/mips/pmc-sierra/msp71xx/msp_setup.c
>  > new file mode 100644
>  > index 0000000..2e835cc
>  > --- /dev/null
>  > +++ b/arch/mips/pmc-sierra/msp71xx/msp_setup.c

[...]

>  > +
>  > +/* Actually performs the reset for 7120-based boards */
>  > +void msp7120_reset( void )
>  > +{
>  > +     int i;
>  > +     unsigned char *iptr, *start, *end;
>  > +
>  > +     local_irq_disable();
>  > +
>  > +#ifdef CONFIG_CPU_MIPS32_R2
> 
> Bare MIPS32R2 does not support multithreading.  So this #ifdef should be
> CONFIG_MIPS_MT instead.

I cannot find which Kconfig file this is defined in. Although I do see
it set in your malta_defconfig, and some Makefiles and r4kcache.h depending
on it.

I'm assuming it was present in older linux version. We don't always enable
SMP/SMTC but we still need to use MT extensions for our RTOS. Possibly I
should test CONFIG_SYS_SUPPORTS_MULTITHREADING instead?


>  > +     dvpe();
>  > +#endif
>  > +
>  > +     /*
>  > +      * Cache the rest of this function, since we put the DDRC into
>  > +      * self-refresh mode, and must ensure we do not touch RAM after 
> that
>  > +      */
>  > +     start = (unsigned char*)&&startpoint;
>  > +     end = (unsigned char*)&&endpoint;
> 
> You're relying on the assumption that gcc will actually compile the code
> between these two two labels.  This may work for this particular code
> and compiler version but has become very fragile with modern gcc which
> frequently moves code out of line for sake of improved branch prediction.
> 
> This is basically something that cannot be done in plain C.  To make this
> actually work reliable I think you will need to implement the part between
> the two labels in assembler - even inline assumbler would be ok.

I wonder if there would be any gcc pragmas that would prevent reordering?
I'd rather not re-write these macros in assembly for a single use.


>  > +
>  > +     if( (unsigned int)start % (unsigned int)(L1_CACHE_BYTES) )
>  > +             start -= ((unsigned int)start % (unsigned 
> int)(L1_CACHE_BYTES));
>  > +
>  > +     for( iptr = start; iptr < end; iptr += L1_CACHE_BYTES )
>  > +             cache_op( Fill, iptr );
>  > +            
>  > +startpoint:
>  > +     /* Put the DDRC into self-refresh mode */
>  > +     DDRC_INDIRECT_WRITE( DDRC_CTL(10), 0xb, (1<<16) );
>  > +
>  > +     /*
>  > +      * IMPORTANT!  DO NOT do anything from here on out that might 
> even think
>  > +      * about fetching from RAM - IE, don't call any not-inline 
> functions,
>  > +      * and be VERY sure that any unline functions you do call do 
> NOT access
>  > +      * any sort of RAM anywhere!
>  > +      */
>  > +
>  > +     /* Wait a bit for the DDRC to settle */
>  > +     for( i = 0; i < 100000000; i++);
>  > +
>  > +#if defined(CONFIG_PMC_MSP7120_GW)
>  > +     /*
>  > +      * Throw GPIO 9 HI, (tied to board reset logic)
>  > +      * GPIO 9 is the 4th GPIO of register 3
>  > +      *
>  > +      * Note, we cannot use the higher-level 'msp_gpio_pin_...' 
> functions
>  > +      * as they look up data in a static table somewhere else in RAM!
>  > +      */
>  > +     set_value_reg32( GPIO_CFG3_REG,
>  > +                     BASIC_MODE_REG_MASK(3),
>  > +                     BASIC_MODE_REG_VALUE(MSP_GPIO_OUTPUT, 3) );
>  > +     set_reg32( GPIO_DATA3_REG,
>  > +                     BASIC_DATA_REG_MASK(3) );
>  > +
>  > +     /*
>  > +      * In case GPIO9 doesn't *really* reset the board (jumper 
> configurable!)
>  > +      * fallback to generic 7120 reset register below to ensure SoC 
> reset.
>  > +      */
>  > +#endif
>  > +
>  > +     /*
>  > +      * There is a reset bit you can write to at 0xBC00_0014.
>  > +      * Writing a 1 to bit 0 will do a reset
>  > +      */
>  > +     *RST_SET_REG = 0x00000001;
>  > +
>  > +endpoint:
>  > +     return;
>  > +}
>  > +
>  > +void msp_restart(char *command)
>  > +{
>  > +     printk("Now rebooting .......\n");
>  > +
>  > +#if defined(CONFIG_PMC_MSP7120_EVAL) \
>  > + || defined(CONFIG_PMC_MSP7120_GW) \
>  > + || defined(CONFIG_PMC_MSP7120_FPGA)
>  > +     msp7120_reset();
>  > +#else
>  > +     /* No chip-specific reset code, just jump to the ROM reset 
> vector */
>  > +     set_c0_status(ST0_BEV | ST0_ERL);
>  > +     change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
>  > +     flush_cache_all();
>  > +     write_c0_wired(0);
>  > +
>  > +     __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
>  > +#endif
>  > +}
>  > +
>  > +void msp_halt(void)
>  > +{
>  > +     printk(KERN_NOTICE "\n** You can safely turn off the power\n");
> 
> This message is soooo Windows 95 ;-)

I'll pass that on to the author of that line :)

[...]

>  > +
>  > +     /*
>  > +      * Processor Core Errata workarounds:
>  > +      * NOTE: cpu_probe is called just before prom_init so it safe 
> to use
>  > +      * current_cpu_data.
>  > +      */
>  > +     if(current_cpu_data.cputype == CPU_34K) {
>  > +             /*
>  > +              * Erratum "RPS May Cause Incorrect Instruction Execution"
>  > +              * This code only handles VPE0, any SMP/SMTC/RTOS code 
> making use of
>  > +              * VPE1 will be responsable for that VPE.
>  > +              */
>  > +             if((current_cpu_data.processor_id & PRID_BITMSK_REV)
>  > +                <= PRID_REV_RTL_1_0_2)
>  > +                     write_c0_config7(read_c0_config7() | 
> CONFIG7_BITMSK_RPS);
>  > +     }
> 
> This 34K erratum affects all systems not just MSPs, so the workaround 
> should
> be in generic MIPS code.  arch/mips/kernel/cpu-probe.c:check_bugs32() seems
> the best place.

OK, I will move this one. I'm not sure they can all be moved to generic code,
some erratum have multiple workarounds to choose from. Different platforms
will choose different options based on performance trade offs.

[...]


>  > +     
>  > +#ifdef CONFIG_SENSORS_PMCTWILED
>  > +     /* setup twi led interface */
>  > +     pmctwiled_setup();
> 
> SENSORS_PMCTWILED is a tristate.  So if configured as a module this call to
> pmctwiled_setup() will result in a link failure.  Aside, inserting these
> hooks should really be part of the "PMC MSP71xx LED driver" patch.
> 
> I think the preferable solution is to invoke PMC MSP71xx LED driver through
> something like subsys_initcall() - at least I didn't notice any ordering
> problems that could result.

It is normally statically linked since we have other drivers which need to
initialize LED states in their subsys_initcall() code. Since we can't assure
the order of initialization, the LED states must be initialized here.

I looked at kallsyms in the past but it's not practical for embedded systems.
Are you aware of any methods of checking if a symbol it's statically linked?


[...]

> diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_prom.h b/include/asm-mips/pmc-sierra/msp71xx/msp_prom.h

[...]

>  > +/* Memory descriptor management. */
>  > +#define PROM_MAX_PMEMBLOCKS    7     /* 6 used */
>  > +
>  > +
>  > +enum yamon_memtypes {
>  > +        yamon_dontuse,
>  > +        yamon_prom,
>  > +        yamon_free,
>  > +};
> 
> Eh..  I thought you're using PMON?

We are using PMON, presumably the author decided to reuse these constants as
from some generic arch/mips code it was based on. See msp_prom.c.


>  > diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_regs.h 
> b/include/asm-mips/pmc-sierra/msp71xx/msp_regs.h

[...]

> +/***************************************************************************/ 
> 
>  > +/* Memory Controller 
> defines                                               */
>  > 
> +/***************************************************************************/ 
> 
>  > +
>  > +/* Indirect memory controller registers */
>  > +#define DDRC_CFG(n)          (n)
>  > +#define DDRC_DEBUG(n)                (0x04 + n)
>  > +#define DDRC_CTL(n)          (0x40 + n)
>  > +
>  > +/* Macro to perform DDRC indirect write */
>  > +#define DDRC_INDIRECT_WRITE( reg, mask, value ) {\
>  > +     *MEM_SS_ADDR = ((mask & 0xf) << 8) | (reg & 0xff); \
>  > +     *MEM_SS_DATA = value; \
>  > +     *MEM_SS_WRITE = 1; \
>  > +}
> 
> Enclosing the macro in a { } is a good idea for macros with multiple
> statements but will fail for a construct like:
> 
>         if (condition)
>                 DDRC_INDIRECT_WRITE(...);
>         else
>                 something_else();
> 
> To make this really bulletproof, enclose the macro in a do { } while (0)
> block instead.  See also http://kernelnewbies.org/FAQ/DoWhile0.

Thanks, I chose the "slightly more legible" method ({ }) described at the end.

[...]

> 
>   Ralf
> 

Marc

From jeff@garzik.org Sat Mar  3 01:11:19 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 01:11:25 +0000 (GMT)
Received: from srv5.dvmed.net ([207.36.208.214]:47576 "EHLO mail.dvmed.net")
	by ftp.linux-mips.org with ESMTP id S28573849AbXCCBLT (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sat, 3 Mar 2007 01:11:19 +0000
Received: from cpe-065-190-194-075.nc.res.rr.com ([65.190.194.75] helo=[10.10.10.10])
	by mail.dvmed.net with esmtpsa (Exim 4.63 #1 (Red Hat Linux))
	id 1HNImI-0001Cw-Sy; Sat, 03 Mar 2007 01:11:15 +0000
Message-ID: <45E8CB32.5060008@garzik.org>
Date:	Fri, 02 Mar 2007 20:11:14 -0500
From:	Jeff Garzik <jeff@garzik.org>
User-Agent: Thunderbird 1.5.0.9 (X11/20070212)
MIME-Version: 1.0
To:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
CC:	linux-mips@linux-mips.org, ralf@linux-mips.org,
	netdev@vger.kernel.org, sshtylyov@ru.mvista.com
Subject: Re: [PATCH 1/2] tc35815 driver update (part 1)
References: <20070302.232407.05600700.anemo@mba.ocn.ne.jp>
In-Reply-To: <20070302.232407.05600700.anemo@mba.ocn.ne.jp>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <jeff@garzik.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14321
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: jeff@garzik.org
Precedence: bulk
X-list: linux-mips

Atsushi Nemoto wrote:
> Current tc35815 driver is very obsolete and less maintained for a long
> time.  Replace it with a new driver based on one from CELF patch
> archive.  It was for 2.6.10 kernel so some adjustment and cleanup are
> added. (remove config.h, SA_ to IRQF_ conversion, etc.)
> 
> Major advantages are:
> 
> * Independent of JMR3927.
>   (Actually independent of MIPS, but AFAIK the chip is used only on
>    MIPS platforms)
> * TX4938 support.
> * 64-bit proof.
> * Asynchronous and on-demand auto negotiation.
> * High performance on non-coherent architecture.
> * ethtool support.
> * Many bugfixes and cleanups.
> 
> And next patch add further improvements/bugfixes/cleanups.
> 
> Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
> ---
> This is a patch against current linux-mips.org git-tree.
> 
>  drivers/net/Kconfig     |    3 
>  drivers/net/tc35815.c   | 2070 +++++++++++++++++++++++++++++++---------------
>  include/linux/pci_ids.h |    1 
>  3 files changed, 1440 insertions(+), 634 deletions(-)

Would you be kind enough to

a) provide a URL to a .c file (or post it, if it's under 100K) so that 
we may more easily review this

b) combine both patches into a single patch.  might as well, since it's 
a rewrite.

c) rediff your patch against linux-2.6.git + Ralf's killall removal 
patch, and resend.  There were some minor conflicting changes that 
appeared, though these changes will certainly become irrelevant once 
your new driver is merged.



From jgarzik@pobox.com Sat Mar  3 01:17:21 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 01:17:26 +0000 (GMT)
Received: from srv5.dvmed.net ([207.36.208.214]:63704 "EHLO mail.dvmed.net")
	by ftp.linux-mips.org with ESMTP id S28575383AbXCCBRV (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sat, 3 Mar 2007 01:17:21 +0000
Received: from cpe-065-190-194-075.nc.res.rr.com ([65.190.194.75] helo=[10.10.10.10])
	by mail.dvmed.net with esmtpsa (Exim 4.63 #1 (Red Hat Linux))
	id 1HNIs9-0001EP-Qp; Sat, 03 Mar 2007 01:17:18 +0000
Message-ID: <45E8CC9C.3080607@pobox.com>
Date:	Fri, 02 Mar 2007 20:17:16 -0500
From:	Jeff Garzik <jgarzik@pobox.com>
User-Agent: Thunderbird 1.5.0.9 (X11/20070212)
MIME-Version: 1.0
To:	Dale Farnsworth <dale@farnsworth.org>
CC:	linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
	linux-mips@linux-mips.org, Ralf Baechle <ralf@linux-mips.org>
Subject: Re: [PATCH 1/2] mv643xx_eth: move mac_addr inside mv643xx_eth_platform_data
References: <20070301233148.GA19550@xyzzy.farnsworth.org>
In-Reply-To: <20070301233148.GA19550@xyzzy.farnsworth.org>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <jgarzik@pobox.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14322
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: jgarzik@pobox.com
Precedence: bulk
X-list: linux-mips

Dale Farnsworth wrote:
> The information contained within platform_data should be self-contained.
> Replace the pointer to a MAC address with the actual MAC address in
> struct mv643xx_eth_platform_data.
> 
> Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
> 
> ---
> 
> Replaced explicit mac address comparison with a call to is_valid_ether_addr(),
> as suggested by Stephen Hemminger <shemminger@linux-foundation.org>.
> 
>  arch/mips/momentum/jaguar_atx/platform.c |   20 ++++----------------
>  arch/mips/momentum/ocelot_3/platform.c   |   20 ++++----------------
>  arch/mips/momentum/ocelot_c/platform.c   |   12 ++----------
>  drivers/net/mv643xx_eth.c                |    2 +-
>  include/linux/mv643xx.h                  |    2 +-
>  5 files changed, 12 insertions(+), 44 deletions(-)

applied



From jeff@garzik.org Sat Mar  3 01:17:50 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 01:17:55 +0000 (GMT)
Received: from srv5.dvmed.net ([207.36.208.214]:473 "EHLO mail.dvmed.net")
	by ftp.linux-mips.org with ESMTP id S28575407AbXCCBRf (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sat, 3 Mar 2007 01:17:35 +0000
Received: from cpe-065-190-194-075.nc.res.rr.com ([65.190.194.75] helo=[10.10.10.10])
	by mail.dvmed.net with esmtpsa (Exim 4.63 #1 (Red Hat Linux))
	id 1HNIsP-0001Ej-8F; Sat, 03 Mar 2007 01:17:33 +0000
Message-ID: <45E8CCAC.7040304@garzik.org>
Date:	Fri, 02 Mar 2007 20:17:32 -0500
From:	Jeff Garzik <jeff@garzik.org>
User-Agent: Thunderbird 1.5.0.9 (X11/20070212)
MIME-Version: 1.0
To:	Dale Farnsworth <dale@farnsworth.org>
CC:	linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
	linux-mips@linux-mips.org, Ralf Baechle <ralf@linux-mips.org>
Subject: Re: [PATCH 2/2] mv643xx_eth: Place explicit port number in mv643xx_eth_platform_data
References: <20070301233148.GA19550@xyzzy.farnsworth.org> <20070301233324.GA20193@xyzzy.farnsworth.org>
In-Reply-To: <20070301233324.GA20193@xyzzy.farnsworth.org>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <jeff@garzik.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14323
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: jeff@garzik.org
Precedence: bulk
X-list: linux-mips

Dale Farnsworth wrote:
> We were using the platform_device.id field to identify which ethernet
> port is used for mv643xx_eth device.  This is not generally correct.
> It will be incorrect, for example, if a hardware platform uses a single
> port but not the first port.  Here, we add an explicit port_number field
> to struct mv643xx_eth_platform_data.
> 
> This makes the mv643xx_eth_platform_data structure required, but that
> isn't an issue since all users currently provide it already.
> 
> Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
> 
> ---
> 
>  arch/mips/momentum/jaguar_atx/platform.c  |    8 ++
>  arch/mips/momentum/ocelot_3/platform.c    |    8 ++
>  arch/mips/momentum/ocelot_c/platform.c    |    4 +
>  arch/powerpc/platforms/chrp/pegasos_eth.c |    2 
>  arch/ppc/syslib/mv64x60.c                 |   12 +++-
>  drivers/net/mv643xx_eth.c                 |   59 ++++++++++----------
>  include/linux/mv643xx.h                   |    1 
>  7 files changed, 62 insertions(+), 32 deletions(-)

ACK but not applied, patch corrupted



From ralf@linux-mips.org Sat Mar  3 14:36:59 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 14:37:01 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:63444 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037749AbXCCOg7 (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Mar 2007 14:36:59 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l23EawlF004339;
	Sat, 3 Mar 2007 14:36:58 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l23Eat9G004326;
	Sat, 3 Mar 2007 14:36:55 GMT
Date:	Sat, 3 Mar 2007 14:36:55 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Florian Fainelli <florian.fainelli@int-evry.fr>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH 1/7] MTX-1 watchdog driver
Message-ID: <20070303143655.GA3792@linux-mips.org>
References: <200703022207.26276.florian.fainelli@int-evry.fr>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <200703022207.26276.florian.fainelli@int-evry.fr>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14324
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Fri, Mar 02, 2007 at 10:07:26PM +0100, Florian Fainelli wrote:

> This patch is required if you want to use a MTX-1 board and do not see it 
> being rebooted every 10 seconds.
> 
> Signed-off-by: Florian Fainelli <florian.fainelli@int-evry.fr>

Watchdog stuff is handled by:

WATCHDOG DEVICE DRIVERS
P:      Wim Van Sebroeck
M:      wim@iguana.be
T:      git kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog.git
S:      Maintained

  Ralf

From ralf@linux-mips.org Sat Mar  3 14:38:08 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 14:38:10 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:5590 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037732AbXCCOiI (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Mar 2007 14:38:08 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l23Ec7P8004365;
	Sat, 3 Mar 2007 14:38:07 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l23Ec7Ef004355;
	Sat, 3 Mar 2007 14:38:07 GMT
Date:	Sat, 3 Mar 2007 14:38:07 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Florian Fainelli <florian.fainelli@int-evry.fr>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH 2/7] Au1000 eth : Link beat detection
Message-ID: <20070303143807.GB3792@linux-mips.org>
References: <200703022207.35218.florian.fainelli@int-evry.fr>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <200703022207.35218.florian.fainelli@int-evry.fr>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14325
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Fri, Mar 02, 2007 at 10:07:35PM +0100, Florian Fainelli wrote:

> This patch fixes the link beat detection when the cable is not plugged at 
> startup. It is not MTX1 specific.

Network drivers are handled by:

NETWORK DEVICE DRIVERS
P:      Andrew Morton
M:      akpm@linux-foundation.org
P:      Jeff Garzik
M:      jgarzik@pobox.com
L:      netdev@vger.kernel.org
T:      git kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
S:      Maintained

  Ralf

From ralf@linux-mips.org Sat Mar  3 14:44:58 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 14:45:00 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:46504 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037762AbXCCOo6 (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Mar 2007 14:44:58 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l23Eivbj004674;
	Sat, 3 Mar 2007 14:44:57 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l23EivgI004667;
	Sat, 3 Mar 2007 14:44:57 GMT
Date:	Sat, 3 Mar 2007 14:44:57 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Florian Fainelli <florian.fainelli@int-evry.fr>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH 3/7] MTX1 setup : remove unneeded settings
Message-ID: <20070303144457.GC3792@linux-mips.org>
References: <200703022207.41964.florian.fainelli@int-evry.fr>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <200703022207.41964.florian.fainelli@int-evry.fr>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14326
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Fri, Mar 02, 2007 at 10:07:41PM +0100, Florian Fainelli wrote:

Applied, thanks.

  Ralf

From ralf@linux-mips.org Sat Mar  3 14:45:23 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 14:45:25 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:47528 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037791AbXCCOpL (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Mar 2007 14:45:11 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l23EjApT004713;
	Sat, 3 Mar 2007 14:45:10 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l23Ej7G2004712;
	Sat, 3 Mar 2007 14:45:07 GMT
Date:	Sat, 3 Mar 2007 14:45:07 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Florian Fainelli <florian.fainelli@int-evry.fr>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH 4/7] MTX1 isdel carbus ressources
Message-ID: <20070303144507.GD3792@linux-mips.org>
References: <200703022207.48159.florian.fainelli@int-evry.fr>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <200703022207.48159.florian.fainelli@int-evry.fr>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14327
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Fri, Mar 02, 2007 at 10:07:48PM +0100, Florian Fainelli wrote:

Thanks, applied.

  Ralf

From ralf@linux-mips.org Sat Mar  3 14:46:23 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 14:46:25 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:63402 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037782AbXCCOqX (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Mar 2007 14:46:23 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l23EkMLc004744;
	Sat, 3 Mar 2007 14:46:22 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l23EkM7V004743;
	Sat, 3 Mar 2007 14:46:22 GMT
Date:	Sat, 3 Mar 2007 14:46:22 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Florian Fainelli <florian.fainelli@int-evry.fr>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH 5/7] MTX1 clear PCI errors
Message-ID: <20070303144622.GE3792@linux-mips.org>
References: <200703022208.01454.florian.fainelli@int-evry.fr>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <200703022208.01454.florian.fainelli@int-evry.fr>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14328
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Fri, Mar 02, 2007 at 10:08:01PM +0100, Florian Fainelli wrote:

Applied, thanks.

  Ralf

From ralf@linux-mips.org Sat Mar  3 14:47:07 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 14:47:08 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:19628 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037791AbXCCOrH (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Mar 2007 14:47:07 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l23El5rY004751;
	Sat, 3 Mar 2007 14:47:05 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l23El5f6004750;
	Sat, 3 Mar 2007 14:47:05 GMT
Date:	Sat, 3 Mar 2007 14:47:05 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Florian Fainelli <florian.fainelli@int-evry.fr>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH 6/7] I2C via MTX-1 GPIO lines
Message-ID: <20070303144705.GF3792@linux-mips.org>
References: <200703022208.06018.florian.fainelli@int-evry.fr>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <200703022208.06018.florian.fainelli@int-evry.fr>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14329
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Fri, Mar 02, 2007 at 10:08:05PM +0100, Florian Fainelli wrote:

I2C stuff is dealt with by

I2C SUBSYSTEM
P:      Jean Delvare
M:      khali@linux-fr.org
L:      i2c@lm-sensors.org
T:      quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/
S:      Maintained

  Ralf

From ralf@linux-mips.org Sat Mar  3 14:47:47 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 14:47:48 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:36525 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S28640108AbXCCOrr (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Mar 2007 14:47:47 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l23Elka3004777;
	Sat, 3 Mar 2007 14:47:46 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l23ElkKJ004776;
	Sat, 3 Mar 2007 14:47:46 GMT
Date:	Sat, 3 Mar 2007 14:47:46 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Florian Fainelli <florian.fainelli@int-evry.fr>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH 7/7] MTX1 LED driver
Message-ID: <20070303144746.GG3792@linux-mips.org>
References: <200703022208.11940.florian.fainelli@int-evry.fr>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <200703022208.11940.florian.fainelli@int-evry.fr>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14330
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Fri, Mar 02, 2007 at 10:08:11PM +0100, Florian Fainelli wrote:

The blinkenlight subsystem is maintained by:

LED SUBSYSTEM
P:      Richard Purdie
M:      rpurdie@rpsys.net
S:      Maintained

  Ralf

From anemo@mba.ocn.ne.jp Sat Mar  3 14:54:39 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 14:54:44 +0000 (GMT)
Received: from mba.ocn.ne.jp ([210.190.142.172]:59849 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20037755AbXCCOyj (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sat, 3 Mar 2007 14:54:39 +0000
Received: from localhost (p6054-ipad201funabasi.chiba.ocn.ne.jp [222.146.69.54])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id 0D607B7F8; Sat,  3 Mar 2007 23:53:14 +0900 (JST)
Date:	Sat, 03 Mar 2007 23:53:13 +0900 (JST)
Message-Id: <20070303.235313.126575362.anemo@mba.ocn.ne.jp>
To:	jeff@garzik.org
Cc:	linux-mips@linux-mips.org, ralf@linux-mips.org,
	netdev@vger.kernel.org, sshtylyov@ru.mvista.com
Subject: Re: [PATCH 1/2] tc35815 driver update (part 1)
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
In-Reply-To: <45E8CB32.5060008@garzik.org>
References: <20070302.232407.05600700.anemo@mba.ocn.ne.jp>
	<45E8CB32.5060008@garzik.org>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14331
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

On Fri, 02 Mar 2007 20:11:14 -0500, Jeff Garzik <jeff@garzik.org> wrote:
> Would you be kind enough to
> 
> a) provide a URL to a .c file (or post it, if it's under 100K) so that 
> we may more easily review this
> 
> b) combine both patches into a single patch.  might as well, since it's 
> a rewrite.
> 
> c) rediff your patch against linux-2.6.git + Ralf's killall removal 
> patch, and resend.  There were some minor conflicting changes that 
> appeared, though these changes will certainly become irrelevant once 
> your new driver is merged.

OK, now linux-2.6.git aleady contains Ralf's killall removal, so I'll
just combine two patches, rediff and resend.  The linux-mips.org tree
is now almost synced with git.kernel.org so it can be applied for
lmo's tree too.

And here is a new tc35815.c just for review.  Thanks.

/*
 * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
 *
 * Based on skelton.c by Donald Becker.
 *
 * This driver is a replacement of older and less maintained version.
 * This is a header of the older version:
 *	-----<snip>-----
 *	Copyright 2001 MontaVista Software Inc.
 *	Author: MontaVista Software, Inc.
 *		ahennessy@mvista.com
 *	Copyright (C) 2000-2001 Toshiba Corporation
 *	static const char *version =
 *		"tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
 *	-----<snip>-----
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * (C) Copyright TOSHIBA CORPORATION 2004-2005
 * All Rights Reserved.
 *
 *  Revision History:
 *	1.13	64-bit proof.
 *	1.14	Do not round-up transmit length.
 *	1.15	Define TC35815_DMA_SYNC_ONDEMAND, cleanup.
 *	1.16	Fix free_page bug introduced in 1.15
 *	1.17	Add mii/ethtool ioctl support.
 *		Remove workaround for early TX4938.  Cleanup.
 *	1.20	Kernel 2.6.
 *	1.21	Fix receive packet length (omit CRC).
 *		Call netif_carrier_on/netif_carrier_off.
 *		Add kernel/module options (speed, duplex, doforce).
 *		Do not try "force link mode" by default.
 *		Reconfigure CAM on restarting.
 *		Reset PHY on restarting.
 *		Add workaround for 100MHalf HUB.
 *	1.22	Minor fix.
 *	1.23	Minor cleanup.
 *	1.24	Remove tc35815_setup since new stype option
 *		("tc35815.speed=10", etc.) can be used for 2.6 kernel.
 *	1.25	TX4939 support.
 *	1.26	Minor cleanup.
 *	1.27	Move TX4939 PCFG.SPEEDn control code out from this driver.
 *		Cleanup init_dev_addr. (NETDEV_REGISTER event notifier
 *		can overwrite dev_addr)
 *		support ETHTOOL_GPERMADDR.
 *	1.28	Minor cleanup.
 *	1.29	support netpoll.
 *	1.30	Minor cleanup.
 *	1.31	NAPI support. (disabled by default)
 *		Use DMA_RxAlign_2 if possible.
 *		Do not use PackedBuffer.
 *		Cleanup.
 *	1.32	Fix free buffer management on non-PackedBuffer mode.
 *	1.33	Fix netpoll build.
 *	1.34	Fix netpoll locking.  "BH rule" for NAPI is not enough with
 *		netpoll, hard_start_xmit might be called from irq context.
 *		PM support.
 */

#ifdef TC35815_NAPI
#define DRV_VERSION	"1.34-NAPI"
#else
#define DRV_VERSION	"1.34"
#endif
static const char *version = "tc35815.c:v" DRV_VERSION "\n";
#define MODNAME			"tc35815"

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <asm/io.h>
#include <asm/byteorder.h>

/* First, a few definitions that the brave might change. */

#define GATHER_TXINT	/* On-Demand Tx Interrupt */
#define WORKAROUND_LOSTCAR
#define WORKAROUND_100HALF_PROMISC
/* #define TC35815_USE_PACKEDBUFFER */

typedef enum {
	TC35815CF = 0,
	TC35815_NWU,
	TC35815_TX4939,
} board_t;

/* indexed by board_t, above */
static const struct {
	const char *name;
} board_info[] __devinitdata = {
	{ "TOSHIBA TC35815CF 10/100BaseTX" },
	{ "TOSHIBA TC35815 with Wake on LAN" },
	{ "TOSHIBA TC35815/TX4939" },
};

static const struct pci_device_id tc35815_pci_tbl[] = {
	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
	{0,}
};
MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);

/* see MODULE_PARM_DESC */
static struct tc35815_options {
	int speed;
	int duplex;
	int doforce;
} options;

/*
 * Registers
 */
struct tc35815_regs {
	volatile __u32 DMA_Ctl;		/* 0x00 */
	volatile __u32 TxFrmPtr;
	volatile __u32 TxThrsh;
	volatile __u32 TxPollCtr;
	volatile __u32 BLFrmPtr;
	volatile __u32 RxFragSize;
	volatile __u32 Int_En;
	volatile __u32 FDA_Bas;
	volatile __u32 FDA_Lim;		/* 0x20 */
	volatile __u32 Int_Src;
	volatile __u32 unused0[2];
	volatile __u32 PauseCnt;
	volatile __u32 RemPauCnt;
	volatile __u32 TxCtlFrmStat;
	volatile __u32 unused1;
	volatile __u32 MAC_Ctl;		/* 0x40 */
	volatile __u32 CAM_Ctl;
	volatile __u32 Tx_Ctl;
	volatile __u32 Tx_Stat;
	volatile __u32 Rx_Ctl;
	volatile __u32 Rx_Stat;
	volatile __u32 MD_Data;
	volatile __u32 MD_CA;
	volatile __u32 CAM_Adr;		/* 0x60 */
	volatile __u32 CAM_Data;
	volatile __u32 CAM_Ena;
	volatile __u32 PROM_Ctl;
	volatile __u32 PROM_Data;
	volatile __u32 Algn_Cnt;
	volatile __u32 CRC_Cnt;
	volatile __u32 Miss_Cnt;
};

/*
 * Bit assignments
 */
/* DMA_Ctl bit asign ------------------------------------------------------- */
#define DMA_RxAlign            0x00c00000 /* 1:Reception Alignment           */
#define DMA_RxAlign_1          0x00400000
#define DMA_RxAlign_2          0x00800000
#define DMA_RxAlign_3          0x00c00000
#define DMA_M66EnStat          0x00080000 /* 1:66MHz Enable State            */
#define DMA_IntMask            0x00040000 /* 1:Interupt mask                 */
#define DMA_SWIntReq           0x00020000 /* 1:Software Interrupt request    */
#define DMA_TxWakeUp           0x00010000 /* 1:Transmit Wake Up              */
#define DMA_RxBigE             0x00008000 /* 1:Receive Big Endian            */
#define DMA_TxBigE             0x00004000 /* 1:Transmit Big Endian           */
#define DMA_TestMode           0x00002000 /* 1:Test Mode                     */
#define DMA_PowrMgmnt          0x00001000 /* 1:Power Management              */
#define DMA_DmBurst_Mask       0x000001fc /* DMA Burst size                  */

/* RxFragSize bit asign ---------------------------------------------------- */
#define RxFrag_EnPack          0x00008000 /* 1:Enable Packing                */
#define RxFrag_MinFragMask     0x00000ffc /* Minimum Fragment                */

/* MAC_Ctl bit asign ------------------------------------------------------- */
#define MAC_Link10             0x00008000 /* 1:Link Status 10Mbits           */
#define MAC_EnMissRoll         0x00002000 /* 1:Enable Missed Roll            */
#define MAC_MissRoll           0x00000400 /* 1:Missed Roll                   */
#define MAC_Loop10             0x00000080 /* 1:Loop 10 Mbps                  */
#define MAC_Conn_Auto          0x00000000 /*00:Connection mode (Automatic)   */
#define MAC_Conn_10M           0x00000020 /*01:                (10Mbps endec)*/
#define MAC_Conn_Mll           0x00000040 /*10:                (Mll clock)   */
#define MAC_MacLoop            0x00000010 /* 1:MAC Loopback                  */
#define MAC_FullDup            0x00000008 /* 1:Full Duplex 0:Half Duplex     */
#define MAC_Reset              0x00000004 /* 1:Software Reset                */
#define MAC_HaltImm            0x00000002 /* 1:Halt Immediate                */
#define MAC_HaltReq            0x00000001 /* 1:Halt request                  */

/* PROM_Ctl bit asign ------------------------------------------------------ */
#define PROM_Busy              0x00008000 /* 1:Busy (Start Operation)        */
#define PROM_Read              0x00004000 /*10:Read operation                */
#define PROM_Write             0x00002000 /*01:Write operation               */
#define PROM_Erase             0x00006000 /*11:Erase operation               */
                                          /*00:Enable or Disable Writting,   */
                                          /*      as specified in PROM_Addr. */
#define PROM_Addr_Ena          0x00000030 /*11xxxx:PROM Write enable         */
                                          /*00xxxx:           disable        */

/* CAM_Ctl bit asign ------------------------------------------------------- */
#define CAM_CompEn             0x00000010 /* 1:CAM Compare Enable            */
#define CAM_NegCAM             0x00000008 /* 1:Reject packets CAM recognizes,*/
                                          /*                    accept other */
#define CAM_BroadAcc           0x00000004 /* 1:Broadcast assept              */
#define CAM_GroupAcc           0x00000002 /* 1:Multicast assept              */
#define CAM_StationAcc         0x00000001 /* 1:unicast accept                */

/* CAM_Ena bit asign ------------------------------------------------------- */
#define CAM_ENTRY_MAX                  21   /* CAM Data entry max count      */
#define CAM_Ena_Mask ((1<<CAM_ENTRY_MAX)-1) /* CAM Enable bits (Max 21bits)  */
#define CAM_Ena_Bit(index)         (1<<(index))
#define CAM_ENTRY_DESTINATION	0
#define CAM_ENTRY_SOURCE	1
#define CAM_ENTRY_MACCTL	20

/* Tx_Ctl bit asign -------------------------------------------------------- */
#define Tx_En                  0x00000001 /* 1:Transmit enable               */
#define Tx_TxHalt              0x00000002 /* 1:Transmit Halt Request         */
#define Tx_NoPad               0x00000004 /* 1:Suppress Padding              */
#define Tx_NoCRC               0x00000008 /* 1:Suppress Padding              */
#define Tx_FBack               0x00000010 /* 1:Fast Back-off                 */
#define Tx_EnUnder             0x00000100 /* 1:Enable Underrun               */
#define Tx_EnExDefer           0x00000200 /* 1:Enable Excessive Deferral     */
#define Tx_EnLCarr             0x00000400 /* 1:Enable Lost Carrier           */
#define Tx_EnExColl            0x00000800 /* 1:Enable Excessive Collision    */
#define Tx_EnLateColl          0x00001000 /* 1:Enable Late Collision         */
#define Tx_EnTxPar             0x00002000 /* 1:Enable Transmit Parity        */
#define Tx_EnComp              0x00004000 /* 1:Enable Completion             */

/* Tx_Stat bit asign ------------------------------------------------------- */
#define Tx_TxColl_MASK         0x0000000F /* Tx Collision Count              */
#define Tx_ExColl              0x00000010 /* Excessive Collision             */
#define Tx_TXDefer             0x00000020 /* Transmit Defered                */
#define Tx_Paused              0x00000040 /* Transmit Paused                 */
#define Tx_IntTx               0x00000080 /* Interrupt on Tx                 */
#define Tx_Under               0x00000100 /* Underrun                        */
#define Tx_Defer               0x00000200 /* Deferral                        */
#define Tx_NCarr               0x00000400 /* No Carrier                      */
#define Tx_10Stat              0x00000800 /* 10Mbps Status                   */
#define Tx_LateColl            0x00001000 /* Late Collision                  */
#define Tx_TxPar               0x00002000 /* Tx Parity Error                 */
#define Tx_Comp                0x00004000 /* Completion                      */
#define Tx_Halted              0x00008000 /* Tx Halted                       */
#define Tx_SQErr               0x00010000 /* Signal Quality Error(SQE)       */

/* Rx_Ctl bit asign -------------------------------------------------------- */
#define Rx_EnGood              0x00004000 /* 1:Enable Good                   */
#define Rx_EnRxPar             0x00002000 /* 1:Enable Receive Parity         */
#define Rx_EnLongErr           0x00000800 /* 1:Enable Long Error             */
#define Rx_EnOver              0x00000400 /* 1:Enable OverFlow               */
#define Rx_EnCRCErr            0x00000200 /* 1:Enable CRC Error              */
#define Rx_EnAlign             0x00000100 /* 1:Enable Alignment              */
#define Rx_IgnoreCRC           0x00000040 /* 1:Ignore CRC Value              */
#define Rx_StripCRC            0x00000010 /* 1:Strip CRC Value               */
#define Rx_ShortEn             0x00000008 /* 1:Short Enable                  */
#define Rx_LongEn              0x00000004 /* 1:Long Enable                   */
#define Rx_RxHalt              0x00000002 /* 1:Receive Halt Request          */
#define Rx_RxEn                0x00000001 /* 1:Receive Intrrupt Enable       */

/* Rx_Stat bit asign ------------------------------------------------------- */
#define Rx_Halted              0x00008000 /* Rx Halted                       */
#define Rx_Good                0x00004000 /* Rx Good                         */
#define Rx_RxPar               0x00002000 /* Rx Parity Error                 */
                            /* 0x00001000    not use                         */
#define Rx_LongErr             0x00000800 /* Rx Long Error                   */
#define Rx_Over                0x00000400 /* Rx Overflow                     */
#define Rx_CRCErr              0x00000200 /* Rx CRC Error                    */
#define Rx_Align               0x00000100 /* Rx Alignment Error              */
#define Rx_10Stat              0x00000080 /* Rx 10Mbps Status                */
#define Rx_IntRx               0x00000040 /* Rx Interrupt                    */
#define Rx_CtlRecd             0x00000020 /* Rx Control Receive              */

#define Rx_Stat_Mask           0x0000EFC0 /* Rx All Status Mask              */

/* Int_En bit asign -------------------------------------------------------- */
#define Int_NRAbtEn            0x00000800 /* 1:Non-recoverable Abort Enable  */
#define Int_TxCtlCmpEn         0x00000400 /* 1:Transmit Control Complete Enable */
#define Int_DmParErrEn         0x00000200 /* 1:DMA Parity Error Enable       */
#define Int_DParDEn            0x00000100 /* 1:Data Parity Error Enable      */
#define Int_EarNotEn           0x00000080 /* 1:Early Notify Enable           */
#define Int_DParErrEn          0x00000040 /* 1:Detected Parity Error Enable  */
#define Int_SSysErrEn          0x00000020 /* 1:Signalled System Error Enable */
#define Int_RMasAbtEn          0x00000010 /* 1:Received Master Abort Enable  */
#define Int_RTargAbtEn         0x00000008 /* 1:Received Target Abort Enable  */
#define Int_STargAbtEn         0x00000004 /* 1:Signalled Target Abort Enable */
#define Int_BLExEn             0x00000002 /* 1:Buffer List Exhausted Enable  */
#define Int_FDAExEn            0x00000001 /* 1:Free Descriptor Area          */
                                          /*               Exhausted Enable  */

/* Int_Src bit asign ------------------------------------------------------- */
#define Int_NRabt              0x00004000 /* 1:Non Recoverable error         */
#define Int_DmParErrStat       0x00002000 /* 1:DMA Parity Error & Clear      */
#define Int_BLEx               0x00001000 /* 1:Buffer List Empty & Clear     */
#define Int_FDAEx              0x00000800 /* 1:FDA Empty & Clear             */
#define Int_IntNRAbt           0x00000400 /* 1:Non Recoverable Abort         */
#define	Int_IntCmp             0x00000200 /* 1:MAC control packet complete   */
#define Int_IntExBD            0x00000100 /* 1:Interrupt Extra BD & Clear    */
#define Int_DmParErr           0x00000080 /* 1:DMA Parity Error & Clear      */
#define Int_IntEarNot          0x00000040 /* 1:Receive Data write & Clear    */
#define Int_SWInt              0x00000020 /* 1:Software request & Clear      */
#define Int_IntBLEx            0x00000010 /* 1:Buffer List Empty & Clear     */
#define Int_IntFDAEx           0x00000008 /* 1:FDA Empty & Clear             */
#define Int_IntPCI             0x00000004 /* 1:PCI controller & Clear        */
#define Int_IntMacRx           0x00000002 /* 1:Rx controller & Clear         */
#define Int_IntMacTx           0x00000001 /* 1:Tx controller & Clear         */

/* MD_CA bit asign --------------------------------------------------------- */
#define MD_CA_PreSup           0x00001000 /* 1:Preamble Supress              */
#define MD_CA_Busy             0x00000800 /* 1:Busy (Start Operation)        */
#define MD_CA_Wr               0x00000400 /* 1:Write 0:Read                  */


/*
 * Descriptors
 */

/* Frame descripter */
struct FDesc {
	volatile __u32 FDNext;
	volatile __u32 FDSystem;
	volatile __u32 FDStat;
	volatile __u32 FDCtl;
};

/* Buffer descripter */
struct BDesc {
	volatile __u32 BuffData;
	volatile __u32 BDCtl;
};

#define FD_ALIGN	16

/* Frame Descripter bit asign ---------------------------------------------- */
#define FD_FDLength_MASK       0x0000FFFF /* Length MASK                     */
#define FD_BDCnt_MASK          0x001F0000 /* BD count MASK in FD             */
#define FD_FrmOpt_MASK         0x7C000000 /* Frame option MASK               */
#define FD_FrmOpt_BigEndian    0x40000000 /* Tx/Rx */
#define FD_FrmOpt_IntTx        0x20000000 /* Tx only */
#define FD_FrmOpt_NoCRC        0x10000000 /* Tx only */
#define FD_FrmOpt_NoPadding    0x08000000 /* Tx only */
#define FD_FrmOpt_Packing      0x04000000 /* Rx only */
#define FD_CownsFD             0x80000000 /* FD Controller owner bit         */
#define FD_Next_EOL            0x00000001 /* FD EOL indicator                */
#define FD_BDCnt_SHIFT         16

/* Buffer Descripter bit asign --------------------------------------------- */
#define BD_BuffLength_MASK     0x0000FFFF /* Recieve Data Size               */
#define BD_RxBDID_MASK         0x00FF0000 /* BD ID Number MASK               */
#define BD_RxBDSeqN_MASK       0x7F000000 /* Rx BD Sequence Number           */
#define BD_CownsBD             0x80000000 /* BD Controller owner bit         */
#define BD_RxBDID_SHIFT        16
#define BD_RxBDSeqN_SHIFT      24


/* Some useful constants. */
#undef NO_CHECK_CARRIER	/* Does not check No-Carrier with TP */

#ifdef NO_CHECK_CARRIER
#define TX_CTL_CMD	(Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
	Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
	Tx_En)	/* maybe  0x7b01 */
#else
#define TX_CTL_CMD	(Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
	Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
	Tx_En)	/* maybe  0x7b01 */
#endif
#define RX_CTL_CMD	(Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
	| Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn)	/* maybe 0x6f01 */
#define INT_EN_CMD  (Int_NRAbtEn | \
	Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \
	Int_SSysErrEn  | Int_RMasAbtEn | Int_RTargAbtEn | \
	Int_STargAbtEn | \
	Int_BLExEn  | Int_FDAExEn) /* maybe 0xb7f*/
#define DMA_CTL_CMD	DMA_BURST_SIZE
#define HAVE_DMA_RXALIGN(lp)	likely((lp)->boardtype != TC35815CF)

/* Tuning parameters */
#define DMA_BURST_SIZE	32
#define TX_THRESHOLD	1024
#define TX_THRESHOLD_MAX 1536       /* used threshold with packet max byte for low pci transfer ability.*/
#define TX_THRESHOLD_KEEP_LIMIT 10  /* setting threshold max value when overrun error occured this count. */

/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */
#ifdef TC35815_USE_PACKEDBUFFER
#define FD_PAGE_NUM 2
#define RX_BUF_NUM	8	/* >= 2 */
#define RX_FD_NUM	250	/* >= 32 */
#define TX_FD_NUM	128
#define RX_BUF_SIZE	PAGE_SIZE
#else /* TC35815_USE_PACKEDBUFFER */
#define FD_PAGE_NUM 4
#define RX_BUF_NUM	128	/* < 256 */
#define RX_FD_NUM	256	/* >= 32 */
#define TX_FD_NUM	128
#if RX_CTL_CMD & Rx_LongEn
#define RX_BUF_SIZE	PAGE_SIZE
#elif RX_CTL_CMD & Rx_StripCRC
#define RX_BUF_SIZE	ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */
#else
#define RX_BUF_SIZE	ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */
#endif
#endif /* TC35815_USE_PACKEDBUFFER */
#define RX_FD_RESERVE	(2 / 2)	/* max 2 BD per RxFD */
#define NAPI_WEIGHT	16

struct TxFD {
	struct FDesc fd;
	struct BDesc bd;
	struct BDesc unused;
};

struct RxFD {
	struct FDesc fd;
	struct BDesc bd[0];	/* variable length */
};

struct FrFD {
	struct FDesc fd;
	struct BDesc bd[RX_BUF_NUM];
};


#define tc_readl(addr)	readl(addr)
#define tc_writel(d, addr)	writel(d, addr)

#define TC35815_TX_TIMEOUT  msecs_to_jiffies(400)

/* Timer state engine. */
enum tc35815_timer_state {
	arbwait  = 0,	/* Waiting for auto negotiation to complete.          */
	lupwait  = 1,	/* Auto-neg complete, awaiting link-up status.        */
	ltrywait = 2,	/* Forcing try of all modes, from fastest to slowest. */
	asleep   = 3,	/* Time inactive.                                     */
	lcheck   = 4,	/* Check link status.                                 */
};

/* Information that need to be kept for each board. */
struct tc35815_local {
	struct pci_dev *pci_dev;

	/* statistics */
	struct net_device_stats stats;
	struct {
		int max_tx_qlen;
		int tx_ints;
		int rx_ints;
	        int tx_underrun;
	} lstats;

	/* Tx control lock.  This protects the transmit buffer ring
	 * state along with the "tx full" state of the driver.  This
	 * means all netif_queue flow control actions are protected
	 * by this lock as well.
	 */
	spinlock_t lock;

	int phy_addr;
	int fullduplex;
	unsigned short saved_lpa;
	struct timer_list timer;
	enum tc35815_timer_state timer_state; /* State of auto-neg timer. */
	unsigned int timer_ticks;	/* Number of clicks at each state  */

	/*
	 * Transmitting: Batch Mode.
	 *	1 BD in 1 TxFD.
	 * Receiving: Packing Mode. (TC35815_USE_PACKEDBUFFER)
	 *	1 circular FD for Free Buffer List.
	 *	RX_BUF_NUM BD in Free Buffer FD.
	 *	One Free Buffer BD has PAGE_SIZE data buffer.
	 * Or Non-Packing Mode.
	 *	1 circular FD for Free Buffer List.
	 *	RX_BUF_NUM BD in Free Buffer FD.
	 *	One Free Buffer BD has ETH_FRAME_LEN data buffer.
	 */
	void * fd_buf;	/* for TxFD, RxFD, FrFD */
	dma_addr_t fd_buf_dma;
	struct TxFD *tfd_base;
	unsigned int tfd_start;
	unsigned int tfd_end;
	struct RxFD *rfd_base;
	struct RxFD *rfd_limit;
	struct RxFD *rfd_cur;
	struct FrFD *fbl_ptr;
#ifdef TC35815_USE_PACKEDBUFFER
	unsigned char fbl_curid;
	void * data_buf[RX_BUF_NUM];		/* packing */
	dma_addr_t data_buf_dma[RX_BUF_NUM];
	struct {
		struct sk_buff *skb;
		dma_addr_t skb_dma;
	} tx_skbs[TX_FD_NUM];
#else
	unsigned int fbl_count;
	struct {
		struct sk_buff *skb;
		dma_addr_t skb_dma;
	} tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM];
#endif
	struct mii_if_info mii;
	unsigned short mii_id[2];
	u32 msg_enable;
	board_t boardtype;
};

static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt)
{
	return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf);
}
#ifdef DEBUG
static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
{
	return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma));
}
#endif
#ifdef TC35815_USE_PACKEDBUFFER
static inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
{
	int i;
	for (i = 0; i < RX_BUF_NUM; i++) {
		if (bus >= lp->data_buf_dma[i] &&
		    bus < lp->data_buf_dma[i] + PAGE_SIZE)
			return (void *)((u8 *)lp->data_buf[i] +
					(bus - lp->data_buf_dma[i]));
	}
	return NULL;
}

#define TC35815_DMA_SYNC_ONDEMAND
static void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle)
{
#ifdef TC35815_DMA_SYNC_ONDEMAND
	void *buf;
	/* pci_map + pci_dma_sync will be more effective than
	 * pci_alloc_consistent on some archs. */
	if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL)
		return NULL;
	*dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE,
				     PCI_DMA_FROMDEVICE);
	if (pci_dma_mapping_error(*dma_handle)) {
		free_page((unsigned long)buf);
		return NULL;
	}
	return buf;
#else
	return pci_alloc_consistent(hwdev, PAGE_SIZE, dma_handle);
#endif
}

static void free_rxbuf_page(struct pci_dev *hwdev, void *buf, dma_addr_t dma_handle)
{
#ifdef TC35815_DMA_SYNC_ONDEMAND
	pci_unmap_single(hwdev, dma_handle, PAGE_SIZE, PCI_DMA_FROMDEVICE);
	free_page((unsigned long)buf);
#else
	pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle);
#endif
}
#else /* TC35815_USE_PACKEDBUFFER */
static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev,
				       struct pci_dev *hwdev,
				       dma_addr_t *dma_handle)
{
	struct sk_buff *skb;
	skb = dev_alloc_skb(RX_BUF_SIZE);
	if (!skb)
		return NULL;
	skb->dev = dev;
	*dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE,
				     PCI_DMA_FROMDEVICE);
	if (pci_dma_mapping_error(*dma_handle)) {
		dev_kfree_skb_any(skb);
		return NULL;
	}
	skb_reserve(skb, 2);	/* make IP header 4byte aligned */
	return skb;
}

static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle)
{
	pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE,
			 PCI_DMA_FROMDEVICE);
	dev_kfree_skb_any(skb);
}
#endif /* TC35815_USE_PACKEDBUFFER */

/* Index to functions, as function prototypes. */

static int	tc35815_open(struct net_device *dev);
static int	tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t	tc35815_interrupt(int irq, void *dev_id);
#ifdef TC35815_NAPI
static int	tc35815_rx(struct net_device *dev, int limit);
static int	tc35815_poll(struct net_device *dev, int *budget);
#else
static void	tc35815_rx(struct net_device *dev);
#endif
static void	tc35815_txdone(struct net_device *dev);
static int	tc35815_close(struct net_device *dev);
static struct	net_device_stats *tc35815_get_stats(struct net_device *dev);
static void	tc35815_set_multicast_list(struct net_device *dev);
static void     tc35815_tx_timeout(struct net_device *dev);
static int	tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void	tc35815_poll_controller(struct net_device *dev);
#endif
static const struct ethtool_ops tc35815_ethtool_ops;

/* Example routines you must write ;->. */
static void 	tc35815_chip_reset(struct net_device *dev);
static void 	tc35815_chip_init(struct net_device *dev);
static void	tc35815_find_phy(struct net_device *dev);
static void 	tc35815_phy_chip_init(struct net_device *dev);

#ifdef DEBUG
static void	panic_queues(struct net_device *dev);
#endif

static void tc35815_timer(unsigned long data);
static void tc35815_start_auto_negotiation(struct net_device *dev,
					   struct ethtool_cmd *ep);
static int tc_mdio_read(struct net_device *dev, int phy_id, int location);
static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
			  int val);

static void __devinit tc35815_init_dev_addr (struct net_device *dev)
{
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;
	int i;

	/* dev_addr will be overwritten on NETDEV_REGISTER event */
	while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
		;
	for (i = 0; i < 6; i += 2) {
		unsigned short data;
		tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
		while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
			;
		data = tc_readl(&tr->PROM_Data);
		dev->dev_addr[i] = data & 0xff;
		dev->dev_addr[i+1] = data >> 8;
	}
}

static int __devinit tc35815_init_one (struct pci_dev *pdev,
				       const struct pci_device_id *ent)
{
	void __iomem *ioaddr = NULL;
	struct net_device *dev;
	struct tc35815_local *lp;
	int rc;
	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;

	static int printed_version;
	if (!printed_version++) {
		printk(version);
		dev_printk(KERN_DEBUG, &pdev->dev,
			   "speed:%d duplex:%d doforce:%d\n",
			   options.speed, options.duplex, options.doforce);
	}

	if (!pdev->irq) {
		dev_warn(&pdev->dev, "no IRQ assigned.\n");
		return -ENODEV;
	}

	/* dev zeroed in alloc_etherdev */
	dev = alloc_etherdev (sizeof (*lp));
	if (dev == NULL) {
		dev_err(&pdev->dev, "unable to alloc new ethernet\n");
		return -ENOMEM;
	}
	SET_MODULE_OWNER(dev);
	SET_NETDEV_DEV(dev, &pdev->dev);
	lp = dev->priv;

	/* enable device (incl. PCI PM wakeup), and bus-mastering */
	rc = pci_enable_device (pdev);
	if (rc)
		goto err_out;

	mmio_start = pci_resource_start (pdev, 1);
	mmio_end = pci_resource_end (pdev, 1);
	mmio_flags = pci_resource_flags (pdev, 1);
	mmio_len = pci_resource_len (pdev, 1);

	/* set this immediately, we need to know before
	 * we talk to the chip directly */

	/* make sure PCI base addr 1 is MMIO */
	if (!(mmio_flags & IORESOURCE_MEM)) {
		dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
		rc = -ENODEV;
		goto err_out;
	}

	/* check for weird/broken PCI region reporting */
	if ((mmio_len < sizeof(struct tc35815_regs))) {
		dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
		rc = -ENODEV;
		goto err_out;
	}

	rc = pci_request_regions (pdev, MODNAME);
	if (rc)
		goto err_out;

	pci_set_master (pdev);

	/* ioremap MMIO region */
	ioaddr = ioremap (mmio_start, mmio_len);
	if (ioaddr == NULL) {
		dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
		rc = -EIO;
		goto err_out_free_res;
	}

	/* Initialize the device structure. */
	dev->open = tc35815_open;
	dev->hard_start_xmit = tc35815_send_packet;
	dev->stop = tc35815_close;
	dev->get_stats = tc35815_get_stats;
	dev->set_multicast_list = tc35815_set_multicast_list;
	dev->do_ioctl = tc35815_ioctl;
	dev->ethtool_ops = &tc35815_ethtool_ops;
	dev->tx_timeout = tc35815_tx_timeout;
	dev->watchdog_timeo = TC35815_TX_TIMEOUT;
#ifdef TC35815_NAPI
	dev->poll = tc35815_poll;
	dev->weight = NAPI_WEIGHT;
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
	dev->poll_controller = tc35815_poll_controller;
#endif

	dev->irq = pdev->irq;
	dev->base_addr = (unsigned long) ioaddr;

	/* dev->priv/lp zeroed and aligned in alloc_etherdev */
	lp = dev->priv;
	spin_lock_init(&lp->lock);
	lp->pci_dev = pdev;
	lp->boardtype = ent->driver_data;

	lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK;
	pci_set_drvdata(pdev, dev);

	/* Soft reset the chip. */
	tc35815_chip_reset(dev);

	/* Retrieve the ethernet address. */
	tc35815_init_dev_addr(dev);

	rc = register_netdev (dev);
	if (rc)
		goto err_out_unmap;

	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
	printk(KERN_INFO "%s: %s at 0x%lx, "
		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
		"IRQ %d\n",
		dev->name,
		board_info[ent->driver_data].name,
		dev->base_addr,
		dev->dev_addr[0], dev->dev_addr[1],
		dev->dev_addr[2], dev->dev_addr[3],
		dev->dev_addr[4], dev->dev_addr[5],
		dev->irq);

	setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev);
	lp->mii.dev = dev;
	lp->mii.mdio_read = tc_mdio_read;
	lp->mii.mdio_write = tc_mdio_write;
	lp->mii.phy_id_mask = 0x1f;
	lp->mii.reg_num_mask = 0x1f;
	tc35815_find_phy(dev);
	lp->mii.phy_id = lp->phy_addr;
	lp->mii.full_duplex = 0;
	lp->mii.force_media = 0;

	return 0;

err_out_unmap:
	iounmap(ioaddr);
err_out_free_res:
	pci_release_regions (pdev);
err_out:
	free_netdev (dev);
	return rc;
}


static void __devexit tc35815_remove_one (struct pci_dev *pdev)
{
	struct net_device *dev = pci_get_drvdata (pdev);
	unsigned long mmio_addr;

	mmio_addr = dev->base_addr;

	unregister_netdev (dev);

	if (mmio_addr) {
		iounmap ((void __iomem *)mmio_addr);
		pci_release_regions (pdev);
	}

	free_netdev (dev);

	pci_set_drvdata (pdev, NULL);
}

static int
tc35815_init_queues(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int i;
	unsigned long fd_addr;

	if (!lp->fd_buf) {
		BUG_ON(sizeof(struct FDesc) +
		       sizeof(struct BDesc) * RX_BUF_NUM +
		       sizeof(struct FDesc) * RX_FD_NUM +
		       sizeof(struct TxFD) * TX_FD_NUM >
		       PAGE_SIZE * FD_PAGE_NUM);

		if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0)
			return -ENOMEM;
		for (i = 0; i < RX_BUF_NUM; i++) {
#ifdef TC35815_USE_PACKEDBUFFER
			if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) {
				while (--i >= 0) {
					free_rxbuf_page(lp->pci_dev,
							lp->data_buf[i],
							lp->data_buf_dma[i]);
					lp->data_buf[i] = NULL;
				}
				pci_free_consistent(lp->pci_dev,
						    PAGE_SIZE * FD_PAGE_NUM,
						    lp->fd_buf,
						    lp->fd_buf_dma);
				lp->fd_buf = NULL;
				return -ENOMEM;
			}
#else
			lp->rx_skbs[i].skb =
				alloc_rxbuf_skb(dev, lp->pci_dev,
						&lp->rx_skbs[i].skb_dma);
			if (!lp->rx_skbs[i].skb) {
				while (--i >= 0) {
					free_rxbuf_skb(lp->pci_dev,
						       lp->rx_skbs[i].skb,
						       lp->rx_skbs[i].skb_dma);
					lp->rx_skbs[i].skb = NULL;
				}
				pci_free_consistent(lp->pci_dev,
						    PAGE_SIZE * FD_PAGE_NUM,
						    lp->fd_buf,
						    lp->fd_buf_dma);
				lp->fd_buf = NULL;
				return -ENOMEM;
			}
#endif
		}
		printk(KERN_DEBUG "%s: FD buf %p DataBuf",
		       dev->name, lp->fd_buf);
#ifdef TC35815_USE_PACKEDBUFFER
		printk(" DataBuf");
		for (i = 0; i < RX_BUF_NUM; i++)
			printk(" %p", lp->data_buf[i]);
#endif
		printk("\n");
	} else {
		for (i = 0; i < FD_PAGE_NUM; i++) {
			clear_page((void *)((unsigned long)lp->fd_buf + i * PAGE_SIZE));
		}
	}
	fd_addr = (unsigned long)lp->fd_buf;

	/* Free Descriptors (for Receive) */
	lp->rfd_base = (struct RxFD *)fd_addr;
	fd_addr += sizeof(struct RxFD) * RX_FD_NUM;
	for (i = 0; i < RX_FD_NUM; i++) {
		lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
	}
	lp->rfd_cur = lp->rfd_base;
	lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1);

	/* Transmit Descriptors */
	lp->tfd_base = (struct TxFD *)fd_addr;
	fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
	for (i = 0; i < TX_FD_NUM; i++) {
		lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1]));
		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
		lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
	}
	lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0]));
	lp->tfd_start = 0;
	lp->tfd_end = 0;

	/* Buffer List (for Receive) */
	lp->fbl_ptr = (struct FrFD *)fd_addr;
	lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr));
	lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD);
#ifndef TC35815_USE_PACKEDBUFFER
	/*
	 * move all allocated skbs to head of rx_skbs[] array.
	 * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in
	 * tc35815_rx() had failed.
	 */
	lp->fbl_count = 0;
	for (i = 0; i < RX_BUF_NUM; i++) {
		if (lp->rx_skbs[i].skb) {
			if (i != lp->fbl_count) {
				lp->rx_skbs[lp->fbl_count].skb =
					lp->rx_skbs[i].skb;
				lp->rx_skbs[lp->fbl_count].skb_dma =
					lp->rx_skbs[i].skb_dma;
			}
			lp->fbl_count++;
		}
	}
#endif
	for (i = 0; i < RX_BUF_NUM; i++) {
#ifdef TC35815_USE_PACKEDBUFFER
		lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(lp->data_buf_dma[i]);
#else
		if (i >= lp->fbl_count) {
			lp->fbl_ptr->bd[i].BuffData = 0;
			lp->fbl_ptr->bd[i].BDCtl = 0;
			continue;
		}
		lp->fbl_ptr->bd[i].BuffData =
			cpu_to_le32(lp->rx_skbs[i].skb_dma);
#endif
		/* BDID is index of FrFD.bd[] */
		lp->fbl_ptr->bd[i].BDCtl =
			cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) |
				    RX_BUF_SIZE);
	}
#ifdef TC35815_USE_PACKEDBUFFER
	lp->fbl_curid = 0;
#endif

	printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n",
	       dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr);
	return 0;
}

static void
tc35815_clear_queues(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int i;

	for (i = 0; i < TX_FD_NUM; i++) {
		u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
		struct sk_buff *skb =
			fdsystem != 0xffffffff ?
			lp->tx_skbs[fdsystem].skb : NULL;
#ifdef DEBUG
		if (lp->tx_skbs[i].skb != skb) {
			printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
			panic_queues(dev);
		}
#else
		BUG_ON(lp->tx_skbs[i].skb != skb);
#endif
		if (skb) {
			pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
			lp->tx_skbs[i].skb = NULL;
			lp->tx_skbs[i].skb_dma = 0;
			dev_kfree_skb_any(skb);
		}
		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
	}

	tc35815_init_queues(dev);
}

static void
tc35815_free_queues(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int i;

	if (lp->tfd_base) {
		for (i = 0; i < TX_FD_NUM; i++) {
			u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
			struct sk_buff *skb =
				fdsystem != 0xffffffff ?
				lp->tx_skbs[fdsystem].skb : NULL;
#ifdef DEBUG
			if (lp->tx_skbs[i].skb != skb) {
				printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
				panic_queues(dev);
			}
#else
			BUG_ON(lp->tx_skbs[i].skb != skb);
#endif
			if (skb) {
				dev_kfree_skb(skb);
				pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
				lp->tx_skbs[i].skb = NULL;
				lp->tx_skbs[i].skb_dma = 0;
			}
			lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
		}
	}

	lp->rfd_base = NULL;
	lp->rfd_limit = NULL;
	lp->rfd_cur = NULL;
	lp->fbl_ptr = NULL;

	for (i = 0; i < RX_BUF_NUM; i++) {
#ifdef TC35815_USE_PACKEDBUFFER
		if (lp->data_buf[i]) {
			free_rxbuf_page(lp->pci_dev,
					lp->data_buf[i], lp->data_buf_dma[i]);
			lp->data_buf[i] = NULL;
		}
#else
		if (lp->rx_skbs[i].skb) {
			free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb,
				       lp->rx_skbs[i].skb_dma);
			lp->rx_skbs[i].skb = NULL;
		}
#endif
	}
	if (lp->fd_buf) {
		pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM,
				    lp->fd_buf, lp->fd_buf_dma);
		lp->fd_buf = NULL;
	}
}

static void
dump_txfd(struct TxFD *fd)
{
	printk("TxFD(%p): %08x %08x %08x %08x\n", fd,
	       le32_to_cpu(fd->fd.FDNext),
	       le32_to_cpu(fd->fd.FDSystem),
	       le32_to_cpu(fd->fd.FDStat),
	       le32_to_cpu(fd->fd.FDCtl));
	printk("BD: ");
	printk(" %08x %08x",
	       le32_to_cpu(fd->bd.BuffData),
	       le32_to_cpu(fd->bd.BDCtl));
	printk("\n");
}

static int
dump_rxfd(struct RxFD *fd)
{
	int i, bd_count = (le32_to_cpu(fd->fd.FDCtl) & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
	if (bd_count > 8)
		bd_count = 8;
	printk("RxFD(%p): %08x %08x %08x %08x\n", fd,
	       le32_to_cpu(fd->fd.FDNext),
	       le32_to_cpu(fd->fd.FDSystem),
	       le32_to_cpu(fd->fd.FDStat),
	       le32_to_cpu(fd->fd.FDCtl));
	if (le32_to_cpu(fd->fd.FDCtl) & FD_CownsFD)
	    return 0;
	printk("BD: ");
	for (i = 0; i < bd_count; i++)
		printk(" %08x %08x",
		       le32_to_cpu(fd->bd[i].BuffData),
		       le32_to_cpu(fd->bd[i].BDCtl));
	printk("\n");
	return bd_count;
}

#if defined(DEBUG) || defined(TC35815_USE_PACKEDBUFFER)
static void
dump_frfd(struct FrFD *fd)
{
	int i;
	printk("FrFD(%p): %08x %08x %08x %08x\n", fd,
	       le32_to_cpu(fd->fd.FDNext),
	       le32_to_cpu(fd->fd.FDSystem),
	       le32_to_cpu(fd->fd.FDStat),
	       le32_to_cpu(fd->fd.FDCtl));
	printk("BD: ");
	for (i = 0; i < RX_BUF_NUM; i++)
		printk(" %08x %08x",
		       le32_to_cpu(fd->bd[i].BuffData),
		       le32_to_cpu(fd->bd[i].BDCtl));
	printk("\n");
}
#endif

#ifdef DEBUG
static void
panic_queues(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int i;

	printk("TxFD base %p, start %u, end %u\n",
	       lp->tfd_base, lp->tfd_start, lp->tfd_end);
	printk("RxFD base %p limit %p cur %p\n",
	       lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
	printk("FrFD %p\n", lp->fbl_ptr);
	for (i = 0; i < TX_FD_NUM; i++)
		dump_txfd(&lp->tfd_base[i]);
	for (i = 0; i < RX_FD_NUM; i++) {
		int bd_count = dump_rxfd(&lp->rfd_base[i]);
		i += (bd_count + 1) / 2;	/* skip BDs */
	}
	dump_frfd(lp->fbl_ptr);
	panic("%s: Illegal queue state.", dev->name);
}
#endif

static void print_eth(char *add)
{
	int i;

	printk("print_eth(%p)\n", add);
	for (i = 0; i < 6; i++)
		printk(" %2.2X", (unsigned char) add[i + 6]);
	printk(" =>");
	for (i = 0; i < 6; i++)
		printk(" %2.2X", (unsigned char) add[i]);
	printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
}

static int tc35815_tx_full(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	return ((lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end);
}

static void tc35815_restart(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int pid = lp->phy_addr;
	int do_phy_reset = 1;
	del_timer(&lp->timer);		/* Kill if running	*/

	if (lp->mii_id[0] == 0x0016 && (lp->mii_id[1] & 0xfc00) == 0xf800) {
		/* Resetting PHY cause problem on some chip... (SEEQ 80221) */
		do_phy_reset = 0;
	}
	if (do_phy_reset) {
		int timeout;
		tc_mdio_write(dev, pid, MII_BMCR, BMCR_RESET);
		timeout = 100;
		while (--timeout) {
			if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_RESET))
				break;
			udelay(1);
		}
		if (!timeout)
			printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name);
	}

	tc35815_chip_reset(dev);
	tc35815_clear_queues(dev);
	tc35815_chip_init(dev);
	/* Reconfigure CAM again since tc35815_chip_init() initialize it. */
	tc35815_set_multicast_list(dev);
}

static void tc35815_tx_timeout(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;

	printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
	       dev->name, tc_readl(&tr->Tx_Stat));

	/* Try to restart the adaptor. */
	spin_lock_irq(&lp->lock);
	tc35815_restart(dev);
	spin_unlock_irq(&lp->lock);

	lp->stats.tx_errors++;

	/* If we have space available to accept new transmit
	 * requests, wake up the queueing layer.  This would
	 * be the case if the chipset_init() call above just
	 * flushes out the tx queue and empties it.
	 *
	 * If instead, the tx queue is retained then the
	 * netif_wake_queue() call should be placed in the
	 * TX completion interrupt handler of the driver instead
	 * of here.
	 */
	if (!tc35815_tx_full(dev))
		netif_wake_queue(dev);
}

/*
 * Open/initialize the board. This is called (in the current kernel)
 * sometime after booting when the 'ifconfig' program is run.
 *
 * This routine should set everything up anew at each open, even
 * registers that "should" only need to be set once at boot, so that
 * there is non-reboot way to recover if something goes wrong.
 */
static int
tc35815_open(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;

	/*
	 * This is used if the interrupt line can turned off (shared).
	 * See 3c503.c for an example of selecting the IRQ at config-time.
	 */
	if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, dev->name, dev)) {
		return -EAGAIN;
	}

	del_timer(&lp->timer);		/* Kill if running	*/
	tc35815_chip_reset(dev);

	if (tc35815_init_queues(dev) != 0) {
		free_irq(dev->irq, dev);
		return -EAGAIN;
	}

	/* Reset the hardware here. Don't forget to set the station address. */
	spin_lock_irq(&lp->lock);
	tc35815_chip_init(dev);
	spin_unlock_irq(&lp->lock);

	/* We are now ready to accept transmit requeusts from
	 * the queueing layer of the networking.
	 */
	netif_start_queue(dev);

	return 0;
}

/* This will only be invoked if your driver is _not_ in XOFF state.
 * What this means is that you need not check it, and that this
 * invariant will hold if you make sure that the netif_*_queue()
 * calls are done at the proper times.
 */
static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	struct TxFD *txfd;
	unsigned long flags;

	/* If some error occurs while trying to transmit this
	 * packet, you should return '1' from this function.
	 * In such a case you _may not_ do anything to the
	 * SKB, it is still owned by the network queueing
	 * layer when an error is returned.  This means you
	 * may not modify any SKB fields, you may not free
	 * the SKB, etc.
	 */

	/* This is the most common case for modern hardware.
	 * The spinlock protects this code from the TX complete
	 * hardware interrupt handler.  Queue flow control is
	 * thus managed under this lock as well.
	 */
	spin_lock_irqsave(&lp->lock, flags);

	/* failsafe... (handle txdone now if half of FDs are used) */
	if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM >
	    TX_FD_NUM / 2)
		tc35815_txdone(dev);

	if (netif_msg_pktdata(lp))
		print_eth(skb->data);
#ifdef DEBUG
	if (lp->tx_skbs[lp->tfd_start].skb) {
		printk("%s: tx_skbs conflict.\n", dev->name);
		panic_queues(dev);
	}
#else
	BUG_ON(lp->tx_skbs[lp->tfd_start].skb);
#endif
	lp->tx_skbs[lp->tfd_start].skb = skb;
	lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);

	/*add to ring */
	txfd = &lp->tfd_base[lp->tfd_start];
	txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma);
	txfd->bd.BDCtl = cpu_to_le32(skb->len);
	txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start);
	txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));

	if (lp->tfd_start == lp->tfd_end) {
		struct tc35815_regs __iomem *tr =
			(struct tc35815_regs __iomem *)dev->base_addr;
		/* Start DMA Transmitter. */
		txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
#ifdef GATHER_TXINT
		txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
#endif
		if (netif_msg_tx_queued(lp)) {
			printk("%s: starting TxFD.\n", dev->name);
			dump_txfd(txfd);
		}
		tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
	} else {
		txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
		if (netif_msg_tx_queued(lp)) {
			printk("%s: queueing TxFD.\n", dev->name);
			dump_txfd(txfd);
		}
	}
	lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;

	dev->trans_start = jiffies;

	/* If we just used up the very last entry in the
	 * TX ring on this device, tell the queueing
	 * layer to send no more.
	 */
	if (tc35815_tx_full(dev)) {
		if (netif_msg_tx_queued(lp))
			printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
		netif_stop_queue(dev);
	}

	/* When the TX completion hw interrupt arrives, this
	 * is when the transmit statistics are updated.
	 */

	spin_unlock_irqrestore(&lp->lock, flags);
	return 0;
}

#define FATAL_ERROR_INT \
	(Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status)
{
	static int count;
	printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
	       dev->name, status);
	if (status & Int_IntPCI)
		printk(" IntPCI");
	if (status & Int_DmParErr)
		printk(" DmParErr");
	if (status & Int_IntNRAbt)
		printk(" IntNRAbt");
	printk("\n");
	if (count++ > 100)
		panic("%s: Too many fatal errors.", dev->name);
	printk(KERN_WARNING "%s: Resetting ...\n", dev->name);
	/* Try to restart the adaptor. */
	tc35815_restart(dev);
}

#ifdef TC35815_NAPI
static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit)
#else
static int tc35815_do_interrupt(struct net_device *dev, u32 status)
#endif
{
	struct tc35815_local *lp = dev->priv;
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;
	int ret = -1;

	/* Fatal errors... */
	if (status & FATAL_ERROR_INT) {
		tc35815_fatal_error_interrupt(dev, status);
		return 0;
	}
	/* recoverable errors */
	if (status & Int_IntFDAEx) {
		/* disable FDAEx int. (until we make rooms...) */
		tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
		printk(KERN_WARNING
		       "%s: Free Descriptor Area Exhausted (%#x).\n",
		       dev->name, status);
		lp->stats.rx_dropped++;
		ret = 0;
	}
	if (status & Int_IntBLEx) {
		/* disable BLEx int. (until we make rooms...) */
		tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
		printk(KERN_WARNING
		       "%s: Buffer List Exhausted (%#x).\n",
		       dev->name, status);
		lp->stats.rx_dropped++;
		ret = 0;
	}
	if (status & Int_IntExBD) {
		printk(KERN_WARNING
		       "%s: Excessive Buffer Descriptiors (%#x).\n",
		       dev->name, status);
		lp->stats.rx_length_errors++;
		ret = 0;
	}

	/* normal notification */
	if (status & Int_IntMacRx) {
		/* Got a packet(s). */
#ifdef TC35815_NAPI
		ret = tc35815_rx(dev, limit);
#else
		tc35815_rx(dev);
		ret = 0;
#endif
		lp->lstats.rx_ints++;
	}
	if (status & Int_IntMacTx) {
		/* Transmit complete. */
		lp->lstats.tx_ints++;
		tc35815_txdone(dev);
		netif_wake_queue(dev);
		ret = 0;
	}
	return ret;
}

/*
 * The typical workload of the driver:
 * Handle the network interface interrupts.
 */
static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
{
	struct net_device *dev = dev_id;
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;
#ifdef TC35815_NAPI
	u32 dmactl = tc_readl(&tr->DMA_Ctl);

	if (!(dmactl & DMA_IntMask)) {
		/* disable interrupts */
		tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
		if (netif_rx_schedule_prep(dev))
			__netif_rx_schedule(dev);
		else {
			printk(KERN_ERR "%s: interrupt taken in poll\n",
			       dev->name);
			BUG();
		}
		(void)tc_readl(&tr->Int_Src);	/* flush */
		return IRQ_HANDLED;
	}
	return IRQ_NONE;
#else
	struct tc35815_local *lp = dev->priv;
	int handled;
	u32 status;

	spin_lock(&lp->lock);
	status = tc_readl(&tr->Int_Src);
	tc_writel(status, &tr->Int_Src);	/* write to clear */
	handled = tc35815_do_interrupt(dev, status);
	(void)tc_readl(&tr->Int_Src);	/* flush */
	spin_unlock(&lp->lock);
	return IRQ_RETVAL(handled >= 0);
#endif /* TC35815_NAPI */
}

#ifdef CONFIG_NET_POLL_CONTROLLER
static void tc35815_poll_controller(struct net_device *dev)
{
	disable_irq(dev->irq);
	tc35815_interrupt(dev->irq, dev);
	enable_irq(dev->irq);
}
#endif

/* We have a good packet(s), get it/them out of the buffers. */
#ifdef TC35815_NAPI
static int
tc35815_rx(struct net_device *dev, int limit)
#else
static void
tc35815_rx(struct net_device *dev)
#endif
{
	struct tc35815_local *lp = dev->priv;
	unsigned int fdctl;
	int i;
	int buf_free_count = 0;
	int fd_free_count = 0;
#ifdef TC35815_NAPI
	int received = 0;
#endif

	while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
		int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
		int pkt_len = fdctl & FD_FDLength_MASK;
		int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
#ifdef DEBUG
		struct RxFD *next_rfd;
#endif
#if (RX_CTL_CMD & Rx_StripCRC) == 0
		pkt_len -= 4;
#endif

		if (netif_msg_rx_status(lp))
			dump_rxfd(lp->rfd_cur);
		if (status & Rx_Good) {
			struct sk_buff *skb;
			unsigned char *data;
			int cur_bd;
#ifdef TC35815_USE_PACKEDBUFFER
			int offset;
#endif

#ifdef TC35815_NAPI
			if (--limit < 0)
				break;
#endif
#ifdef TC35815_USE_PACKEDBUFFER
			BUG_ON(bd_count > 2);
			skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
			if (skb == NULL) {
				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
				       dev->name);
				lp->stats.rx_dropped++;
				break;
			}
			skb_reserve(skb, 2);   /* 16 bit alignment */
			skb->dev = dev;

			data = skb_put(skb, pkt_len);

			/* copy from receive buffer */
			cur_bd = 0;
			offset = 0;
			while (offset < pkt_len && cur_bd < bd_count) {
				int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) &
					BD_BuffLength_MASK;
				dma_addr_t dma = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData);
				void *rxbuf = rxbuf_bus_to_virt(lp, dma);
				if (offset + len > pkt_len)
					len = pkt_len - offset;
#ifdef TC35815_DMA_SYNC_ONDEMAND
				pci_dma_sync_single_for_cpu(lp->pci_dev,
							    dma, len,
							    PCI_DMA_FROMDEVICE);
#endif
				memcpy(data + offset, rxbuf, len);
				offset += len;
				cur_bd++;
			}
#else /* TC35815_USE_PACKEDBUFFER */
			BUG_ON(bd_count > 1);
			cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl)
				  & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
#ifdef DEBUG
			if (cur_bd >= RX_BUF_NUM) {
				printk("%s: invalid BDID.\n", dev->name);
				panic_queues(dev);
			}
			BUG_ON(lp->rx_skbs[cur_bd].skb_dma !=
			       (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3));
			if (!lp->rx_skbs[cur_bd].skb) {
				printk("%s: NULL skb.\n", dev->name);
				panic_queues(dev);
			}
#else
			BUG_ON(cur_bd >= RX_BUF_NUM);
#endif
			skb = lp->rx_skbs[cur_bd].skb;
			prefetch(skb->data);
			lp->rx_skbs[cur_bd].skb = NULL;
			lp->fbl_count--;
			pci_unmap_single(lp->pci_dev,
					 lp->rx_skbs[cur_bd].skb_dma,
					 RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
			if (!HAVE_DMA_RXALIGN(lp))
				memmove(skb->data, skb->data - 2, pkt_len);
			data = skb_put(skb, pkt_len);
#endif /* TC35815_USE_PACKEDBUFFER */
			if (netif_msg_pktdata(lp))
				print_eth(data);
			skb->protocol = eth_type_trans(skb, dev);
#ifdef TC35815_NAPI
			netif_receive_skb(skb);
			received++;
#else
			netif_rx(skb);
#endif
			dev->last_rx = jiffies;
			lp->stats.rx_packets++;
			lp->stats.rx_bytes += pkt_len;
		} else {
			lp->stats.rx_errors++;
			printk(KERN_DEBUG "%s: Rx error (status %x)\n",
			       dev->name, status & Rx_Stat_Mask);
			/* WORKAROUND: LongErr and CRCErr means Overflow. */
			if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
				status &= ~(Rx_LongErr|Rx_CRCErr);
				status |= Rx_Over;
			}
			if (status & Rx_LongErr) lp->stats.rx_length_errors++;
			if (status & Rx_Over) lp->stats.rx_fifo_errors++;
			if (status & Rx_CRCErr) lp->stats.rx_crc_errors++;
			if (status & Rx_Align) lp->stats.rx_frame_errors++;
		}

		if (bd_count > 0) {
			/* put Free Buffer back to controller */
			int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
			unsigned char id =
				(bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
#ifdef DEBUG
			if (id >= RX_BUF_NUM) {
				printk("%s: invalid BDID.\n", dev->name);
				panic_queues(dev);
			}
#else
			BUG_ON(id >= RX_BUF_NUM);
#endif
			/* free old buffers */
#ifdef TC35815_USE_PACKEDBUFFER
			while (lp->fbl_curid != id)
#else
			while (lp->fbl_count < RX_BUF_NUM)
#endif
			{
#ifdef TC35815_USE_PACKEDBUFFER
				unsigned char curid = lp->fbl_curid;
#else
				unsigned char curid =
					(id + 1 + lp->fbl_count) % RX_BUF_NUM;
#endif
				struct BDesc *bd = &lp->fbl_ptr->bd[curid];
#ifdef DEBUG
				bdctl = le32_to_cpu(bd->BDCtl);
				if (bdctl & BD_CownsBD) {
					printk("%s: Freeing invalid BD.\n",
					       dev->name);
					panic_queues(dev);
				}
#endif
				/* pass BD to controler */
#ifndef TC35815_USE_PACKEDBUFFER
				if (!lp->rx_skbs[curid].skb) {
					lp->rx_skbs[curid].skb =
						alloc_rxbuf_skb(dev,
								lp->pci_dev,
								&lp->rx_skbs[curid].skb_dma);
					if (!lp->rx_skbs[curid].skb)
						break; /* try on next reception */
					bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma);
				}
#endif /* TC35815_USE_PACKEDBUFFER */
				/* Note: BDLength was modified by chip. */
				bd->BDCtl = cpu_to_le32(BD_CownsBD |
							(curid << BD_RxBDID_SHIFT) |
							RX_BUF_SIZE);
#ifdef TC35815_USE_PACKEDBUFFER
				lp->fbl_curid = (curid + 1) % RX_BUF_NUM;
				if (netif_msg_rx_status(lp)) {
					printk("%s: Entering new FBD %d\n",
					       dev->name, lp->fbl_curid);
					dump_frfd(lp->fbl_ptr);
				}
#else
				lp->fbl_count++;
#endif
				buf_free_count++;
			}
		}

		/* put RxFD back to controller */
#ifdef DEBUG
		next_rfd = fd_bus_to_virt(lp,
					  le32_to_cpu(lp->rfd_cur->fd.FDNext));
		if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
			printk("%s: RxFD FDNext invalid.\n", dev->name);
			panic_queues(dev);
		}
#endif
		for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
			/* pass FD to controler */
#ifdef DEBUG
			lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);
#else
			lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL);
#endif
			lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
			lp->rfd_cur++;
			fd_free_count++;
		}
		if (lp->rfd_cur > lp->rfd_limit)
			lp->rfd_cur = lp->rfd_base;
#ifdef DEBUG
		if (lp->rfd_cur != next_rfd)
			printk("rfd_cur = %p, next_rfd %p\n",
			       lp->rfd_cur, next_rfd);
#endif
	}

	/* re-enable BL/FDA Exhaust interrupts. */
	if (fd_free_count) {
		struct tc35815_regs __iomem *tr =
			(struct tc35815_regs __iomem *)dev->base_addr;
		u32 en, en_old = tc_readl(&tr->Int_En);
		en = en_old | Int_FDAExEn;
		if (buf_free_count)
			en |= Int_BLExEn;
		if (en != en_old)
			tc_writel(en, &tr->Int_En);
	}
#ifdef TC35815_NAPI
	return received;
#endif
}

#ifdef TC35815_NAPI
static int
tc35815_poll(struct net_device *dev, int *budget)
{
	struct tc35815_local *lp = dev->priv;
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;
	int limit = min(*budget, dev->quota);
	int received = 0, handled;
	u32 status;

	spin_lock(&lp->lock);
	status = tc_readl(&tr->Int_Src);
	do {
		tc_writel(status, &tr->Int_Src);	/* write to clear */

		handled = tc35815_do_interrupt(dev, status, limit);
		if (handled >= 0) {
			received += handled;
			limit -= handled;
			if (limit <= 0)
				break;
		}
		status = tc_readl(&tr->Int_Src);
	} while (status);
	spin_unlock(&lp->lock);

	dev->quota -= received;
	*budget -= received;
	if (limit <= 0)
		return 1;

	netif_rx_complete(dev);
	/* enable interrupts */
	tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
	return 0;
}
#endif

#ifdef NO_CHECK_CARRIER
#define TX_STA_ERR	(Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr)
#else
#define TX_STA_ERR	(Tx_ExColl|Tx_Under|Tx_Defer|Tx_NCarr|Tx_LateColl|Tx_TxPar|Tx_SQErr)
#endif

static void
tc35815_check_tx_stat(struct net_device *dev, int status)
{
	struct tc35815_local *lp = dev->priv;
	const char *msg = NULL;

	/* count collisions */
	if (status & Tx_ExColl)
		lp->stats.collisions += 16;
	if (status & Tx_TxColl_MASK)
		lp->stats.collisions += status & Tx_TxColl_MASK;

#ifndef NO_CHECK_CARRIER
	/* TX4939 does not have NCarr */
	if (lp->boardtype == TC35815_TX4939)
		status &= ~Tx_NCarr;
#ifdef WORKAROUND_LOSTCAR
	/* WORKAROUND: ignore LostCrS in full duplex operation */
	if ((lp->timer_state != asleep && lp->timer_state != lcheck)
	    || lp->fullduplex)
		status &= ~Tx_NCarr;
#endif
#endif

	if (!(status & TX_STA_ERR)) {
		/* no error. */
		lp->stats.tx_packets++;
		return;
	}

	lp->stats.tx_errors++;
	if (status & Tx_ExColl) {
		lp->stats.tx_aborted_errors++;
		msg = "Excessive Collision.";
	}
	if (status & Tx_Under) {
		lp->stats.tx_fifo_errors++;
		msg = "Tx FIFO Underrun.";
		if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) {
			lp->lstats.tx_underrun++;
			if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {
				struct tc35815_regs __iomem *tr =
					(struct tc35815_regs __iomem *)dev->base_addr;
				tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);
				msg = "Tx FIFO Underrun.Change Tx threshold to max.";
			}
		}
	}
	if (status & Tx_Defer) {
		lp->stats.tx_fifo_errors++;
		msg = "Excessive Deferral.";
	}
#ifndef NO_CHECK_CARRIER
	if (status & Tx_NCarr) {
		lp->stats.tx_carrier_errors++;
		msg = "Lost Carrier Sense.";
	}
#endif
	if (status & Tx_LateColl) {
		lp->stats.tx_aborted_errors++;
		msg = "Late Collision.";
	}
	if (status & Tx_TxPar) {
		lp->stats.tx_fifo_errors++;
		msg = "Transmit Parity Error.";
	}
	if (status & Tx_SQErr) {
		lp->stats.tx_heartbeat_errors++;
		msg = "Signal Quality Error.";
	}
	if (msg && netif_msg_tx_err(lp))
		printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
}

/* This handles TX complete events posted by the device
 * via interrupts.
 */
static void
tc35815_txdone(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	struct TxFD *txfd;
	unsigned int fdctl;

	txfd = &lp->tfd_base[lp->tfd_end];
	while (lp->tfd_start != lp->tfd_end &&
	       !((fdctl = le32_to_cpu(txfd->fd.FDCtl)) & FD_CownsFD)) {
		int status = le32_to_cpu(txfd->fd.FDStat);
		struct sk_buff *skb;
		unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
		u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem);

		if (netif_msg_tx_done(lp)) {
			printk("%s: complete TxFD.\n", dev->name);
			dump_txfd(txfd);
		}
		tc35815_check_tx_stat(dev, status);

		skb = fdsystem != 0xffffffff ?
			lp->tx_skbs[fdsystem].skb : NULL;
#ifdef DEBUG
		if (lp->tx_skbs[lp->tfd_end].skb != skb) {
			printk("%s: tx_skbs mismatch.\n", dev->name);
			panic_queues(dev);
		}
#else
		BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb);
#endif
		if (skb) {
			lp->stats.tx_bytes += skb->len;
			pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE);
			lp->tx_skbs[lp->tfd_end].skb = NULL;
			lp->tx_skbs[lp->tfd_end].skb_dma = 0;
#ifdef TC35815_NAPI
			dev_kfree_skb_any(skb);
#else
			dev_kfree_skb_irq(skb);
#endif
		}
		txfd->fd.FDSystem = cpu_to_le32(0xffffffff);

		lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
		txfd = &lp->tfd_base[lp->tfd_end];
#ifdef DEBUG
		if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) {
			printk("%s: TxFD FDNext invalid.\n", dev->name);
			panic_queues(dev);
		}
#endif
		if (fdnext & FD_Next_EOL) {
			/* DMA Transmitter has been stopping... */
			if (lp->tfd_end != lp->tfd_start) {
				struct tc35815_regs __iomem *tr =
					(struct tc35815_regs __iomem *)dev->base_addr;
				int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
				struct TxFD* txhead = &lp->tfd_base[head];
				int qlen = (lp->tfd_start + TX_FD_NUM
					    - lp->tfd_end) % TX_FD_NUM;

#ifdef DEBUG
				if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
					printk("%s: TxFD FDCtl invalid.\n", dev->name);
					panic_queues(dev);
				}
#endif
				/* log max queue length */
				if (lp->lstats.max_tx_qlen < qlen)
					lp->lstats.max_tx_qlen = qlen;


				/* start DMA Transmitter again */
				txhead->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
#ifdef GATHER_TXINT
				txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
#endif
				if (netif_msg_tx_queued(lp)) {
					printk("%s: start TxFD on queue.\n",
					       dev->name);
					dump_txfd(txfd);
				}
				tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
			}
			break;
		}
	}

	/* If we had stopped the queue due to a "tx full"
	 * condition, and space has now been made available,
	 * wake up the queue.
	 */
	if (netif_queue_stopped(dev) && ! tc35815_tx_full(dev))
		netif_wake_queue(dev);
}

/* The inverse routine to tc35815_open(). */
static int
tc35815_close(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	netif_stop_queue(dev);

	/* Flush the Tx and disable Rx here. */

	del_timer(&lp->timer);		/* Kill if running	*/
	tc35815_chip_reset(dev);
	free_irq(dev->irq, dev);

	tc35815_free_queues(dev);

	return 0;

}

/*
 * Get the current statistics.
 * This may be called with the card open or closed.
 */
static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;
	if (netif_running(dev)) {
		/* Update the statistics from the device registers. */
		lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);
	}

	return &lp->stats;
}

static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr)
{
	struct tc35815_local *lp = dev->priv;
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;
	int cam_index = index * 6;
	u32 cam_data;
	u32 saved_addr;
	saved_addr = tc_readl(&tr->CAM_Adr);

	if (netif_msg_hw(lp)) {
		int i;
		printk(KERN_DEBUG "%s: CAM %d:", dev->name, index);
		for (i = 0; i < 6; i++)
			printk(" %02x", addr[i]);
		printk("\n");
	}
	if (index & 1) {
		/* read modify write */
		tc_writel(cam_index - 2, &tr->CAM_Adr);
		cam_data = tc_readl(&tr->CAM_Data) & 0xffff0000;
		cam_data |= addr[0] << 8 | addr[1];
		tc_writel(cam_data, &tr->CAM_Data);
		/* write whole word */
		tc_writel(cam_index + 2, &tr->CAM_Adr);
		cam_data = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
		tc_writel(cam_data, &tr->CAM_Data);
	} else {
		/* write whole word */
		tc_writel(cam_index, &tr->CAM_Adr);
		cam_data = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
		tc_writel(cam_data, &tr->CAM_Data);
		/* read modify write */
		tc_writel(cam_index + 4, &tr->CAM_Adr);
		cam_data = tc_readl(&tr->CAM_Data) & 0x0000ffff;
		cam_data |= addr[4] << 24 | (addr[5] << 16);
		tc_writel(cam_data, &tr->CAM_Data);
	}

	tc_writel(saved_addr, &tr->CAM_Adr);
}


/*
 * Set or clear the multicast filter for this adaptor.
 * num_addrs == -1	Promiscuous mode, receive all packets
 * num_addrs == 0	Normal mode, clear multicast list
 * num_addrs > 0	Multicast mode, receive normal and MC packets,
 *			and do best-effort filtering.
 */
static void
tc35815_set_multicast_list(struct net_device *dev)
{
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;

	if (dev->flags&IFF_PROMISC)
	{
#ifdef WORKAROUND_100HALF_PROMISC
		/* With some (all?) 100MHalf HUB, controller will hang
		 * if we enabled promiscuous mode before linkup... */
		struct tc35815_local *lp = dev->priv;
		int pid = lp->phy_addr;
		if (!(tc_mdio_read(dev, pid, MII_BMSR) & BMSR_LSTATUS))
			return;
#endif
		/* Enable promiscuous mode */
		tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
	}
	else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > CAM_ENTRY_MAX - 3)
	{
		/* CAM 0, 1, 20 are reserved. */
		/* Disable promiscuous mode, use normal mode. */
		tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl);
	}
	else if(dev->mc_count)
	{
		struct dev_mc_list* cur_addr = dev->mc_list;
		int i;
		int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE);

		tc_writel(0, &tr->CAM_Ctl);
		/* Walk the address list, and load the filter */
		for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) {
			if (!cur_addr)
				break;
			/* entry 0,1 is reserved. */
			tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr);
			ena_bits |= CAM_Ena_Bit(i + 2);
		}
		tc_writel(ena_bits, &tr->CAM_Ena);
		tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
	}
	else {
		tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
		tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
	}
}

static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
	struct tc35815_local *lp = dev->priv;
	strcpy(info->driver, MODNAME);
	strcpy(info->version, DRV_VERSION);
	strcpy(info->bus_info, pci_name(lp->pci_dev));
}

static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
	struct tc35815_local *lp = dev->priv;
	spin_lock_irq(&lp->lock);
	mii_ethtool_gset(&lp->mii, cmd);
	spin_unlock_irq(&lp->lock);
	return 0;
}

static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
	struct tc35815_local *lp = dev->priv;
	int rc;
#if 1	/* use our negotiation method... */
	/* Verify the settings we care about. */
	if (cmd->autoneg != AUTONEG_ENABLE &&
	    cmd->autoneg != AUTONEG_DISABLE)
		return -EINVAL;
	if (cmd->autoneg == AUTONEG_DISABLE &&
	    ((cmd->speed != SPEED_100 &&
	      cmd->speed != SPEED_10) ||
	     (cmd->duplex != DUPLEX_HALF &&
	      cmd->duplex != DUPLEX_FULL)))
		return -EINVAL;

	/* Ok, do it to it. */
	spin_lock_irq(&lp->lock);
	del_timer(&lp->timer);
	tc35815_start_auto_negotiation(dev, cmd);
	spin_unlock_irq(&lp->lock);
	rc = 0;
#else
	spin_lock_irq(&lp->lock);
	rc = mii_ethtool_sset(&lp->mii, cmd);
	spin_unlock_irq(&lp->lock);
#endif
	return rc;
}

static int tc35815_nway_reset(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int rc;
	spin_lock_irq(&lp->lock);
	rc = mii_nway_restart(&lp->mii);
	spin_unlock_irq(&lp->lock);
	return rc;
}

static u32 tc35815_get_link(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int rc;
	spin_lock_irq(&lp->lock);
	rc = mii_link_ok(&lp->mii);
	spin_unlock_irq(&lp->lock);
	return rc;
}

static u32 tc35815_get_msglevel(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	return lp->msg_enable;
}

static void tc35815_set_msglevel(struct net_device *dev, u32 datum)
{
	struct tc35815_local *lp = dev->priv;
	lp->msg_enable = datum;
}

static int tc35815_get_stats_count(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	return sizeof(lp->lstats) / sizeof(int);
}

static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
{
	struct tc35815_local *lp = dev->priv;
	data[0] = lp->lstats.max_tx_qlen;
	data[1] = lp->lstats.tx_ints;
	data[2] = lp->lstats.rx_ints;
	data[3] = lp->lstats.tx_underrun;
}

static struct {
	const char str[ETH_GSTRING_LEN];
} ethtool_stats_keys[] = {
	{ "max_tx_qlen" },
	{ "tx_ints" },
	{ "rx_ints" },
	{ "tx_underrun" },
};

static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
	memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
}

static const struct ethtool_ops tc35815_ethtool_ops = {
	.get_drvinfo		= tc35815_get_drvinfo,
	.get_settings		= tc35815_get_settings,
	.set_settings		= tc35815_set_settings,
	.nway_reset		= tc35815_nway_reset,
	.get_link		= tc35815_get_link,
	.get_msglevel		= tc35815_get_msglevel,
	.set_msglevel		= tc35815_set_msglevel,
	.get_strings		= tc35815_get_strings,
	.get_stats_count	= tc35815_get_stats_count,
	.get_ethtool_stats	= tc35815_get_ethtool_stats,
	.get_perm_addr		= ethtool_op_get_perm_addr,
};

static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
	struct tc35815_local *lp = dev->priv;
	int rc;

	if (!netif_running(dev))
		return -EINVAL;

	spin_lock_irq(&lp->lock);
	rc = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
	spin_unlock_irq(&lp->lock);

	return rc;
}

static int tc_mdio_read(struct net_device *dev, int phy_id, int location)
{
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;
	u32 data;
	tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA);
	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
		;
	data = tc_readl(&tr->MD_Data);
	return data & 0xffff;
}

static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
			  int val)
{
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;
	tc_writel(val, &tr->MD_Data);
	tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA);
	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
		;
}

/* Auto negotiation.  The scheme is very simple.  We have a timer routine
 * that keeps watching the auto negotiation process as it progresses.
 * The DP83840 is first told to start doing it's thing, we set up the time
 * and place the timer state machine in it's initial state.
 *
 * Here the timer peeks at the DP83840 status registers at each click to see
 * if the auto negotiation has completed, we assume here that the DP83840 PHY
 * will time out at some point and just tell us what (didn't) happen.  For
 * complete coverage we only allow so many of the ticks at this level to run,
 * when this has expired we print a warning message and try another strategy.
 * This "other" strategy is to force the interface into various speed/duplex
 * configurations and we stop when we see a link-up condition before the
 * maximum number of "peek" ticks have occurred.
 *
 * Once a valid link status has been detected we configure the BigMAC and
 * the rest of the Happy Meal to speak the most efficient protocol we could
 * get a clean link for.  The priority for link configurations, highest first
 * is:
 *                 100 Base-T Full Duplex
 *                 100 Base-T Half Duplex
 *                 10 Base-T Full Duplex
 *                 10 Base-T Half Duplex
 *
 * We start a new timer now, after a successful auto negotiation status has
 * been detected.  This timer just waits for the link-up bit to get set in
 * the BMCR of the DP83840.  When this occurs we print a kernel log message
 * describing the link type in use and the fact that it is up.
 *
 * If a fatal error of some sort is signalled and detected in the interrupt
 * service routine, and the chip is reset, or the link is ifconfig'd down
 * and then back up, this entire process repeats itself all over again.
 */
/* Note: Above comments are come from sunhme driver. */

static int tc35815_try_next_permutation(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int pid = lp->phy_addr;
	unsigned short bmcr;

	bmcr = tc_mdio_read(dev, pid, MII_BMCR);

	/* Downgrade from full to half duplex.  Only possible via ethtool.  */
	if (bmcr & BMCR_FULLDPLX) {
		bmcr &= ~BMCR_FULLDPLX;
		printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
		return 0;
	}

	/* Downgrade from 100 to 10. */
	if (bmcr & BMCR_SPEED100) {
		bmcr &= ~BMCR_SPEED100;
		printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
		return 0;
	}

	/* We've tried everything. */
	return -1;
}

static void
tc35815_display_link_mode(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int pid = lp->phy_addr;
	unsigned short lpa, bmcr;
	char *speed = "", *duplex = "";

	lpa = tc_mdio_read(dev, pid, MII_LPA);
	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
	if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
		speed = "100Mb/s";
	else
		speed = "10Mb/s";
	if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
		duplex = "Full Duplex";
	else
		duplex = "Half Duplex";

	if (netif_msg_link(lp))
		printk(KERN_INFO "%s: Link is up at %s, %s.\n",
		       dev->name, speed, duplex);
	printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
	       dev->name,
	       bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
}

static void tc35815_display_forced_link_mode(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int pid = lp->phy_addr;
	unsigned short bmcr;
	char *speed = "", *duplex = "";

	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
	if (bmcr & BMCR_SPEED100)
		speed = "100Mb/s";
	else
		speed = "10Mb/s";
	if (bmcr & BMCR_FULLDPLX)
		duplex = "Full Duplex.\n";
	else
		duplex = "Half Duplex.\n";

	if (netif_msg_link(lp))
		printk(KERN_INFO "%s: Link has been forced up at %s, %s",
		       dev->name, speed, duplex);
}

static void tc35815_set_link_modes(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;
	int pid = lp->phy_addr;
	unsigned short bmcr, lpa;
	int speed;

	if (lp->timer_state == arbwait) {
		lpa = tc_mdio_read(dev, pid, MII_LPA);
		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
		printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
		       dev->name,
		       bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
		if (!(lpa & (LPA_10HALF | LPA_10FULL |
			     LPA_100HALF | LPA_100FULL))) {
			/* fall back to 10HALF */
			printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n",
			       dev->name, lpa);
			lpa = LPA_10HALF;
		}
		if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
			lp->fullduplex = 1;
		else
			lp->fullduplex = 0;
		if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
			speed = 100;
		else
			speed = 10;
	} else {
		/* Forcing a link mode. */
		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
		if (bmcr & BMCR_FULLDPLX)
			lp->fullduplex = 1;
		else
			lp->fullduplex = 0;
		if (bmcr & BMCR_SPEED100)
			speed = 100;
		else
			speed = 10;
	}

	tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl);
	if (lp->fullduplex) {
		tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
	} else {
		tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl);
	}
	tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl);

	/* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */

#ifndef NO_CHECK_CARRIER
	/* TX4939 does not have EnLCarr */
	if (lp->boardtype != TC35815_TX4939) {
#ifdef WORKAROUND_LOSTCAR
		/* WORKAROUND: enable LostCrS only if half duplex operation */
		if (!lp->fullduplex && lp->boardtype != TC35815_TX4939)
			tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl);
#endif
	}
#endif
	lp->mii.full_duplex = lp->fullduplex;
}

static void tc35815_timer(unsigned long data)
{
	struct net_device *dev = (struct net_device *)data;
	struct tc35815_local *lp = dev->priv;
	int pid = lp->phy_addr;
	unsigned short bmsr, bmcr, lpa;
	int restart_timer = 0;

	spin_lock_irq(&lp->lock);

	lp->timer_ticks++;
	switch (lp->timer_state) {
	case arbwait:
		/*
		 * Only allow for 5 ticks, thats 10 seconds and much too
		 * long to wait for arbitration to complete.
		 */
		/* TC35815 need more times... */
		if (lp->timer_ticks >= 10) {
			/* Enter force mode. */
			if (!options.doforce) {
				printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
				       " cable probblem?\n", dev->name);
				/* Try to restart the adaptor. */
				tc35815_restart(dev);
				goto out;
			}
			printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
			       " trying force link mode\n", dev->name);
			printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name,
			       tc_mdio_read(dev, pid, MII_BMCR),
			       tc_mdio_read(dev, pid, MII_BMSR));
			bmcr = BMCR_SPEED100;
			tc_mdio_write(dev, pid, MII_BMCR, bmcr);

			/*
			 * OK, seems we need do disable the transceiver
			 * for the first tick to make sure we get an
			 * accurate link state at the second tick.
			 */

			lp->timer_state = ltrywait;
			lp->timer_ticks = 0;
			restart_timer = 1;
		} else {
			/* Anything interesting happen? */
			bmsr = tc_mdio_read(dev, pid, MII_BMSR);
			if (bmsr & BMSR_ANEGCOMPLETE) {
				/* Just what we've been waiting for... */
				tc35815_set_link_modes(dev);

				/*
				 * Success, at least so far, advance our state
				 * engine.
				 */
				lp->timer_state = lupwait;
				restart_timer = 1;
			} else {
				restart_timer = 1;
			}
		}
		break;

	case lupwait:
		/*
		 * Auto negotiation was successful and we are awaiting a
		 * link up status.  I have decided to let this timer run
		 * forever until some sort of error is signalled, reporting
		 * a message to the user at 10 second intervals.
		 */
		bmsr = tc_mdio_read(dev, pid, MII_BMSR);
		if (bmsr & BMSR_LSTATUS) {
			/*
			 * Wheee, it's up, display the link mode in use and put
			 * the timer to sleep.
			 */
			tc35815_display_link_mode(dev);
			netif_carrier_on(dev);
#ifdef WORKAROUND_100HALF_PROMISC
			/* delayed promiscuous enabling */
			if (dev->flags & IFF_PROMISC)
				tc35815_set_multicast_list(dev);
#endif
#if 1
			lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
			lp->timer_state = lcheck;
			restart_timer = 1;
#else
			lp->timer_state = asleep;
			restart_timer = 0;
#endif
		} else {
			if (lp->timer_ticks >= 10) {
				printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
				       "not completely up.\n", dev->name);
				lp->timer_ticks = 0;
				restart_timer = 1;
			} else {
				restart_timer = 1;
			}
		}
		break;

	case ltrywait:
		/*
		 * Making the timeout here too long can make it take
		 * annoyingly long to attempt all of the link mode
		 * permutations, but then again this is essentially
		 * error recovery code for the most part.
		 */
		bmsr = tc_mdio_read(dev, pid, MII_BMSR);
		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
		if (lp->timer_ticks == 1) {
			/*
			 * Re-enable transceiver, we'll re-enable the
			 * transceiver next tick, then check link state
			 * on the following tick.
			 */
			restart_timer = 1;
			break;
		}
		if (lp->timer_ticks == 2) {
			restart_timer = 1;
			break;
		}
		if (bmsr & BMSR_LSTATUS) {
			/* Force mode selection success. */
			tc35815_display_forced_link_mode(dev);
			netif_carrier_on(dev);
			tc35815_set_link_modes(dev);
#ifdef WORKAROUND_100HALF_PROMISC
			/* delayed promiscuous enabling */
			if (dev->flags & IFF_PROMISC)
				tc35815_set_multicast_list(dev);
#endif
#if 1
			lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
			lp->timer_state = lcheck;
			restart_timer = 1;
#else
			lp->timer_state = asleep;
			restart_timer = 0;
#endif
		} else {
			if (lp->timer_ticks >= 4) { /* 6 seconds or so... */
				int ret;

				ret = tc35815_try_next_permutation(dev);
				if (ret == -1) {
					/*
					 * Aieee, tried them all, reset the
					 * chip and try all over again.
					 */
					printk(KERN_NOTICE "%s: Link down, "
					       "cable problem?\n",
					       dev->name);

					/* Try to restart the adaptor. */
					tc35815_restart(dev);
					goto out;
				}
				lp->timer_ticks = 0;
				restart_timer = 1;
			} else {
				restart_timer = 1;
			}
		}
		break;

	case lcheck:
		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
		lpa = tc_mdio_read(dev, pid, MII_LPA);
		if (bmcr & (BMCR_PDOWN | BMCR_ISOLATE | BMCR_RESET)) {
			printk(KERN_ERR "%s: PHY down? (BMCR %x)\n", dev->name,
			       bmcr);
		} else if ((lp->saved_lpa ^ lpa) &
			   (LPA_100FULL|LPA_100HALF|LPA_10FULL|LPA_10HALF)) {
			printk(KERN_NOTICE "%s: link status changed"
			       " (BMCR %x LPA %x->%x)\n", dev->name,
			       bmcr, lp->saved_lpa, lpa);
		} else {
			/* go on */
			restart_timer = 1;
			break;
		}
		/* Try to restart the adaptor. */
		tc35815_restart(dev);
		goto out;

	case asleep:
	default:
		/* Can't happens.... */
		printk(KERN_ERR "%s: Aieee, link timer is asleep but we got "
		       "one anyways!\n", dev->name);
		restart_timer = 0;
		lp->timer_ticks = 0;
		lp->timer_state = asleep; /* foo on you */
		break;
	}

	if (restart_timer) {
		lp->timer.expires = jiffies + msecs_to_jiffies(1200);
		add_timer(&lp->timer);
	}
out:
	spin_unlock_irq(&lp->lock);
}

static void tc35815_start_auto_negotiation(struct net_device *dev,
					   struct ethtool_cmd *ep)
{
	struct tc35815_local *lp = dev->priv;
	int pid = lp->phy_addr;
	unsigned short bmsr, bmcr, advertize;
	int timeout;

	netif_carrier_off(dev);
	bmsr = tc_mdio_read(dev, pid, MII_BMSR);
	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
	advertize = tc_mdio_read(dev, pid, MII_ADVERTISE);

	if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
		if (options.speed || options.duplex) {
			/* Advertise only specified configuration. */
			advertize &= ~(ADVERTISE_10HALF |
				       ADVERTISE_10FULL |
				       ADVERTISE_100HALF |
				       ADVERTISE_100FULL);
			if (options.speed != 10) {
				if (options.duplex != 1)
					advertize |= ADVERTISE_100FULL;
				if (options.duplex != 2)
					advertize |= ADVERTISE_100HALF;
			}
			if (options.speed != 100) {
				if (options.duplex != 1)
					advertize |= ADVERTISE_10FULL;
				if (options.duplex != 2)
					advertize |= ADVERTISE_10HALF;
			}
			if (options.speed == 100)
				bmcr |= BMCR_SPEED100;
			else if (options.speed == 10)
				bmcr &= ~BMCR_SPEED100;
			if (options.duplex == 2)
				bmcr |= BMCR_FULLDPLX;
			else if (options.duplex == 1)
				bmcr &= ~BMCR_FULLDPLX;
		} else {
			/* Advertise everything we can support. */
			if (bmsr & BMSR_10HALF)
				advertize |= ADVERTISE_10HALF;
			else
				advertize &= ~ADVERTISE_10HALF;
			if (bmsr & BMSR_10FULL)
				advertize |= ADVERTISE_10FULL;
			else
				advertize &= ~ADVERTISE_10FULL;
			if (bmsr & BMSR_100HALF)
				advertize |= ADVERTISE_100HALF;
			else
				advertize &= ~ADVERTISE_100HALF;
			if (bmsr & BMSR_100FULL)
				advertize |= ADVERTISE_100FULL;
			else
				advertize &= ~ADVERTISE_100FULL;
		}

		tc_mdio_write(dev, pid, MII_ADVERTISE, advertize);

		/* Enable Auto-Negotiation, this is usually on already... */
		bmcr |= BMCR_ANENABLE;
		tc_mdio_write(dev, pid, MII_BMCR, bmcr);

		/* Restart it to make sure it is going. */
		bmcr |= BMCR_ANRESTART;
		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
		printk(KERN_DEBUG "%s: ADVERTISE %x BMCR %x\n", dev->name, advertize, bmcr);

		/* BMCR_ANRESTART self clears when the process has begun. */
		timeout = 64;  /* More than enough. */
		while (--timeout) {
			bmcr = tc_mdio_read(dev, pid, MII_BMCR);
			if (!(bmcr & BMCR_ANRESTART))
				break; /* got it. */
			udelay(10);
		}
		if (!timeout) {
			printk(KERN_ERR "%s: TC35815 would not start auto "
			       "negotiation BMCR=0x%04x\n",
			       dev->name, bmcr);
			printk(KERN_NOTICE "%s: Performing force link "
			       "detection.\n", dev->name);
			goto force_link;
		} else {
			printk(KERN_DEBUG "%s: auto negotiation started.\n", dev->name);
			lp->timer_state = arbwait;
		}
	} else {
force_link:
		/* Force the link up, trying first a particular mode.
		 * Either we are here at the request of ethtool or
		 * because the Happy Meal would not start to autoneg.
		 */

		/* Disable auto-negotiation in BMCR, enable the duplex and
		 * speed setting, init the timer state machine, and fire it off.
		 */
		if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
			bmcr = BMCR_SPEED100;
		} else {
			if (ep->speed == SPEED_100)
				bmcr = BMCR_SPEED100;
			else
				bmcr = 0;
			if (ep->duplex == DUPLEX_FULL)
				bmcr |= BMCR_FULLDPLX;
		}
		tc_mdio_write(dev, pid, MII_BMCR, bmcr);

		/* OK, seems we need do disable the transceiver for the first
		 * tick to make sure we get an accurate link state at the
		 * second tick.
		 */
		lp->timer_state = ltrywait;
	}

	del_timer(&lp->timer);
	lp->timer_ticks = 0;
	lp->timer.expires = jiffies + msecs_to_jiffies(1200);
	add_timer(&lp->timer);
}

static void tc35815_find_phy(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int pid = lp->phy_addr;
	unsigned short id0;

	/* find MII phy */
	for (pid = 31; pid >= 0; pid--) {
		id0 = tc_mdio_read(dev, pid, MII_BMSR);
		if (id0 != 0xffff && id0 != 0x0000 &&
		    (id0 & BMSR_RESV) != (0xffff & BMSR_RESV) /* paranoia? */
			) {
			lp->phy_addr = pid;
			break;
		}
	}
	if (pid < 0) {
		printk(KERN_ERR "%s: No MII Phy found.\n",
		       dev->name);
		lp->phy_addr = pid = 0;
	}

	lp->mii_id[0] = tc_mdio_read(dev, pid, MII_PHYSID1);
	lp->mii_id[1] = tc_mdio_read(dev, pid, MII_PHYSID2);
	if (netif_msg_hw(lp))
		printk(KERN_INFO "%s: PHY(%02x) ID %04x %04x\n", dev->name,
		       pid, lp->mii_id[0], lp->mii_id[1]);
}

static void tc35815_phy_chip_init(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	int pid = lp->phy_addr;
	unsigned short bmcr;
	struct ethtool_cmd ecmd, *ep;

	/* dis-isolate if needed. */
	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
	if (bmcr & BMCR_ISOLATE) {
		int count = 32;
		printk(KERN_DEBUG "%s: unisolating...", dev->name);
		tc_mdio_write(dev, pid, MII_BMCR, bmcr & ~BMCR_ISOLATE);
		while (--count) {
			if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_ISOLATE))
				break;
			udelay(20);
		}
		printk(" %s.\n", count ? "done" : "failed");
	}

	if (options.speed && options.duplex) {
		ecmd.autoneg = AUTONEG_DISABLE;
		ecmd.speed = options.speed == 10 ? SPEED_10 : SPEED_100;
		ecmd.duplex = options.duplex == 1 ? DUPLEX_HALF : DUPLEX_FULL;
		ep = &ecmd;
	} else {
		ep = NULL;
	}
	tc35815_start_auto_negotiation(dev, ep);
}

static void tc35815_chip_reset(struct net_device *dev)
{
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;
	int i;
	/* reset the controller */
	tc_writel(MAC_Reset, &tr->MAC_Ctl);
	udelay(4); /* 3200ns */
	i = 0;
	while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) {
		if (i++ > 100) {
			printk(KERN_ERR "%s: MAC reset failed.\n", dev->name);
			break;
		}
		mdelay(1);
	}
	tc_writel(0, &tr->MAC_Ctl);

	/* initialize registers to default value */
	tc_writel(0, &tr->DMA_Ctl);
	tc_writel(0, &tr->TxThrsh);
	tc_writel(0, &tr->TxPollCtr);
	tc_writel(0, &tr->RxFragSize);
	tc_writel(0, &tr->Int_En);
	tc_writel(0, &tr->FDA_Bas);
	tc_writel(0, &tr->FDA_Lim);
	tc_writel(0xffffffff, &tr->Int_Src);	/* Write 1 to clear */
	tc_writel(0, &tr->CAM_Ctl);
	tc_writel(0, &tr->Tx_Ctl);
	tc_writel(0, &tr->Rx_Ctl);
	tc_writel(0, &tr->CAM_Ena);
	(void)tc_readl(&tr->Miss_Cnt);	/* Read to clear */

	/* initialize internal SRAM */
	tc_writel(DMA_TestMode, &tr->DMA_Ctl);
	for (i = 0; i < 0x1000; i += 4) {
		tc_writel(i, &tr->CAM_Adr);
		tc_writel(0, &tr->CAM_Data);
	}
	tc_writel(0, &tr->DMA_Ctl);
}

static void tc35815_chip_init(struct net_device *dev)
{
	struct tc35815_local *lp = dev->priv;
	struct tc35815_regs __iomem *tr =
		(struct tc35815_regs __iomem *)dev->base_addr;
	unsigned long txctl = TX_CTL_CMD;

	tc35815_phy_chip_init(dev);

	/* load station address to CAM */
	tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr);

	/* Enable CAM (broadcast and unicast) */
	tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
	tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);

	/* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */
	if (HAVE_DMA_RXALIGN(lp))
		tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl);
	else
		tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
#ifdef TC35815_USE_PACKEDBUFFER
	tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize);	/* Packing */
#else
	tc_writel(ETH_ZLEN, &tr->RxFragSize);
#endif
	tc_writel(0, &tr->TxPollCtr);	/* Batch mode */
	tc_writel(TX_THRESHOLD, &tr->TxThrsh);
	tc_writel(INT_EN_CMD, &tr->Int_En);

	/* set queues */
	tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas);
	tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
		  &tr->FDA_Lim);
	/*
	 * Activation method:
	 * First, enable the MAC Transmitter and the DMA Receive circuits.
	 * Then enable the DMA Transmitter and the MAC Receive circuits.
	 */
	tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr);	/* start DMA receiver */
	tc_writel(RX_CTL_CMD, &tr->Rx_Ctl);	/* start MAC receiver */

	/* start MAC transmitter */
#ifndef NO_CHECK_CARRIER
	/* TX4939 does not have EnLCarr */
	if (lp->boardtype == TC35815_TX4939)
		txctl &= ~Tx_EnLCarr;
#ifdef WORKAROUND_LOSTCAR
	/* WORKAROUND: ignore LostCrS in full duplex operation */
	if ((lp->timer_state != asleep && lp->timer_state != lcheck) ||
	    lp->fullduplex)
		txctl &= ~Tx_EnLCarr;
#endif
#endif /* !NO_CHECK_CARRIER */
#ifdef GATHER_TXINT
	txctl &= ~Tx_EnComp;	/* disable global tx completion int. */
#endif
	tc_writel(txctl, &tr->Tx_Ctl);
}

#ifdef CONFIG_PM
static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state)
{
	struct net_device *dev = pci_get_drvdata(pdev);
	struct tc35815_local *lp = dev->priv;
	unsigned long flags;

	pci_save_state(pdev);
	if (!netif_running(dev))
		return 0;
	netif_device_detach(dev);
	spin_lock_irqsave(&lp->lock, flags);
	del_timer(&lp->timer);		/* Kill if running	*/
	tc35815_chip_reset(dev);
	spin_unlock_irqrestore(&lp->lock, flags);
	pci_set_power_state(pdev, PCI_D3hot);
	return 0;
}

static int tc35815_resume(struct pci_dev *pdev)
{
	struct net_device *dev = pci_get_drvdata(pdev);
	struct tc35815_local *lp = dev->priv;
	unsigned long flags;

	pci_restore_state(pdev);
	if (!netif_running(dev))
		return 0;
	pci_set_power_state(pdev, PCI_D0);
	spin_lock_irqsave(&lp->lock, flags);
	tc35815_restart(dev);
	spin_unlock_irqrestore(&lp->lock, flags);
	netif_device_attach(dev);
	return 0;
}
#endif /* CONFIG_PM */

static struct pci_driver tc35815_pci_driver = {
	.name		= MODNAME,
	.id_table	= tc35815_pci_tbl,
	.probe		= tc35815_init_one,
	.remove		= __devexit_p(tc35815_remove_one),
#ifdef CONFIG_PM
	.suspend	= tc35815_suspend,
	.resume		= tc35815_resume,
#endif
};

module_param_named(speed, options.speed, int, 0);
MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps");
module_param_named(duplex, options.duplex, int, 0);
MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full");
module_param_named(doforce, options.doforce, int, 0);
MODULE_PARM_DESC(doforce, "try force link mode if auto-negotiation failed");

static int __init tc35815_init_module(void)
{
	return pci_register_driver(&tc35815_pci_driver);
}

static void __exit tc35815_cleanup_module(void)
{
	pci_unregister_driver(&tc35815_pci_driver);
}

module_init(tc35815_init_module);
module_exit(tc35815_cleanup_module);

MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver");
MODULE_LICENSE("GPL");

From anemo@mba.ocn.ne.jp Sat Mar  3 14:56:41 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 14:56:46 +0000 (GMT)
Received: from mba.ocn.ne.jp ([210.190.142.172]:15845 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20037755AbXCCO4l (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sat, 3 Mar 2007 14:56:41 +0000
Received: from localhost (p6054-ipad201funabasi.chiba.ocn.ne.jp [222.146.69.54])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id B77F99717; Sat,  3 Mar 2007 23:54:59 +0900 (JST)
Date:	Sat, 03 Mar 2007 23:54:59 +0900 (JST)
Message-Id: <20070303.235459.25478204.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org, netdev@vger.kernel.org, jeff@garzik.org,
	sshtylyov@ru.mvista.com
Subject: [PATCH] tc35815 driver update (take 2)
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14332
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

Current tc35815 driver is very obsolete and less maintained for a long
time.  Replace it with a new driver based on one from CELF patch
archive.

Major advantages of CELF version (version 1.23, for kernel 2.6.10) are:

* Independent of JMR3927.
  (Actually independent of MIPS, but AFAIK the chip is used only on
   MIPS platforms)
* TX4938 support.
* 64-bit proof.
* Asynchronous and on-demand auto negotiation.
* High performance on non-coherent architecture.
* ethtool support.
* Many bugfixes and cleanups.

And improvoments since version 1.23 are:

* TX4939 support.
* NETPOLL support.
* NAPI support. (disabled by default)
* Reduce memcpy on receiving.
* PM support.
* Many cleanups and bugfixes.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>

 drivers/net/Kconfig     |    3 
 drivers/net/tc35815.c   | 2587 ++++++++++++++++++++++++++++++++++------------
 include/linux/pci_ids.h |    2 
 3 files changed, 1917 insertions(+), 675 deletions(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 5ff0922..52d7239 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1444,7 +1444,8 @@ config CS89x0
 
 config TC35815
 	tristate "TOSHIBA TC35815 Ethernet support"
-	depends on NET_PCI && PCI && TOSHIBA_JMR3927
+	depends on NET_PCI && PCI && MIPS
+	select MII
 
 config DGRS
 	tristate "Digi Intl. RightSwitch SE-X support"
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index e3a7e3c..ec888db 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1,35 +1,72 @@
-/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *                ahennessy@mvista.com
+/*
+ * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
  *
  * Based on skelton.c by Donald Becker.
- * Copyright (C) 2000-2001 Toshiba Corporation
  *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * This driver is a replacement of older and less maintained version.
+ * This is a header of the older version:
+ *	-----<snip>-----
+ *	Copyright 2001 MontaVista Software Inc.
+ *	Author: MontaVista Software, Inc.
+ *		ahennessy@mvista.com
+ *	Copyright (C) 2000-2001 Toshiba Corporation
+ *	static const char *version =
+ *		"tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+ *	-----<snip>-----
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
  *
- * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2005
+ * All Rights Reserved.
  *
- * 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.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  Revision History:
+ *	1.13	64-bit proof.
+ *	1.14	Do not round-up transmit length.
+ *	1.15	Define TC35815_DMA_SYNC_ONDEMAND, cleanup.
+ *	1.16	Fix free_page bug introduced in 1.15
+ *	1.17	Add mii/ethtool ioctl support.
+ *		Remove workaround for early TX4938.  Cleanup.
+ *	1.20	Kernel 2.6.
+ *	1.21	Fix receive packet length (omit CRC).
+ *		Call netif_carrier_on/netif_carrier_off.
+ *		Add kernel/module options (speed, duplex, doforce).
+ *		Do not try "force link mode" by default.
+ *		Reconfigure CAM on restarting.
+ *		Reset PHY on restarting.
+ *		Add workaround for 100MHalf HUB.
+ *	1.22	Minor fix.
+ *	1.23	Minor cleanup.
+ *	1.24	Remove tc35815_setup since new stype option
+ *		("tc35815.speed=10", etc.) can be used for 2.6 kernel.
+ *	1.25	TX4939 support.
+ *	1.26	Minor cleanup.
+ *	1.27	Move TX4939 PCFG.SPEEDn control code out from this driver.
+ *		Cleanup init_dev_addr. (NETDEV_REGISTER event notifier
+ *		can overwrite dev_addr)
+ *		support ETHTOOL_GPERMADDR.
+ *	1.28	Minor cleanup.
+ *	1.29	support netpoll.
+ *	1.30	Minor cleanup.
+ *	1.31	NAPI support. (disabled by default)
+ *		Use DMA_RxAlign_2 if possible.
+ *		Do not use PackedBuffer.
+ *		Cleanup.
+ *	1.32	Fix free buffer management on non-PackedBuffer mode.
+ *	1.33	Fix netpoll build.
+ *	1.34	Fix netpoll locking.  "BH rule" for NAPI is not enough with
+ *		netpoll, hard_start_xmit might be called from irq context.
+ *		PM support.
  */
 
-static const char *version =
-	"tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+#ifdef TC35815_NAPI
+#define DRV_VERSION	"1.34-NAPI"
+#else
+#define DRV_VERSION	"1.34"
+#endif
+static const char *version = "tc35815.c:v" DRV_VERSION "\n";
+#define MODNAME			"tc35815"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -40,6 +77,7 @@ static const char *version =
 #include <linux/in.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
@@ -47,36 +85,47 @@ static const char *version =
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
 #include <asm/io.h>
-#include <asm/dma.h>
 #include <asm/byteorder.h>
 
-/*
- * The name of the card. Is used for messages and in the requests for
- * io regions, irqs and dma channels
- */
-static const char* cardname = "TC35815CF";
-#define TC35815_PROC_ENTRY "net/tc35815"
-
-#define TC35815_MODULE_NAME "TC35815CF"
-#define TX_TIMEOUT (4*HZ)
-
 /* First, a few definitions that the brave might change. */
 
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef TC35815_DEBUG
-#define TC35815_DEBUG 1
-#endif
-static unsigned int tc35815_debug = TC35815_DEBUG;
-
 #define GATHER_TXINT	/* On-Demand Tx Interrupt */
+#define WORKAROUND_LOSTCAR
+#define WORKAROUND_100HALF_PROMISC
+/* #define TC35815_USE_PACKEDBUFFER */
+
+typedef enum {
+	TC35815CF = 0,
+	TC35815_NWU,
+	TC35815_TX4939,
+} board_t;
+
+/* indexed by board_t, above */
+static const struct {
+	const char *name;
+} board_info[] __devinitdata = {
+	{ "TOSHIBA TC35815CF 10/100BaseTX" },
+	{ "TOSHIBA TC35815 with Wake on LAN" },
+	{ "TOSHIBA TC35815/TX4939" },
+};
+
+static const struct pci_device_id tc35815_pci_tbl[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
+	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
+	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
+	{0,}
+};
+MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
 
-#define vtonocache(p)	KSEG1ADDR(virt_to_phys(p))
+/* see MODULE_PARM_DESC */
+static struct tc35815_options {
+	int speed;
+	int duplex;
+	int doforce;
+} options;
 
 /*
  * Registers
@@ -119,6 +168,11 @@ struct tc35815_regs {
  * Bit assignments
  */
 /* DMA_Ctl bit asign ------------------------------------------------------- */
+#define DMA_RxAlign            0x00c00000 /* 1:Reception Alignment           */
+#define DMA_RxAlign_1          0x00400000
+#define DMA_RxAlign_2          0x00800000
+#define DMA_RxAlign_3          0x00c00000
+#define DMA_M66EnStat          0x00080000 /* 1:66MHz Enable State            */
 #define DMA_IntMask            0x00040000 /* 1:Interupt mask                 */
 #define DMA_SWIntReq           0x00020000 /* 1:Software Interrupt request    */
 #define DMA_TxWakeUp           0x00010000 /* 1:Transmit Wake Up              */
@@ -269,42 +323,6 @@ struct tc35815_regs {
 #define MD_CA_Wr               0x00000400 /* 1:Write 0:Read                  */
 
 
-/* MII register offsets */
-#define MII_CONTROL             0x0000
-#define MII_STATUS              0x0001
-#define MII_PHY_ID0             0x0002
-#define MII_PHY_ID1             0x0003
-#define MII_ANAR                0x0004
-#define MII_ANLPAR              0x0005
-#define MII_ANER                0x0006
-/* MII Control register bit definitions. */
-#define MIICNTL_FDX             0x0100
-#define MIICNTL_RST_AUTO        0x0200
-#define MIICNTL_ISOLATE         0x0400
-#define MIICNTL_PWRDWN          0x0800
-#define MIICNTL_AUTO            0x1000
-#define MIICNTL_SPEED           0x2000
-#define MIICNTL_LPBK            0x4000
-#define MIICNTL_RESET           0x8000
-/* MII Status register bit significance. */
-#define MIISTAT_EXT             0x0001
-#define MIISTAT_JAB             0x0002
-#define MIISTAT_LINK            0x0004
-#define MIISTAT_CAN_AUTO        0x0008
-#define MIISTAT_FAULT           0x0010
-#define MIISTAT_AUTO_DONE       0x0020
-#define MIISTAT_CAN_T           0x0800
-#define MIISTAT_CAN_T_FDX       0x1000
-#define MIISTAT_CAN_TX          0x2000
-#define MIISTAT_CAN_TX_FDX      0x4000
-#define MIISTAT_CAN_T4          0x8000
-/* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */
-#define MII_AN_TX_FDX           0x0100
-#define MII_AN_TX_HDX           0x0080
-#define MII_AN_10_FDX           0x0040
-#define MII_AN_10_HDX           0x0020
-
-
 /*
  * Descriptors
  */
@@ -352,32 +370,51 @@ struct BDesc {
 
 #ifdef NO_CHECK_CARRIER
 #define TX_CTL_CMD	(Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
-	Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
-	Tx_En)	/* maybe  0x7d01 */
+	Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
+	Tx_En)	/* maybe  0x7b01 */
 #else
 #define TX_CTL_CMD	(Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
-	Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
-	Tx_En)	/* maybe  0x7f01 */
+	Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
+	Tx_En)	/* maybe  0x7b01 */
 #endif
 #define RX_CTL_CMD	(Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
 	| Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn)	/* maybe 0x6f01 */
-
 #define INT_EN_CMD  (Int_NRAbtEn | \
-	 Int_DParDEn | Int_DParErrEn | \
+	Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \
 	Int_SSysErrEn  | Int_RMasAbtEn | Int_RTargAbtEn | \
 	Int_STargAbtEn | \
 	Int_BLExEn  | Int_FDAExEn) /* maybe 0xb7f*/
+#define DMA_CTL_CMD	DMA_BURST_SIZE
+#define HAVE_DMA_RXALIGN(lp)	likely((lp)->boardtype != TC35815CF)
 
 /* Tuning parameters */
 #define DMA_BURST_SIZE	32
 #define TX_THRESHOLD	1024
+#define TX_THRESHOLD_MAX 1536       /* used threshold with packet max byte for low pci transfer ability.*/
+#define TX_THRESHOLD_KEEP_LIMIT 10  /* setting threshold max value when overrun error occured this count. */
 
+/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */
+#ifdef TC35815_USE_PACKEDBUFFER
 #define FD_PAGE_NUM 2
-#define FD_PAGE_ORDER 1
-/* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */
-#define RX_BUF_PAGES	8	/* >= 2 */
+#define RX_BUF_NUM	8	/* >= 2 */
 #define RX_FD_NUM	250	/* >= 32 */
 #define TX_FD_NUM	128
+#define RX_BUF_SIZE	PAGE_SIZE
+#else /* TC35815_USE_PACKEDBUFFER */
+#define FD_PAGE_NUM 4
+#define RX_BUF_NUM	128	/* < 256 */
+#define RX_FD_NUM	256	/* >= 32 */
+#define TX_FD_NUM	128
+#if RX_CTL_CMD & Rx_LongEn
+#define RX_BUF_SIZE	PAGE_SIZE
+#elif RX_CTL_CMD & Rx_StripCRC
+#define RX_BUF_SIZE	ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */
+#else
+#define RX_BUF_SIZE	ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */
+#endif
+#endif /* TC35815_USE_PACKEDBUFFER */
+#define RX_FD_RESERVE	(2 / 2)	/* max 2 BD per RxFD */
+#define NAPI_WEIGHT	16
 
 struct TxFD {
 	struct FDesc fd;
@@ -392,18 +429,27 @@ struct RxFD {
 
 struct FrFD {
 	struct FDesc fd;
-	struct BDesc bd[RX_BUF_PAGES];
+	struct BDesc bd[RX_BUF_NUM];
 };
 
 
-extern unsigned long tc_readl(volatile __u32 *addr);
-extern void tc_writel(unsigned long data, volatile __u32 *addr);
+#define tc_readl(addr)	readl(addr)
+#define tc_writel(d, addr)	writel(d, addr)
 
-dma_addr_t priv_dma_handle;
+#define TC35815_TX_TIMEOUT  msecs_to_jiffies(400)
+
+/* Timer state engine. */
+enum tc35815_timer_state {
+	arbwait  = 0,	/* Waiting for auto negotiation to complete.          */
+	lupwait  = 1,	/* Auto-neg complete, awaiting link-up status.        */
+	ltrywait = 2,	/* Forcing try of all modes, from fastest to slowest. */
+	asleep   = 3,	/* Time inactive.                                     */
+	lcheck   = 4,	/* Check link status.                                 */
+};
 
 /* Information that need to be kept for each board. */
 struct tc35815_local {
-	struct net_device *next_module;
+	struct pci_dev *pci_dev;
 
 	/* statistics */
 	struct net_device_stats stats;
@@ -411,216 +457,372 @@ struct tc35815_local {
 		int max_tx_qlen;
 		int tx_ints;
 		int rx_ints;
+	        int tx_underrun;
 	} lstats;
 
-	int tbusy;
-	int option;
-#define TC35815_OPT_AUTO	0x00
-#define TC35815_OPT_10M	0x01
-#define TC35815_OPT_100M	0x02
-#define TC35815_OPT_FULLDUP	0x04
-	int linkspeed;	/* 10 or 100 */
+	/* Tx control lock.  This protects the transmit buffer ring
+	 * state along with the "tx full" state of the driver.  This
+	 * means all netif_queue flow control actions are protected
+	 * by this lock as well.
+	 */
+	spinlock_t lock;
+
+	int phy_addr;
 	int fullduplex;
+	unsigned short saved_lpa;
+	struct timer_list timer;
+	enum tc35815_timer_state timer_state; /* State of auto-neg timer. */
+	unsigned int timer_ticks;	/* Number of clicks at each state  */
 
 	/*
 	 * Transmitting: Batch Mode.
 	 *	1 BD in 1 TxFD.
-	 * Receiving: Packing Mode.
+	 * Receiving: Packing Mode. (TC35815_USE_PACKEDBUFFER)
 	 *	1 circular FD for Free Buffer List.
-	 *	RX_BUG_PAGES BD in Free Buffer FD.
+	 *	RX_BUF_NUM BD in Free Buffer FD.
 	 *	One Free Buffer BD has PAGE_SIZE data buffer.
+	 * Or Non-Packing Mode.
+	 *	1 circular FD for Free Buffer List.
+	 *	RX_BUF_NUM BD in Free Buffer FD.
+	 *	One Free Buffer BD has ETH_FRAME_LEN data buffer.
 	 */
-        struct pci_dev *pdev;
-	dma_addr_t fd_buf_dma_handle;
-	void * fd_buf;	/* for TxFD, TxFD, FrFD */
+	void * fd_buf;	/* for TxFD, RxFD, FrFD */
+	dma_addr_t fd_buf_dma;
 	struct TxFD *tfd_base;
-	int tfd_start;
-	int tfd_end;
+	unsigned int tfd_start;
+	unsigned int tfd_end;
 	struct RxFD *rfd_base;
 	struct RxFD *rfd_limit;
 	struct RxFD *rfd_cur;
 	struct FrFD *fbl_ptr;
+#ifdef TC35815_USE_PACKEDBUFFER
 	unsigned char fbl_curid;
-	dma_addr_t data_buf_dma_handle[RX_BUF_PAGES];
-	void * data_buf[RX_BUF_PAGES];		/* packing */
-	spinlock_t lock;
+	void * data_buf[RX_BUF_NUM];		/* packing */
+	dma_addr_t data_buf_dma[RX_BUF_NUM];
+	struct {
+		struct sk_buff *skb;
+		dma_addr_t skb_dma;
+	} tx_skbs[TX_FD_NUM];
+#else
+	unsigned int fbl_count;
+	struct {
+		struct sk_buff *skb;
+		dma_addr_t skb_dma;
+	} tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM];
+#endif
+	struct mii_if_info mii;
+	unsigned short mii_id[2];
+	u32 msg_enable;
+	board_t boardtype;
 };
 
-/* Index to functions, as function prototypes. */
+static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt)
+{
+	return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf);
+}
+#ifdef DEBUG
+static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
+{
+	return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma));
+}
+#endif
+#ifdef TC35815_USE_PACKEDBUFFER
+static inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
+{
+	int i;
+	for (i = 0; i < RX_BUF_NUM; i++) {
+		if (bus >= lp->data_buf_dma[i] &&
+		    bus < lp->data_buf_dma[i] + PAGE_SIZE)
+			return (void *)((u8 *)lp->data_buf[i] +
+					(bus - lp->data_buf_dma[i]));
+	}
+	return NULL;
+}
 
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq);
+#define TC35815_DMA_SYNC_ONDEMAND
+static void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+	void *buf;
+	/* pci_map + pci_dma_sync will be more effective than
+	 * pci_alloc_consistent on some archs. */
+	if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL)
+		return NULL;
+	*dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE,
+				     PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(*dma_handle)) {
+		free_page((unsigned long)buf);
+		return NULL;
+	}
+	return buf;
+#else
+	return pci_alloc_consistent(hwdev, PAGE_SIZE, dma_handle);
+#endif
+}
+
+static void free_rxbuf_page(struct pci_dev *hwdev, void *buf, dma_addr_t dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+	pci_unmap_single(hwdev, dma_handle, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+	free_page((unsigned long)buf);
+#else
+	pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle);
+#endif
+}
+#else /* TC35815_USE_PACKEDBUFFER */
+static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev,
+				       struct pci_dev *hwdev,
+				       dma_addr_t *dma_handle)
+{
+	struct sk_buff *skb;
+	skb = dev_alloc_skb(RX_BUF_SIZE);
+	if (!skb)
+		return NULL;
+	skb->dev = dev;
+	*dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE,
+				     PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(*dma_handle)) {
+		dev_kfree_skb_any(skb);
+		return NULL;
+	}
+	skb_reserve(skb, 2);	/* make IP header 4byte aligned */
+	return skb;
+}
+
+static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle)
+{
+	pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE,
+			 PCI_DMA_FROMDEVICE);
+	dev_kfree_skb_any(skb);
+}
+#endif /* TC35815_USE_PACKEDBUFFER */
+
+/* Index to functions, as function prototypes. */
 
 static int	tc35815_open(struct net_device *dev);
 static int	tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void     tc35815_tx_timeout(struct net_device *dev);
-static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
+static irqreturn_t	tc35815_interrupt(int irq, void *dev_id);
+#ifdef TC35815_NAPI
+static int	tc35815_rx(struct net_device *dev, int limit);
+static int	tc35815_poll(struct net_device *dev, int *budget);
+#else
 static void	tc35815_rx(struct net_device *dev);
+#endif
 static void	tc35815_txdone(struct net_device *dev);
 static int	tc35815_close(struct net_device *dev);
 static struct	net_device_stats *tc35815_get_stats(struct net_device *dev);
 static void	tc35815_set_multicast_list(struct net_device *dev);
+static void     tc35815_tx_timeout(struct net_device *dev);
+static int	tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void	tc35815_poll_controller(struct net_device *dev);
+#endif
+static const struct ethtool_ops tc35815_ethtool_ops;
 
+/* Example routines you must write ;->. */
 static void 	tc35815_chip_reset(struct net_device *dev);
 static void 	tc35815_chip_init(struct net_device *dev);
+static void	tc35815_find_phy(struct net_device *dev);
 static void 	tc35815_phy_chip_init(struct net_device *dev);
 
-/* A list of all installed tc35815 devices. */
-static struct net_device *root_tc35815_dev = NULL;
+#ifdef DEBUG
+static void	panic_queues(struct net_device *dev);
+#endif
 
-/*
- * PCI device identifiers for "new style" Linux PCI Device Drivers
- */
-static struct pci_device_id tc35815_pci_tbl[] = {
-    { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-    { 0, }
-};
+static void tc35815_timer(unsigned long data);
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+					   struct ethtool_cmd *ep);
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location);
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+			  int val);
 
-MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
+static void __devinit tc35815_init_dev_addr (struct net_device *dev)
+{
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int i;
 
-int
-tc35815_probe(struct pci_dev *pdev,
-		const struct pci_device_id *ent)
+	/* dev_addr will be overwritten on NETDEV_REGISTER event */
+	while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+		;
+	for (i = 0; i < 6; i += 2) {
+		unsigned short data;
+		tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
+		while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+			;
+		data = tc_readl(&tr->PROM_Data);
+		dev->dev_addr[i] = data & 0xff;
+		dev->dev_addr[i+1] = data >> 8;
+	}
+}
+
+static int __devinit tc35815_init_one (struct pci_dev *pdev,
+				       const struct pci_device_id *ent)
 {
-	int err = 0;
-	int ret;
-	unsigned long pci_memaddr;
-	unsigned int pci_irq_line;
+	void __iomem *ioaddr = NULL;
+	struct net_device *dev;
+	struct tc35815_local *lp;
+	int rc;
+	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+
+	static int printed_version;
+	if (!printed_version++) {
+		printk(version);
+		dev_printk(KERN_DEBUG, &pdev->dev,
+			   "speed:%d duplex:%d doforce:%d\n",
+			   options.speed, options.duplex, options.doforce);
+	}
 
-	printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device);
+	if (!pdev->irq) {
+		dev_warn(&pdev->dev, "no IRQ assigned.\n");
+		return -ENODEV;
+	}
 
-	err = pci_enable_device(pdev);
-	if (err)
-		return err;
+	/* dev zeroed in alloc_etherdev */
+	dev = alloc_etherdev (sizeof (*lp));
+	if (dev == NULL) {
+		dev_err(&pdev->dev, "unable to alloc new ethernet\n");
+		return -ENOMEM;
+	}
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	lp = dev->priv;
 
-        pci_memaddr = pci_resource_start (pdev, 1);
+	/* enable device (incl. PCI PM wakeup), and bus-mastering */
+	rc = pci_enable_device (pdev);
+	if (rc)
+		goto err_out;
 
-        printk(KERN_INFO "    pci_memaddr=%#08lx  resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0));
+	mmio_start = pci_resource_start (pdev, 1);
+	mmio_end = pci_resource_end (pdev, 1);
+	mmio_flags = pci_resource_flags (pdev, 1);
+	mmio_len = pci_resource_len (pdev, 1);
 
-	if (!pci_memaddr) {
-		printk(KERN_WARNING "no PCI MEM resources, aborting\n");
-		ret = -ENODEV;
+	/* set this immediately, we need to know before
+	 * we talk to the chip directly */
+
+	/* make sure PCI base addr 1 is MMIO */
+	if (!(mmio_flags & IORESOURCE_MEM)) {
+		dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
+		rc = -ENODEV;
 		goto err_out;
 	}
-	pci_irq_line = pdev->irq;
-	/* irq disabled. */
-	if (pci_irq_line == 0) {
-		printk(KERN_WARNING "no PCI irq, aborting\n");
-		ret = -ENODEV;
+
+	/* check for weird/broken PCI region reporting */
+	if ((mmio_len < sizeof(struct tc35815_regs))) {
+		dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
+		rc = -ENODEV;
 		goto err_out;
 	}
 
-	ret =  tc35815_probe1(pdev, pci_memaddr, pci_irq_line);
-	if (ret)
+	rc = pci_request_regions (pdev, MODNAME);
+	if (rc)
 		goto err_out;
 
-	pci_set_master(pdev);
+	pci_set_master (pdev);
 
-	return 0;
-
-err_out:
-	pci_disable_device(pdev);
-	return ret;
-}
+	/* ioremap MMIO region */
+	ioaddr = ioremap (mmio_start, mmio_len);
+	if (ioaddr == NULL) {
+		dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
+		rc = -EIO;
+		goto err_out_free_res;
+	}
 
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq)
-{
-	static unsigned version_printed = 0;
-	int i, ret;
-	struct tc35815_local *lp;
-	struct tc35815_regs *tr;
-	struct net_device *dev;
+	/* Initialize the device structure. */
+	dev->open = tc35815_open;
+	dev->hard_start_xmit = tc35815_send_packet;
+	dev->stop = tc35815_close;
+	dev->get_stats = tc35815_get_stats;
+	dev->set_multicast_list = tc35815_set_multicast_list;
+	dev->do_ioctl = tc35815_ioctl;
+	dev->ethtool_ops = &tc35815_ethtool_ops;
+	dev->tx_timeout = tc35815_tx_timeout;
+	dev->watchdog_timeo = TC35815_TX_TIMEOUT;
+#ifdef TC35815_NAPI
+	dev->poll = tc35815_poll;
+	dev->weight = NAPI_WEIGHT;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = tc35815_poll_controller;
+#endif
 
-	/* Allocate a new 'dev' if needed. */
-	dev = alloc_etherdev(sizeof(struct tc35815_local));
-	if (dev == NULL)
-		return -ENOMEM;
+	dev->irq = pdev->irq;
+	dev->base_addr = (unsigned long) ioaddr;
 
-	/*
-	 * alloc_etherdev allocs and zeros dev->priv
-	 */
+	/* dev->priv/lp zeroed and aligned in alloc_etherdev */
 	lp = dev->priv;
+	spin_lock_init(&lp->lock);
+	lp->pci_dev = pdev;
+	lp->boardtype = ent->driver_data;
 
-	if (tc35815_debug  &&  version_printed++ == 0)
-		printk(KERN_DEBUG "%s", version);
-
-	/* Fill in the 'dev' fields. */
-	dev->irq = irq;
-	dev->base_addr = (unsigned long)ioremap(base_addr,
-						sizeof(struct tc35815_regs));
-	if (!dev->base_addr) {
-		ret = -ENOMEM;
-		goto err_out;
-	}
-	tr = (struct tc35815_regs*)dev->base_addr;
+	lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK;
+	pci_set_drvdata(pdev, dev);
 
+	/* Soft reset the chip. */
 	tc35815_chip_reset(dev);
 
-	/* Retrieve and print the ethernet address. */
-	while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-		;
-	for (i = 0; i < 6; i += 2) {
-		unsigned short data;
-		tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
-		while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-			;
-		data = tc_readl(&tr->PROM_Data);
-		dev->dev_addr[i] = data & 0xff;
-		dev->dev_addr[i+1] = data >> 8;
-	}
+	/* Retrieve the ethernet address. */
+	tc35815_init_dev_addr(dev);
+
+	rc = register_netdev (dev);
+	if (rc)
+		goto err_out_unmap;
+
+	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+	printk(KERN_INFO "%s: %s at 0x%lx, "
+		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+		"IRQ %d\n",
+		dev->name,
+		board_info[ent->driver_data].name,
+		dev->base_addr,
+		dev->dev_addr[0], dev->dev_addr[1],
+		dev->dev_addr[2], dev->dev_addr[3],
+		dev->dev_addr[4], dev->dev_addr[5],
+		dev->irq);
+
+	setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev);
+	lp->mii.dev = dev;
+	lp->mii.mdio_read = tc_mdio_read;
+	lp->mii.mdio_write = tc_mdio_write;
+	lp->mii.phy_id_mask = 0x1f;
+	lp->mii.reg_num_mask = 0x1f;
+	tc35815_find_phy(dev);
+	lp->mii.phy_id = lp->phy_addr;
+	lp->mii.full_duplex = 0;
+	lp->mii.force_media = 0;
 
-	/* Initialize the device structure. */
-	lp->pdev = pdev;
-	lp->next_module = root_tc35815_dev;
-	root_tc35815_dev = dev;
+	return 0;
 
-	spin_lock_init(&lp->lock);
+err_out_unmap:
+	iounmap(ioaddr);
+err_out_free_res:
+	pci_release_regions (pdev);
+err_out:
+	free_netdev (dev);
+	return rc;
+}
 
-	if (dev->mem_start > 0) {
-		lp->option = dev->mem_start;
-		if ((lp->option & TC35815_OPT_10M) &&
-		    (lp->option & TC35815_OPT_100M)) {
-			/* if both speed speficied, auto select. */
-			lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M);
-		}
-	}
-	//XXX fixme
-        lp->option |= TC35815_OPT_10M;
 
-	/* do auto negotiation */
-	tc35815_phy_chip_init(dev);
+static void __devexit tc35815_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	unsigned long mmio_addr;
 
-	dev->open		= tc35815_open;
-	dev->stop		= tc35815_close;
-	dev->tx_timeout         = tc35815_tx_timeout;
-	dev->watchdog_timeo     = TX_TIMEOUT;
-	dev->hard_start_xmit	= tc35815_send_packet;
-	dev->get_stats		= tc35815_get_stats;
-	dev->set_multicast_list = tc35815_set_multicast_list;
-	SET_MODULE_OWNER(dev);
-	SET_NETDEV_DEV(dev, &pdev->dev);
+	mmio_addr = dev->base_addr;
 
-	ret = register_netdev(dev);
-	if (ret)
-		goto err_out_iounmap;
+	unregister_netdev (dev);
 
-	printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC",
-	       dev->name, cardname, base_addr, irq);
-	for (i = 0; i < 6; i++)
-		printk(" %2.2x", dev->dev_addr[i]);
-	printk("\n");
-	printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n",
-	       dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half");
+	if (mmio_addr) {
+		iounmap ((void __iomem *)mmio_addr);
+		pci_release_regions (pdev);
+	}
 
-	return 0;
+	free_netdev (dev);
 
-err_out_iounmap:
-	iounmap((void *) dev->base_addr);
-err_out:
-	free_netdev(dev);
-	return ret;
+	pci_set_drvdata (pdev, NULL);
 }
 
-
 static int
 tc35815_init_queues(struct net_device *dev)
 {
@@ -629,44 +831,64 @@ tc35815_init_queues(struct net_device *d
 	unsigned long fd_addr;
 
 	if (!lp->fd_buf) {
-		if (sizeof(struct FDesc) +
-		    sizeof(struct BDesc) * RX_BUF_PAGES +
-		    sizeof(struct FDesc) * RX_FD_NUM +
-		    sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) {
-			printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name);
-			return -ENOMEM;
-		}
+		BUG_ON(sizeof(struct FDesc) +
+		       sizeof(struct BDesc) * RX_BUF_NUM +
+		       sizeof(struct FDesc) * RX_FD_NUM +
+		       sizeof(struct TxFD) * TX_FD_NUM >
+		       PAGE_SIZE * FD_PAGE_NUM);
 
-		if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0)
+		if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0)
 			return -ENOMEM;
-		for (i = 0; i < RX_BUF_PAGES; i++) {
-			if ((lp->data_buf[i] = (void *)get_zeroed_page(GFP_KERNEL)) == 0) {
+		for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+			if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) {
 				while (--i >= 0) {
-					free_page((unsigned long)lp->data_buf[i]);
-					lp->data_buf[i] = 0;
+					free_rxbuf_page(lp->pci_dev,
+							lp->data_buf[i],
+							lp->data_buf_dma[i]);
+					lp->data_buf[i] = NULL;
 				}
-				free_page((unsigned long)lp->fd_buf);
-				lp->fd_buf = 0;
+				pci_free_consistent(lp->pci_dev,
+						    PAGE_SIZE * FD_PAGE_NUM,
+						    lp->fd_buf,
+						    lp->fd_buf_dma);
+				lp->fd_buf = NULL;
+				return -ENOMEM;
+			}
+#else
+			lp->rx_skbs[i].skb =
+				alloc_rxbuf_skb(dev, lp->pci_dev,
+						&lp->rx_skbs[i].skb_dma);
+			if (!lp->rx_skbs[i].skb) {
+				while (--i >= 0) {
+					free_rxbuf_skb(lp->pci_dev,
+						       lp->rx_skbs[i].skb,
+						       lp->rx_skbs[i].skb_dma);
+					lp->rx_skbs[i].skb = NULL;
+				}
+				pci_free_consistent(lp->pci_dev,
+						    PAGE_SIZE * FD_PAGE_NUM,
+						    lp->fd_buf,
+						    lp->fd_buf_dma);
+				lp->fd_buf = NULL;
 				return -ENOMEM;
 			}
-#ifdef __mips__
-			dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM);
 #endif
 		}
-#ifdef __mips__
-		dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
+		printk(KERN_DEBUG "%s: FD buf %p DataBuf",
+		       dev->name, lp->fd_buf);
+#ifdef TC35815_USE_PACKEDBUFFER
+		printk(" DataBuf");
+		for (i = 0; i < RX_BUF_NUM; i++)
+			printk(" %p", lp->data_buf[i]);
 #endif
+		printk("\n");
 	} else {
-		memset(lp->fd_buf, 0, PAGE_SIZE * FD_PAGE_NUM);
-#ifdef __mips__
-		dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
-#endif
+		for (i = 0; i < FD_PAGE_NUM; i++) {
+			clear_page((void *)((unsigned long)lp->fd_buf + i * PAGE_SIZE));
+		}
 	}
-#ifdef __mips__
-	fd_addr = (unsigned long)vtonocache(lp->fd_buf);
-#else
 	fd_addr = (unsigned long)lp->fd_buf;
-#endif
 
 	/* Free Descriptors (for Receive) */
 	lp->rfd_base = (struct RxFD *)fd_addr;
@@ -675,34 +897,66 @@ tc35815_init_queues(struct net_device *d
 		lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
 	}
 	lp->rfd_cur = lp->rfd_base;
-	lp->rfd_limit = (struct RxFD *)(fd_addr -
-					sizeof(struct FDesc) -
-					sizeof(struct BDesc) * 30);
+	lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1);
 
 	/* Transmit Descriptors */
 	lp->tfd_base = (struct TxFD *)fd_addr;
 	fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
 	for (i = 0; i < TX_FD_NUM; i++) {
-		lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1]));
-		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+		lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1]));
+		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
 		lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
 	}
-	lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0]));
+	lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0]));
 	lp->tfd_start = 0;
 	lp->tfd_end = 0;
 
 	/* Buffer List (for Receive) */
 	lp->fbl_ptr = (struct FrFD *)fd_addr;
-	lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr));
-	lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD);
-	for (i = 0; i < RX_BUF_PAGES; i++) {
-		lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i]));
+	lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr));
+	lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD);
+#ifndef TC35815_USE_PACKEDBUFFER
+	/*
+	 * move all allocated skbs to head of rx_skbs[] array.
+	 * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in
+	 * tc35815_rx() had failed.
+	 */
+	lp->fbl_count = 0;
+	for (i = 0; i < RX_BUF_NUM; i++) {
+		if (lp->rx_skbs[i].skb) {
+			if (i != lp->fbl_count) {
+				lp->rx_skbs[lp->fbl_count].skb =
+					lp->rx_skbs[i].skb;
+				lp->rx_skbs[lp->fbl_count].skb_dma =
+					lp->rx_skbs[i].skb_dma;
+			}
+			lp->fbl_count++;
+		}
+	}
+#endif
+	for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+		lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(lp->data_buf_dma[i]);
+#else
+		if (i >= lp->fbl_count) {
+			lp->fbl_ptr->bd[i].BuffData = 0;
+			lp->fbl_ptr->bd[i].BDCtl = 0;
+			continue;
+		}
+		lp->fbl_ptr->bd[i].BuffData =
+			cpu_to_le32(lp->rx_skbs[i].skb_dma);
+#endif
 		/* BDID is index of FrFD.bd[] */
 		lp->fbl_ptr->bd[i].BDCtl =
-			cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE);
+			cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) |
+				    RX_BUF_SIZE);
 	}
+#ifdef TC35815_USE_PACKEDBUFFER
 	lp->fbl_curid = 0;
+#endif
 
+	printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n",
+	       dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr);
 	return 0;
 }
 
@@ -713,11 +967,25 @@ tc35815_clear_queues(struct net_device *
 	int i;
 
 	for (i = 0; i < TX_FD_NUM; i++) {
-		struct sk_buff *skb = (struct sk_buff *)
-			le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
-		if (skb)
+		u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+		struct sk_buff *skb =
+			fdsystem != 0xffffffff ?
+			lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+		if (lp->tx_skbs[i].skb != skb) {
+			printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+			panic_queues(dev);
+		}
+#else
+		BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
+		if (skb) {
+			pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+			lp->tx_skbs[i].skb = NULL;
+			lp->tx_skbs[i].skb_dma = 0;
 			dev_kfree_skb_any(skb);
-		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+		}
+		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
 	}
 
 	tc35815_init_queues(dev);
@@ -731,28 +999,53 @@ tc35815_free_queues(struct net_device *d
 
 	if (lp->tfd_base) {
 		for (i = 0; i < TX_FD_NUM; i++) {
-			struct sk_buff *skb = (struct sk_buff *)
-				le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
-			if (skb)
-				dev_kfree_skb_any(skb);
-			lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+			u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+			struct sk_buff *skb =
+				fdsystem != 0xffffffff ?
+				lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+			if (lp->tx_skbs[i].skb != skb) {
+				printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+				panic_queues(dev);
+			}
+#else
+			BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
+			if (skb) {
+				dev_kfree_skb(skb);
+				pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+				lp->tx_skbs[i].skb = NULL;
+				lp->tx_skbs[i].skb_dma = 0;
+			}
+			lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
 		}
 	}
 
 	lp->rfd_base = NULL;
-	lp->rfd_base = NULL;
 	lp->rfd_limit = NULL;
 	lp->rfd_cur = NULL;
 	lp->fbl_ptr = NULL;
 
-	for (i = 0; i < RX_BUF_PAGES; i++) {
-		if (lp->data_buf[i])
-			free_page((unsigned long)lp->data_buf[i]);
-		lp->data_buf[i] = 0;
+	for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+		if (lp->data_buf[i]) {
+			free_rxbuf_page(lp->pci_dev,
+					lp->data_buf[i], lp->data_buf_dma[i]);
+			lp->data_buf[i] = NULL;
+		}
+#else
+		if (lp->rx_skbs[i].skb) {
+			free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb,
+				       lp->rx_skbs[i].skb_dma);
+			lp->rx_skbs[i].skb = NULL;
+		}
+#endif
+	}
+	if (lp->fd_buf) {
+		pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM,
+				    lp->fd_buf, lp->fd_buf_dma);
+		lp->fd_buf = NULL;
 	}
-	if (lp->fd_buf)
-		__free_pages(lp->fd_buf, FD_PAGE_ORDER);
-	lp->fd_buf = NULL;
 }
 
 static void
@@ -792,6 +1085,7 @@ dump_rxfd(struct RxFD *fd)
 	return bd_count;
 }
 
+#if defined(DEBUG) || defined(TC35815_USE_PACKEDBUFFER)
 static void
 dump_frfd(struct FrFD *fd)
 {
@@ -802,20 +1096,22 @@ dump_frfd(struct FrFD *fd)
 	       le32_to_cpu(fd->fd.FDStat),
 	       le32_to_cpu(fd->fd.FDCtl));
 	printk("BD: ");
-	for (i = 0; i < RX_BUF_PAGES; i++)
+	for (i = 0; i < RX_BUF_NUM; i++)
 		printk(" %08x %08x",
 		       le32_to_cpu(fd->bd[i].BuffData),
 		       le32_to_cpu(fd->bd[i].BDCtl));
 	printk("\n");
 }
+#endif
 
+#ifdef DEBUG
 static void
 panic_queues(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
 	int i;
 
-	printk("TxFD base %p, start %d, end %d\n",
+	printk("TxFD base %p, start %u, end %u\n",
 	       lp->tfd_base, lp->tfd_start, lp->tfd_end);
 	printk("RxFD base %p limit %p cur %p\n",
 	       lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
@@ -829,31 +1125,13 @@ panic_queues(struct net_device *dev)
 	dump_frfd(lp->fbl_ptr);
 	panic("%s: Illegal queue state.", dev->name);
 }
-
-#if 0
-static void print_buf(char *add, int length)
-{
-	int i;
-	int len = length;
-
-	printk("print_buf(%08x)(%x)\n", (unsigned int) add,length);
-
-	if (len > 100)
-		len = 100;
-	for (i = 0; i < len; i++) {
-		printk(" %2.2X", (unsigned char) add[i]);
-		if (!(i % 16))
-			printk("\n");
-	}
-	printk("\n");
-}
 #endif
 
 static void print_eth(char *add)
 {
 	int i;
 
-	printk("print_eth(%08x)\n", (unsigned int) add);
+	printk("print_eth(%p)\n", add);
 	for (i = 0; i < 6; i++)
 		printk(" %2.2X", (unsigned char) add[i + 6]);
 	printk(" =>");
@@ -862,6 +1140,73 @@ static void print_eth(char *add)
 	printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
 }
 
+static int tc35815_tx_full(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	return ((lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end);
+}
+
+static void tc35815_restart(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	int do_phy_reset = 1;
+	del_timer(&lp->timer);		/* Kill if running	*/
+
+	if (lp->mii_id[0] == 0x0016 && (lp->mii_id[1] & 0xfc00) == 0xf800) {
+		/* Resetting PHY cause problem on some chip... (SEEQ 80221) */
+		do_phy_reset = 0;
+	}
+	if (do_phy_reset) {
+		int timeout;
+		tc_mdio_write(dev, pid, MII_BMCR, BMCR_RESET);
+		timeout = 100;
+		while (--timeout) {
+			if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_RESET))
+				break;
+			udelay(1);
+		}
+		if (!timeout)
+			printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name);
+	}
+
+	tc35815_chip_reset(dev);
+	tc35815_clear_queues(dev);
+	tc35815_chip_init(dev);
+	/* Reconfigure CAM again since tc35815_chip_init() initialize it. */
+	tc35815_set_multicast_list(dev);
+}
+
+static void tc35815_tx_timeout(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+
+	printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+	       dev->name, tc_readl(&tr->Tx_Stat));
+
+	/* Try to restart the adaptor. */
+	spin_lock_irq(&lp->lock);
+	tc35815_restart(dev);
+	spin_unlock_irq(&lp->lock);
+
+	lp->stats.tx_errors++;
+
+	/* If we have space available to accept new transmit
+	 * requests, wake up the queueing layer.  This would
+	 * be the case if the chipset_init() call above just
+	 * flushes out the tx queue and empties it.
+	 *
+	 * If instead, the tx queue is retained then the
+	 * netif_wake_queue() call should be placed in the
+	 * TX completion interrupt handler of the driver instead
+	 * of here.
+	 */
+	if (!tc35815_tx_full(dev))
+		netif_wake_queue(dev);
+}
+
 /*
  * Open/initialize the board. This is called (in the current kernel)
  * sometime after booting when the 'ifconfig' program is run.
@@ -874,16 +1219,16 @@ static int
 tc35815_open(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
+
 	/*
 	 * This is used if the interrupt line can turned off (shared).
 	 * See 3c503.c for an example of selecting the IRQ at config-time.
 	 */
-
-	if (dev->irq == 0  ||
-	    request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, cardname, dev)) {
+	if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, dev->name, dev)) {
 		return -EAGAIN;
 	}
 
+	del_timer(&lp->timer);		/* Kill if running	*/
 	tc35815_chip_reset(dev);
 
 	if (tc35815_init_queues(dev) != 0) {
@@ -892,138 +1237,119 @@ tc35815_open(struct net_device *dev)
 	}
 
 	/* Reset the hardware here. Don't forget to set the station address. */
+	spin_lock_irq(&lp->lock);
 	tc35815_chip_init(dev);
+	spin_unlock_irq(&lp->lock);
 
-	lp->tbusy = 0;
+	/* We are now ready to accept transmit requeusts from
+	 * the queueing layer of the networking.
+	 */
 	netif_start_queue(dev);
 
 	return 0;
 }
 
-static void tc35815_tx_timeout(struct net_device *dev)
-{
-	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
-	unsigned long flags;
-
-	spin_lock_irqsave(&lp->lock, flags);
-	printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
-	       dev->name, tc_readl(&tr->Tx_Stat));
-	/* Try to restart the adaptor. */
-	tc35815_chip_reset(dev);
-	tc35815_clear_queues(dev);
-	tc35815_chip_init(dev);
-	lp->tbusy=0;
-	spin_unlock_irqrestore(&lp->lock, flags);
-	dev->trans_start = jiffies;
-	netif_wake_queue(dev);
-}
-
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
 static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
-
-	if (netif_queue_stopped(dev)) {
-		/*
-		 * If we get here, some higher level has decided we are broken.
-		 * There should really be a "kick me" function call instead.
-		 */
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 5)
-			return 1;
-		printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
-		       dev->name, tc_readl(&tr->Tx_Stat));
-		/* Try to restart the adaptor. */
-		tc35815_chip_reset(dev);
-		tc35815_clear_queues(dev);
-		tc35815_chip_init(dev);
-		lp->tbusy=0;
-		dev->trans_start = jiffies;
-		netif_wake_queue(dev);
-	}
+	struct TxFD *txfd;
+	unsigned long flags;
 
-	/*
-	 * Block a timer-based transmit from overlapping. This could better be
-	 * done with atomic_swap(1, lp->tbusy), but set_bit() works as well.
+	/* If some error occurs while trying to transmit this
+	 * packet, you should return '1' from this function.
+	 * In such a case you _may not_ do anything to the
+	 * SKB, it is still owned by the network queueing
+	 * layer when an error is returned.  This means you
+	 * may not modify any SKB fields, you may not free
+	 * the SKB, etc.
 	 */
-	if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) {
-		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
-		dev_kfree_skb_any(skb);
-	} else {
-		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-		unsigned char *buf = skb->data;
-		struct TxFD *txfd = &lp->tfd_base[lp->tfd_start];
-		unsigned long flags;
-		lp->stats.tx_bytes += skb->len;
 
+	/* This is the most common case for modern hardware.
+	 * The spinlock protects this code from the TX complete
+	 * hardware interrupt handler.  Queue flow control is
+	 * thus managed under this lock as well.
+	 */
+	spin_lock_irqsave(&lp->lock, flags);
 
-#ifdef __mips__
-		dma_cache_wback_inv((unsigned long)buf, length);
+	/* failsafe... (handle txdone now if half of FDs are used) */
+	if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM >
+	    TX_FD_NUM / 2)
+		tc35815_txdone(dev);
+
+	if (netif_msg_pktdata(lp))
+		print_eth(skb->data);
+#ifdef DEBUG
+	if (lp->tx_skbs[lp->tfd_start].skb) {
+		printk("%s: tx_skbs conflict.\n", dev->name);
+		panic_queues(dev);
+	}
+#else
+	BUG_ON(lp->tx_skbs[lp->tfd_start].skb);
 #endif
-
-		spin_lock_irqsave(&lp->lock, flags);
-
-		/* failsafe... */
-		if (lp->tfd_start != lp->tfd_end)
-			tc35815_txdone(dev);
-
-
-		txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf));
-
-		txfd->bd.BDCtl = cpu_to_le32(length);
-		txfd->fd.FDSystem = cpu_to_le32((__u32)skb);
-		txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
-
-		if (lp->tfd_start == lp->tfd_end) {
-			/* Start DMA Transmitter. */
-			txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+	lp->tx_skbs[lp->tfd_start].skb = skb;
+	lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+	/*add to ring */
+	txfd = &lp->tfd_base[lp->tfd_start];
+	txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma);
+	txfd->bd.BDCtl = cpu_to_le32(skb->len);
+	txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start);
+	txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
+
+	if (lp->tfd_start == lp->tfd_end) {
+		struct tc35815_regs __iomem *tr =
+			(struct tc35815_regs __iomem *)dev->base_addr;
+		/* Start DMA Transmitter. */
+		txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
 #ifdef GATHER_TXINT
-			txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+		txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
 #endif
-			if (tc35815_debug > 2) {
-				printk("%s: starting TxFD.\n", dev->name);
-				dump_txfd(txfd);
-				if (tc35815_debug > 3)
-					print_eth(buf);
-			}
-			tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
-		} else {
-			txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
-			if (tc35815_debug > 2) {
-				printk("%s: queueing TxFD.\n", dev->name);
-				dump_txfd(txfd);
-				if (tc35815_debug > 3)
-					print_eth(buf);
-			}
+		if (netif_msg_tx_queued(lp)) {
+			printk("%s: starting TxFD.\n", dev->name);
+			dump_txfd(txfd);
+		}
+		tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
+	} else {
+		txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
+		if (netif_msg_tx_queued(lp)) {
+			printk("%s: queueing TxFD.\n", dev->name);
+			dump_txfd(txfd);
 		}
-		lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
+	}
+	lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
 
-		dev->trans_start = jiffies;
+	dev->trans_start = jiffies;
 
-		if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) {
-			/* we can send another packet */
-			lp->tbusy = 0;
-			netif_start_queue(dev);
-		} else {
-			netif_stop_queue(dev);
-			if (tc35815_debug > 1)
-				printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
-		}
-		spin_unlock_irqrestore(&lp->lock, flags);
+	/* If we just used up the very last entry in the
+	 * TX ring on this device, tell the queueing
+	 * layer to send no more.
+	 */
+	if (tc35815_tx_full(dev)) {
+		if (netif_msg_tx_queued(lp))
+			printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
+		netif_stop_queue(dev);
 	}
 
+	/* When the TX completion hw interrupt arrives, this
+	 * is when the transmit statistics are updated.
+	 */
+
+	spin_unlock_irqrestore(&lp->lock, flags);
 	return 0;
 }
 
 #define FATAL_ERROR_INT \
 	(Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
-static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
+static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status)
 {
 	static int count;
 	printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
 	       dev->name, status);
-
 	if (status & Int_IntPCI)
 		printk(" IntPCI");
 	if (status & Int_DmParErr)
@@ -1033,110 +1359,170 @@ static void tc35815_fatal_error_interrup
 	printk("\n");
 	if (count++ > 100)
 		panic("%s: Too many fatal errors.", dev->name);
-	printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname);
+	printk(KERN_WARNING "%s: Resetting ...\n", dev->name);
 	/* Try to restart the adaptor. */
-	tc35815_chip_reset(dev);
-	tc35815_clear_queues(dev);
-	tc35815_chip_init(dev);
+	tc35815_restart(dev);
+}
+
+#ifdef TC35815_NAPI
+static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit)
+#else
+static int tc35815_do_interrupt(struct net_device *dev, u32 status)
+#endif
+{
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int ret = -1;
+
+	/* Fatal errors... */
+	if (status & FATAL_ERROR_INT) {
+		tc35815_fatal_error_interrupt(dev, status);
+		return 0;
+	}
+	/* recoverable errors */
+	if (status & Int_IntFDAEx) {
+		/* disable FDAEx int. (until we make rooms...) */
+		tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
+		printk(KERN_WARNING
+		       "%s: Free Descriptor Area Exhausted (%#x).\n",
+		       dev->name, status);
+		lp->stats.rx_dropped++;
+		ret = 0;
+	}
+	if (status & Int_IntBLEx) {
+		/* disable BLEx int. (until we make rooms...) */
+		tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
+		printk(KERN_WARNING
+		       "%s: Buffer List Exhausted (%#x).\n",
+		       dev->name, status);
+		lp->stats.rx_dropped++;
+		ret = 0;
+	}
+	if (status & Int_IntExBD) {
+		printk(KERN_WARNING
+		       "%s: Excessive Buffer Descriptiors (%#x).\n",
+		       dev->name, status);
+		lp->stats.rx_length_errors++;
+		ret = 0;
+	}
+
+	/* normal notification */
+	if (status & Int_IntMacRx) {
+		/* Got a packet(s). */
+#ifdef TC35815_NAPI
+		ret = tc35815_rx(dev, limit);
+#else
+		tc35815_rx(dev);
+		ret = 0;
+#endif
+		lp->lstats.rx_ints++;
+	}
+	if (status & Int_IntMacTx) {
+		/* Transmit complete. */
+		lp->lstats.tx_ints++;
+		tc35815_txdone(dev);
+		netif_wake_queue(dev);
+		ret = 0;
+	}
+	return ret;
 }
 
 /*
  * The typical workload of the driver:
- *   Handle the network interface interrupts.
+ * Handle the network interface interrupts.
  */
 static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
-	struct tc35815_regs *tr;
-	struct tc35815_local *lp;
-	int status, boguscount = 0;
-	int handled = 0;
-
-	if (dev == NULL) {
-		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
-		return IRQ_NONE;
-	}
-
-	tr = (struct tc35815_regs*)dev->base_addr;
-	lp = dev->priv;
-
-	do {
-		status = tc_readl(&tr->Int_Src);
-		if (status == 0)
-			break;
-		handled = 1;
-		tc_writel(status, &tr->Int_Src);	/* write to clear */
-
-		/* Fatal errors... */
-		if (status & FATAL_ERROR_INT) {
-			tc35815_fatal_error_interrupt(dev, status);
-			break;
-		}
-		/* recoverable errors */
-		if (status & Int_IntFDAEx) {
-			/* disable FDAEx int. (until we make rooms...) */
-			tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
-			printk(KERN_WARNING
-			       "%s: Free Descriptor Area Exhausted (%#x).\n",
-			       dev->name, status);
-			lp->stats.rx_dropped++;
-		}
-		if (status & Int_IntBLEx) {
-			/* disable BLEx int. (until we make rooms...) */
-			tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
-			printk(KERN_WARNING
-			       "%s: Buffer List Exhausted (%#x).\n",
-			       dev->name, status);
-			lp->stats.rx_dropped++;
-		}
-		if (status & Int_IntExBD) {
-			printk(KERN_WARNING
-			       "%s: Excessive Buffer Descriptiors (%#x).\n",
-			       dev->name, status);
-			lp->stats.rx_length_errors++;
-		}
-		/* normal notification */
-		if (status & Int_IntMacRx) {
-			/* Got a packet(s). */
-			lp->lstats.rx_ints++;
-			tc35815_rx(dev);
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+#ifdef TC35815_NAPI
+	u32 dmactl = tc_readl(&tr->DMA_Ctl);
+
+	if (!(dmactl & DMA_IntMask)) {
+		/* disable interrupts */
+		tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
+		if (netif_rx_schedule_prep(dev))
+			__netif_rx_schedule(dev);
+		else {
+			printk(KERN_ERR "%s: interrupt taken in poll\n",
+			       dev->name);
+			BUG();
 		}
-		if (status & Int_IntMacTx) {
-			lp->lstats.tx_ints++;
-			tc35815_txdone(dev);
-		}
-	} while (++boguscount < 20) ;
+		(void)tc_readl(&tr->Int_Src);	/* flush */
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+#else
+	struct tc35815_local *lp = dev->priv;
+	int handled;
+	u32 status;
+
+	spin_lock(&lp->lock);
+	status = tc_readl(&tr->Int_Src);
+	tc_writel(status, &tr->Int_Src);	/* write to clear */
+	handled = tc35815_do_interrupt(dev, status);
+	(void)tc_readl(&tr->Int_Src);	/* flush */
+	spin_unlock(&lp->lock);
+	return IRQ_RETVAL(handled >= 0);
+#endif /* TC35815_NAPI */
+}
 
-	return IRQ_RETVAL(handled);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void tc35815_poll_controller(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	tc35815_interrupt(dev->irq, dev);
+	enable_irq(dev->irq);
 }
+#endif
 
 /* We have a good packet(s), get it/them out of the buffers. */
+#ifdef TC35815_NAPI
+static int
+tc35815_rx(struct net_device *dev, int limit)
+#else
 static void
 tc35815_rx(struct net_device *dev)
+#endif
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
 	unsigned int fdctl;
 	int i;
 	int buf_free_count = 0;
 	int fd_free_count = 0;
+#ifdef TC35815_NAPI
+	int received = 0;
+#endif
 
 	while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
 		int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
 		int pkt_len = fdctl & FD_FDLength_MASK;
-		struct RxFD *next_rfd;
 		int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+#ifdef DEBUG
+		struct RxFD *next_rfd;
+#endif
+#if (RX_CTL_CMD & Rx_StripCRC) == 0
+		pkt_len -= 4;
+#endif
 
-		if (tc35815_debug > 2)
+		if (netif_msg_rx_status(lp))
 			dump_rxfd(lp->rfd_cur);
 		if (status & Rx_Good) {
-			/* Malloc up new buffer. */
 			struct sk_buff *skb;
 			unsigned char *data;
-			int cur_bd, offset;
-
-			lp->stats.rx_bytes += pkt_len;
+			int cur_bd;
+#ifdef TC35815_USE_PACKEDBUFFER
+			int offset;
+#endif
 
+#ifdef TC35815_NAPI
+			if (--limit < 0)
+				break;
+#endif
+#ifdef TC35815_USE_PACKEDBUFFER
+			BUG_ON(bd_count > 2);
 			skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
 			if (skb == NULL) {
 				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
@@ -1155,25 +1541,64 @@ tc35815_rx(struct net_device *dev)
 			while (offset < pkt_len && cur_bd < bd_count) {
 				int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) &
 					BD_BuffLength_MASK;
-				void *rxbuf =
-					bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData));
-#ifdef __mips__
-				dma_cache_inv((unsigned long)rxbuf, len);
+				dma_addr_t dma = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData);
+				void *rxbuf = rxbuf_bus_to_virt(lp, dma);
+				if (offset + len > pkt_len)
+					len = pkt_len - offset;
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+				pci_dma_sync_single_for_cpu(lp->pci_dev,
+							    dma, len,
+							    PCI_DMA_FROMDEVICE);
 #endif
 				memcpy(data + offset, rxbuf, len);
 				offset += len;
 				cur_bd++;
 			}
-#if 0
-			print_buf(data,pkt_len);
+#else /* TC35815_USE_PACKEDBUFFER */
+			BUG_ON(bd_count > 1);
+			cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl)
+				  & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
+#ifdef DEBUG
+			if (cur_bd >= RX_BUF_NUM) {
+				printk("%s: invalid BDID.\n", dev->name);
+				panic_queues(dev);
+			}
+			BUG_ON(lp->rx_skbs[cur_bd].skb_dma !=
+			       (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3));
+			if (!lp->rx_skbs[cur_bd].skb) {
+				printk("%s: NULL skb.\n", dev->name);
+				panic_queues(dev);
+			}
+#else
+			BUG_ON(cur_bd >= RX_BUF_NUM);
 #endif
-			if (tc35815_debug > 3)
+			skb = lp->rx_skbs[cur_bd].skb;
+			prefetch(skb->data);
+			lp->rx_skbs[cur_bd].skb = NULL;
+			lp->fbl_count--;
+			pci_unmap_single(lp->pci_dev,
+					 lp->rx_skbs[cur_bd].skb_dma,
+					 RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			if (!HAVE_DMA_RXALIGN(lp))
+				memmove(skb->data, skb->data - 2, pkt_len);
+			data = skb_put(skb, pkt_len);
+#endif /* TC35815_USE_PACKEDBUFFER */
+			if (netif_msg_pktdata(lp))
 				print_eth(data);
 			skb->protocol = eth_type_trans(skb, dev);
+#ifdef TC35815_NAPI
+			netif_receive_skb(skb);
+			received++;
+#else
 			netif_rx(skb);
+#endif
+			dev->last_rx = jiffies;
 			lp->stats.rx_packets++;
+			lp->stats.rx_bytes += pkt_len;
 		} else {
 			lp->stats.rx_errors++;
+			printk(KERN_DEBUG "%s: Rx error (status %x)\n",
+			       dev->name, status & Rx_Stat_Mask);
 			/* WORKAROUND: LongErr and CRCErr means Overflow. */
 			if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
 				status &= ~(Rx_LongErr|Rx_CRCErr);
@@ -1190,63 +1615,150 @@ tc35815_rx(struct net_device *dev)
 			int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
 			unsigned char id =
 				(bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
-			if (id >= RX_BUF_PAGES) {
+#ifdef DEBUG
+			if (id >= RX_BUF_NUM) {
 				printk("%s: invalid BDID.\n", dev->name);
 				panic_queues(dev);
 			}
+#else
+			BUG_ON(id >= RX_BUF_NUM);
+#endif
 			/* free old buffers */
-			while (lp->fbl_curid != id) {
-				bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl);
+#ifdef TC35815_USE_PACKEDBUFFER
+			while (lp->fbl_curid != id)
+#else
+			while (lp->fbl_count < RX_BUF_NUM)
+#endif
+			{
+#ifdef TC35815_USE_PACKEDBUFFER
+				unsigned char curid = lp->fbl_curid;
+#else
+				unsigned char curid =
+					(id + 1 + lp->fbl_count) % RX_BUF_NUM;
+#endif
+				struct BDesc *bd = &lp->fbl_ptr->bd[curid];
+#ifdef DEBUG
+				bdctl = le32_to_cpu(bd->BDCtl);
 				if (bdctl & BD_CownsBD) {
 					printk("%s: Freeing invalid BD.\n",
 					       dev->name);
 					panic_queues(dev);
 				}
+#endif
 				/* pass BD to controler */
+#ifndef TC35815_USE_PACKEDBUFFER
+				if (!lp->rx_skbs[curid].skb) {
+					lp->rx_skbs[curid].skb =
+						alloc_rxbuf_skb(dev,
+								lp->pci_dev,
+								&lp->rx_skbs[curid].skb_dma);
+					if (!lp->rx_skbs[curid].skb)
+						break; /* try on next reception */
+					bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma);
+				}
+#endif /* TC35815_USE_PACKEDBUFFER */
 				/* Note: BDLength was modified by chip. */
-				lp->fbl_ptr->bd[lp->fbl_curid].BDCtl =
-					cpu_to_le32(BD_CownsBD |
-						    (lp->fbl_curid << BD_RxBDID_SHIFT) |
-						    PAGE_SIZE);
-				lp->fbl_curid =
-					(lp->fbl_curid + 1) % RX_BUF_PAGES;
-				if (tc35815_debug > 2) {
+				bd->BDCtl = cpu_to_le32(BD_CownsBD |
+							(curid << BD_RxBDID_SHIFT) |
+							RX_BUF_SIZE);
+#ifdef TC35815_USE_PACKEDBUFFER
+				lp->fbl_curid = (curid + 1) % RX_BUF_NUM;
+				if (netif_msg_rx_status(lp)) {
 					printk("%s: Entering new FBD %d\n",
 					       dev->name, lp->fbl_curid);
 					dump_frfd(lp->fbl_ptr);
 				}
+#else
+				lp->fbl_count++;
+#endif
 				buf_free_count++;
 			}
 		}
 
 		/* put RxFD back to controller */
-		next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext));
-#ifdef __mips__
-		next_rfd = (struct RxFD *)vtonocache(next_rfd);
-#endif
+#ifdef DEBUG
+		next_rfd = fd_bus_to_virt(lp,
+					  le32_to_cpu(lp->rfd_cur->fd.FDNext));
 		if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
 			printk("%s: RxFD FDNext invalid.\n", dev->name);
 			panic_queues(dev);
 		}
+#endif
 		for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
 			/* pass FD to controler */
-			lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);	/* for debug */
+#ifdef DEBUG
+			lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);
+#else
+			lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL);
+#endif
 			lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
 			lp->rfd_cur++;
 			fd_free_count++;
 		}
-
-		lp->rfd_cur = next_rfd;
+		if (lp->rfd_cur > lp->rfd_limit)
+			lp->rfd_cur = lp->rfd_base;
+#ifdef DEBUG
+		if (lp->rfd_cur != next_rfd)
+			printk("rfd_cur = %p, next_rfd %p\n",
+			       lp->rfd_cur, next_rfd);
+#endif
 	}
 
 	/* re-enable BL/FDA Exhaust interrupts. */
 	if (fd_free_count) {
-		tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En);
+		struct tc35815_regs __iomem *tr =
+			(struct tc35815_regs __iomem *)dev->base_addr;
+		u32 en, en_old = tc_readl(&tr->Int_En);
+		en = en_old | Int_FDAExEn;
 		if (buf_free_count)
-			tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En);
+			en |= Int_BLExEn;
+		if (en != en_old)
+			tc_writel(en, &tr->Int_En);
 	}
+#ifdef TC35815_NAPI
+	return received;
+#endif
 }
 
+#ifdef TC35815_NAPI
+static int
+tc35815_poll(struct net_device *dev, int *budget)
+{
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int limit = min(*budget, dev->quota);
+	int received = 0, handled;
+	u32 status;
+
+	spin_lock(&lp->lock);
+	status = tc_readl(&tr->Int_Src);
+	do {
+		tc_writel(status, &tr->Int_Src);	/* write to clear */
+
+		handled = tc35815_do_interrupt(dev, status, limit);
+		if (handled >= 0) {
+			received += handled;
+			limit -= handled;
+			if (limit <= 0)
+				break;
+		}
+		status = tc_readl(&tr->Int_Src);
+	} while (status);
+	spin_unlock(&lp->lock);
+
+	dev->quota -= received;
+	*budget -= received;
+	if (limit <= 0)
+		return 1;
+
+	netif_rx_complete(dev);
+	/* enable interrupts */
+	tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
+	return 0;
+}
+#endif
+
 #ifdef NO_CHECK_CARRIER
 #define TX_STA_ERR	(Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr)
 #else
@@ -1265,9 +1777,17 @@ tc35815_check_tx_stat(struct net_device
 	if (status & Tx_TxColl_MASK)
 		lp->stats.collisions += status & Tx_TxColl_MASK;
 
+#ifndef NO_CHECK_CARRIER
+	/* TX4939 does not have NCarr */
+	if (lp->boardtype == TC35815_TX4939)
+		status &= ~Tx_NCarr;
+#ifdef WORKAROUND_LOSTCAR
 	/* WORKAROUND: ignore LostCrS in full duplex operation */
-	if (lp->fullduplex)
+	if ((lp->timer_state != asleep && lp->timer_state != lcheck)
+	    || lp->fullduplex)
 		status &= ~Tx_NCarr;
+#endif
+#endif
 
 	if (!(status & TX_STA_ERR)) {
 		/* no error. */
@@ -1283,6 +1803,15 @@ tc35815_check_tx_stat(struct net_device
 	if (status & Tx_Under) {
 		lp->stats.tx_fifo_errors++;
 		msg = "Tx FIFO Underrun.";
+		if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) {
+			lp->lstats.tx_underrun++;
+			if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {
+				struct tc35815_regs __iomem *tr =
+					(struct tc35815_regs __iomem *)dev->base_addr;
+				tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);
+				msg = "Tx FIFO Underrun.Change Tx threshold to max.";
+			}
+		}
 	}
 	if (status & Tx_Defer) {
 		lp->stats.tx_fifo_errors++;
@@ -1306,18 +1835,19 @@ tc35815_check_tx_stat(struct net_device
 		lp->stats.tx_heartbeat_errors++;
 		msg = "Signal Quality Error.";
 	}
-	if (msg)
+	if (msg && netif_msg_tx_err(lp))
 		printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
 }
 
+/* This handles TX complete events posted by the device
+ * via interrupts.
+ */
 static void
 tc35815_txdone(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
 	struct TxFD *txfd;
 	unsigned int fdctl;
-	int num_done = 0;
 
 	txfd = &lp->tfd_base[lp->tfd_end];
 	while (lp->tfd_start != lp->tfd_end &&
@@ -1325,38 +1855,61 @@ tc35815_txdone(struct net_device *dev)
 		int status = le32_to_cpu(txfd->fd.FDStat);
 		struct sk_buff *skb;
 		unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
+		u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem);
 
-		if (tc35815_debug > 2) {
+		if (netif_msg_tx_done(lp)) {
 			printk("%s: complete TxFD.\n", dev->name);
 			dump_txfd(txfd);
 		}
 		tc35815_check_tx_stat(dev, status);
 
-		skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem);
+		skb = fdsystem != 0xffffffff ?
+			lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+		if (lp->tx_skbs[lp->tfd_end].skb != skb) {
+			printk("%s: tx_skbs mismatch.\n", dev->name);
+			panic_queues(dev);
+		}
+#else
+		BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb);
+#endif
 		if (skb) {
+			lp->stats.tx_bytes += skb->len;
+			pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE);
+			lp->tx_skbs[lp->tfd_end].skb = NULL;
+			lp->tx_skbs[lp->tfd_end].skb_dma = 0;
+#ifdef TC35815_NAPI
 			dev_kfree_skb_any(skb);
+#else
+			dev_kfree_skb_irq(skb);
+#endif
 		}
-		txfd->fd.FDSystem = cpu_to_le32(0);
+		txfd->fd.FDSystem = cpu_to_le32(0xffffffff);
 
-		num_done++;
 		lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
 		txfd = &lp->tfd_base[lp->tfd_end];
-		if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) {
+#ifdef DEBUG
+		if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) {
 			printk("%s: TxFD FDNext invalid.\n", dev->name);
 			panic_queues(dev);
 		}
+#endif
 		if (fdnext & FD_Next_EOL) {
 			/* DMA Transmitter has been stopping... */
 			if (lp->tfd_end != lp->tfd_start) {
+				struct tc35815_regs __iomem *tr =
+					(struct tc35815_regs __iomem *)dev->base_addr;
 				int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
 				struct TxFD* txhead = &lp->tfd_base[head];
 				int qlen = (lp->tfd_start + TX_FD_NUM
 					    - lp->tfd_end) % TX_FD_NUM;
 
+#ifdef DEBUG
 				if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
 					printk("%s: TxFD FDCtl invalid.\n", dev->name);
 					panic_queues(dev);
 				}
+#endif
 				/* log max queue length */
 				if (lp->lstats.max_tx_qlen < qlen)
 					lp->lstats.max_tx_qlen = qlen;
@@ -1367,21 +1920,23 @@ tc35815_txdone(struct net_device *dev)
 #ifdef GATHER_TXINT
 				txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
 #endif
-				if (tc35815_debug > 2) {
+				if (netif_msg_tx_queued(lp)) {
 					printk("%s: start TxFD on queue.\n",
 					       dev->name);
 					dump_txfd(txfd);
 				}
-				tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
+				tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
 			}
 			break;
 		}
 	}
 
-	if (num_done > 0 && lp->tbusy) {
-		lp->tbusy = 0;
-		netif_start_queue(dev);
-	}
+	/* If we had stopped the queue due to a "tx full"
+	 * condition, and space has now been made available,
+	 * wake up the queue.
+	 */
+	if (netif_queue_stopped(dev) && ! tc35815_tx_full(dev))
+		netif_wake_queue(dev);
 }
 
 /* The inverse routine to tc35815_open(). */
@@ -1389,18 +1944,18 @@ static int
 tc35815_close(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-
-	lp->tbusy = 1;
 	netif_stop_queue(dev);
 
 	/* Flush the Tx and disable Rx here. */
 
+	del_timer(&lp->timer);		/* Kill if running	*/
 	tc35815_chip_reset(dev);
 	free_irq(dev->irq, dev);
 
 	tc35815_free_queues(dev);
 
 	return 0;
+
 }
 
 /*
@@ -1410,29 +1965,29 @@ tc35815_close(struct net_device *dev)
 static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-	unsigned long flags;
-
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	if (netif_running(dev)) {
-		spin_lock_irqsave(&lp->lock, flags);
 		/* Update the statistics from the device registers. */
 		lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);
-		spin_unlock_irqrestore(&lp->lock, flags);
 	}
 
 	return &lp->stats;
 }
 
-static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr)
+static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr)
 {
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	int cam_index = index * 6;
-	unsigned long cam_data;
-	unsigned long saved_addr;
+	u32 cam_data;
+	u32 saved_addr;
 	saved_addr = tc_readl(&tr->CAM_Adr);
 
-	if (tc35815_debug > 1) {
+	if (netif_msg_hw(lp)) {
 		int i;
-		printk(KERN_DEBUG "%s: CAM %d:", cardname, index);
+		printk(KERN_DEBUG "%s: CAM %d:", dev->name, index);
 		for (i = 0; i < 6; i++)
 			printk(" %02x", addr[i]);
 		printk("\n");
@@ -1459,14 +2014,6 @@ static void tc35815_set_cam_entry(struct
 		tc_writel(cam_data, &tr->CAM_Data);
 	}
 
-	if (tc35815_debug > 2) {
-		int i;
-		for (i = cam_index / 4; i < cam_index / 4 + 2; i++) {
-			tc_writel(i * 4, &tr->CAM_Adr);
-			printk("CAM 0x%x: %08lx",
-			       i * 4, tc_readl(&tr->CAM_Data));
-		}
-	}
 	tc_writel(saved_addr, &tr->CAM_Adr);
 }
 
@@ -1481,10 +2028,19 @@ static void tc35815_set_cam_entry(struct
 static void
 tc35815_set_multicast_list(struct net_device *dev)
 {
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 
 	if (dev->flags&IFF_PROMISC)
 	{
+#ifdef WORKAROUND_100HALF_PROMISC
+		/* With some (all?) 100MHalf HUB, controller will hang
+		 * if we enabled promiscuous mode before linkup... */
+		struct tc35815_local *lp = dev->priv;
+		int pid = lp->phy_addr;
+		if (!(tc_mdio_read(dev, pid, MII_BMSR) & BMSR_LSTATUS))
+			return;
+#endif
 		/* Enable promiscuous mode */
 		tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
 	}
@@ -1506,7 +2062,7 @@ tc35815_set_multicast_list(struct net_de
 			if (!cur_addr)
 				break;
 			/* entry 0,1 is reserved. */
-			tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr);
+			tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr);
 			ena_bits |= CAM_Ena_Bit(i + 2);
 		}
 		tc_writel(ena_bits, &tr->CAM_Ena);
@@ -1518,122 +2074,753 @@ tc35815_set_multicast_list(struct net_de
 	}
 }
 
-static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr, int phy, int phy_reg)
+static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct tc35815_local *lp = dev->priv;
-	unsigned long data;
-	unsigned long flags;
+	strcpy(info->driver, MODNAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(lp->pci_dev));
+}
 
-	spin_lock_irqsave(&lp->lock, flags);
+static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct tc35815_local *lp = dev->priv;
+	spin_lock_irq(&lp->lock);
+	mii_ethtool_gset(&lp->mii, cmd);
+	spin_unlock_irq(&lp->lock);
+	return 0;
+}
 
-	tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
+static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+#if 1	/* use our negotiation method... */
+	/* Verify the settings we care about. */
+	if (cmd->autoneg != AUTONEG_ENABLE &&
+	    cmd->autoneg != AUTONEG_DISABLE)
+		return -EINVAL;
+	if (cmd->autoneg == AUTONEG_DISABLE &&
+	    ((cmd->speed != SPEED_100 &&
+	      cmd->speed != SPEED_10) ||
+	     (cmd->duplex != DUPLEX_HALF &&
+	      cmd->duplex != DUPLEX_FULL)))
+		return -EINVAL;
+
+	/* Ok, do it to it. */
+	spin_lock_irq(&lp->lock);
+	del_timer(&lp->timer);
+	tc35815_start_auto_negotiation(dev, cmd);
+	spin_unlock_irq(&lp->lock);
+	rc = 0;
+#else
+	spin_lock_irq(&lp->lock);
+	rc = mii_ethtool_sset(&lp->mii, cmd);
+	spin_unlock_irq(&lp->lock);
+#endif
+	return rc;
+}
+
+static int tc35815_nway_reset(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+	spin_lock_irq(&lp->lock);
+	rc = mii_nway_restart(&lp->mii);
+	spin_unlock_irq(&lp->lock);
+	return rc;
+}
+
+static u32 tc35815_get_link(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+	spin_lock_irq(&lp->lock);
+	rc = mii_link_ok(&lp->mii);
+	spin_unlock_irq(&lp->lock);
+	return rc;
+}
+
+static u32 tc35815_get_msglevel(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	return lp->msg_enable;
+}
+
+static void tc35815_set_msglevel(struct net_device *dev, u32 datum)
+{
+	struct tc35815_local *lp = dev->priv;
+	lp->msg_enable = datum;
+}
+
+static int tc35815_get_stats_count(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	return sizeof(lp->lstats) / sizeof(int);
+}
+
+static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
+{
+	struct tc35815_local *lp = dev->priv;
+	data[0] = lp->lstats.max_tx_qlen;
+	data[1] = lp->lstats.tx_ints;
+	data[2] = lp->lstats.rx_ints;
+	data[3] = lp->lstats.tx_underrun;
+}
+
+static struct {
+	const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+	{ "max_tx_qlen" },
+	{ "tx_ints" },
+	{ "rx_ints" },
+	{ "tx_underrun" },
+};
+
+static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+static const struct ethtool_ops tc35815_ethtool_ops = {
+	.get_drvinfo		= tc35815_get_drvinfo,
+	.get_settings		= tc35815_get_settings,
+	.set_settings		= tc35815_set_settings,
+	.nway_reset		= tc35815_nway_reset,
+	.get_link		= tc35815_get_link,
+	.get_msglevel		= tc35815_get_msglevel,
+	.set_msglevel		= tc35815_set_msglevel,
+	.get_strings		= tc35815_get_strings,
+	.get_stats_count	= tc35815_get_stats_count,
+	.get_ethtool_stats	= tc35815_get_ethtool_stats,
+	.get_perm_addr		= ethtool_op_get_perm_addr,
+};
+
+static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	spin_lock_irq(&lp->lock);
+	rc = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
+	spin_unlock_irq(&lp->lock);
+
+	return rc;
+}
+
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	u32 data;
+	tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA);
 	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
 		;
 	data = tc_readl(&tr->MD_Data);
-	spin_unlock_irqrestore(&lp->lock, flags);
-	return data;
+	return data & 0xffff;
+}
+
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+			  int val)
+{
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	tc_writel(val, &tr->MD_Data);
+	tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA);
+	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+		;
 }
 
-static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg)
+/* Auto negotiation.  The scheme is very simple.  We have a timer routine
+ * that keeps watching the auto negotiation process as it progresses.
+ * The DP83840 is first told to start doing it's thing, we set up the time
+ * and place the timer state machine in it's initial state.
+ *
+ * Here the timer peeks at the DP83840 status registers at each click to see
+ * if the auto negotiation has completed, we assume here that the DP83840 PHY
+ * will time out at some point and just tell us what (didn't) happen.  For
+ * complete coverage we only allow so many of the ticks at this level to run,
+ * when this has expired we print a warning message and try another strategy.
+ * This "other" strategy is to force the interface into various speed/duplex
+ * configurations and we stop when we see a link-up condition before the
+ * maximum number of "peek" ticks have occurred.
+ *
+ * Once a valid link status has been detected we configure the BigMAC and
+ * the rest of the Happy Meal to speak the most efficient protocol we could
+ * get a clean link for.  The priority for link configurations, highest first
+ * is:
+ *                 100 Base-T Full Duplex
+ *                 100 Base-T Half Duplex
+ *                 10 Base-T Full Duplex
+ *                 10 Base-T Half Duplex
+ *
+ * We start a new timer now, after a successful auto negotiation status has
+ * been detected.  This timer just waits for the link-up bit to get set in
+ * the BMCR of the DP83840.  When this occurs we print a kernel log message
+ * describing the link type in use and the fact that it is up.
+ *
+ * If a fatal error of some sort is signalled and detected in the interrupt
+ * service routine, and the chip is reset, or the link is ifconfig'd down
+ * and then back up, this entire process repeats itself all over again.
+ */
+/* Note: Above comments are come from sunhme driver. */
+
+static int tc35815_try_next_permutation(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	unsigned long flags;
+	int pid = lp->phy_addr;
+	unsigned short bmcr;
 
-	spin_lock_irqsave(&lp->lock, flags);
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
 
-	tc_writel(d, &tr->MD_Data);
-	tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA);
-	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
-		;
-	spin_unlock_irqrestore(&lp->lock, flags);
+	/* Downgrade from full to half duplex.  Only possible via ethtool.  */
+	if (bmcr & BMCR_FULLDPLX) {
+		bmcr &= ~BMCR_FULLDPLX;
+		printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+		return 0;
+	}
+
+	/* Downgrade from 100 to 10. */
+	if (bmcr & BMCR_SPEED100) {
+		bmcr &= ~BMCR_SPEED100;
+		printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+		return 0;
+	}
+
+	/* We've tried everything. */
+	return -1;
 }
 
-static void tc35815_phy_chip_init(struct net_device *dev)
+static void
+tc35815_display_link_mode(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-	static int first = 1;
-	unsigned short ctl;
-
-	if (first) {
-		unsigned short id0, id1;
-		int count;
-		first = 0;
-
-		/* first data written to the PHY will be an ID number */
-		tc_phy_write(dev, 0, tr, 0, MII_CONTROL);	/* ID:0 */
-#if 0
-		tc_phy_write(dev, MIICNTL_RESET, tr, 0, MII_CONTROL);
-		printk(KERN_INFO "%s: Resetting PHY...", dev->name);
-		while (tc_phy_read(dev, tr, 0, MII_CONTROL) & MIICNTL_RESET)
-			;
-		printk("\n");
-		tc_phy_write(dev, MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0,
-			     MII_CONTROL);
-#endif
-		id0 = tc_phy_read(dev, tr, 0, MII_PHY_ID0);
-		id1 = tc_phy_read(dev, tr, 0, MII_PHY_ID1);
-		printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name,
-		       id0, id1);
-		if (lp->option & TC35815_OPT_10M) {
-			lp->linkspeed = 10;
-			lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
-		} else if (lp->option & TC35815_OPT_100M) {
-			lp->linkspeed = 100;
-			lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
+	int pid = lp->phy_addr;
+	unsigned short lpa, bmcr;
+	char *speed = "", *duplex = "";
+
+	lpa = tc_mdio_read(dev, pid, MII_LPA);
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+		speed = "100Mb/s";
+	else
+		speed = "10Mb/s";
+	if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+		duplex = "Full Duplex";
+	else
+		duplex = "Half Duplex";
+
+	if (netif_msg_link(lp))
+		printk(KERN_INFO "%s: Link is up at %s, %s.\n",
+		       dev->name, speed, duplex);
+	printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+	       dev->name,
+	       bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+}
+
+static void tc35815_display_forced_link_mode(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmcr;
+	char *speed = "", *duplex = "";
+
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	if (bmcr & BMCR_SPEED100)
+		speed = "100Mb/s";
+	else
+		speed = "10Mb/s";
+	if (bmcr & BMCR_FULLDPLX)
+		duplex = "Full Duplex.\n";
+	else
+		duplex = "Half Duplex.\n";
+
+	if (netif_msg_link(lp))
+		printk(KERN_INFO "%s: Link has been forced up at %s, %s",
+		       dev->name, speed, duplex);
+}
+
+static void tc35815_set_link_modes(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int pid = lp->phy_addr;
+	unsigned short bmcr, lpa;
+	int speed;
+
+	if (lp->timer_state == arbwait) {
+		lpa = tc_mdio_read(dev, pid, MII_LPA);
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+		       dev->name,
+		       bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+		if (!(lpa & (LPA_10HALF | LPA_10FULL |
+			     LPA_100HALF | LPA_100FULL))) {
+			/* fall back to 10HALF */
+			printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n",
+			       dev->name, lpa);
+			lpa = LPA_10HALF;
+		}
+		if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+			lp->fullduplex = 1;
+		else
+			lp->fullduplex = 0;
+		if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+			speed = 100;
+		else
+			speed = 10;
+	} else {
+		/* Forcing a link mode. */
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		if (bmcr & BMCR_FULLDPLX)
+			lp->fullduplex = 1;
+		else
+			lp->fullduplex = 0;
+		if (bmcr & BMCR_SPEED100)
+			speed = 100;
+		else
+			speed = 10;
+	}
+
+	tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl);
+	if (lp->fullduplex) {
+		tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+	} else {
+		tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl);
+	}
+	tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl);
+
+	/* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */
+
+#ifndef NO_CHECK_CARRIER
+	/* TX4939 does not have EnLCarr */
+	if (lp->boardtype != TC35815_TX4939) {
+#ifdef WORKAROUND_LOSTCAR
+		/* WORKAROUND: enable LostCrS only if half duplex operation */
+		if (!lp->fullduplex && lp->boardtype != TC35815_TX4939)
+			tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl);
+#endif
+	}
+#endif
+	lp->mii.full_duplex = lp->fullduplex;
+}
+
+static void tc35815_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmsr, bmcr, lpa;
+	int restart_timer = 0;
+
+	spin_lock_irq(&lp->lock);
+
+	lp->timer_ticks++;
+	switch (lp->timer_state) {
+	case arbwait:
+		/*
+		 * Only allow for 5 ticks, thats 10 seconds and much too
+		 * long to wait for arbitration to complete.
+		 */
+		/* TC35815 need more times... */
+		if (lp->timer_ticks >= 10) {
+			/* Enter force mode. */
+			if (!options.doforce) {
+				printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+				       " cable probblem?\n", dev->name);
+				/* Try to restart the adaptor. */
+				tc35815_restart(dev);
+				goto out;
+			}
+			printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+			       " trying force link mode\n", dev->name);
+			printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name,
+			       tc_mdio_read(dev, pid, MII_BMCR),
+			       tc_mdio_read(dev, pid, MII_BMSR));
+			bmcr = BMCR_SPEED100;
+			tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+			/*
+			 * OK, seems we need do disable the transceiver
+			 * for the first tick to make sure we get an
+			 * accurate link state at the second tick.
+			 */
+
+			lp->timer_state = ltrywait;
+			lp->timer_ticks = 0;
+			restart_timer = 1;
 		} else {
-			/* auto negotiation */
-			unsigned long neg_result;
-			tc_phy_write(dev, MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL);
-			printk(KERN_INFO "%s: Auto Negotiation...", dev->name);
-			count = 0;
-			while (!(tc_phy_read(dev, tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) {
-				if (count++ > 5000) {
-					printk(" failed. Assume 10Mbps\n");
-					lp->linkspeed = 10;
-					lp->fullduplex = 0;
-					goto done;
+			/* Anything interesting happen? */
+			bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+			if (bmsr & BMSR_ANEGCOMPLETE) {
+				/* Just what we've been waiting for... */
+				tc35815_set_link_modes(dev);
+
+				/*
+				 * Success, at least so far, advance our state
+				 * engine.
+				 */
+				lp->timer_state = lupwait;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case lupwait:
+		/*
+		 * Auto negotiation was successful and we are awaiting a
+		 * link up status.  I have decided to let this timer run
+		 * forever until some sort of error is signalled, reporting
+		 * a message to the user at 10 second intervals.
+		 */
+		bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+		if (bmsr & BMSR_LSTATUS) {
+			/*
+			 * Wheee, it's up, display the link mode in use and put
+			 * the timer to sleep.
+			 */
+			tc35815_display_link_mode(dev);
+			netif_carrier_on(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+			/* delayed promiscuous enabling */
+			if (dev->flags & IFF_PROMISC)
+				tc35815_set_multicast_list(dev);
+#endif
+#if 1
+			lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+			lp->timer_state = lcheck;
+			restart_timer = 1;
+#else
+			lp->timer_state = asleep;
+			restart_timer = 0;
+#endif
+		} else {
+			if (lp->timer_ticks >= 10) {
+				printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
+				       "not completely up.\n", dev->name);
+				lp->timer_ticks = 0;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case ltrywait:
+		/*
+		 * Making the timeout here too long can make it take
+		 * annoyingly long to attempt all of the link mode
+		 * permutations, but then again this is essentially
+		 * error recovery code for the most part.
+		 */
+		bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		if (lp->timer_ticks == 1) {
+			/*
+			 * Re-enable transceiver, we'll re-enable the
+			 * transceiver next tick, then check link state
+			 * on the following tick.
+			 */
+			restart_timer = 1;
+			break;
+		}
+		if (lp->timer_ticks == 2) {
+			restart_timer = 1;
+			break;
+		}
+		if (bmsr & BMSR_LSTATUS) {
+			/* Force mode selection success. */
+			tc35815_display_forced_link_mode(dev);
+			netif_carrier_on(dev);
+			tc35815_set_link_modes(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+			/* delayed promiscuous enabling */
+			if (dev->flags & IFF_PROMISC)
+				tc35815_set_multicast_list(dev);
+#endif
+#if 1
+			lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+			lp->timer_state = lcheck;
+			restart_timer = 1;
+#else
+			lp->timer_state = asleep;
+			restart_timer = 0;
+#endif
+		} else {
+			if (lp->timer_ticks >= 4) { /* 6 seconds or so... */
+				int ret;
+
+				ret = tc35815_try_next_permutation(dev);
+				if (ret == -1) {
+					/*
+					 * Aieee, tried them all, reset the
+					 * chip and try all over again.
+					 */
+					printk(KERN_NOTICE "%s: Link down, "
+					       "cable problem?\n",
+					       dev->name);
+
+					/* Try to restart the adaptor. */
+					tc35815_restart(dev);
+					goto out;
 				}
-				if (count % 512 == 0)
-					printk(".");
-				mdelay(1);
+				lp->timer_ticks = 0;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case lcheck:
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		lpa = tc_mdio_read(dev, pid, MII_LPA);
+		if (bmcr & (BMCR_PDOWN | BMCR_ISOLATE | BMCR_RESET)) {
+			printk(KERN_ERR "%s: PHY down? (BMCR %x)\n", dev->name,
+			       bmcr);
+		} else if ((lp->saved_lpa ^ lpa) &
+			   (LPA_100FULL|LPA_100HALF|LPA_10FULL|LPA_10HALF)) {
+			printk(KERN_NOTICE "%s: link status changed"
+			       " (BMCR %x LPA %x->%x)\n", dev->name,
+			       bmcr, lp->saved_lpa, lpa);
+		} else {
+			/* go on */
+			restart_timer = 1;
+			break;
+		}
+		/* Try to restart the adaptor. */
+		tc35815_restart(dev);
+		goto out;
+
+	case asleep:
+	default:
+		/* Can't happens.... */
+		printk(KERN_ERR "%s: Aieee, link timer is asleep but we got "
+		       "one anyways!\n", dev->name);
+		restart_timer = 0;
+		lp->timer_ticks = 0;
+		lp->timer_state = asleep; /* foo on you */
+		break;
+	}
+
+	if (restart_timer) {
+		lp->timer.expires = jiffies + msecs_to_jiffies(1200);
+		add_timer(&lp->timer);
+	}
+out:
+	spin_unlock_irq(&lp->lock);
+}
+
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+					   struct ethtool_cmd *ep)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmsr, bmcr, advertize;
+	int timeout;
+
+	netif_carrier_off(dev);
+	bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	advertize = tc_mdio_read(dev, pid, MII_ADVERTISE);
+
+	if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+		if (options.speed || options.duplex) {
+			/* Advertise only specified configuration. */
+			advertize &= ~(ADVERTISE_10HALF |
+				       ADVERTISE_10FULL |
+				       ADVERTISE_100HALF |
+				       ADVERTISE_100FULL);
+			if (options.speed != 10) {
+				if (options.duplex != 1)
+					advertize |= ADVERTISE_100FULL;
+				if (options.duplex != 2)
+					advertize |= ADVERTISE_100HALF;
+			}
+			if (options.speed != 100) {
+				if (options.duplex != 1)
+					advertize |= ADVERTISE_10FULL;
+				if (options.duplex != 2)
+					advertize |= ADVERTISE_10HALF;
 			}
-			printk(" done.\n");
-			neg_result = tc_phy_read(dev, tr, 0, MII_ANLPAR);
-			if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX))
-				lp->linkspeed = 100;
+			if (options.speed == 100)
+				bmcr |= BMCR_SPEED100;
+			else if (options.speed == 10)
+				bmcr &= ~BMCR_SPEED100;
+			if (options.duplex == 2)
+				bmcr |= BMCR_FULLDPLX;
+			else if (options.duplex == 1)
+				bmcr &= ~BMCR_FULLDPLX;
+		} else {
+			/* Advertise everything we can support. */
+			if (bmsr & BMSR_10HALF)
+				advertize |= ADVERTISE_10HALF;
 			else
-				lp->linkspeed = 10;
-			if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX))
-				lp->fullduplex = 1;
+				advertize &= ~ADVERTISE_10HALF;
+			if (bmsr & BMSR_10FULL)
+				advertize |= ADVERTISE_10FULL;
 			else
-				lp->fullduplex = 0;
-		done:
-			;
+				advertize &= ~ADVERTISE_10FULL;
+			if (bmsr & BMSR_100HALF)
+				advertize |= ADVERTISE_100HALF;
+			else
+				advertize &= ~ADVERTISE_100HALF;
+			if (bmsr & BMSR_100FULL)
+				advertize |= ADVERTISE_100FULL;
+			else
+				advertize &= ~ADVERTISE_100FULL;
+		}
+
+		tc_mdio_write(dev, pid, MII_ADVERTISE, advertize);
+
+		/* Enable Auto-Negotiation, this is usually on already... */
+		bmcr |= BMCR_ANENABLE;
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+		/* Restart it to make sure it is going. */
+		bmcr |= BMCR_ANRESTART;
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+		printk(KERN_DEBUG "%s: ADVERTISE %x BMCR %x\n", dev->name, advertize, bmcr);
+
+		/* BMCR_ANRESTART self clears when the process has begun. */
+		timeout = 64;  /* More than enough. */
+		while (--timeout) {
+			bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+			if (!(bmcr & BMCR_ANRESTART))
+				break; /* got it. */
+			udelay(10);
 		}
+		if (!timeout) {
+			printk(KERN_ERR "%s: TC35815 would not start auto "
+			       "negotiation BMCR=0x%04x\n",
+			       dev->name, bmcr);
+			printk(KERN_NOTICE "%s: Performing force link "
+			       "detection.\n", dev->name);
+			goto force_link;
+		} else {
+			printk(KERN_DEBUG "%s: auto negotiation started.\n", dev->name);
+			lp->timer_state = arbwait;
+		}
+	} else {
+force_link:
+		/* Force the link up, trying first a particular mode.
+		 * Either we are here at the request of ethtool or
+		 * because the Happy Meal would not start to autoneg.
+		 */
+
+		/* Disable auto-negotiation in BMCR, enable the duplex and
+		 * speed setting, init the timer state machine, and fire it off.
+		 */
+		if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+			bmcr = BMCR_SPEED100;
+		} else {
+			if (ep->speed == SPEED_100)
+				bmcr = BMCR_SPEED100;
+			else
+				bmcr = 0;
+			if (ep->duplex == DUPLEX_FULL)
+				bmcr |= BMCR_FULLDPLX;
+		}
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+		/* OK, seems we need do disable the transceiver for the first
+		 * tick to make sure we get an accurate link state at the
+		 * second tick.
+		 */
+		lp->timer_state = ltrywait;
 	}
 
-	ctl = 0;
-	if (lp->linkspeed == 100)
-		ctl |= MIICNTL_SPEED;
-	if (lp->fullduplex)
-		ctl |= MIICNTL_FDX;
-	tc_phy_write(dev, ctl, tr, 0, MII_CONTROL);
+	del_timer(&lp->timer);
+	lp->timer_ticks = 0;
+	lp->timer.expires = jiffies + msecs_to_jiffies(1200);
+	add_timer(&lp->timer);
+}
 
-	if (lp->fullduplex) {
-		tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+static void tc35815_find_phy(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short id0;
+
+	/* find MII phy */
+	for (pid = 31; pid >= 0; pid--) {
+		id0 = tc_mdio_read(dev, pid, MII_BMSR);
+		if (id0 != 0xffff && id0 != 0x0000 &&
+		    (id0 & BMSR_RESV) != (0xffff & BMSR_RESV) /* paranoia? */
+			) {
+			lp->phy_addr = pid;
+			break;
+		}
 	}
+	if (pid < 0) {
+		printk(KERN_ERR "%s: No MII Phy found.\n",
+		       dev->name);
+		lp->phy_addr = pid = 0;
+	}
+
+	lp->mii_id[0] = tc_mdio_read(dev, pid, MII_PHYSID1);
+	lp->mii_id[1] = tc_mdio_read(dev, pid, MII_PHYSID2);
+	if (netif_msg_hw(lp))
+		printk(KERN_INFO "%s: PHY(%02x) ID %04x %04x\n", dev->name,
+		       pid, lp->mii_id[0], lp->mii_id[1]);
 }
 
-static void tc35815_chip_reset(struct net_device *dev)
+static void tc35815_phy_chip_init(struct net_device *dev)
 {
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmcr;
+	struct ethtool_cmd ecmd, *ep;
+
+	/* dis-isolate if needed. */
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	if (bmcr & BMCR_ISOLATE) {
+		int count = 32;
+		printk(KERN_DEBUG "%s: unisolating...", dev->name);
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr & ~BMCR_ISOLATE);
+		while (--count) {
+			if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_ISOLATE))
+				break;
+			udelay(20);
+		}
+		printk(" %s.\n", count ? "done" : "failed");
+	}
+
+	if (options.speed && options.duplex) {
+		ecmd.autoneg = AUTONEG_DISABLE;
+		ecmd.speed = options.speed == 10 ? SPEED_10 : SPEED_100;
+		ecmd.duplex = options.duplex == 1 ? DUPLEX_HALF : DUPLEX_FULL;
+		ep = &ecmd;
+	} else {
+		ep = NULL;
+	}
+	tc35815_start_auto_negotiation(dev, ep);
+}
 
+static void tc35815_chip_reset(struct net_device *dev)
+{
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int i;
 	/* reset the controller */
 	tc_writel(MAC_Reset, &tr->MAC_Ctl);
-	while (tc_readl(&tr->MAC_Ctl) & MAC_Reset)
-		;
-
+	udelay(4); /* 3200ns */
+	i = 0;
+	while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) {
+		if (i++ > 100) {
+			printk(KERN_ERR "%s: MAC reset failed.\n", dev->name);
+			break;
+		}
+		mdelay(1);
+	}
 	tc_writel(0, &tr->MAC_Ctl);
 
 	/* initialize registers to default value */
@@ -1651,90 +2838,142 @@ static void tc35815_chip_reset(struct ne
 	tc_writel(0, &tr->CAM_Ena);
 	(void)tc_readl(&tr->Miss_Cnt);	/* Read to clear */
 
+	/* initialize internal SRAM */
+	tc_writel(DMA_TestMode, &tr->DMA_Ctl);
+	for (i = 0; i < 0x1000; i += 4) {
+		tc_writel(i, &tr->CAM_Adr);
+		tc_writel(0, &tr->CAM_Data);
+	}
+	tc_writel(0, &tr->DMA_Ctl);
 }
 
 static void tc35815_chip_init(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-	unsigned long flags;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	unsigned long txctl = TX_CTL_CMD;
 
 	tc35815_phy_chip_init(dev);
 
 	/* load station address to CAM */
-	tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr);
+	tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr);
 
 	/* Enable CAM (broadcast and unicast) */
 	tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
 	tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
 
-	spin_lock_irqsave(&lp->lock, flags);
-
-	tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
-
+	/* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */
+	if (HAVE_DMA_RXALIGN(lp))
+		tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl);
+	else
+		tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
+#ifdef TC35815_USE_PACKEDBUFFER
 	tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize);	/* Packing */
+#else
+	tc_writel(ETH_ZLEN, &tr->RxFragSize);
+#endif
 	tc_writel(0, &tr->TxPollCtr);	/* Batch mode */
 	tc_writel(TX_THRESHOLD, &tr->TxThrsh);
 	tc_writel(INT_EN_CMD, &tr->Int_En);
 
 	/* set queues */
-	tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas);
+	tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas);
 	tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
 		  &tr->FDA_Lim);
 	/*
 	 * Activation method:
-	 * First, enable eht MAC Transmitter and the DMA Receive circuits.
+	 * First, enable the MAC Transmitter and the DMA Receive circuits.
 	 * Then enable the DMA Transmitter and the MAC Receive circuits.
 	 */
-	tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr);	/* start DMA receiver */
+	tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr);	/* start DMA receiver */
 	tc_writel(RX_CTL_CMD, &tr->Rx_Ctl);	/* start MAC receiver */
+
 	/* start MAC transmitter */
+#ifndef NO_CHECK_CARRIER
+	/* TX4939 does not have EnLCarr */
+	if (lp->boardtype == TC35815_TX4939)
+		txctl &= ~Tx_EnLCarr;
+#ifdef WORKAROUND_LOSTCAR
 	/* WORKAROUND: ignore LostCrS in full duplex operation */
-	if (lp->fullduplex)
-		txctl = TX_CTL_CMD & ~Tx_EnLCarr;
+	if ((lp->timer_state != asleep && lp->timer_state != lcheck) ||
+	    lp->fullduplex)
+		txctl &= ~Tx_EnLCarr;
+#endif
+#endif /* !NO_CHECK_CARRIER */
 #ifdef GATHER_TXINT
 	txctl &= ~Tx_EnComp;	/* disable global tx completion int. */
 #endif
 	tc_writel(txctl, &tr->Tx_Ctl);
-#if 0	/* No need to polling */
-	tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr);	/* start DMA transmitter */
-#endif
+}
+
+#ifdef CONFIG_PM
+static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct tc35815_local *lp = dev->priv;
+	unsigned long flags;
+
+	pci_save_state(pdev);
+	if (!netif_running(dev))
+		return 0;
+	netif_device_detach(dev);
+	spin_lock_irqsave(&lp->lock, flags);
+	del_timer(&lp->timer);		/* Kill if running	*/
+	tc35815_chip_reset(dev);
 	spin_unlock_irqrestore(&lp->lock, flags);
+	pci_set_power_state(pdev, PCI_D3hot);
+	return 0;
 }
 
-static struct pci_driver tc35815_driver = {
-	.name = TC35815_MODULE_NAME,
-	.probe = tc35815_probe,
-	.remove = NULL,
-	.id_table = tc35815_pci_tbl,
+static int tc35815_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct tc35815_local *lp = dev->priv;
+	unsigned long flags;
+
+	pci_restore_state(pdev);
+	if (!netif_running(dev))
+		return 0;
+	pci_set_power_state(pdev, PCI_D0);
+	spin_lock_irqsave(&lp->lock, flags);
+	tc35815_restart(dev);
+	spin_unlock_irqrestore(&lp->lock, flags);
+	netif_device_attach(dev);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct pci_driver tc35815_pci_driver = {
+	.name		= MODNAME,
+	.id_table	= tc35815_pci_tbl,
+	.probe		= tc35815_init_one,
+	.remove		= __devexit_p(tc35815_remove_one),
+#ifdef CONFIG_PM
+	.suspend	= tc35815_suspend,
+	.resume		= tc35815_resume,
+#endif
 };
 
+module_param_named(speed, options.speed, int, 0);
+MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps");
+module_param_named(duplex, options.duplex, int, 0);
+MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full");
+module_param_named(doforce, options.doforce, int, 0);
+MODULE_PARM_DESC(doforce, "try force link mode if auto-negotiation failed");
+
 static int __init tc35815_init_module(void)
 {
-	return pci_register_driver(&tc35815_driver);
+	return pci_register_driver(&tc35815_pci_driver);
 }
 
 static void __exit tc35815_cleanup_module(void)
 {
-	struct net_device *next_dev;
-
-	/*
-	 * TODO: implement a tc35815_driver.remove hook, and
-	 * move this code into that function.  Then, delete
-	 * all root_tc35815_dev list handling code.
-	 */
-	while (root_tc35815_dev) {
-		struct net_device *dev = root_tc35815_dev;
-		next_dev = ((struct tc35815_local *)dev->priv)->next_module;
-		iounmap((void *)(dev->base_addr));
-		unregister_netdev(dev);
-		free_netdev(dev);
-		root_tc35815_dev = next_dev;
-	}
-
-	pci_unregister_driver(&tc35815_driver);
+	pci_unregister_driver(&tc35815_pci_driver);
 }
 
 module_init(tc35815_init_module);
 module_exit(tc35815_cleanup_module);
+
+MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 600308f..247b5e6 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1459,6 +1459,8 @@
 
 #define PCI_VENDOR_ID_TOSHIBA_2		0x102f
 #define PCI_DEVICE_ID_TOSHIBA_TC35815CF	0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU	0x0031
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939	0x0032
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE	0x0105
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC	0x0108
 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3

From anemo@mba.ocn.ne.jp Sat Mar  3 17:43:12 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 17:43:17 +0000 (GMT)
Received: from mba.ocn.ne.jp ([210.190.142.172]:14023 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20037679AbXCCRnM (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sat, 3 Mar 2007 17:43:12 +0000
Received: from localhost (p6054-ipad201funabasi.chiba.ocn.ne.jp [222.146.69.54])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id 8416CB665; Sun,  4 Mar 2007 02:41:52 +0900 (JST)
Date:	Sun, 04 Mar 2007 02:41:52 +0900 (JST)
Message-Id: <20070304.024152.96687132.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org
Subject: [PATCH] store sign-extend register values for PTRACE_GETREGS
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14333
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

A comment on ptrace_getregs() states "Registers are sign extended to
fill the available space." but it is not true.  Fix code to match the
comment.  Also fix casts on each caller to get rid of some warnings.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 478355a..5560b6d 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -66,13 +66,13 @@ int ptrace_getregs (struct task_struct *
 	regs = task_pt_regs(child);
 
 	for (i = 0; i < 32; i++)
-		__put_user (regs->regs[i], data + i);
-	__put_user (regs->lo, data + EF_LO - EF_R0);
-	__put_user (regs->hi, data + EF_HI - EF_R0);
-	__put_user (regs->cp0_epc, data + EF_CP0_EPC - EF_R0);
-	__put_user (regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0);
-	__put_user (regs->cp0_status, data + EF_CP0_STATUS - EF_R0);
-	__put_user (regs->cp0_cause, data + EF_CP0_CAUSE - EF_R0);
+		__put_user ((long)regs->regs[i], data + i);
+	__put_user ((long)regs->lo, data + EF_LO - EF_R0);
+	__put_user ((long)regs->hi, data + EF_HI - EF_R0);
+	__put_user ((long)regs->cp0_epc, data + EF_CP0_EPC - EF_R0);
+	__put_user ((long)regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0);
+	__put_user ((long)regs->cp0_status, data + EF_CP0_STATUS - EF_R0);
+	__put_user ((long)regs->cp0_cause, data + EF_CP0_CAUSE - EF_R0);
 
 	return 0;
 }
@@ -403,11 +403,11 @@ long arch_ptrace(struct task_struct *chi
 		}
 
 	case PTRACE_GETREGS:
-		ret = ptrace_getregs (child, (__u64 __user *) data);
+		ret = ptrace_getregs (child, (__s64 __user *) data);
 		break;
 
 	case PTRACE_SETREGS:
-		ret = ptrace_setregs (child, (__u64 __user *) data);
+		ret = ptrace_setregs (child, (__s64 __user *) data);
 		break;
 
 	case PTRACE_GETFPREGS:
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index d9a39c1..2c60320 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -346,11 +346,11 @@ asmlinkage int sys32_ptrace(int request,
 		}
 
 	case PTRACE_GETREGS:
-		ret = ptrace_getregs (child, (__u64 __user *) (__u64) data);
+		ret = ptrace_getregs (child, (__s64 __user *) (__u64) data);
 		break;
 
 	case PTRACE_SETREGS:
-		ret = ptrace_setregs (child, (__u64 __user *) (__u64) data);
+		ret = ptrace_setregs (child, (__s64 __user *) (__u64) data);
 		break;
 
 	case PTRACE_GETFPREGS:

From anemo@mba.ocn.ne.jp Sat Mar  3 17:44:33 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 17:44:38 +0000 (GMT)
Received: from mba.ocn.ne.jp ([210.190.142.172]:51155 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20037679AbXCCRod (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sat, 3 Mar 2007 17:44:33 +0000
Received: from localhost (p6054-ipad201funabasi.chiba.ocn.ne.jp [222.146.69.54])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id 6451BADDE; Sun,  4 Mar 2007 02:43:13 +0900 (JST)
Date:	Sun, 04 Mar 2007 02:43:13 +0900 (JST)
Message-Id: <20070304.024313.63742228.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org
Subject: [PATCH] Cleanup includes in early_printk.c
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14334
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
diff --git a/arch/mips/kernel/early_printk.c b/arch/mips/kernel/early_printk.c
index 5a5f610..304efdc 100644
--- a/arch/mips/kernel/early_printk.c
+++ b/arch/mips/kernel/early_printk.c
@@ -7,10 +7,8 @@
  * Copyright (C) 2007 MIPS Technologies, Inc.
  *   written by Ralf Baechle (ralf@linux-mips.org)
  */
-#include <stdarg.h>
 #include <linux/console.h>
 #include <linux/init.h>
-#include <linux/kernel.h>
 
 extern void prom_putchar(char);
 

From djohnson@sw.starentnetworks.com Sat Mar  3 18:22:13 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 18:22:18 +0000 (GMT)
Received: from newmail.sw.starentnetworks.com ([12.33.234.78]:6790 "EHLO
	mail.sw.starentnetworks.com") by ftp.linux-mips.org with ESMTP
	id S20037592AbXCCSWN (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Mar 2007 18:22:13 +0000
Received: from zeus.sw.starentnetworks.com (zeus.sw.starentnetworks.com [12.33.233.46])
	by mail.sw.starentnetworks.com (Postfix) with ESMTP id 7A5543E38E
	for <linux-mips@linux-mips.org>; Sat,  3 Mar 2007 13:20:31 -0500 (EST)
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Message-ID: <17897.48239.366047.442797@zeus.sw.starentnetworks.com>
Date:	Sat, 3 Mar 2007 13:20:31 -0500
From:	Dave Johnson <djohnson+linux-mips@sw.starentnetworks.com>
To:	linux-mips@linux-mips.org
Subject: SMP+PREEMPT causes NULL dereference in khelper on startup
X-Mailer: VM 7.17 under 21.4 (patch 17) "Jumbo Shrimp" XEmacs Lucid
Return-Path: <djohnson@sw.starentnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14335
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: djohnson+linux-mips@sw.starentnetworks.com
Precedence: bulk
X-list: linux-mips


Sibyte 1250, tested on both A8 and B2 steppings.

Code is from linux-mips.org's git tree at 2.6.18 plus some patches
from 2.6.18.7.

I can boot fine with SMP, and I can boot fine with PREEMPT, but if I
turn on both, I get this crash during kernel startup every time.

For another datapoint, I changed plat_smp_setup() to only bring online
1 core.  Just building with SMP+PREEMPT (running on a single core) is
enough to cause the problem.


CPU 0 Unable to handle kernel paging request at virtual address 0000000000000000, epc == ffffffff80154fa8, ra == ffffffff8013d508
Oops[#1]:
Cpu 0
$ 0   : 0000000000000000 0000000014001fe0 0000000000000000 0000000000000000
$ 4   : 0000000000000000 a8000000cffd3688 0000000000000001 000000000000000c
$ 8   : a8000000007b1f88 0000000000000000 0000000000000000 0000000000000000
$12   : 0000000000000008 ffffffff80284188 0000000000000000 0000000000000000
$16   : a80000000fea0cc0 ffffffff80154f78 ffffffff80586618 a800000007fee1a0
$20   : ffffffff8054f000 ffffffff80131b30 0000000000000000 ffffffff80285210
$24   : 0000000000000000 0000000000000000 a80000000fea0cc0 a80000000fea2160
$28   : a800000008990000 a800000008993ea0 ffffffff80269c70 ffffffff8013d508
Hi    : 0000000000000000
Lo    : 0000000000000000
epc   : ffffffff80154fa8 detach_pid+0x30/0x90     Not tainted
ra    : ffffffff8013d508 __unhash_process+0xf8/0x158
Status: 14001fe2    KX SX UX KERNEL EXL 
Cause : 9080800c
BadVA : 0000000000000000
PrId  : 01040102
Modules linked in:
Process khelper (pid: 12, threadinfo=a800000008990000, task=a80000000fea0cc0)
Stack : ffffffff8013d508 ffffffff803d24c8 a8000000007b1d20 a80000000fea0cc0
        a800000007fef1a8 ffffffff8013d690 a80000000fea0cc0 a80000000fea1980
        0000000000000000 0000000000000020 ffffffff8013d8a8 a80000000fea1980
        a800000008993f20 a80000000fea1980 a80000000fea0cc0 ffffffff8013ef58
        a800000008993f20 a800000008993f20 0000000000000000 a80000000fea0cc0
        ffffffff80131c68 ffffffff803cfd40 ffffffff8012ecd8 ffffffff8013f6c0
        0000000000000000 0000000000000000 a800000083a23d68 0000000000000000
        0000000000000000 0000000000000000 0000000000000000 0000000000000000
        0000000000000000 0000000000000000 0000000000000000 ffffffff80153058
        0000000000000000 ffffffff80106448 0000000000000000 ffffffff80106438
        ...
Call Trace:
[<ffffffff80154fa8>] detach_pid+0x30/0x90
[<ffffffff8013d508>] __unhash_process+0xf8/0x158
[<ffffffff8013d690>] __exit_signal+0x128/0x228
[<ffffffff8013d8a8>] release_task+0xb8/0x1a8
[<ffffffff8013ef58>] exit_notify+0x220/0x408
[<ffffffff8013f6c0>] do_exit+0x580/0x8c8
[<ffffffff80153058>] wait_for_helper+0x0/0xb0
Code: dc820178  dca30008  dca40010 <10400002> fc620000  fc430008  3c020020  34420200  fca00010 
Kernel panic - not syncing: Fatal exception


Disassembly shows:

ffffffff80154f78 <detach_pid>:
ffffffff80154f78:       0005283c        dsll32  a1,a1,0x0
ffffffff80154f7c:       67bdfff0        daddiu  sp,sp,-16

ffffffff80154f80 <$LCFI28>:
ffffffff80154f80:       0005283e        dsrl32  a1,a1,0x0
ffffffff80154f84:       ffbf0000        sd      ra,0(sp)

ffffffff80154f88 <$LCFI29>:
ffffffff80154f88:       00051078        dsll    v0,a1,0x1
ffffffff80154f8c:       0045102d        daddu   v0,v0,a1
ffffffff80154f90:       000210f8        dsll    v0,v0,0x3
ffffffff80154f94:       0082202d        daddu   a0,a0,v0
ffffffff80154f98:       64850178        daddiu  a1,a0,376      <<< a1 = a8000000cffd3688 => link

ffffffff80154f9c <$LBB73>:
ffffffff80154f9c:       dc820178        ld      v0,376(a0)     <<< v0 = 0000000000000000 => link->node->next
ffffffff80154fa0:       dca30008        ld      v1,8(a1)       <<< v1 = 0000000000000000 => link->node->ppriv

ffffffff80154fa4 <$LBE73>:
ffffffff80154fa4:       dca40010        ld      a0,16(a1)      <<< a0 = 0000000000000000 => pid

ffffffff80154fa8 <$LBB76>:
ffffffff80154fa8:       10400002        beqz    v0,ffffffff80154fb4 <$L166>
ffffffff80154fac:       fc620000        sd      v0,0(v1)       <<< '*pprev = next' => BOOM!
ffffffff80154fb0:       fc430008        sd      v1,8(v0)
[...]

It appears a0 to detach_pid (*task) points to somewhere wrong as
'link' (now in a1) is a valid pointer, but points to a bunch of
zeros.


-- 
Dave Johnson
Starent Networks


From ralf@linux-mips.org Sat Mar  3 20:47:15 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 20:47:16 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:35472 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037678AbXCCUrP (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Mar 2007 20:47:15 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l23KlCJV026029;
	Sat, 3 Mar 2007 20:47:12 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l23KlBlP026028;
	Sat, 3 Mar 2007 20:47:11 GMT
Date:	Sat, 3 Mar 2007 20:47:11 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH] Cleanup includes in early_printk.c
Message-ID: <20070303204711.GA25866@linux-mips.org>
References: <20070304.024313.63742228.anemo@mba.ocn.ne.jp>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20070304.024313.63742228.anemo@mba.ocn.ne.jp>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14336
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Sun, Mar 04, 2007 at 02:43:13AM +0900, Atsushi Nemoto wrote:

Thanks, applied.

  Ralf

From ralf@linux-mips.org Sat Mar  3 21:13:04 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Mar 2007 21:13:06 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:29859 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037687AbXCCVNE (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Mar 2007 21:13:04 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l23FVpp0017951
	for <linux-mips@linux-mips.org>; Sat, 3 Mar 2007 15:31:51 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l23F3ExR005359;
	Sat, 3 Mar 2007 15:03:14 GMT
Date:	Sat, 3 Mar 2007 15:03:14 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Martin Michlmayr <tbm@cyrius.com>
Cc:	linux-mips@linux-mips.org
Subject: Re: Creating infrastructure to allow one kernel for multiple machines
Message-ID: <20070303150314.GE16562@linux-mips.org>
References: <20070227144818.GA25883@deprecation.cyrius.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20070227144818.GA25883@deprecation.cyrius.com>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14337
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Tue, Feb 27, 2007 at 02:48:18PM +0000, Martin Michlmayr wrote:

> On ARM and PowerPC, you can compile one kernel that will support
> multiple machines, as long as they all belong to the same group (e.g.
> have a compatible CPU).  On ARM, each machine needs to register a
> machine id at http://www.arm.linux.org.uk/developer/machines/ and then
> the boot loader passes this value to the kernel via a register.  On
> PowerPC, information about the machine can be found in OF's
> device-tree.
> 
> On MIPS, you need a separate kernel for each machine, which makes it
> hard for distros to support many machines.  For example, it would be
> nice if you could compile one kernel for vr41xx devices since they
> only differ slightly, e.g. in their PCI mappings.  I'm therefore
> wondering if there are any plans to introduce a scheme on MIPS that
> would allow one kernel for several machines.

In some cases that works but in many case it would simply be painful or
even impossible to implement due to conflicting load addresses, different
word sizes or endianess.  Probing for the system type would be required
and that would turn out to be about as fun as ISA probing.  So there
are limitations and within those I'm not so sure if the pain would be
justifyable.  As usual, I however will consider patches :-9

  Ralf

From marco.braga@gmail.com Sun Mar  4 12:27:41 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Mar 2007 12:27:43 +0000 (GMT)
Received: from an-out-0708.google.com ([209.85.132.249]:27214 "EHLO
	an-out-0708.google.com") by ftp.linux-mips.org with ESMTP
	id S20038418AbXCDM1l (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sun, 4 Mar 2007 12:27:41 +0000
Received: by an-out-0708.google.com with SMTP id c8so1100980ana
        for <linux-mips@linux-mips.org>; Sun, 04 Mar 2007 04:27:37 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:mime-version:content-type;
        b=az89yB9YBI9ZnX2G9Be1TQ5AKO71asiwlhhJVoVACojvp81gN5HvBT87acWhKElE5hSQ2KM8mu5ngjRRtL5bKulrpYZEfAFP89+4mie6I50kBBMglQp5DPFZXgq41nPI9kNDby09+A+Hate5vogYO1ji4hwaMNjNmjpPW6on46k=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:mime-version:content-type;
        b=iJOokR0xIHHDuBocAiBzTza6Ue4odppLjh0FEsTmPpBVDMYydUiNldZiBMTiyboVgEamks/JHLZ9jLZUEdMRGF2xHYzoMAztuo3FmZCy/A4TwxtEYdOq7UA3DE5Kx5ycrbkYC0QNEQZe2eiTIuVIX8sFqkyqZCPW/0Ks10EKGns=
Received: by 10.114.126.1 with SMTP id y1mr940827wac.1173011257053;
        Sun, 04 Mar 2007 04:27:37 -0800 (PST)
Received: by 10.114.80.18 with HTTP; Sun, 4 Mar 2007 04:27:37 -0800 (PST)
Message-ID: <d459bb380703040427g4a8cad08kd8e3190f7d109c86@mail.gmail.com>
Date:	Sun, 4 Mar 2007 13:27:37 +0100
From:	"Marco Braga" <marco.braga@gmail.com>
To:	linux-mips@linux-mips.org
Subject: Linux kernel 2.6.20, PCI and hpt266
MIME-Version: 1.0
Content-Type: multipart/alternative; 
	boundary="----=_Part_114607_12873744.1173011257020"
Return-Path: <marco.braga@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14338
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: marco.braga@gmail.com
Precedence: bulk
X-list: linux-mips

------=_Part_114607_12873744.1173011257020
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hello, I am trying to run kernel 2.6.20 on an Au1500 based board. Versions
2.4.x of the kernel are correctly working.

Problem: on the board there is a HighPoint 371N ATA controller. At the
moment the kernel 2.6.20 boots and runs, but the ATA controller does not
recognize the IDE disk.

Details:
The driver I use is "drivers/ide/pci/hpt266.c". I've already fixed the
timing problems and PLL configuration that afflict this controller, and
removed RESOURCE_64BIT to fix problems with the PCI bus on mips and
resource_size_t casts.

I've managed to follow the problem to ide-probe.c, in function
"actual_try_to_identify". It seems that the values read from the ATA
registers through IO ports are not correct. As every ATA controller, it
needs 8 bytes in IO port space for Command Block registers, and 4 bytes for
the Control Block registers. They are mapped by the kernel at:

1400-1407 (8 bytes) Command block channel 0
1408-140F (8 bytes) Command block channel 1
1410-1413 (4 bytes) Control block channel 0
1414-1417 (4 bytes) Control block channel 1

Notice that Highpoint 371N has registers for 2 channel, but the pinout for
only 1 channel. In fact the first channel is disabled by the driver, so the
actual registers are in the range 1408-140F and 1414-1417. The first sign of
the problem is that INB do not read the correct values for the ALTSTATUS
register. In fact the kernel reports:

 ... probing with STATUS(...) instead of ALTSTATUS(...)

[as in ide-probe.c, line 290]

The values read from the ATA registers are completely wrong. The registers
are accessed through hwif->INB, that are common "inb" functions. This makes
me suspect that "inX" functions are not working, but I don't know how to
test this. Notice that the PCI controller configuration space is correctly
accessed, as I can confirm reading sys/bus/pci/.../config.

Can you help or suggest me anything?
Thanx!

------=_Part_114607_12873744.1173011257020
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hello, I am trying to run kernel 2.6.20 on an Au1500 based board. Versions 2.4.x of the kernel are correctly working.<br><br>Problem: on the board there is a HighPoint 371N ATA controller. At the moment the kernel 2.6.20 boots and runs, but the ATA controller does not recognize the IDE disk.
<br><br>Details:<br>The driver I use is &quot;drivers/ide/pci/hpt266.c&quot;. I&#39;ve already fixed the timing problems and PLL configuration that afflict this controller, and removed RESOURCE_64BIT to fix problems with the PCI bus on mips and resource_size_t casts.
<br><br>I&#39;ve managed to follow the problem to ide-probe.c, in function &quot;actual_try_to_identify&quot;. It seems that the values read from the ATA registers through IO ports are not correct. As every ATA controller, it needs 8 bytes in IO port space for Command Block registers, and 4 bytes for the Control Block registers. They are mapped by the kernel at:
<br><br>1400-1407 (8 bytes) Command block channel 0<br>1408-140F (8 bytes) Command block channel 1<br>1410-1413 (4 bytes) Control block channel 0<br>1414-1417 (4 bytes) Control block channel 1<br><br>Notice that Highpoint 371N has registers for 2 channel, but the pinout for only 1 channel. In fact the first channel is disabled by the driver, so the actual registers are in the range 1408-140F and 1414-1417. The first sign of the problem is that INB do not read the correct values for the ALTSTATUS register. In fact the kernel reports:
<br><br>&nbsp;... probing with STATUS(...) instead of ALTSTATUS(...)<br><br>[as in ide-probe.c, line 290]<br><br>The values read from the ATA registers are completely wrong. The registers are accessed through hwif-&gt;INB, that are common &quot;inb&quot; functions. This makes me suspect that &quot;inX&quot; functions are not working, but I don&#39;t know how to test this. Notice that the PCI controller configuration space is correctly accessed, as I can confirm reading sys/bus/pci/.../config.
<br><br>Can you help or suggest me anything?<br>Thanx!<br><br>

------=_Part_114607_12873744.1173011257020--

From anemo@mba.ocn.ne.jp Sun Mar  4 15:43:02 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Mar 2007 15:43:05 +0000 (GMT)
Received: from mba.ocn.ne.jp ([210.190.142.172]:38134 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20038823AbXCDPnC (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sun, 4 Mar 2007 15:43:02 +0000
Received: from localhost (p4244-ipad29funabasi.chiba.ocn.ne.jp [221.184.71.244])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id 13F58D31; Mon,  5 Mar 2007 00:41:39 +0900 (JST)
Date:	Mon, 05 Mar 2007 00:41:39 +0900 (JST)
Message-Id: <20070305.004139.89066671.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org
Subject: [PATCH] Remove redundant tx39_blast_icache() calls
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14339
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

Apply commit 0550d9d13e02b30efa117d47fcadea450bb23d23 to c-tx39.c too.
And fix a warning in local_tx39_flush_data_cache_page().

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c
index f32ebde..560a6de 100644
--- a/arch/mips/mm/c-tx39.c
+++ b/arch/mips/mm/c-tx39.c
@@ -128,7 +128,6 @@ static inline void tx39_flush_cache_all(
 		return;
 
 	tx39_blast_dcache();
-	tx39_blast_icache();
 }
 
 static inline void tx39___flush_cache_all(void)
@@ -142,24 +141,19 @@ static void tx39_flush_cache_mm(struct m
 	if (!cpu_has_dc_aliases)
 		return;
 
-	if (cpu_context(smp_processor_id(), mm) != 0) {
-		tx39_flush_cache_all();
-	}
+	if (cpu_context(smp_processor_id(), mm) != 0)
+		tx39_blast_dcache();
 }
 
 static void tx39_flush_cache_range(struct vm_area_struct *vma,
 	unsigned long start, unsigned long end)
 {
-	int exec;
-
+	if (!cpu_has_dc_aliases)
+		return;
 	if (!(cpu_context(smp_processor_id(), vma->vm_mm)))
 		return;
 
-	exec = vma->vm_flags & VM_EXEC;
-	if (cpu_has_dc_aliases || exec)
-		tx39_blast_dcache();
-	if (exec)
-		tx39_blast_icache();
+	tx39_blast_dcache();
 }
 
 static void tx39_flush_cache_page(struct vm_area_struct *vma, unsigned long page, unsigned long pfn)
@@ -218,7 +212,7 @@ static void tx39_flush_cache_page(struct
 
 static void local_tx39_flush_data_cache_page(void * addr)
 {
-	tx39_blast_dcache_page(addr);
+	tx39_blast_dcache_page((unsigned long)addr);
 }
 
 static void tx39_flush_data_cache_page(unsigned long addr)

From ralf@linux-mips.org Sun Mar  4 16:22:20 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Mar 2007 16:22:22 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:53389 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037751AbXCDQWU (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sun, 4 Mar 2007 16:22:20 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l24GKVoK002890
	for <linux-mips@linux-mips.org>; Sun, 4 Mar 2007 16:20:31 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l24GKUIu002889
	for linux-mips@linux-mips.org; Sun, 4 Mar 2007 16:20:30 GMT
Date:	Sun, 4 Mar 2007 16:20:30 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	linux-mips@linux-mips.org
Subject: PNX8550_V2PCI build breakage
Message-ID: <20070304162030.GA2853@linux-mips.org>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14340
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

pnx8550-v2pci_defconfig fails with:

  AR      arch/mips/lib-32/lib.a
  GEN     .version
  CHK     include/linux/compile.h
  UPD     include/linux/compile.h
  CC      init/version.o
  LD      init/built-in.o
  LD      .tmp_vmlinux1
/usr/bin/mipsel-linux-ld:arch/mips/kernel/vmlinux.lds:37: syntax error
make: *** [.tmp_vmlinux1] Error 1

Can somebody PNX knowledgable take care of that?

  Ralf

From yoichi_yuasa@tripeaks.co.jp Sun Mar  4 20:50:14 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Mar 2007 20:50:17 +0000 (GMT)
Received: from mo31.po.2iij.net ([210.128.50.54]:40523 "EHLO mo31.po.2iij.net")
	by ftp.linux-mips.org with ESMTP id S20037729AbXCDUuO (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sun, 4 Mar 2007 20:50:14 +0000
Received: by mo.po.2iij.net (mo31) id l24KmsMT041647; Mon, 5 Mar 2007 05:48:54 +0900 (JST)
Received: from localhost.localdomain (70.27.30.125.dy.iij4u.or.jp [125.30.27.70])
	by mbox.po.2iij.net (mbox30) id l24Kmq2O039567
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT);
	Mon, 5 Mar 2007 05:48:53 +0900 (JST)
Date:	Mon, 5 Mar 2007 05:48:51 +0900
From:	Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	yoichi_yuasa@tripeaks.co.jp, linux-mips@linux-mips.org
Subject: Re: [PATCH][MIPS] fix Cobalt early printk
Message-Id: <20070305054851.492386c8.yoichi_yuasa@tripeaks.co.jp>
In-Reply-To: <20070302133644.GB19957@linux-mips.org>
References: <20070302124233.6b9f2c67.yoichi_yuasa@tripeaks.co.jp>
	<20070302133644.GB19957@linux-mips.org>
Organization: TriPeaks Corporation
X-Mailer: Sylpheed version 1.0.6 (GTK+ 1.2.10; i486-pc-linux-gnu)
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Return-Path: <yoichi_yuasa@tripeaks.co.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14341
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: yoichi_yuasa@tripeaks.co.jp
Precedence: bulk
X-list: linux-mips

Hi Ralf,

On Fri, 2 Mar 2007 13:36:44 +0000
Ralf Baechle <ralf@linux-mips.org> wrote:

> On Fri, Mar 02, 2007 at 12:42:33PM +0900, Yoichi Yuasa wrote:
> 
> > This patch has fixed Cobalt early printk.
> 
> Applied.  Thanks,

It's only applied to 2.6.20-stable.
Please apply to master too.

Yoichi

From ralf@linux-mips.org Sun Mar  4 21:37:38 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Mar 2007 21:37:40 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:18111 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037832AbXCDVhi (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sun, 4 Mar 2007 21:37:38 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l24LZj8i008185;
	Sun, 4 Mar 2007 21:35:45 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l24LZhet008184;
	Sun, 4 Mar 2007 21:35:43 GMT
Date:	Sun, 4 Mar 2007 21:35:43 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH][MIPS] fix Cobalt early printk
Message-ID: <20070304213543.GA8141@linux-mips.org>
References: <20070302124233.6b9f2c67.yoichi_yuasa@tripeaks.co.jp> <20070302133644.GB19957@linux-mips.org> <20070305054851.492386c8.yoichi_yuasa@tripeaks.co.jp>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20070305054851.492386c8.yoichi_yuasa@tripeaks.co.jp>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14342
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Mon, Mar 05, 2007 at 05:48:51AM +0900, Yoichi Yuasa wrote:

> On Fri, 2 Mar 2007 13:36:44 +0000
> Ralf Baechle <ralf@linux-mips.org> wrote:
> 
> > On Fri, Mar 02, 2007 at 12:42:33PM +0900, Yoichi Yuasa wrote:
> > 
> > > This patch has fixed Cobalt early printk.
> > 
> > Applied.  Thanks,
> 
> It's only applied to 2.6.20-stable.
> Please apply to master too.

Indeed.  Worse, the patch happened to apply cleanly on 2.6.20-stable but
doesn't work there so I reverted it on 2.6.20 and applied it on master.

Thanks,

  Ralf

From ralf@linux-mips.org Sun Mar  4 22:05:37 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Mar 2007 22:05:38 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:50899 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037729AbXCDWFh (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sun, 4 Mar 2007 22:05:37 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l24M3l50013751;
	Sun, 4 Mar 2007 22:03:47 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l24M3kOQ013750;
	Sun, 4 Mar 2007 22:03:46 GMT
Date:	Sun, 4 Mar 2007 22:03:46 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH] Remove redundant tx39_blast_icache() calls
Message-ID: <20070304220346.GA13508@linux-mips.org>
References: <20070305.004139.89066671.anemo@mba.ocn.ne.jp>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20070305.004139.89066671.anemo@mba.ocn.ne.jp>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14343
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Mon, Mar 05, 2007 at 12:41:39AM +0900, Atsushi Nemoto wrote:

> Apply commit 0550d9d13e02b30efa117d47fcadea450bb23d23 to c-tx39.c too.
> And fix a warning in local_tx39_flush_data_cache_page().

Applied, thanks.

  Ralf

From maillist@jg555.com Sun Mar  4 23:20:03 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Mar 2007 23:20:05 +0000 (GMT)
Received: from rrcs-64-183-102-11.west.biz.rr.com ([64.183.102.11]:52426 "EHLO
	jg555.com") by ftp.linux-mips.org with ESMTP id S20038414AbXCDXUD
	(ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sun, 4 Mar 2007 23:20:03 +0000
Received: from [192.168.55.157] ([::ffff:192.168.55.157])
  (AUTH: PLAIN root, TLS: TLSv1/SSLv3,256bits,AES256-SHA)
  by jg555.com with esmtp; Sun, 04 Mar 2007 15:18:57 -0800
  id 0047C25C.45EB53E1.0000556C
Message-ID: <45EB53D5.8060007@jg555.com>
Date:	Sun, 04 Mar 2007 15:18:45 -0800
From:	Jim Gifford <maillist@jg555.com>
User-Agent: Thunderbird 1.5.0.10 (Windows/20070221)
MIME-Version: 1.0
To:	Linux MIPS List <linux-mips@linux-mips.org>
Subject: Building 64 bit kernel on Cobalt
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <maillist@jg555.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14344
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: maillist@jg555.com
Precedence: bulk
X-list: linux-mips

Last working Kernel was 2.6.19 series.

Some changes from 2.6.19 and the 2.6.20 make it impossible to build a 64 
bit kernel to boot on the cobalt. Ya, I know why, building a N32 
actually but need a 64 bit kernel in order to do that. Anyone got any 
suggestions. Looking through the difference between the kernels to 
figure this out, but it's like looking for a needle in a haystack. Any 
suggestions as to a starting point?

From ralf@linux-mips.org Sun Mar  4 23:29:22 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Mar 2007 23:29:23 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:2206 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20038411AbXCDX3W (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sun, 4 Mar 2007 23:29:22 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l24NRWXs025650;
	Sun, 4 Mar 2007 23:27:32 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l24NRVuI025649;
	Sun, 4 Mar 2007 23:27:31 GMT
Date:	Sun, 4 Mar 2007 23:27:31 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Jim Gifford <maillist@jg555.com>
Cc:	Linux MIPS List <linux-mips@linux-mips.org>
Subject: Re: Building 64 bit kernel on Cobalt
Message-ID: <20070304232731.GA25039@linux-mips.org>
References: <45EB53D5.8060007@jg555.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <45EB53D5.8060007@jg555.com>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14345
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Sun, Mar 04, 2007 at 03:18:45PM -0800, Jim Gifford wrote:

> Last working Kernel was 2.6.19 series.
> 
> Some changes from 2.6.19 and the 2.6.20 make it impossible to build a 64 
> bit kernel to boot on the cobalt. Ya, I know why, building a N32 
> actually but need a 64 bit kernel in order to do that. Anyone got any 
> suggestions. Looking through the difference between the kernels to 
> figure this out, but it's like looking for a needle in a haystack. Any 
> suggestions as to a starting point?

Try git-bisect to track down the changeset that broke things.

  Ralf

From yoichi_yuasa@tripeaks.co.jp Mon Mar  5 10:11:26 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 10:11:30 +0000 (GMT)
Received: from mo32.po.2iij.net ([210.128.50.17]:56332 "EHLO mo32.po.2iij.net")
	by ftp.linux-mips.org with ESMTP id S20037348AbXCEKL0 (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Mon, 5 Mar 2007 10:11:26 +0000
Received: by mo.po.2iij.net (mo32) id l25AA4cp059000; Mon, 5 Mar 2007 19:10:04 +0900 (JST)
Received: from localhost.localdomain (65.126.232.202.bf.2iij.net [202.232.126.65])
	by mbox.po.2iij.net (mbox32) id l25AA3Of016823
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT);
	Mon, 5 Mar 2007 19:10:03 +0900 (JST)
Date:	Mon, 5 Mar 2007 19:10:03 +0900
From:	Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	yoichi_yuasa@tripeaks.co.jp, linux-mips <linux-mips@linux-mips.org>
Subject: [PATCH][MIPS] separate Cobalt PCI codes from setup.c
Message-Id: <20070305191003.5357b4bf.yoichi_yuasa@tripeaks.co.jp>
Organization: TriPeaks Corporation
X-Mailer: Sylpheed version 1.0.4 (GTK+ 1.2.10; i386-pc-linux-gnu)
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Return-Path: <yoichi_yuasa@tripeaks.co.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14346
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: yoichi_yuasa@tripeaks.co.jp
Precedence: bulk
X-list: linux-mips

Hi Ralf,

This patch has separated cobalt PCI codes from setup.c .
It's removed #ifdef CONFIG_PCI/#endif from cobalt setup.c .

Yoichi

Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>

diff -pruN -X mips/Documentation/dontdiff mips-orig/arch/mips/cobalt/Makefile mips/arch/mips/cobalt/Makefile
--- mips-orig/arch/mips/cobalt/Makefile	2007-03-02 09:56:33.696816750 +0900
+++ mips/arch/mips/cobalt/Makefile	2007-03-02 09:55:59.466677500 +0900
@@ -4,5 +4,6 @@
 
 obj-y	 := irq.o reset.o setup.o
 
+obj-$(CONFIG_PCI)		+= pci.o
 obj-$(CONFIG_EARLY_PRINTK)	+= console.o
 obj-$(CONFIG_MTD_PHYSMAP)	+= mtd.o
diff -pruN -X mips/Documentation/dontdiff mips-orig/arch/mips/cobalt/pci.c mips/arch/mips/cobalt/pci.c
--- mips-orig/arch/mips/cobalt/pci.c	1970-01-01 09:00:00.000000000 +0900
+++ mips/arch/mips/cobalt/pci.c	2007-03-02 09:55:59.486678750 +0900
@@ -0,0 +1,47 @@
+/*
+ * Register PCI controller.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1996, 1997, 2004, 05 by Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
+ *
+ */
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/gt64120.h>
+
+extern struct pci_ops gt64111_pci_ops;
+
+static struct resource cobalt_mem_resource = {
+	.start	= GT_DEF_PCI0_MEM0_BASE,
+	.end	= GT_DEF_PCI0_MEM0_BASE + GT_DEF_PCI0_MEM0_SIZE - 1,
+	.name	= "PCI memory",
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct resource cobalt_io_resource = {
+	.start	= 0x1000,
+	.end	= GT_DEF_PCI0_IO_SIZE - 1,
+	.name	= "PCI I/O",
+	.flags	= IORESOURCE_IO,
+};
+
+static struct pci_controller cobalt_pci_controller = {
+	.pci_ops	= &gt64111_pci_ops,
+	.mem_resource	= &cobalt_mem_resource,
+	.io_resource	= &cobalt_io_resource,
+	.io_offset	= 0 - GT_DEF_PCI0_IO_BASE,
+};
+
+static int __init cobalt_pci_init(void)
+{
+	register_pci_controller(&cobalt_pci_controller);
+
+	return 0;
+}
+
+arch_initcall(cobalt_pci_init);
diff -pruN -X mips/Documentation/dontdiff mips-orig/arch/mips/cobalt/setup.c mips/arch/mips/cobalt/setup.c
--- mips-orig/arch/mips/cobalt/setup.c	2007-03-02 09:56:33.984834750 +0900
+++ mips/arch/mips/cobalt/setup.c	2007-03-02 09:55:59.490679000 +0900
@@ -63,22 +63,6 @@ void __init plat_timer_setup(struct irqa
 	GT_WRITE(GT_INTRMASK_OFS, GT_INTR_T0EXP_MSK | GT_READ(GT_INTRMASK_OFS));
 }
 
-extern struct pci_ops gt64111_pci_ops;
-
-static struct resource cobalt_mem_resource = {
-	.start	= GT_DEF_PCI0_MEM0_BASE,
-	.end	= GT_DEF_PCI0_MEM0_BASE + GT_DEF_PCI0_MEM0_SIZE - 1,
-	.name	= "PCI memory",
-	.flags	= IORESOURCE_MEM
-};
-
-static struct resource cobalt_io_resource = {
-	.start	= 0x1000,
-	.end	= 0xffff,
-	.name	= "PCI I/O",
-	.flags	= IORESOURCE_IO
-};
-
 /*
  * Cobalt doesn't have PS/2 keyboard/mouse interfaces,
  * keyboard conntroller is never used.
@@ -111,14 +95,6 @@ static struct resource cobalt_reserved_r
 	},
 };
 
-static struct pci_controller cobalt_pci_controller = {
-	.pci_ops	= &gt64111_pci_ops,
-	.mem_resource	= &cobalt_mem_resource,
-	.mem_offset	= 0,
-	.io_resource	= &cobalt_io_resource,
-	.io_offset	= 0 - GT_DEF_PCI0_IO_BASE,
-};
-
 void __init plat_mem_setup(void)
 {
 	static struct uart_port uart;
@@ -146,10 +122,6 @@ void __init plat_mem_setup(void)
 
 	printk("Cobalt board ID: %d\n", cobalt_board_id);
 
-#ifdef CONFIG_PCI
-	register_pci_controller(&cobalt_pci_controller);
-#endif
-
 	if (cobalt_board_id > COBALT_BRD_ID_RAQ1) {
 #ifdef CONFIG_SERIAL_8250
 		uart.line	= 0;

From akpm@linux-foundation.org Mon Mar  5 10:21:05 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 10:21:07 +0000 (GMT)
Received: from smtp.osdl.org ([65.172.181.24]:22172 "EHLO smtp.osdl.org")
	by ftp.linux-mips.org with ESMTP id S20037396AbXCEKVF (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Mon, 5 Mar 2007 10:21:05 +0000
Received: from shell0.pdx.osdl.net (fw.osdl.org [65.172.181.6])
	by smtp.osdl.org (8.12.8/8.12.8) with ESMTP id l25AHjq8018485
	(version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=NO);
	Mon, 5 Mar 2007 02:17:45 -0800
Received: from box (shell0.pdx.osdl.net [10.9.0.31])
	by shell0.pdx.osdl.net (8.13.1/8.11.6) with SMTP id l25AHjNJ015821;
	Mon, 5 Mar 2007 02:17:45 -0800
Date:	Mon, 5 Mar 2007 02:17:44 -0800
From:	Andrew Morton <akpm@linux-foundation.org>
To:	Marc St-Jean <stjeanma@pmc-sierra.com>
Cc:	linux-kernel@vger.kernel.org, linux-mips@linux-mips.org
Subject: Re: [PATCH] drivers: PMC MSP71xx TWI driver
Message-Id: <20070305021744.bb34a7ce.akpm@linux-foundation.org>
In-Reply-To: <200702262348.l1QNm6LY015085@pasqua.pmc-sierra.bc.ca>
References: <200702262348.l1QNm6LY015085@pasqua.pmc-sierra.bc.ca>
X-Mailer: Sylpheed version 2.2.7 (GTK+ 2.8.17; x86_64-unknown-linux-gnu)
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
X-MIMEDefang-Filter: osdl$Revision: 1.176 $
X-Scanned-By: MIMEDefang 2.36
Return-Path: <akpm@linux-foundation.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14347
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: akpm@linux-foundation.org
Precedence: bulk
X-list: linux-mips

Previous comments apply - please convert all this code to kernel coding style.

There are many typecasts of void*, eg:

> +	struct pmcmsp_priv_data *p = (struct pmcmsp_priv_data*)data;

Such casts are unneeded and give an undesirable decrease in typesafety - please
remove them all.

pmcmsp_priv_data.lock should be converted from semaphore to a mutex

Convert u_intN_t -> uN throughout.

Convert all symbol of the form getClockConfig to (in this case)
get_clock_config.

These:

> +/* The default settings */
> +const static struct pmctwi_clockcfg pmctwi_defclockcfg = {
> +	.standard = {
> +		.filter = 0x3,
> +		.clock = 0x1f,
> +	},
> +	.highspeed = {
> +		.filter = 0x3,
> +		.clock = 0x1f,
> +	},
> +};
> +
> +const static struct pmctwi_cfg pmctwi_deftwicfg = {
> +	.arbf		= 0x03,
> +	.nak		= 0x03,
> +	.add10		= 0x00,
> +	.mst_code	= 0x00,
> +	.arb		= 0x01,
> +	.highspeed	= 0x00,
> +};

Should be in a .c file, not a .h file.

From akpm@linux-foundation.org Mon Mar  5 10:21:30 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 10:21:34 +0000 (GMT)
Received: from smtp.osdl.org ([65.172.181.24]:22428 "EHLO smtp.osdl.org")
	by ftp.linux-mips.org with ESMTP id S20037410AbXCEKVG (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Mon, 5 Mar 2007 10:21:06 +0000
Received: from shell0.pdx.osdl.net (fw.osdl.org [65.172.181.6])
	by smtp.osdl.org (8.12.8/8.12.8) with ESMTP id l25AHfq8018481
	(version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=NO);
	Mon, 5 Mar 2007 02:17:42 -0800
Received: from box (shell0.pdx.osdl.net [10.9.0.31])
	by shell0.pdx.osdl.net (8.13.1/8.11.6) with SMTP id l25AHf2e015816;
	Mon, 5 Mar 2007 02:17:41 -0800
Date:	Mon, 5 Mar 2007 02:17:41 -0800
From:	Andrew Morton <akpm@linux-foundation.org>
To:	Marc St-Jean <stjeanma@pmc-sierra.com>
Cc:	linux-kernel@vger.kernel.org, linux-mips@linux-mips.org
Subject: Re: [PATCH] drivers: PMC MSP71xx LED driver
Message-Id: <20070305021741.b3e3ee5f.akpm@linux-foundation.org>
In-Reply-To: <200702262348.l1QNmtBV015237@pasqua.pmc-sierra.bc.ca>
References: <200702262348.l1QNmtBV015237@pasqua.pmc-sierra.bc.ca>
X-Mailer: Sylpheed version 2.2.7 (GTK+ 2.8.17; x86_64-unknown-linux-gnu)
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
X-MIMEDefang-Filter: osdl$Revision: 1.176 $
X-Scanned-By: MIMEDefang 2.36
Return-Path: <akpm@linux-foundation.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14348
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: akpm@linux-foundation.org
Precedence: bulk
X-list: linux-mips

> On Mon, 26 Feb 2007 17:48:55 -0600 Marc St-Jean <stjeanma@pmc-sierra.com> wrote:
> [PATCH] drivers: PMC MSP71xx LED driver
> 
> Patch to add LED driver for the PMC-Sierra MSP71xx devices.
> 
> This patch references some platform support files previously
> submitted to the linux-mips@linux-mips.org list.
> 
> Thanks,
> @@ -0,0 +1,464 @@
> +/*
> +    Special LED-over-TWI-PCA9554 driver for PMC Sierra's Garibaldi
> +    (and potentially other) boards
> +
> +    Based on pca9539.c Copyright (C) 2005 Ben Gardner <bgardner@wabtec.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; version 2 of the License.
> +*/
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/kthread.h>
> +#include <linux/i2c.h>
> +
> +#include <msp_led_macros.h>
> +
> +#define POLL_PERIOD msecs_to_jiffies(125) /* Poll at 125ms */
> +
> +/* The externally available "registers" */
> +/* TODO: We must somehow ensure these are in "shared memory" for the other VPE
> + *       to access */
> +u32 _msp_led_register[MSP_LED_COUNT];
> +
> +/* Internal polling data */
> +static struct i2c_client *pmctwiled_device[MSP_LED_NUM_DEVICES];
> +static int pmctwiled_running;
> +static struct task_struct *pmctwiled_pollthread;
> +static u32 private_msp_led_register[MSP_LED_COUNT];
> +static u16 current_period;
> +
> +/* Addresses to scan */
> +#define PMCTWILED_BASEADDRESS	(0x38)
> +
> +static unsigned short normal_i2c[] = {
> +	PMCTWILED_BASEADDRESS + 0,
> +	PMCTWILED_BASEADDRESS + 1,
> +	PMCTWILED_BASEADDRESS + 2,
> +	PMCTWILED_BASEADDRESS + 3,
> +	PMCTWILED_BASEADDRESS + 4,
> +	I2C_CLIENT_END
> +};
> +
> +/* Insmod parameters */
> +I2C_CLIENT_INSMOD_1(pmctwiled);
> +
> +enum pca9554_cmd {
> +	PCA9554_INPUT		= 0,
> +	PCA9554_OUTPUT		= 1,
> +	PCA9554_INVERT		= 2,
> +	PCA9554_DIRECTION	= 3,
> +};
> +
> +static int pmctwiled_attach_adapter(struct i2c_adapter *adapter);
> +static int pmctwiled_detect(struct i2c_adapter *adapter, int address, int kind);
> +static int pmctwiled_detach_client(struct i2c_client *client);
> +
> +/* This is the driver that will be inserted */
> +static struct i2c_driver pmctwiled_driver = {
> +	.driver = {
> +		.name		= "pmctwiled",
> +	},
> +	.attach_adapter	= pmctwiled_attach_adapter,
> +	.detach_client	= pmctwiled_detach_client,
> +};
> +
> +struct pmctwiled_data {
> +	struct i2c_client client;
> +};
> +
> +static int pmctwiled_attach_adapter( struct i2c_adapter *adapter )
> +{
> +	return i2c_probe(adapter, &addr_data, pmctwiled_detect);
> +}
> +
> +/* This function is called by i2c_probe */
> +static int pmctwiled_detect( struct i2c_adapter *adapter, int address, int kind )
> +{
> +	struct i2c_client *new_client = NULL;	/* client structure */
> +	struct pmctwiled_data *data = NULL;		/* local data structure */
> +	int err = 0;
> +	int devId = address - PMCTWILED_BASEADDRESS;
> +
> +	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
> +		goto exit;
> +
> +	/* OK. For now, we presume we have a valid client. We now create the
> +	   client structure, even though we cannot fill it completely yet. */
> +	if (!(data = kzalloc(sizeof(struct pmctwiled_data), GFP_KERNEL))) {

It is more robust to use kzalloc(sizeof(*data), ...) here.

> +		err = -ENOMEM;
> +		goto exit;
> +	}
> +	memset (data, 0x00, sizeof(*data));

As you did here.

This memset is unneeded.

> +	new_client = &data->client;
> +	i2c_set_clientdata(new_client, data);
> +	new_client->addr = address;
> +	new_client->adapter = adapter;
> +	new_client->driver = &pmctwiled_driver;
> +	new_client->flags = 0;
> +
> +	/* Detection:
> +	 *   The pca9554 only has 4 registers (0-3).
> +	 * All other reads should fail
> +	 */
> +	if( i2c_smbus_read_byte_data(new_client, 3) < 0
> +	 || i2c_smbus_read_byte_data(new_client, 4) >= 0 )

Previous coding style comments apply.

> +		goto exit_kfree;
> +
> +	/* Found PCA9554 (probably) */
> +	strlcpy(new_client->name, "pca9554", I2C_NAME_SIZE);
> +	printk( "Detected PCA9554 I/O chip (device %d) at 0x%02x\n",
> +			devId, address);
> +
> +	/* Tell the I2C layer a new client has arrived */
> +	if ((err = i2c_attach_client(new_client)))
> +		goto exit_kfree;
> +
> +	/* Register this in the list of available devices, and set up the
> +	 * initial state */
> +	i2c_smbus_write_byte_data( new_client, PCA9554_OUTPUT,
> +		i2c_smbus_read_byte_data(new_client, PCA9554_INPUT) );
> +	i2c_smbus_write_byte_data( new_client, PCA9554_DIRECTION,
> +			(u8)mspLedInitialInputState[devId] );
> +	pmctwiled_device[devId] = new_client;
> +	
> +	return 0;
> +
> +exit_kfree:
> +	kfree(data);
> +exit:
> +	return err;
> +}
> +
> +static int pmctwiled_detach_client( struct i2c_client *client )
> +{
> +	int err;
> +	int devId = client->addr - PMCTWILED_BASEADDRESS;
> +
> +	/* Clear reference so poll thread doesn't use while detaching */
> +	pmctwiled_device[devId] = NULL;
> +
> +	/* Remove this device from the list of devices */
> +	if ((err = i2c_detach_client(client)))
> +		return err;

Please avoid compounding operations in this manner.  We prefer

	err = i2c_detach_client(client);
	if (err)
		return err;

> +	kfree(i2c_get_clientdata(client));
> +	
> +	return 0;
> +}
>
> ...
>
> +inline void mode_bits_update( u32 *ledRegPtr, msp_led_mode_t mode )
> +{
> +	/* TODO: validate mode*/
> +	*ledRegPtr |= MSP_LED_MODE_MASK;
> +	*ledRegPtr &= (~((u32) MSP_LED_MODE_MASK) | mode);
> +}

Lose the StudlyCaps.   led_reg_ptr here.

> +/**
> + * sync_led_timer_with_polling_count - Synchronizes the led timer with polling thread
> + * 									   count
> + * @ledId: Index for the private led register used to obtain timer information
> + * @ledRegPtr: Pointer to the new led register value
> + *  
> + * returns 0: If led is in its final period
> + * returns 1: If led is in its initial period
> + * 
> + * This function determines if the led timer is in its initial period or the final, 
> + * relative to the TWI-polling thread count (current_period) and updates the previous
> + * timer value in the private led register.  If the state of the led needs to be
> + * turned off (i.e. when the led has timed out) then the mode bits in the current led 
> + * register pointer is set to MSP_LED_OFF and the other data bits are set to 0.         

This comment looks awful in an 80-column display.

> + **/
> +inline int sync_led_timer_with_polling_count( int ledId, u32 *ledRegPtr )

This non-static inline function will cause two copies to be generated: one
in the caller in this C file, one for external callers.

It's too large to inline: delete the `inline' keyword.

> +{
> +	/* Timer variables */
> +	int isInInitialPeriod = 0;
> +	u8 timer, ledTimeOut,initialPeriod, finalPeriod;
> +	u16 totalPeriod;

No StudlyCaps, please.

> +	/* determine the progress into the current cycle, relative to the POLL_PERIOD */
> +	initialPeriod = (u8)(*ledRegPtr >> MSP_LED_INITIALPERIOD_SHIFT);
> +	finalPeriod = (u8)(*ledRegPtr >> MSP_LED_FINALPERIOD_SHIFT);
> +	ledTimeOut = (u8)(*ledRegPtr >> MSP_LED_WATCHDOG_SHIFT);
> +	timer = (u8)(private_msp_led_register[ledId] >> MSP_LED_WATCHDOG_SHIFT);

I assume all these (u8) casts are unneeded.

> +	totalPeriod = (u16)initialPeriod + (u16)finalPeriod;

And here.

> +	if (totalPeriod != 0) {
> +		isInInitialPeriod = (current_period % totalPeriod) < initialPeriod;
> +	}
> +
> +	/* if the ledTimeOut is set, adjust the current state to be either ON or OFF */
> +	if (ledTimeOut > 0) {
> +		if (timer >= ledTimeOut) {
> +			/* set the register to OFF state */
> +			mode_bits_update(ledRegPtr,MSP_LED_OFF);
> +			timer = 0;
> +			
> +			/*
> +			 * TODO:
> +			 * This introduces a race condition with other thread using
> +			 * shared memory and must be fixed.
> +			 */
> +			msp_led_turn_off(ledId);
> +		}
> +		else {
> +			timer += 1;
> +		}
> +		/* update timer */
> +		*ledRegPtr &= ~(0xff << MSP_LED_WATCHDOG_SHIFT);
> +		*ledRegPtr |= (timer << MSP_LED_WATCHDOG_SHIFT);
> +	}
> +	
> +	return isInInitialPeriod;
> +}
> +
> +/**
> + * led_update - Sets the mode bits of the given led register
> + * @ledId - id pertaining to the led that needs update
> + * @prevDirectionBitsPtr - points to the previous direction bits on the bus
> + * @prevDataBitsPtr - points to the previous data bits on the bus
> + * @currDirectionBitsPtr - points to the new direction bits for bus update
> + * @currDataBitsPtr - points to the new data bits for bus update
> + * 
> + * returns 1 - led is in output mode
> + *         0 - led is in input mode and hasn't been updated
> + * 
> + * Sets the given mode value to the given led register.
> + **/
> +inline int led_update( int ledId, u8 *prevDirectionBitsPtr, u8 *prevDataBitsPtr, 
> +						u8 *currDirectionBitsPtr, u8 *currDataBitsPtr )

80-cols.

Remove inline.

> +	u32 currLedReg;
> +	msp_led_mode_t currMode, prevMode;
> +	msp_led_direction_t currDirection, prevDirection;
> +	int isInInitialPeriod;
> +	
> +	/* Read the shared memory into a temporary variable */
> +	int pin = ledId % MSP_LED_NUM_DEVICE_PINS;
> +	currLedReg = _msp_led_register[ledId];
> +				
> +	/* Check if the input direction has changed to output */
> +	prevDirection = (msp_led_direction_t)
> +				((private_msp_led_register[ledId] & MSP_LED_DIRECTION_MASK) >> 
> +				   MSP_LED_DIRECTION_SHIFT);
> +	currDirection = (msp_led_direction_t)
> +				((currLedReg & MSP_LED_DIRECTION_MASK) >>
> +				   MSP_LED_DIRECTION_SHIFT);
> +	if ((prevDirection == MSP_LED_INPUT) && (currDirection != MSP_LED_OUTPUT))
> +		return 0;
> +
> +	/* get the previous mode of the LED */
> +	prevMode = (msp_led_mode_t)(private_msp_led_register[ledId] & MSP_LED_MODE_MASK);
> +
> +	if (prevMode == MSP_LED_ON)
> +		*prevDataBitsPtr |= (1 << pin);
> +
> +	if (prevDirection == MSP_LED_INPUT)
> +		*prevDirectionBitsPtr |= (1 << pin);
> +
> +
> +	/* Update timer and obtain the current period */
> +	isInInitialPeriod = sync_led_timer_with_polling_count(ledId, &currLedReg);
> +
> +	/* get the current mode of the LED */
> +	currMode = (msp_led_mode_t)(currLedReg & MSP_LED_MODE_MASK);
> +
> +	switch (currMode) {
> +		case MSP_LED_BLINK:
> +			if (isInInitialPeriod) {
> +				*currDataBitsPtr |= (1 << pin);
> +				mode_bits_update(&currLedReg, MSP_LED_ON);
> +			} else {
> +				mode_bits_update(&currLedReg,MSP_LED_OFF);
> +			}
> +			break;
> +		case MSP_LED_BLINK_INVERT:
> +			if (!isInInitialPeriod) {
> +				*currDataBitsPtr |= (1 << pin);
> +				mode_bits_update(&currLedReg, MSP_LED_ON);
> +			} else {
> +				mode_bits_update(&currLedReg,MSP_LED_OFF);
> +
> +			}
> +			break;
> +		case MSP_LED_OFF:
> +			/* Assuming that the led be turned off when set to output mode */
> +			break;
> +		case MSP_LED_ON:
> +			*currDataBitsPtr |= (1 << pin);
> +			break;
> +	}

Indent the switch body one tabstop to the left.

> +	if (currDirection == MSP_LED_INPUT)
> +		*currDirectionBitsPtr |= (1 << pin);
> +
> +	/* save the current mode */
> +	private_msp_led_register[ledId] = currLedReg;
> +	
> +	return 1;
> +}
> +
> +/**
> + * device_update - Updates led device(s) on GPIO
> + * @devId - id pertaining to the device that needs update
> + * 
> + * returns 1 - device exists
> + * 		   0 - device does not exist 
> + * 
> + * Every pin connected to the GPIO is updated if the state of the pin has changed
> + * from its previous value stored in the memory register.  A temporary variable,
> + * currLedReg is used to store the current value of the register corresponding to
> + * the pin under focus.  curLedReg gets its value from the global shared memory 
> + * registers for leds.  This value is compared with the previous value to determine
> + * if a change to the led pin is required.  The previous values are stored in the
> + * private led register, private_msp_led_register.
> + * 
> + **/
> +inline int device_update( int devId )

Coding-style, StudlyCaps, remove inline

> +{
> +	int pin;
> +	u8 currDirectionBits, currDataBits, prevDataBits, prevDirectionBits;
> +	currDirectionBits = currDataBits = prevDataBits = prevDirectionBits = 0;

The unneeded initialisations here are just to suppress the incorrect gcc
warning, yes?

If so, that should at least be comented.  And try to avoid declarations o
this form as well as multiple assignments.  So you want:

	u8 curr_direction_bits = 0;	/* Suppress gcc warning */
	u8 curr_data_bits = 0;		/* Suppress gcc warning */
	u8 prev_data_bits = 0;		/* Suppress gcc warning */
	u8 prev_direction_bits = 0;	/* Suppress gcc warning */

the initialisation does cause extra ode to be generated and we usually just
let te warning come out.  I think later gcc's fixed it.

> +	/* if the device wasn't detected */
> +	if (pmctwiled_device[devId] == NULL)
> +		return 0;					
> +
> +	/* iterate through each pin of the device and update register as necessary */
> +	for (pin=0; pin < MSP_LED_NUM_DEVICE_PINS; pin++) {

Put a space either side of '='

> +		int ledId = MSP_LED_DEVPIN(devId, pin);	
> +		led_update(ledId, &prevDirectionBits, &prevDataBits,
> +					&currDirectionBits, &currDataBits);
> +	}
> +	
> +	/* BUS OPERATIONS: if the previous state is different from the current state */
> +	if (currDataBits != prevDataBits) {
> +		i2c_smbus_write_byte_data(
> +			pmctwiled_device[devId], PCA9554_OUTPUT,
> +			~(currDataBits) );
> +	}
> +	if (currDirectionBits != prevDirectionBits) {
> +		i2c_smbus_write_byte_data(
> +			pmctwiled_device[devId], PCA9554_DIRECTION,
> +			currDirectionBits );
> +	}
> +	
> +	return 1;
> +} 
> +
> +static int pmctwiled_poll( void *data )
> +{
> +	pmctwiled_running = 1;
> +	current_period = 0;
> +	
> +	/* start the polling loop */
> +	while( pmctwiled_running ) {
> +		/* Starting Time */
> +		unsigned long pollEnd;
> +		unsigned long timeLeft;
> +		unsigned int pollStart = jiffies;
> +		
> +		/* update every device in here for the current period */
> +		int devId;
> +		for (devId = 0; devId < MSP_LED_NUM_DEVICES; devId++)
> +			device_update(devId);
> +		
> +		/* Ending Time */
> +		pollEnd = jiffies;
> +		if (pollEnd >= pollStart) {
> +			timeLeft = POLL_PERIOD - (pollEnd - pollStart);
> +		} else {
> +			timeLeft = POLL_PERIOD - ((0xffffffff - pollStart) + pollEnd);
> +			printk( "Warning: Delaying for %lu jiffies.  This may not be correct because of clock wrapping\n", timeLeft );
> +		}
> +		if (timeLeft > POLL_PERIOD) {
> +			printk( "Warning: Delay of %lu jiffies requested, defaulting back to %lu\n", timeLeft, POLL_PERIOD );
> +			timeLeft = POLL_PERIOD;
> +		}
> +		
> +		/* reshedule next polling interval */
> +		set_current_state(TASK_INTERRUPTIBLE);
> +		schedule_timeout(timeLeft);
> +		current_period++;
> +	}
> +
> +	return 0;
> +}

Remove pmctwiled_running, use kthread_should_stop()

> +void __init pmctwiled_setup(void)
> +{
> +	static int called;
> +	int dev;
> +
> +	/* check if already initialized */
> +	if( called )
> +		return;

This cannot happen (can it?)

> +	/* initialize LEDs to default state */
> +	for( dev = 0; dev < MSP_LED_NUM_DEVICES; dev++ ) {
> +		int pin;
> +		pmctwiled_device[dev] = NULL;
> +		
> +		for( pin = 0; pin < 8; pin++ ) {
> +			int led = MSP_LED_DEVPIN(dev,pin);
> +			if (mspLedInitialInputState[dev] & (1 << pin)) {				
> +				msp_led_disable(led);
> +			} else {
> +				msp_led_enable(led);
> +				if (mspLedInitialPinState[dev] & (1 << pin))									
> +					msp_led_turn_on(led);				
> +				else			
> +					msp_led_turn_off(led);
> +			}
> +			
> +			/* Initialize the private led register memory */
> +			private_msp_led_register[led] = 0;
> +		}
> +	}
> +	
> +	/* indicate initialised */
> +	called++;
> +}
>
>
> +++ b/include/asm-mips/pmc-sierra/msp71xx/msp_led_macros.h
> @@ -0,0 +1,282 @@
> +/*
> + * $Id: msp_led_macros.h,v 1.3 2006/12/18 18:16:19 stjeanma Exp $

Please remove all CVS IDs from all patches.  Once this code hits mainline
they become meaningless.

> +static const u8 mspLedInitialInputState[] = {
> +	/* No outputs on device 0 or 1, these are inputs only */
> +	MSP_LED_INPUT_MODE, MSP_LED_INPUT_MODE,
> +	/* All outputs on device 2 through 4 */
> +	MSP_LED_OUTPUT_MODE, MSP_LED_OUTPUT_MODE, MSP_LED_OUTPUT_MODE,
> +};
> +
> +/* For each device, which output pins should start on and off:
> + * One byte per device:
> + *  0 = OFF = HI
> + *  1 = ON  = Lo
> + */
> +static const u8 mspLedInitialPinState[] = {
> +	0, 0, 	/* No initial state, these are input only */
> +	(1 << 1),	/* PWR_GREEN LED on, all others off */
> +	0,	/* All off */
> +	0,	/* All off */
> +};

Move these into a .c file.

> +typedef enum {
> +	MSP_LED_INPUT = 0,
> +	MSP_LED_OUTPUT,
> +} msp_led_direction_t;

No typedefs, please.   Convert this to

enum msp_led_direction {
	...
};

> +/* Output modes */
> +typedef enum {
> +	MSP_LED_OFF = 0,		/* Off steady */
> +	MSP_LED_ON,				/* On steady */
> +	MSP_LED_BLINK,			/* On for initialPeriod, off for finalPeriod */
> +	MSP_LED_BLINK_INVERT,	/* Off for initialPeriod, on for finalPeriod */
> +} msp_led_mode_t;

Ditto.

> +/* For non-LED pins, these macros set HI and LO accordingly */
> +#define msp_led_pin_hi	msp_led_turn_off
> +#define msp_led_pin_lo	msp_led_turn_on

eww.

static inline wrapper functions are preferred.  Write code in C, not cpp
where possible.



From sshtylyov@ru.mvista.com Mon Mar  5 12:42:52 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 12:42:53 +0000 (GMT)
Received: from h155.mvista.com ([63.81.120.155]:31460 "EHLO imap.sh.mvista.com")
	by ftp.linux-mips.org with ESMTP id S20037479AbXCEMmw (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Mon, 5 Mar 2007 12:42:52 +0000
Received: from [192.168.1.248] (unknown [10.150.0.9])
	by imap.sh.mvista.com (Postfix) with ESMTP
	id BF36F3EC9; Mon,  5 Mar 2007 04:42:12 -0800 (PST)
Message-ID: <45EC101D.8050600@ru.mvista.com>
Date:	Mon, 05 Mar 2007 15:42:05 +0300
From:	Sergei Shtylyov <sshtylyov@ru.mvista.com>
Organization: MontaVista Software Inc.
User-Agent: Mozilla/5.0 (X11; U; Linux i686; rv:1.7.2) Gecko/20040803
X-Accept-Language: ru, en-us, en-gb
MIME-Version: 1.0
To:	Marco Braga <marco.braga@gmail.com>
Cc:	linux-mips@linux-mips.org
Subject: Re: Linux kernel 2.6.20, PCI and hpt266
References: <d459bb380703040427g4a8cad08kd8e3190f7d109c86@mail.gmail.com>
In-Reply-To: <d459bb380703040427g4a8cad08kd8e3190f7d109c86@mail.gmail.com>
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <sshtylyov@ru.mvista.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14349
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: sshtylyov@ru.mvista.com
Precedence: bulk
X-list: linux-mips

Hello.

Marco Braga wrote:

> Hello, I am trying to run kernel 2.6.20 on an Au1500 based board. Versions
> 2.4.x of the kernel are correctly working.

    How could they work I wonder? :-O

> Problem: on the board there is a HighPoint 371N ATA controller. At the

    There's *no* proper support for HPT371N in 2.4.x.

> moment the kernel 2.6.20 boots and runs, but the ATA controller does not
> recognize the IDE disk.

> Details:
> The driver I use is "drivers/ide/pci/hpt266.c". I've already fixed the

    I guess you mean hpt366.c. :-)

> timing problems and PLL configuration that afflict this controller, and
> removed RESOURCE_64BIT to fix problems with the PCI bus on mips and
> resource_size_t casts.

    Erm, does it indeed fix the problem I wonder?

> I've managed to follow the problem to ide-probe.c, in function
> "actual_try_to_identify". It seems that the values read from the ATA
> registers through IO ports are not correct. As every ATA controller, it
> needs 8 bytes in IO port space for Command Block registers, and 4 bytes for
> the Control Block registers. They are mapped by the kernel at:

> 1400-1407 (8 bytes) Command block channel 0
> 1408-140F (8 bytes) Command block channel 1
> 1410-1413 (4 bytes) Control block channel 0
> 1414-1417 (4 bytes) Control block channel 1

> Notice that Highpoint 371N has registers for 2 channel, but the pinout for
> only 1 channel. In fact the first channel is disabled by the driver, so the
> actual registers are in the range 1408-140F and 1414-1417. The first 
> sign of
> the problem is that INB do not read the correct values for the ALTSTATUS
> register. In fact the kernel reports:

> ... probing with STATUS(...) instead of ALTSTATUS(...)

> [as in ide-probe.c, line 290]

> The values read from the ATA registers are completely wrong. The registers
> are accessed through hwif->INB, that are common "inb" functions. This makes
> me suspect that "inX" functions are not working, but I don't know how to
> test this. Notice that the PCI controller configuration space is correctly
> accessed, as I can confirm reading sys/bus/pci/.../config.

    The PCI config. space accesses use completely different meachanism form 
I/O and memory accesses.

> Can you help or suggest me anything?

    Well, I guess I'll try the current kernel on one of my DBAu1x00 boards...

> Thanx!

WBR, Sergei

From ralf@linux-mips.org Mon Mar  5 13:13:54 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 13:13:56 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:42410 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037484AbXCENNy (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 13:13:54 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l25DC5Nd029224;
	Mon, 5 Mar 2007 13:12:05 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l25DC3HJ029223;
	Mon, 5 Mar 2007 13:12:03 GMT
Date:	Mon, 5 Mar 2007 13:12:03 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Cc:	linux-mips <linux-mips@linux-mips.org>
Subject: Re: [PATCH][MIPS] separate Cobalt PCI codes from setup.c
Message-ID: <20070305131203.GA29204@linux-mips.org>
References: <20070305191003.5357b4bf.yoichi_yuasa@tripeaks.co.jp>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20070305191003.5357b4bf.yoichi_yuasa@tripeaks.co.jp>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14350
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Mon, Mar 05, 2007 at 07:10:03PM +0900, Yoichi Yuasa wrote:

> This patch has separated cobalt PCI codes from setup.c .
> It's removed #ifdef CONFIG_PCI/#endif from cobalt setup.c .

Thanks, queued.

2.6.21 ante portas ;-)

  Ralf

From Mile.Davidovic@micronasnit.com Mon Mar  5 13:48:43 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 13:48:51 +0000 (GMT)
Received: from krt.tmd.ns.ac.yu ([147.91.177.65]:41623 "HELO krt.neobee.net")
	by ftp.linux-mips.org with SMTP id S20037477AbXCENsn (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Mon, 5 Mar 2007 13:48:43 +0000
Received: from localhost (localhost [127.0.0.1])
	by krt.neobee.net (Postfix) with ESMTP id DC46CCDE28
	for <linux-mips@linux-mips.org>; Mon,  5 Mar 2007 14:48:11 +0100 (CET)
X-Virus-Scanned: amavisd-new at krt.neobee.net
Received: from krt.neobee.net ([127.0.0.1])
	by localhost (krt.neobee.net [127.0.0.1]) (amavisd-new, port 10024)
	with LMTP id HZvRI9TJLDab for <linux-mips@linux-mips.org>;
	Mon,  5 Mar 2007 14:48:11 +0100 (CET)
Received: from had (unknown [192.168.193.88])
	by krt.neobee.net (Postfix) with ESMTP id 5130ECDE30
	for <linux-mips@linux-mips.org>; Mon,  5 Mar 2007 14:48:09 +0100 (CET)
From:	"Mile Davidovic" <Mile.Davidovic@micronasnit.com>
To:	<linux-mips@linux-mips.org>
Subject: Encrypt user file system
Date:	Mon, 5 Mar 2007 14:51:10 +0100
Message-ID: <06b401c75f2d$552b8130$ff828390$@Davidovic@micronasnit.com>
MIME-Version: 1.0
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
X-Mailer: Microsoft Office Outlook 12.0
Thread-Index: AcdfLVPzHZiHXQOnR66OGNXFLNoW8A==
Content-Language: sr
Return-Path: <Mile.Davidovic@micronasnit.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14351
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: Mile.Davidovic@micronasnit.com
Precedence: bulk
X-list: linux-mips

Hello all,
What is mips way for encrypting user file system? 
On intel we can use combination dm-crypt and we could crypt complete user FS I
suppose that should work on MIPS too?


Thanks in advice
Mile


From marco.braga@gmail.com Mon Mar  5 13:58:14 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 13:58:16 +0000 (GMT)
Received: from ug-out-1314.google.com ([66.249.92.174]:40646 "EHLO
	ug-out-1314.google.com") by ftp.linux-mips.org with ESMTP
	id S20037484AbXCEN6O (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 13:58:14 +0000
Received: by ug-out-1314.google.com with SMTP id 40so1416182uga
        for <linux-mips@linux-mips.org>; Mon, 05 Mar 2007 05:57:14 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:in-reply-to:mime-version:content-type:references;
        b=kqfrB3KGWkPdKLIU3njbopvqM/tBBHEf3w747IZGY98jzG3eRQWsV9HxSIxvlcRfPyOXGlCdkcTbwnoUzGpmkjAhdmUFxA//+BO7ww3OpPQLvUMHbs+liur1OtdNJj8r3xZBGFxJt2w59klCa0RmF3D4PfCbEC9346mwBONAIMs=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:in-reply-to:mime-version:content-type:references;
        b=mWyaWfwouY348mSX0YROEDtBwDuJG+Hc35kJZzq4w1J0eAfo8th/MVPuAHVkz61A1VD0W9GFVvQ+PXbrRJgDfvxYxTSOlyD5tmfbk00NNUhtKo9Qy0sk+ICSmMlkOKa0BURH9rELafILhX/U0H9Ns9zxo4Isl2Jl00T1upA87ck=
Received: by 10.115.77.1 with SMTP id e1mr1233585wal.1173103032690;
        Mon, 05 Mar 2007 05:57:12 -0800 (PST)
Received: by 10.114.80.18 with HTTP; Mon, 5 Mar 2007 05:57:12 -0800 (PST)
Message-ID: <d459bb380703050557o4dea6fs5fa3b336d37b9f@mail.gmail.com>
Date:	Mon, 5 Mar 2007 14:57:12 +0100
From:	"Marco Braga" <marco.braga@gmail.com>
To:	linux-mips@linux-mips.org
Subject: Re: Linux kernel 2.6.20, PCI and hpt266
In-Reply-To: <45EC101D.8050600@ru.mvista.com>
MIME-Version: 1.0
Content-Type: multipart/alternative; 
	boundary="----=_Part_134094_29693496.1173103032644"
References: <d459bb380703040427g4a8cad08kd8e3190f7d109c86@mail.gmail.com>
	 <45EC101D.8050600@ru.mvista.com>
Return-Path: <marco.braga@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14352
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: marco.braga@gmail.com
Precedence: bulk
X-list: linux-mips

------=_Part_134094_29693496.1173103032644
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

2007/3/5, Sergei Shtylyov <sshtylyov@ru.mvista.com>:

> Hello, I am trying to run kernel 2.6.20 on an Au1500 based board. Versions
> > 2.4.x of the kernel are correctly working.
>
>     How could they work I wonder? :-O


Eheheh :-)


> > Problem: on the board there is a HighPoint 371N ATA controller. At the
>
>     There's *no* proper support for HPT371N in 2.4.x.


We've modified them to work. We fixed the "first channel disabled" problem
and the "set pll with a wrong algorithm", etc. :-)


> Details:
> > The driver I use is "drivers/ide/pci/hpt266.c". I've already fixed the
>
>     I guess you mean hpt366.c. :-)


Whoops. Right. I'm using hpt366.c. I'd also like to try the nel libata
drivers.


> > timing problems and PLL configuration that afflict this controller, and
> > removed RESOURCE_64BIT to fix problems with the PCI bus on mips and
> > resource_size_t casts.
>
>     Erm, does it indeed fix the problem I wonder?


Well, at least this change removed the "skipping PCI config due to resource
conflict" error.


>     The PCI config. space accesses use completely different meachanism
> form
> I/O and memory accesses.


I suspected this, but sadly I am novice to PCI. Thank you very much, Sergei.

Today I've done another test: dumping I/O ATA registers, and the results are
puzzling:

The format is:

[hw->io_ports index] [I/O port addr] [I/O port value]

[17179571.588000] 0 addr: 0x1408  val: 0x08
[17179571.596000] 1 addr: 0x1409  val: 0x09
[17179571.608000] 2 addr: 0x140a  val: 0x0a
[17179571.620000] 3 addr: 0x140b  val: 0x0b
[17179571.632000] 4 addr: 0x140c  val: 0x0c
[17179571.644000] 5 addr: 0x140d  val: 0x0d
[17179571.656000] 6 addr: 0x140e  val: 0xa0
[17179571.668000] 7 addr: 0x140f  val: 0x0f
[17179571.680000] 8 addr: 0x1416  val: 0x0a
[17179571.692000] 9 addr: 0x00  val: 0x48

The values seem wrong to me..

Bye!

------=_Part_134094_29693496.1173103032644
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

2007/3/5, Sergei Shtylyov &lt;<a href="mailto:sshtylyov@ru.mvista.com" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">sshtylyov@ru.mvista.com</a>&gt;:<br><br><span class="q"><span class="gmail_quote">
</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
&gt; Hello, I am trying to run kernel 2.6.20 on an Au1500 based board. Versions<br>&gt; 2.4.x of the kernel are correctly working.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;How could they work I wonder? :-O</blockquote></span><div><br>Eheheh :-)<br>&nbsp;<br>
</div><span class="q">
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">&gt; Problem: on the board there is a HighPoint 371N ATA controller. At the<br><br>&nbsp;&nbsp;&nbsp;&nbsp;There&#39;s *no* proper support for HPT371N in 
2.4.x.</blockquote></span><div><br>We&#39;ve modified them to work. We fixed the &quot;first channel disabled&quot; problem and the &quot;set pll with a wrong algorithm&quot;, etc. :-)<br><br></div><span class="q"><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

&gt; Details:<br>&gt; The driver I use is &quot;drivers/ide/pci/hpt266.c&quot;. I&#39;ve already fixed the<br><br>&nbsp;&nbsp;&nbsp;&nbsp;I guess you mean hpt366.c. :-)</blockquote></span><div><br>Whoops. Right. I&#39;m using hpt366.c. I&#39;d also like to try the nel libata drivers.
<br>&nbsp;<br></div><span class="q"><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">&gt; timing problems and PLL configuration that afflict this controller, and
<br>
&gt; removed RESOURCE_64BIT to fix problems with the PCI bus on mips and<br>&gt; resource_size_t casts.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;Erm, does it indeed fix the problem I wonder?</blockquote></span><div><br>Well, at least this change removed the &quot;skipping PCI config due to resource conflict&quot; error.
<br>&nbsp;<br></div><span class="q"><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">&nbsp;&nbsp;&nbsp; The PCI config. space accesses use completely different meachanism form
<br>
I/O and memory accesses.</blockquote></span><br>I suspected this, but sadly I am novice to PCI. Thank you very much, Sergei.<br><br>Today I&#39;ve done another test: dumping I/O ATA registers, and the results are puzzling:
<br>
<br>The format is: <br><br>[hw-&gt;io_ports index] [I/O port addr] [I/O port value]<br><br>[17179571.588000] 0 addr: 0x1408&nbsp; val: 0x08<br>[17179571.596000] 1 addr: 0x1409&nbsp; val: 0x09<br>[17179571.608000] 2 addr: 0x140a&nbsp; val: 0x0a
<br>[17179571.620000] 3 addr: 0x140b&nbsp; val: 0x0b<br>[17179571.632000] 4 addr: 0x140c&nbsp; val: 0x0c<br>[17179571.644000] 5 addr: 0x140d&nbsp; val: 0x0d<br>[17179571.656000] 6 addr: 0x140e&nbsp; val: 0xa0<br>[17179571.668000] 7 addr: 0x140f&nbsp; val: 0x0f
<br>[17179571.680000] 8 addr: 0x1416&nbsp; val: 0x0a<br>[17179571.692000] 9 addr: 0x00&nbsp; val: 0x48<br><br>The values seem wrong to me..<br><br>Bye!

------=_Part_134094_29693496.1173103032644--

From vagabon.xyz@gmail.com Mon Mar  5 14:16:50 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 14:16:53 +0000 (GMT)
Received: from hu-out-0506.google.com ([72.14.214.228]:1185 "EHLO
	hu-out-0506.google.com") by ftp.linux-mips.org with ESMTP
	id S20037518AbXCEOQu (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 14:16:50 +0000
Received: by hu-out-0506.google.com with SMTP id 22so1327156hug
        for <linux-mips@linux-mips.org>; Mon, 05 Mar 2007 06:15:49 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=BWutyqVkxnzVuLWswrmL2hXQF9gOTii2Lyb5pL5vhBVC0Tn3+fMXAiktAcZmmI6Wwxa/hB8j6MDCL6ETZd2nCA0FblQZBUFPGnqkS54ApmMT7nh5dVpCv3B2qAJMrRxglZFavF6j8NfNjf4FedUQa6B9KUE1VWjPgC4FT6QwQZw=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=VHCPWbrFy+jZbqLWkdt6sC1hCgc50FntDL/x+pQnJuTWMtrrBrY5A6SwD76ic55lcZCbVluSUPXaG61l2Esn7Wh2KveNzI4lUJvKqAJRPEAFCA3RIll9LavHszQN/cksyhyTKlB/4cx23kfC2D85VN1eN/LfF+KASSXJMKE5Tb8=
Received: by 10.114.202.15 with SMTP id z15mr1270833waf.1173104147291;
        Mon, 05 Mar 2007 06:15:47 -0800 (PST)
Received: by 10.114.136.11 with HTTP; Mon, 5 Mar 2007 06:15:46 -0800 (PST)
Message-ID: <cda58cb80703050615r4e559ca1u78517634ac23a27@mail.gmail.com>
Date:	Mon, 5 Mar 2007 15:15:46 +0100
From:	"Franck Bui-Huu" <vagabon.xyz@gmail.com>
To:	mbizon@freebox.fr
Subject: Re: [PATCH 0/2] FLATMEM: allow memory to start at pfn != 0 [take #2]
Cc:	ralf <ralf@linux-mips.org>, linux-mips <linux-mips@linux-mips.org>
In-Reply-To: <1172879147.964.65.camel@sakura.staff.proxad.net>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
References: <116841864595-git-send-email-fbuihuu@gmail.com>
	 <1172879147.964.65.camel@sakura.staff.proxad.net>
Return-Path: <vagabon.xyz@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14353
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: vagabon.xyz@gmail.com
Precedence: bulk
X-list: linux-mips

Hi,

On 3/3/07, Maxime Bizon <mbizon@freebox.fr> wrote:
> Looking at phys_to_virt(), it looks like I also need to change
> PAGE_OFFSET to 0x90000000 to get correct values. This makes the kernel
> boot with a correct memory map, but userspace doesn't work anymore.

No phys_to_virt() should already take care of that:

static inline void * phys_to_virt(unsigned long address)
{
        return (void *)(address + PAGE_OFFSET - PHYS_OFFSET);
}

Does your platform code do some address translation by using
CPHYSADDR() macro or by using anything else than pa() ?

>
> Just in case, I'm not using git head, but a 2.6.20 kernel with the 2

2.6.20 should be OK. This patchset need some commits which have been
applied before.

> patches applied. Just tell me if you need complete dmesg.
>

yes, please, it may help. Can you send your config file as well ?

Just to be sure, is your PAGE_OFFSET equal to 0x80000000 ?

Thanks
-- 
               Franck

From demiourgos@gmail.com Mon Mar  5 14:20:19 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 14:20:23 +0000 (GMT)
Received: from nf-out-0910.google.com ([64.233.182.186]:141 "EHLO
	nf-out-0910.google.com") by ftp.linux-mips.org with ESMTP
	id S20037495AbXCEOUT (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 14:20:19 +0000
Received: by nf-out-0910.google.com with SMTP id l24so2015840nfc
        for <linux-mips@linux-mips.org>; Mon, 05 Mar 2007 06:19:18 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:mime-version:content-type:content-transfer-encoding:content-disposition;
        b=OMRWmGY/vN/XEgbbaxTZYnNptGOzeXc9HpRJxGjlUbYQ4wYQDDT6Gb6RDqZJn/EuREA5buO3sJdNMCCIAJBKYPhD7AgVHFkqlSIX2vGzXlMxTuWVTmjsvbKAFYFI0DSmT5YmKTojru3mG+V4RYSrvVClV9qEbxUOTXgOhb5CXng=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:mime-version:content-type:content-transfer-encoding:content-disposition;
        b=U0Ccd9MHFBN6vYEZ5m0RR6nmjeV8jeCzHJTHpXRbCi9AzrpVRIy8KkPR2Z1hEr//uLp8X0Ux1UrBZtjpd5xAKnNVwgbb/fNDTJslb2XAY+MU8oSAipL4P/akJW4cs+Wnr5gNQhCnJykBHP+9CxfG4kRK/81pmd0pu0nXc8/K/Xo=
Received: by 10.78.192.20 with SMTP id p20mr626592huf.1173104358198;
        Mon, 05 Mar 2007 06:19:18 -0800 (PST)
Received: by 10.78.44.13 with HTTP; Mon, 5 Mar 2007 06:19:18 -0800 (PST)
Message-ID: <c4357ccd0703050619r6b5a7452j6b582687bf1794d3@mail.gmail.com>
Date:	Mon, 5 Mar 2007 16:19:18 +0200
From:	"Alexander Sirotkin" <demiourgos@gmail.com>
To:	linux-mips@linux-mips.org
Subject: 0 function size
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Return-Path: <demiourgos@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14354
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: demiourgos@gmail.com
Precedence: bulk
X-list: linux-mips

I'm trying to see the function sizes for some object file compiled for
MIPS. On x86 one can use objdump  or readelf to see the sizes, however
for same weird reason on MIPS these routines show 0 for all functions.

Any idea what I'm missing ?

From anemo@mba.ocn.ne.jp Mon Mar  5 15:53:06 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 15:53:11 +0000 (GMT)
Received: from mba.ocn.ne.jp ([210.190.142.172]:56811 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20037530AbXCEPxG (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Mon, 5 Mar 2007 15:53:06 +0000
Received: from localhost (p3231-ipad01funabasi.chiba.ocn.ne.jp [61.207.77.231])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id 15828B7F8; Tue,  6 Mar 2007 00:51:44 +0900 (JST)
Date:	Tue, 06 Mar 2007 00:51:43 +0900 (JST)
Message-Id: <20070306.005143.69025642.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org
Subject: [PATCH] Add some sysfs files to debug unaligned accesses
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14355
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

Currently a number of unaligned instructions is counted but not used.
Add /sys/kernel/mips/unaligned_instructions file to show the value.

And add /sys/kernel/mips/unaligned_action to control behavior upon an
unaligned access.  Possible actions are:

quiet: silently fixup the unaligned access.
signal: send SIGBUS.
show: dump registers, process name, etc. and fixup.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
 arch/mips/kernel/setup.c     |   14 ++++++++
 arch/mips/kernel/unaligned.c |   70 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 4975da0..af88f27 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -574,3 +574,17 @@ __setup("nodsp", dsp_disable);
 
 unsigned long kernelsp[NR_CPUS];
 unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
+
+static struct attribute *mips_attrs[] = {
+	NULL
+};
+static struct attribute_group mips_attr_group = {
+	.name = "mips",
+	.attrs = mips_attrs,
+};
+
+static int __init sysfs_mips(void)
+{
+	return sysfs_create_group(&kernel_subsys.kset.kobj, &mips_attr_group);
+}
+arch_initcall(sysfs_mips);
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 24b7b05..3f08ab9 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -88,9 +88,14 @@
 #define STR(x)  __STR(x)
 #define __STR(x)  #x
 
-#ifdef CONFIG_PROC_FS
-unsigned long unaligned_instructions;
+#ifdef CONFIG_SYSFS
+static unsigned long unaligned_instructions;
+static int unaligned_action;
+static const char *unaligned_actions[] = {"quiet", "signal", "show"};
+#else
+#define unaligned_action 0
 #endif
+extern void show_registers(struct pt_regs *regs);
 
 static inline int emulate_load_store_insn(struct pt_regs *regs,
 	void __user *addr, unsigned int __user *pc,
@@ -460,7 +465,7 @@ static inline int emulate_load_store_ins
 		goto sigill;
 	}
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_SYSFS
 	unaligned_instructions++;
 #endif
 
@@ -517,6 +522,10 @@ asmlinkage void do_ade(struct pt_regs *r
 	pc = (unsigned int __user *) exception_epc(regs);
 	if (user_mode(regs) && (current->thread.mflags & MF_FIXADE) == 0)
 		goto sigbus;
+	if (unaligned_action == 1)
+		goto sigbus;
+	else if (unaligned_action == 2)
+		show_registers(regs);
 
 	/*
 	 * Do branch emulation only if we didn't forward the exception.
@@ -547,3 +556,58 @@ sigbus:
 	 * XXX On return from the signal handler we should advance the epc
 	 */
 }
+
+#ifdef CONFIG_SYSFS
+static ssize_t unaligned_instructions_show(struct subsystem *subsys, char *buf)
+{
+	return sprintf(buf, "%lu\n", unaligned_instructions);
+}
+
+static ssize_t unaligned_action_show(struct subsystem *subsys, char *buf)
+{
+	int i;
+	char *s = buf;
+
+	for (i = 0; i < ARRAY_SIZE(unaligned_actions); i++) {
+		if (i == unaligned_action)
+			s += sprintf(s, "[%s] ", unaligned_actions[i]);
+		else
+			s += sprintf(s, "%s ", unaligned_actions[i]);
+	}
+	s += sprintf(s, "\n");
+	return s - buf;
+}
+
+static ssize_t unaligned_action_store(struct subsystem *subsys,
+				      const char *buf, size_t count)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(unaligned_actions); i++) {
+		if (!strncmp(buf, unaligned_actions[i],
+			     min(count, strlen(unaligned_actions[i])))) {
+			unaligned_action = i;
+			return count;
+		}
+	}
+	return -EINVAL;
+}
+
+#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)
+static struct subsys_attribute unaligned_attrs[] = {
+	__ATTR_RO(unaligned_instructions),
+	__ATTR_RW(unaligned_action),
+};
+
+static int __init sysfs_unaligned(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(unaligned_attrs); i++)
+		sysfs_add_file_to_group(&kernel_subsys.kset.kobj,
+					&unaligned_attrs[i].attr,
+					"mips");
+	return 0;
+}
+__initcall(sysfs_unaligned);
+#endif

From rajat.noida.india@gmail.com Mon Mar  5 16:21:27 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 16:21:32 +0000 (GMT)
Received: from mu-out-0910.google.com ([209.85.134.184]:9332 "EHLO
	mu-out-0910.google.com") by ftp.linux-mips.org with ESMTP
	id S20037551AbXCEQV1 (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 16:21:27 +0000
Received: by mu-out-0910.google.com with SMTP id w1so1638341mue
        for <linux-mips@linux-mips.org>; Mon, 05 Mar 2007 08:21:26 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=uYO8OqreABaEP948N2RCp40TZUvnGhw3EnCIdSDszLyDAp5wVv11Fwj64HXGbR6ddZhROsu8c6QJGldzGLCtEAEmoOU0f3uLX7E7M9NB82r8tBON1ccITPKnDlBQDjq2G/BulRyweFWmOmAoot8+juWrIgXjbuEjmZ+zq6FAusQ=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=PBOXlg2b02xbLIH1hIs44zXSBPQNZyLk0eozr3oRxOfYMJK0kVBCuiVOj+se7oZ02wB0FdotKTDM2TpIzZylQVKtAuMgTee+DhPUMYjMsy2qfKgJbdl10ldRqADEiuqD5UiJPG22T40CHcVavrMdhpPD8uv+X752pInKSw1Y2qs=
Received: by 10.82.177.3 with SMTP id z3mr5306226bue.1173111685885;
        Mon, 05 Mar 2007 08:21:25 -0800 (PST)
Received: by 10.82.178.13 with HTTP; Mon, 5 Mar 2007 08:21:25 -0800 (PST)
Message-ID: <b115cb5f0703050821v50667580oa8dfa26412c05b08@mail.gmail.com>
Date:	Mon, 5 Mar 2007 21:51:25 +0530
From:	"Rajat Jain" <rajat.noida.india@gmail.com>
To:	"Alexander Sirotkin" <demiourgos@gmail.com>
Subject: Re: 0 function size
Cc:	linux-mips@linux-mips.org
In-Reply-To: <c4357ccd0703050619r6b5a7452j6b582687bf1794d3@mail.gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
References: <c4357ccd0703050619r6b5a7452j6b582687bf1794d3@mail.gmail.com>
Return-Path: <rajat.noida.india@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14356
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: rajat.noida.india@gmail.com
Precedence: bulk
X-list: linux-mips

On 3/5/07, Alexander Sirotkin <demiourgos@gmail.com> wrote:
> I'm trying to see the function sizes for some object file compiled for
> MIPS. On x86 one can use objdump  or readelf to see the sizes, however
> for same weird reason on MIPS these routines show 0 for all functions.
>
> Any idea what I'm missing ?
>

Are you using a native compiler or a cross compiler?

If you are using a cross compiler, then you need to use the "cross
compiler" version of objdump / readelf  utilities as well. For
instance if you are using mips-linux-gcc to compile, then you need
mips-linux-readelf / mips-linux-objdump etc.

Thanks,

Rajat

From ralf@linux-mips.org Mon Mar  5 16:22:20 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 16:22:22 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:30151 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037605AbXCEQWU (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 16:22:20 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l25GKSi9001831;
	Mon, 5 Mar 2007 16:20:28 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l25GKS0W001829;
	Mon, 5 Mar 2007 16:20:28 GMT
Date:	Mon, 5 Mar 2007 16:20:28 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Alexander Sirotkin <demiourgos@gmail.com>
Cc:	linux-mips@linux-mips.org
Subject: Re: 0 function size
Message-ID: <20070305162028.GA786@linux-mips.org>
References: <c4357ccd0703050619r6b5a7452j6b582687bf1794d3@mail.gmail.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <c4357ccd0703050619r6b5a7452j6b582687bf1794d3@mail.gmail.com>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14357
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Mon, Mar 05, 2007 at 04:19:18PM +0200, Alexander Sirotkin wrote:

> I'm trying to see the function sizes for some object file compiled for
> MIPS. On x86 one can use objdump  or readelf to see the sizes, however
> for same weird reason on MIPS these routines show 0 for all functions.
> 
> Any idea what I'm missing ?

Works fine here:

801f3f10 l     F .text  00000074 rekey_seq_generator
80327f2c l     O .data  00000028 rekey_work
80345dd0 l     F .init.text     00000020 seqgen_init
801f3fd0 l     F .text  000000f4 uuid_strategy
801f40c4 l     F .text  0000012c proc_do_uuid
801f42e0 l     F .text  0000012c extract_entropy_user
801f440c l     F .text  0000000c urandom_read
801f4418 l     F .text  000000fc random_write
801f4514 l     F .text  000001f4 random_ioctl
801f484c l     F .text  00000090 random_poll
801f4ac8 l     F .text  00000190 random_read
80327f64 l     O .data  00000004 sysctl_poolsize

So seems to be a defect with your particular toolchain or objdump or readelf.

  Ralf

From ralf@linux-mips.org Mon Mar  5 16:29:35 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 16:29:37 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:48271 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037609AbXCEQ3f (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 16:29:35 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l25GRjdU007312;
	Mon, 5 Mar 2007 16:27:45 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l25GRj1S007311;
	Mon, 5 Mar 2007 16:27:45 GMT
Date:	Mon, 5 Mar 2007 16:27:45 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Rajat Jain <rajat.noida.india@gmail.com>
Cc:	Alexander Sirotkin <demiourgos@gmail.com>,
	linux-mips@linux-mips.org
Subject: Re: 0 function size
Message-ID: <20070305162745.GB786@linux-mips.org>
References: <c4357ccd0703050619r6b5a7452j6b582687bf1794d3@mail.gmail.com> <b115cb5f0703050821v50667580oa8dfa26412c05b08@mail.gmail.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <b115cb5f0703050821v50667580oa8dfa26412c05b08@mail.gmail.com>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14358
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Mon, Mar 05, 2007 at 09:51:25PM +0530, Rajat Jain wrote:

> Are you using a native compiler or a cross compiler?
> 
> If you are using a cross compiler, then you need to use the "cross
> compiler" version of objdump / readelf  utilities as well. For
> instance if you are using mips-linux-gcc to compile, then you need
> mips-linux-readelf / mips-linux-objdump etc.

In general your're right but for this particular purpose for example an
i386-linux-objdump will do the job for 32-bit big and little endian
MIPS ELF.  It will - depending on the exact binutils configuration - fail
with an error message for 64-bit ELF.

  Ralf

From demiourgos@gmail.com Mon Mar  5 16:30:00 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 16:30:06 +0000 (GMT)
Received: from nf-out-0910.google.com ([64.233.182.189]:61236 "EHLO
	nf-out-0910.google.com") by ftp.linux-mips.org with ESMTP
	id S20037608AbXCEQ3p (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 16:29:45 +0000
Received: by nf-out-0910.google.com with SMTP id l24so2058536nfc
        for <linux-mips@linux-mips.org>; Mon, 05 Mar 2007 08:28:42 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=TheGobGUAstWxt8Za6z/ZxTVW7j2cU2llnj+GbF6k56nzcpx0mh1EC+ez/EroHk2vNlzjy6djKohIim9plywEbV9+Bd73om3ETMpz3f6qCOkOYLd6w9IW48AVMVyCsg/OXITKe0ulKBESUr4r319EfXn5u+HvDkZ9gaXATsVeEs=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=nM1BC76lNgbK60mv1YN+UhG9Y9JZMIJyNV/oy1tFi/7Ie3a1KgY6EJgiiTxcYKz4s/QoC4qDPxIJiLNxDUlilU8jg5DnI9pyot4/nUb/HkOM61Gbs1Gz+ICZU9hOnvSyogOqRpv/p2zhHnuMdKYp7cdH2MUogXuesyGLsIUSSho=
Received: by 10.78.201.2 with SMTP id y2mr654827huf.1173112122732;
        Mon, 05 Mar 2007 08:28:42 -0800 (PST)
Received: by 10.78.44.13 with HTTP; Mon, 5 Mar 2007 08:28:42 -0800 (PST)
Message-ID: <c4357ccd0703050828g7ee6eb30w516bb0d60928bbc6@mail.gmail.com>
Date:	Mon, 5 Mar 2007 18:28:42 +0200
From:	"Alexander Sirotkin" <demiourgos@gmail.com>
To:	"Ralf Baechle" <ralf@linux-mips.org>
Subject: Re: 0 function size
Cc:	linux-mips@linux-mips.org
In-Reply-To: <20070305162028.GA786@linux-mips.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
References: <c4357ccd0703050619r6b5a7452j6b582687bf1794d3@mail.gmail.com>
	 <20070305162028.GA786@linux-mips.org>
Return-Path: <demiourgos@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14359
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: demiourgos@gmail.com
Precedence: bulk
X-list: linux-mips

On 3/5/07, Ralf Baechle <ralf@linux-mips.org> wrote:
> On Mon, Mar 05, 2007 at 04:19:18PM +0200, Alexander Sirotkin wrote:
>
> > I'm trying to see the function sizes for some object file compiled for
> > MIPS. On x86 one can use objdump  or readelf to see the sizes, however
> > for same weird reason on MIPS these routines show 0 for all functions.
> >
> > Any idea what I'm missing ?
>
> Works fine here:
>
> 801f3f10 l     F .text  00000074 rekey_seq_generator
> 80327f2c l     O .data  00000028 rekey_work
> 80345dd0 l     F .init.text     00000020 seqgen_init
> 801f3fd0 l     F .text  000000f4 uuid_strategy
> 801f40c4 l     F .text  0000012c proc_do_uuid
> 801f42e0 l     F .text  0000012c extract_entropy_user
> 801f440c l     F .text  0000000c urandom_read
> 801f4418 l     F .text  000000fc random_write
> 801f4514 l     F .text  000001f4 random_ioctl
> 801f484c l     F .text  00000090 random_poll
> 801f4ac8 l     F .text  00000190 random_read
> 80327f64 l     O .data  00000004 sysctl_poolsize
>
> So seems to be a defect with your particular toolchain or objdump or readelf.
Yeah, it is indeed a problem with the particular toolchain I was using. Thanks.
>
>   Ralf
>

From ralf@linux-mips.org Mon Mar  5 16:30:29 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 16:30:31 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:53136 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20037615AbXCEQaV (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 16:30:21 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l25GSRoP007325;
	Mon, 5 Mar 2007 16:28:27 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l25GSQpU007324;
	Mon, 5 Mar 2007 16:28:26 GMT
Date:	Mon, 5 Mar 2007 16:28:26 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Mile Davidovic <Mile.Davidovic@micronasnit.com>
Cc:	linux-mips@linux-mips.org
Subject: Re: Encrypt user file system
Message-ID: <20070305162826.GC786@linux-mips.org>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14360
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Mon, Mar 05, 2007 at 02:51:10PM +0100, Mile Davidovic wrote:

> What is mips way for encrypting user file system? 
> On intel we can use combination dm-crypt and we could crypt complete user FS I
> suppose that should work on MIPS too?

Yes, of course.

  Ralf

From mbizon@freebox.fr Mon Mar  5 16:37:12 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 16:37:16 +0000 (GMT)
Received: from sakura.staff.proxad.net ([213.228.1.107]:63147 "EHLO
	sakura.staff.proxad.net") by ftp.linux-mips.org with ESMTP
	id S20037479AbXCEQhM (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 16:37:12 +0000
Received: from max by sakura.staff.proxad.net with local (Exim 3.36 #1 (Debian))
	id 1HOG8H-0006Ef-00; Mon, 05 Mar 2007 17:33:53 +0100
Subject: Re: [PATCH 0/2] FLATMEM: allow memory to start at pfn != 0 [take
	#2]
From:	Maxime Bizon <mbizon@freebox.fr>
Reply-To: mbizon@freebox.fr
To:	Franck Bui-Huu <vagabon.xyz@gmail.com>
Cc:	linux-mips <linux-mips@linux-mips.org>
In-Reply-To: <cda58cb80703050615r4e559ca1u78517634ac23a27@mail.gmail.com>
References: <116841864595-git-send-email-fbuihuu@gmail.com>
	 <1172879147.964.65.camel@sakura.staff.proxad.net>
	 <cda58cb80703050615r4e559ca1u78517634ac23a27@mail.gmail.com>
Content-Type: multipart/mixed; boundary="=-7g/3cxzQffsJDqhryWgC"
Organization: Freebox
Date:	Mon, 05 Mar 2007 17:33:53 +0100
Message-Id: <1173112433.7093.36.camel@sakura.staff.proxad.net>
Mime-Version: 1.0
X-Mailer: Evolution 2.8.1 
Return-Path: <mbizon@freebox.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14361
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: mbizon@freebox.fr
Precedence: bulk
X-list: linux-mips


--=-7g/3cxzQffsJDqhryWgC
Content-Type: text/plain
Content-Transfer-Encoding: 7bit


On Mon, 2007-03-05 at 15:15 +0100, Franck Bui-Huu wrote:

Thanks for caring Franck,

> Does your platform code do some address translation by using
> CPHYSADDR() macro or by using anything else than pa() ?

Not at all, I've reduced platform code to minimum for the test, it
basically registers a prom console, and do add_memory_region(0x10000000,
32 << 20), remaining is basic irq and time stuff.

> Just to be sure, is your PAGE_OFFSET equal to 0x80000000 ?

Yes, here is my spaces.h content:

#define PHYS_OFFSET             0x10000000

#define CAC_BASE                0x90000000
#define IO_BASE                 0xa0000000
#define UNCAC_BASE              0xa0000000
#define MAP_BASE                0xc0000000

#define PAGE_OFFSET             0x80000000UL

Note: The CAC_BASE value of 0x90000000 is for the linux exception code
to work as-is, since there is no RAM at 0x80000000 to put vector code.



I dug a little and found the following.

My kernel is loaded at 0x9012d000, '&_end' value is 0x901d4020. In
bootmem_init(), we try to compute reserved_end by using
__pa_symbol(&_end), which adds PHYS_OFFSET to it, though it was already
accounted.

The loop in setup.c is thus unable to compute a correct 'map_start'
value since 'reserved_end' is way above all declared memory.

init_bootmem_node() is then called with a 'map_start' default value of
~0. Maybe that case should fall in the invalid memory map panic ?


I tried to set 'reserved_end' value manually and it went furter, but I
end up with the following message:

Bad page state in process 'swapper'
page:81000000 flags:0x00000000 mapping:00000000 mapcount:1 count:0
Trying to fix it up, but a reboot is needed
Backtrace:
Call Trace:
[<90029f10>] dump_stack+0x8/0x34
[<9006ac58>] bad_page+0x68/0xa8
[<9006b0a4>] __free_pages_ok+0x358/0x37c
[<9013d374>] free_all_bootmem_core+0x24c/0x270
[<90134f30>] mem_init+0x40/0x19c
[<9012d828>] start_kernel+0x1d4/0x36c


Full dmesg with and without manual set of reserved_end attached.

Regards,

-- 
Maxime


--=-7g/3cxzQffsJDqhryWgC
Content-Disposition: attachment; filename=dotconfig
Content-Type: text/plain; name=dotconfig; charset=ANSI_X3.4-1968
Content-Transfer-Encoding: base64

Iw0KIyBBdXRvbWF0aWNhbGx5IGdlbmVyYXRlZCBtYWtlIGNvbmZpZzogZG9uJ3QgZWRpdA0KIyBM
aW51eCBrZXJuZWwgdmVyc2lvbjogMi42LjIwDQojIE1vbiBNYXIgIDUgMTU6NTU6MDIgMjAwNw0K
Iw0KQ09ORklHX01JUFM9eQ0KDQojDQojIE1hY2hpbmUgc2VsZWN0aW9uDQojDQojIENPTkZJR19C
Q005NjN4eCBpcyBub3Qgc2V0DQpDT05GSUdfVEFOR08yPXkNCiMgQ09ORklHX01JUFNfTVRYMSBp
cyBub3Qgc2V0DQojIENPTkZJR19NSVBTX0JPU1BPUlVTIGlzIG5vdCBzZXQNCiMgQ09ORklHX01J
UFNfUEIxMDAwIGlzIG5vdCBzZXQNCiMgQ09ORklHX01JUFNfUEIxMTAwIGlzIG5vdCBzZXQNCiMg
Q09ORklHX01JUFNfUEIxNTAwIGlzIG5vdCBzZXQNCiMgQ09ORklHX01JUFNfUEIxNTUwIGlzIG5v
dCBzZXQNCiMgQ09ORklHX01JUFNfUEIxMjAwIGlzIG5vdCBzZXQNCiMgQ09ORklHX01JUFNfREIx
MDAwIGlzIG5vdCBzZXQNCiMgQ09ORklHX01JUFNfREIxMTAwIGlzIG5vdCBzZXQNCiMgQ09ORklH
X01JUFNfREIxNTAwIGlzIG5vdCBzZXQNCiMgQ09ORklHX01JUFNfREIxNTUwIGlzIG5vdCBzZXQN
CiMgQ09ORklHX01JUFNfREIxMjAwIGlzIG5vdCBzZXQNCiMgQ09ORklHX01JUFNfTUlSQUdFIGlz
IG5vdCBzZXQNCiMgQ09ORklHX0JBU0xFUl9FWENJVEUgaXMgbm90IHNldA0KIyBDT05GSUdfTUlQ
U19DT0JBTFQgaXMgbm90IHNldA0KIyBDT05GSUdfTUFDSF9ERUNTVEFUSU9OIGlzIG5vdCBzZXQN
CiMgQ09ORklHX01JUFNfRVY2NDEyMCBpcyBub3Qgc2V0DQojIENPTkZJR19NQUNIX0pBWlogaXMg
bm90IHNldA0KIyBDT05GSUdfTEFTQVQgaXMgbm90IHNldA0KIyBDT05GSUdfTUlQU19BVExBUyBp
cyBub3Qgc2V0DQojIENPTkZJR19NSVBTX01BTFRBIGlzIG5vdCBzZXQNCiMgQ09ORklHX01JUFNf
U0VBRCBpcyBub3Qgc2V0DQojIENPTkZJR19XUl9QUE1DIGlzIG5vdCBzZXQNCiMgQ09ORklHX01J
UFNfU0lNIGlzIG5vdCBzZXQNCiMgQ09ORklHX01PTUVOQ09fSkFHVUFSX0FUWCBpcyBub3Qgc2V0
DQojIENPTkZJR19NT01FTkNPX09DRUxPVCBpcyBub3Qgc2V0DQojIENPTkZJR19NT01FTkNPX09D
RUxPVF8zIGlzIG5vdCBzZXQNCiMgQ09ORklHX01PTUVOQ09fT0NFTE9UX0MgaXMgbm90IHNldA0K
IyBDT05GSUdfTU9NRU5DT19PQ0VMT1RfRyBpcyBub3Qgc2V0DQojIENPTkZJR19NSVBTX1hYUzE1
MDAgaXMgbm90IHNldA0KIyBDT05GSUdfUE5YODU1MF9WMlBDSSBpcyBub3Qgc2V0DQojIENPTkZJ
R19QTlg4NTUwX0pCUyBpcyBub3Qgc2V0DQojIENPTkZJR19QTlg4NTUwX1NUQjgxMCBpcyBub3Qg
c2V0DQojIENPTkZJR19EREI1NDc3IGlzIG5vdCBzZXQNCiMgQ09ORklHX01BQ0hfVlI0MVhYIGlz
IG5vdCBzZXQNCiMgQ09ORklHX1BNQ19ZT1NFTUlURSBpcyBub3Qgc2V0DQojIENPTkZJR19RRU1V
IGlzIG5vdCBzZXQNCiMgQ09ORklHX01BUktFSU5TIGlzIG5vdCBzZXQNCiMgQ09ORklHX1NHSV9J
UDIyIGlzIG5vdCBzZXQNCiMgQ09ORklHX1NHSV9JUDI3IGlzIG5vdCBzZXQNCiMgQ09ORklHX1NH
SV9JUDMyIGlzIG5vdCBzZXQNCiMgQ09ORklHX1NJQllURV9CSUdTVVIgaXMgbm90IHNldA0KIyBD
T05GSUdfU0lCWVRFX1NXQVJNIGlzIG5vdCBzZXQNCiMgQ09ORklHX1NJQllURV9TRU5UT1NBIGlz
IG5vdCBzZXQNCiMgQ09ORklHX1NJQllURV9SSE9ORSBpcyBub3Qgc2V0DQojIENPTkZJR19TSUJZ
VEVfQ0FSTUVMIGlzIG5vdCBzZXQNCiMgQ09ORklHX1NJQllURV9QVFNXQVJNIGlzIG5vdCBzZXQN
CiMgQ09ORklHX1NJQllURV9MSVRUTEVTVVIgaXMgbm90IHNldA0KIyBDT05GSUdfU0lCWVRFX0NS
SElORSBpcyBub3Qgc2V0DQojIENPTkZJR19TSUJZVEVfQ1JIT05FIGlzIG5vdCBzZXQNCiMgQ09O
RklHX1NOSV9STSBpcyBub3Qgc2V0DQojIENPTkZJR19UT1NISUJBX0pNUjM5MjcgaXMgbm90IHNl
dA0KIyBDT05GSUdfVE9TSElCQV9SQlRYNDkyNyBpcyBub3Qgc2V0DQojIENPTkZJR19UT1NISUJB
X1JCVFg0OTM4IGlzIG5vdCBzZXQNCiMgQ09ORklHX1RBTkdPMl9FUzEgaXMgbm90IHNldA0KIyBD
T05GSUdfVEFOR08yX0VTMiBpcyBub3Qgc2V0DQojIENPTkZJR19UQU5HTzJfRVMzIGlzIG5vdCBz
ZXQNCiMgQ09ORklHX1RBTkdPMl9FUzQgaXMgbm90IHNldA0KIyBDT05GSUdfVEFOR08yX0VTNSBp
cyBub3Qgc2V0DQpDT05GSUdfVEFOR08yX0VTNj15DQojIENPTkZJR19LRVhFQyBpcyBub3Qgc2V0
DQpDT05GSUdfUldTRU1fR0VORVJJQ19TUElOTE9DSz15DQojIENPTkZJR19BUkNIX0hBU19JTE9H
Ml9VMzIgaXMgbm90IHNldA0KIyBDT05GSUdfQVJDSF9IQVNfSUxPRzJfVTY0IGlzIG5vdCBzZXQN
CkNPTkZJR19HRU5FUklDX0ZJTkRfTkVYVF9CSVQ9eQ0KQ09ORklHX0dFTkVSSUNfSFdFSUdIVD15
DQpDT05GSUdfR0VORVJJQ19DQUxJQlJBVEVfREVMQVk9eQ0KQ09ORklHX0dFTkVSSUNfVElNRT15
DQpDT05GSUdfU0NIRURfTk9fTk9fT01JVF9GUkFNRV9QT0lOVEVSPXkNCiMgQ09ORklHX0dFTkVS
SUNfSEFSRElSUVNfTk9fX0RPX0lSUSBpcyBub3Qgc2V0DQpDT05GSUdfRE1BX05PTkNPSEVSRU5U
PXkNCkNPTkZJR19ETUFfTkVFRF9QQ0lfTUFQX1NUQVRFPXkNCiMgQ09ORklHX0NQVV9CSUdfRU5E
SUFOIGlzIG5vdCBzZXQNCkNPTkZJR19DUFVfTElUVExFX0VORElBTj15DQpDT05GSUdfU1lTX1NV
UFBPUlRTX0xJVFRMRV9FTkRJQU49eQ0KQ09ORklHX0lSUV9DUFU9eQ0KQ09ORklHX01JUFNfTDFf
Q0FDSEVfU0hJRlQ9NQ0KDQojDQojIENQVSBzZWxlY3Rpb24NCiMNCiMgQ09ORklHX0NQVV9NSVBT
MzJfUjEgaXMgbm90IHNldA0KQ09ORklHX0NQVV9NSVBTMzJfUjI9eQ0KIyBDT05GSUdfQ1BVX01J
UFM2NF9SMSBpcyBub3Qgc2V0DQojIENPTkZJR19DUFVfTUlQUzY0X1IyIGlzIG5vdCBzZXQNCiMg
Q09ORklHX0NQVV9SMzAwMCBpcyBub3Qgc2V0DQojIENPTkZJR19DUFVfVFgzOVhYIGlzIG5vdCBz
ZXQNCiMgQ09ORklHX0NQVV9WUjQxWFggaXMgbm90IHNldA0KIyBDT05GSUdfQ1BVX1I0MzAwIGlz
IG5vdCBzZXQNCiMgQ09ORklHX0NQVV9SNFgwMCBpcyBub3Qgc2V0DQojIENPTkZJR19DUFVfVFg0
OVhYIGlzIG5vdCBzZXQNCiMgQ09ORklHX0NQVV9SNTAwMCBpcyBub3Qgc2V0DQojIENPTkZJR19D
UFVfUjU0MzIgaXMgbm90IHNldA0KIyBDT05GSUdfQ1BVX1I2MDAwIGlzIG5vdCBzZXQNCiMgQ09O
RklHX0NQVV9ORVZBREEgaXMgbm90IHNldA0KIyBDT05GSUdfQ1BVX1I4MDAwIGlzIG5vdCBzZXQN
CiMgQ09ORklHX0NQVV9SMTAwMDAgaXMgbm90IHNldA0KIyBDT05GSUdfQ1BVX1JNNzAwMCBpcyBu
b3Qgc2V0DQojIENPTkZJR19DUFVfUk05MDAwIGlzIG5vdCBzZXQNCiMgQ09ORklHX0NQVV9TQjEg
aXMgbm90IHNldA0KQ09ORklHX1NZU19IQVNfQ1BVX01JUFMzMl9SMT15DQpDT05GSUdfU1lTX0hB
U19DUFVfTUlQUzMyX1IyPXkNCkNPTkZJR19DUFVfTUlQUzMyPXkNCkNPTkZJR19DUFVfTUlQU1Iy
PXkNCkNPTkZJR19TWVNfU1VQUE9SVFNfMzJCSVRfS0VSTkVMPXkNCkNPTkZJR19DUFVfU1VQUE9S
VFNfMzJCSVRfS0VSTkVMPXkNCg0KIw0KIyBLZXJuZWwgdHlwZQ0KIw0KQ09ORklHXzMyQklUPXkN
CiMgQ09ORklHXzY0QklUIGlzIG5vdCBzZXQNCkNPTkZJR19QQUdFX1NJWkVfNEtCPXkNCiMgQ09O
RklHX1BBR0VfU0laRV84S0IgaXMgbm90IHNldA0KIyBDT05GSUdfUEFHRV9TSVpFXzE2S0IgaXMg
bm90IHNldA0KIyBDT05GSUdfUEFHRV9TSVpFXzY0S0IgaXMgbm90IHNldA0KQ09ORklHX0NQVV9I
QVNfUFJFRkVUQ0g9eQ0KQ09ORklHX01JUFNfTVRfRElTQUJMRUQ9eQ0KIyBDT05GSUdfTUlQU19N
VF9TTVAgaXMgbm90IHNldA0KIyBDT05GSUdfTUlQU19NVF9TTVRDIGlzIG5vdCBzZXQNCiMgQ09O
RklHX01JUFNfVlBFX0xPQURFUiBpcyBub3Qgc2V0DQojIENPTkZJR182NEJJVF9QSFlTX0FERFIg
aXMgbm90IHNldA0KQ09ORklHX0NQVV9IQVNfTExTQz15DQpDT05GSUdfQ1BVX0hBU19TWU5DPXkN
CkNPTkZJR19HRU5FUklDX0hBUkRJUlFTPXkNCkNPTkZJR19HRU5FUklDX0lSUV9QUk9CRT15DQpD
T05GSUdfQ1BVX1NVUFBPUlRTX0hJR0hNRU09eQ0KQ09ORklHX0FSQ0hfRkxBVE1FTV9FTkFCTEU9
eQ0KQ09ORklHX1NFTEVDVF9NRU1PUllfTU9ERUw9eQ0KQ09ORklHX0ZMQVRNRU1fTUFOVUFMPXkN
CiMgQ09ORklHX0RJU0NPTlRJR01FTV9NQU5VQUwgaXMgbm90IHNldA0KIyBDT05GSUdfU1BBUlNF
TUVNX01BTlVBTCBpcyBub3Qgc2V0DQpDT05GSUdfRkxBVE1FTT15DQpDT05GSUdfRkxBVF9OT0RF
X01FTV9NQVA9eQ0KIyBDT05GSUdfU1BBUlNFTUVNX1NUQVRJQyBpcyBub3Qgc2V0DQpDT05GSUdf
U1BMSVRfUFRMT0NLX0NQVVM9NA0KIyBDT05GSUdfUkVTT1VSQ0VTXzY0QklUIGlzIG5vdCBzZXQN
CiMgQ09ORklHX0haXzQ4IGlzIG5vdCBzZXQNCiMgQ09ORklHX0haXzEwMCBpcyBub3Qgc2V0DQoj
IENPTkZJR19IWl8xMjggaXMgbm90IHNldA0KQ09ORklHX0haXzI1MD15DQojIENPTkZJR19IWl8y
NTYgaXMgbm90IHNldA0KIyBDT05GSUdfSFpfMTAwMCBpcyBub3Qgc2V0DQojIENPTkZJR19IWl8x
MDI0IGlzIG5vdCBzZXQNCkNPTkZJR19TWVNfU1VQUE9SVFNfQVJCSVRfSFo9eQ0KQ09ORklHX0ha
PTI1MA0KQ09ORklHX1BSRUVNUFRfTk9ORT15DQojIENPTkZJR19QUkVFTVBUX1ZPTFVOVEFSWSBp
cyBub3Qgc2V0DQojIENPTkZJR19QUkVFTVBUIGlzIG5vdCBzZXQNCkNPTkZJR19MT0NLREVQX1NV
UFBPUlQ9eQ0KQ09ORklHX1NUQUNLVFJBQ0VfU1VQUE9SVD15DQpDT05GSUdfREVGQ09ORklHX0xJ
U1Q9Ii9saWIvbW9kdWxlcy8kVU5BTUVfUkVMRUFTRS8uY29uZmlnIg0KDQojDQojIENvZGUgbWF0
dXJpdHkgbGV2ZWwgb3B0aW9ucw0KIw0KQ09ORklHX0VYUEVSSU1FTlRBTD15DQpDT05GSUdfQlJP
S0VOX09OX1NNUD15DQpDT05GSUdfSU5JVF9FTlZfQVJHX0xJTUlUPTMyDQoNCiMNCiMgR2VuZXJh
bCBzZXR1cA0KIw0KQ09ORklHX0xPQ0FMVkVSU0lPTj0iIg0KIyBDT05GSUdfTE9DQUxWRVJTSU9O
X0FVVE8gaXMgbm90IHNldA0KIyBDT05GSUdfSUdOT1JFX0NPTVBJTEVfSU5GTyBpcyBub3Qgc2V0
DQojIENPTkZJR19TWVNWSVBDIGlzIG5vdCBzZXQNCiMgQ09ORklHX0JTRF9QUk9DRVNTX0FDQ1Qg
aXMgbm90IHNldA0KIyBDT05GSUdfVVRTX05TIGlzIG5vdCBzZXQNCiMgQ09ORklHX0lLQ09ORklH
IGlzIG5vdCBzZXQNCiMgQ09ORklHX1NZU0ZTX0RFUFJFQ0FURUQgaXMgbm90IHNldA0KIyBDT05G
SUdfUkVMQVkgaXMgbm90IHNldA0KQ09ORklHX0lOSVRSQU1GU19VU0VfR1pJUD15DQpDT05GSUdf
SU5JVFJBTUZTX1NPVVJDRT0iLi4vLi4vYnVpbGRyb290L2ltYWdlcy9yb290LW5vdmVyc2lvbi8i
DQpDT05GSUdfSU5JVFJBTUZTX1JPT1RfVUlEPTANCkNPTkZJR19JTklUUkFNRlNfUk9PVF9HSUQ9
MA0KIyBDT05GSUdfQ0NfT1BUSU1JWkVfRk9SX1NJWkUgaXMgbm90IHNldA0KQ09ORklHX1NZU0NU
TD15DQpDT05GSUdfRU1CRURERUQ9eQ0KQ09ORklHX1NZU0NUTF9TWVNDQUxMPXkNCkNPTkZJR19L
QUxMU1lNUz15DQpDT05GSUdfS0FMTFNZTVNfQUxMPXkNCiMgQ09ORklHX0tBTExTWU1TX0VYVFJB
X1BBU1MgaXMgbm90IHNldA0KQ09ORklHX0hPVFBMVUc9eQ0KQ09ORklHX1BSSU5USz15DQpDT05G
SUdfQlVHPXkNCiMgQ09ORklHX0VMRl9DT1JFIGlzIG5vdCBzZXQNCkNPTkZJR19CQVNFX0ZVTEw9
eQ0KIyBDT05GSUdfRlVURVggaXMgbm90IHNldA0KIyBDT05GSUdfRVBPTEwgaXMgbm90IHNldA0K
IyBDT05GSUdfU0hNRU0gaXMgbm90IHNldA0KQ09ORklHX1NMQUI9eQ0KQ09ORklHX1ZNX0VWRU5U
X0NPVU5URVJTPXkNCkNPTkZJR19USU5ZX1NITUVNPXkNCkNPTkZJR19CQVNFX1NNQUxMPTANCiMg
Q09ORklHX1NMT0IgaXMgbm90IHNldA0KDQojDQojIExvYWRhYmxlIG1vZHVsZSBzdXBwb3J0DQoj
DQojIENPTkZJR19NT0RVTEVTIGlzIG5vdCBzZXQNCg0KIw0KIyBCbG9jayBsYXllcg0KIw0KIyBD
T05GSUdfQkxPQ0sgaXMgbm90IHNldA0KDQojDQojIEJ1cyBvcHRpb25zIChQQ0ksIFBDTUNJQSwg
RUlTQSwgSVNBLCBUQykNCiMNCkNPTkZJR19IV19IQVNfUENJPXkNCiMgQ09ORklHX1BDSSBpcyBu
b3Qgc2V0DQpDT05GSUdfTU1VPXkNCg0KIw0KIyBQQ0NBUkQgKFBDTUNJQS9DYXJkQnVzKSBzdXBw
b3J0DQojDQojIENPTkZJR19QQ0NBUkQgaXMgbm90IHNldA0KDQojDQojIFBDSSBIb3RwbHVnIFN1
cHBvcnQNCiMNCg0KIw0KIyBFeGVjdXRhYmxlIGZpbGUgZm9ybWF0cw0KIw0KQ09ORklHX0JJTkZN
VF9FTEY9eQ0KIyBDT05GSUdfQklORk1UX01JU0MgaXMgbm90IHNldA0KQ09ORklHX1RSQURfU0lH
TkFMUz15DQoNCiMNCiMgTmV0d29ya2luZw0KIw0KIyBDT05GSUdfTkVUIGlzIG5vdCBzZXQNCg0K
Iw0KIyBEZXZpY2UgRHJpdmVycw0KIw0KDQojDQojIEdlbmVyaWMgRHJpdmVyIE9wdGlvbnMNCiMN
CkNPTkZJR19TVEFOREFMT05FPXkNCiMgQ09ORklHX1BSRVZFTlRfRklSTVdBUkVfQlVJTEQgaXMg
bm90IHNldA0KQ09ORklHX0ZXX0xPQURFUj15DQojIENPTkZJR19ERUJVR19EUklWRVIgaXMgbm90
IHNldA0KIyBDT05GSUdfU1lTX0hZUEVSVklTT1IgaXMgbm90IHNldA0KDQojDQojIENvbm5lY3Rv
ciAtIHVuaWZpZWQgdXNlcnNwYWNlIDwtPiBrZXJuZWxzcGFjZSBsaW5rZXINCiMNCg0KIw0KIyBN
ZW1vcnkgVGVjaG5vbG9neSBEZXZpY2VzIChNVEQpDQojDQojIENPTkZJR19NVEQgaXMgbm90IHNl
dA0KDQojDQojIFBhcmFsbGVsIHBvcnQgc3VwcG9ydA0KIw0KIyBDT05GSUdfUEFSUE9SVCBpcyBu
b3Qgc2V0DQoNCiMNCiMgUGx1ZyBhbmQgUGxheSBzdXBwb3J0DQojDQoNCiMNCiMgTWlzYyBkZXZp
Y2VzDQojDQojIENPTkZJR19USUZNX0NPUkUgaXMgbm90IHNldA0KDQojDQojIFNDU0kgZGV2aWNl
IHN1cHBvcnQNCiMNCiMgQ09ORklHX1NDU0lfTkVUTElOSyBpcyBub3Qgc2V0DQoNCiMNCiMgU2Vy
aWFsIEFUQSAocHJvZCkgYW5kIFBhcmFsbGVsIEFUQSAoZXhwZXJpbWVudGFsKSBkcml2ZXJzDQoj
DQoNCiMNCiMgRnVzaW9uIE1QVCBkZXZpY2Ugc3VwcG9ydA0KIw0KIyBDT05GSUdfRlVTSU9OIGlz
IG5vdCBzZXQNCg0KIw0KIyBJRUVFIDEzOTQgKEZpcmVXaXJlKSBzdXBwb3J0DQojDQoNCiMNCiMg
STJPIGRldmljZSBzdXBwb3J0DQojDQoNCiMNCiMgSVNETiBzdWJzeXN0ZW0NCiMNCg0KIw0KIyBU
ZWxlcGhvbnkgU3VwcG9ydA0KIw0KIyBDT05GSUdfUEhPTkUgaXMgbm90IHNldA0KDQojDQojIElu
cHV0IGRldmljZSBzdXBwb3J0DQojDQpDT05GSUdfSU5QVVQ9eQ0KIyBDT05GSUdfSU5QVVRfRkZf
TUVNTEVTUyBpcyBub3Qgc2V0DQoNCiMNCiMgVXNlcmxhbmQgaW50ZXJmYWNlcw0KIw0KIyBDT05G
SUdfSU5QVVRfTU9VU0VERVYgaXMgbm90IHNldA0KIyBDT05GSUdfSU5QVVRfSk9ZREVWIGlzIG5v
dCBzZXQNCiMgQ09ORklHX0lOUFVUX1RTREVWIGlzIG5vdCBzZXQNCkNPTkZJR19JTlBVVF9FVkRF
Vj15DQojIENPTkZJR19JTlBVVF9FVkJVRyBpcyBub3Qgc2V0DQoNCiMNCiMgSW5wdXQgRGV2aWNl
IERyaXZlcnMNCiMNCiMgQ09ORklHX0lOUFVUX0tFWUJPQVJEIGlzIG5vdCBzZXQNCiMgQ09ORklH
X0lOUFVUX01PVVNFIGlzIG5vdCBzZXQNCiMgQ09ORklHX0lOUFVUX0pPWVNUSUNLIGlzIG5vdCBz
ZXQNCiMgQ09ORklHX0lOUFVUX1RPVUNIU0NSRUVOIGlzIG5vdCBzZXQNCiMgQ09ORklHX0lOUFVU
X01JU0MgaXMgbm90IHNldA0KDQojDQojIEhhcmR3YXJlIEkvTyBwb3J0cw0KIw0KIyBDT05GSUdf
U0VSSU8gaXMgbm90IHNldA0KIyBDT05GSUdfR0FNRVBPUlQgaXMgbm90IHNldA0KDQojDQojIENo
YXJhY3RlciBkZXZpY2VzDQojDQojIENPTkZJR19WVCBpcyBub3Qgc2V0DQojIENPTkZJR19TRVJJ
QUxfTk9OU1RBTkRBUkQgaXMgbm90IHNldA0KDQojDQojIFNlcmlhbCBkcml2ZXJzDQojDQpDT05G
SUdfU0VSSUFMXzgyNTA9eQ0KQ09ORklHX1NFUklBTF84MjUwX0NPTlNPTEU9eQ0KQ09ORklHX1NF
UklBTF84MjUwX05SX1VBUlRTPTINCkNPTkZJR19TRVJJQUxfODI1MF9SVU5USU1FX1VBUlRTPTIN
CiMgQ09ORklHX1NFUklBTF84MjUwX0VYVEVOREVEIGlzIG5vdCBzZXQNCg0KIw0KIyBOb24tODI1
MCBzZXJpYWwgcG9ydCBzdXBwb3J0DQojDQpDT05GSUdfU0VSSUFMX0NPUkU9eQ0KQ09ORklHX1NF
UklBTF9DT1JFX0NPTlNPTEU9eQ0KQ09ORklHX1VOSVg5OF9QVFlTPXkNCkNPTkZJR19MRUdBQ1lf
UFRZUz15DQpDT05GSUdfTEVHQUNZX1BUWV9DT1VOVD04DQoNCiMNCiMgSVBNSQ0KIw0KIyBDT05G
SUdfSVBNSV9IQU5ETEVSIGlzIG5vdCBzZXQNCg0KIw0KIyBXYXRjaGRvZyBDYXJkcw0KIw0KIyBD
T05GSUdfV0FUQ0hET0cgaXMgbm90IHNldA0KIyBDT05GSUdfSFdfUkFORE9NIGlzIG5vdCBzZXQN
CiMgQ09ORklHX1JUQyBpcyBub3Qgc2V0DQojIENPTkZJR19HRU5fUlRDIGlzIG5vdCBzZXQNCiMg
Q09ORklHX0RUTEsgaXMgbm90IHNldA0KIyBDT05GSUdfUjM5NjQgaXMgbm90IHNldA0KDQojDQoj
IFRQTSBkZXZpY2VzDQojDQojIENPTkZJR19UQ0dfVFBNIGlzIG5vdCBzZXQNCg0KIw0KIyBJMkMg
c3VwcG9ydA0KIw0KQ09ORklHX0kyQz15DQojIENPTkZJR19JMkNfQ0hBUkRFViBpcyBub3Qgc2V0
DQoNCiMNCiMgSTJDIEFsZ29yaXRobXMNCiMNCkNPTkZJR19JMkNfQUxHT0JJVD15DQojIENPTkZJ
R19JMkNfQUxHT1BDRiBpcyBub3Qgc2V0DQojIENPTkZJR19JMkNfQUxHT1BDQSBpcyBub3Qgc2V0
DQoNCiMNCiMgSTJDIEhhcmR3YXJlIEJ1cyBzdXBwb3J0DQojDQojIENPTkZJR19JMkNfT0NPUkVT
IGlzIG5vdCBzZXQNCiMgQ09ORklHX0kyQ19QQVJQT1JUX0xJR0hUIGlzIG5vdCBzZXQNCiMgQ09O
RklHX0kyQ19QQ0FfSVNBIGlzIG5vdCBzZXQNCg0KIw0KIyBNaXNjZWxsYW5lb3VzIEkyQyBDaGlw
IHN1cHBvcnQNCiMNCiMgQ09ORklHX1NFTlNPUlNfRFMxMzM3IGlzIG5vdCBzZXQNCiMgQ09ORklH
X1NFTlNPUlNfRFMxMzc0IGlzIG5vdCBzZXQNCiMgQ09ORklHX1NFTlNPUlNfRUVQUk9NIGlzIG5v
dCBzZXQNCiMgQ09ORklHX1NFTlNPUlNfUENGODU3NCBpcyBub3Qgc2V0DQojIENPTkZJR19TRU5T
T1JTX1BDQTk1MzkgaXMgbm90IHNldA0KIyBDT05GSUdfU0VOU09SU19QQ0Y4NTkxIGlzIG5vdCBz
ZXQNCiMgQ09ORklHX1NFTlNPUlNfTUFYNjg3NSBpcyBub3Qgc2V0DQojIENPTkZJR19JMkNfREVC
VUdfQ09SRSBpcyBub3Qgc2V0DQojIENPTkZJR19JMkNfREVCVUdfQUxHTyBpcyBub3Qgc2V0DQoj
IENPTkZJR19JMkNfREVCVUdfQlVTIGlzIG5vdCBzZXQNCiMgQ09ORklHX0kyQ19ERUJVR19DSElQ
IGlzIG5vdCBzZXQNCg0KIw0KIyBTUEkgc3VwcG9ydA0KIw0KIyBDT05GSUdfU1BJIGlzIG5vdCBz
ZXQNCiMgQ09ORklHX1NQSV9NQVNURVIgaXMgbm90IHNldA0KDQojDQojIERhbGxhcydzIDEtd2ly
ZSBidXMNCiMNCiMgQ09ORklHX1cxIGlzIG5vdCBzZXQNCg0KIw0KIyBIYXJkd2FyZSBNb25pdG9y
aW5nIHN1cHBvcnQNCiMNCiMgQ09ORklHX0hXTU9OIGlzIG5vdCBzZXQNCiMgQ09ORklHX0hXTU9O
X1ZJRCBpcyBub3Qgc2V0DQoNCiMNCiMgTXVsdGltZWRpYSBkZXZpY2VzDQojDQojIENPTkZJR19W
SURFT19ERVYgaXMgbm90IHNldA0KDQojDQojIERpZ2l0YWwgVmlkZW8gQnJvYWRjYXN0aW5nIERl
dmljZXMNCiMNCg0KIw0KIyBHcmFwaGljcyBzdXBwb3J0DQojDQojIENPTkZJR19GSVJNV0FSRV9F
RElEIGlzIG5vdCBzZXQNCiMgQ09ORklHX0ZCIGlzIG5vdCBzZXQNCiMgQ09ORklHX0JBQ0tMSUdI
VF9MQ0RfU1VQUE9SVCBpcyBub3Qgc2V0DQoNCiMNCiMgU291bmQNCiMNCiMgQ09ORklHX1NPVU5E
IGlzIG5vdCBzZXQNCg0KIw0KIyBISUQgRGV2aWNlcw0KIw0KQ09ORklHX0hJRD15DQoNCiMNCiMg
VVNCIHN1cHBvcnQNCiMNCiMgQ09ORklHX1VTQl9BUkNIX0hBU19IQ0QgaXMgbm90IHNldA0KIyBD
T05GSUdfVVNCX0FSQ0hfSEFTX09IQ0kgaXMgbm90IHNldA0KIyBDT05GSUdfVVNCX0FSQ0hfSEFT
X0VIQ0kgaXMgbm90IHNldA0KDQojDQojIE5PVEU6IFVTQl9TVE9SQUdFIGVuYWJsZXMgU0NTSSwg
YW5kICdTQ1NJIGRpc2sgc3VwcG9ydCcNCiMNCg0KIw0KIyBVU0IgR2FkZ2V0IFN1cHBvcnQNCiMN
CiMgQ09ORklHX1VTQl9HQURHRVQgaXMgbm90IHNldA0KDQojDQojIE1NQy9TRCBDYXJkIHN1cHBv
cnQNCiMNCiMgQ09ORklHX01NQyBpcyBub3Qgc2V0DQoNCiMNCiMgTEVEIGRldmljZXMNCiMNCiMg
Q09ORklHX05FV19MRURTIGlzIG5vdCBzZXQNCg0KIw0KIyBMRUQgZHJpdmVycw0KIw0KDQojDQoj
IExFRCBUcmlnZ2Vycw0KIw0KDQojDQojIEluZmluaUJhbmQgc3VwcG9ydA0KIw0KDQojDQojIEVE
QUMgLSBlcnJvciBkZXRlY3Rpb24gYW5kIHJlcG9ydGluZyAoUkFTKSAoRVhQRVJJTUVOVEFMKQ0K
Iw0KDQojDQojIFJlYWwgVGltZSBDbG9jaw0KIw0KIyBDT05GSUdfUlRDX0NMQVNTIGlzIG5vdCBz
ZXQNCg0KIw0KIyBUYW5nbzIgZGV2aWNlcw0KIw0KIyBDT05GSUdfVEFOR08yX0ZJUCBpcyBub3Qg
c2V0DQojIENPTkZJR19UQU5HTzJfR1BJTyBpcyBub3Qgc2V0DQojIENPTkZJR19UQU5HTzJfSVIg
aXMgbm90IHNldA0KDQojDQojIERNQSBFbmdpbmUgc3VwcG9ydA0KIw0KIyBDT05GSUdfRE1BX0VO
R0lORSBpcyBub3Qgc2V0DQoNCiMNCiMgRE1BIENsaWVudHMNCiMNCg0KIw0KIyBETUEgRGV2aWNl
cw0KIw0KDQojDQojIFZpcnR1YWxpemF0aW9uDQojDQoNCiMNCiMgRmlsZSBzeXN0ZW1zDQojDQoj
IENPTkZJR19JTk9USUZZIGlzIG5vdCBzZXQNCiMgQ09ORklHX1FVT1RBIGlzIG5vdCBzZXQNCiMg
Q09ORklHX0ROT1RJRlkgaXMgbm90IHNldA0KIyBDT05GSUdfQVVUT0ZTX0ZTIGlzIG5vdCBzZXQN
CiMgQ09ORklHX0FVVE9GUzRfRlMgaXMgbm90IHNldA0KIyBDT05GSUdfRlVTRV9GUyBpcyBub3Qg
c2V0DQoNCiMNCiMgUHNldWRvIGZpbGVzeXN0ZW1zDQojDQpDT05GSUdfUFJPQ19GUz15DQojIENP
TkZJR19QUk9DX0tDT1JFIGlzIG5vdCBzZXQNCkNPTkZJR19QUk9DX1NZU0NUTD15DQpDT05GSUdf
U1lTRlM9eQ0KQ09ORklHX1RNUEZTPXkNCiMgQ09ORklHX1RNUEZTX1BPU0lYX0FDTCBpcyBub3Qg
c2V0DQojIENPTkZJR19IVUdFVExCX1BBR0UgaXMgbm90IHNldA0KQ09ORklHX1JBTUZTPXkNCiMg
Q09ORklHX0NPTkZJR0ZTX0ZTIGlzIG5vdCBzZXQNCiMgQ09ORklHX0NUTVBfRlMgaXMgbm90IHNl
dA0KDQojDQojIE1pc2NlbGxhbmVvdXMgZmlsZXN5c3RlbXMNCiMNCiMgQ09ORklHX1NRVUFTSEZT
IGlzIG5vdCBzZXQNCg0KIw0KIyBOYXRpdmUgTGFuZ3VhZ2UgU3VwcG9ydA0KIw0KQ09ORklHX05M
Uz15DQpDT05GSUdfTkxTX0RFRkFVTFQ9Imlzbzg4NTktMSINCkNPTkZJR19OTFNfQ09ERVBBR0Vf
NDM3PXkNCiMgQ09ORklHX05MU19DT0RFUEFHRV83MzcgaXMgbm90IHNldA0KIyBDT05GSUdfTkxT
X0NPREVQQUdFXzc3NSBpcyBub3Qgc2V0DQpDT05GSUdfTkxTX0NPREVQQUdFXzg1MD15DQojIENP
TkZJR19OTFNfQ09ERVBBR0VfODUyIGlzIG5vdCBzZXQNCiMgQ09ORklHX05MU19DT0RFUEFHRV84
NTUgaXMgbm90IHNldA0KIyBDT05GSUdfTkxTX0NPREVQQUdFXzg1NyBpcyBub3Qgc2V0DQojIENP
TkZJR19OTFNfQ09ERVBBR0VfODYwIGlzIG5vdCBzZXQNCiMgQ09ORklHX05MU19DT0RFUEFHRV84
NjEgaXMgbm90IHNldA0KIyBDT05GSUdfTkxTX0NPREVQQUdFXzg2MiBpcyBub3Qgc2V0DQojIENP
TkZJR19OTFNfQ09ERVBBR0VfODYzIGlzIG5vdCBzZXQNCiMgQ09ORklHX05MU19DT0RFUEFHRV84
NjQgaXMgbm90IHNldA0KIyBDT05GSUdfTkxTX0NPREVQQUdFXzg2NSBpcyBub3Qgc2V0DQojIENP
TkZJR19OTFNfQ09ERVBBR0VfODY2IGlzIG5vdCBzZXQNCiMgQ09ORklHX05MU19DT0RFUEFHRV84
NjkgaXMgbm90IHNldA0KIyBDT05GSUdfTkxTX0NPREVQQUdFXzkzNiBpcyBub3Qgc2V0DQojIENP
TkZJR19OTFNfQ09ERVBBR0VfOTUwIGlzIG5vdCBzZXQNCiMgQ09ORklHX05MU19DT0RFUEFHRV85
MzIgaXMgbm90IHNldA0KIyBDT05GSUdfTkxTX0NPREVQQUdFXzk0OSBpcyBub3Qgc2V0DQojIENP
TkZJR19OTFNfQ09ERVBBR0VfODc0IGlzIG5vdCBzZXQNCiMgQ09ORklHX05MU19JU084ODU5Xzgg
aXMgbm90IHNldA0KIyBDT05GSUdfTkxTX0NPREVQQUdFXzEyNTAgaXMgbm90IHNldA0KIyBDT05G
SUdfTkxTX0NPREVQQUdFXzEyNTEgaXMgbm90IHNldA0KQ09ORklHX05MU19BU0NJST15DQpDT05G
SUdfTkxTX0lTTzg4NTlfMT15DQojIENPTkZJR19OTFNfSVNPODg1OV8yIGlzIG5vdCBzZXQNCiMg
Q09ORklHX05MU19JU084ODU5XzMgaXMgbm90IHNldA0KIyBDT05GSUdfTkxTX0lTTzg4NTlfNCBp
cyBub3Qgc2V0DQojIENPTkZJR19OTFNfSVNPODg1OV81IGlzIG5vdCBzZXQNCiMgQ09ORklHX05M
U19JU084ODU5XzYgaXMgbm90IHNldA0KIyBDT05GSUdfTkxTX0lTTzg4NTlfNyBpcyBub3Qgc2V0
DQojIENPTkZJR19OTFNfSVNPODg1OV85IGlzIG5vdCBzZXQNCiMgQ09ORklHX05MU19JU084ODU5
XzEzIGlzIG5vdCBzZXQNCiMgQ09ORklHX05MU19JU084ODU5XzE0IGlzIG5vdCBzZXQNCkNPTkZJ
R19OTFNfSVNPODg1OV8xNT15DQojIENPTkZJR19OTFNfS09JOF9SIGlzIG5vdCBzZXQNCiMgQ09O
RklHX05MU19LT0k4X1UgaXMgbm90IHNldA0KQ09ORklHX05MU19VVEY4PXkNCg0KIw0KIyBQcm9m
aWxpbmcgc3VwcG9ydA0KIw0KIyBDT05GSUdfUFJPRklMSU5HIGlzIG5vdCBzZXQNCg0KIw0KIyBL
ZXJuZWwgaGFja2luZw0KIw0KQ09ORklHX1RSQUNFX0lSUUZMQUdTX1NVUFBPUlQ9eQ0KIyBDT05G
SUdfUFJJTlRLX1RJTUUgaXMgbm90IHNldA0KQ09ORklHX0VOQUJMRV9NVVNUX0NIRUNLPXkNCiMg
Q09ORklHX01BR0lDX1NZU1JRIGlzIG5vdCBzZXQNCiMgQ09ORklHX1VOVVNFRF9TWU1CT0xTIGlz
IG5vdCBzZXQNCiMgQ09ORklHX0RFQlVHX0ZTIGlzIG5vdCBzZXQNCiMgQ09ORklHX0hFQURFUlNf
Q0hFQ0sgaXMgbm90IHNldA0KQ09ORklHX0RFQlVHX0tFUk5FTD15DQpDT05GSUdfTE9HX0JVRl9T
SElGVD0xNA0KQ09ORklHX0RFVEVDVF9TT0ZUTE9DS1VQPXkNCiMgQ09ORklHX1NDSEVEU1RBVFMg
aXMgbm90IHNldA0KIyBDT05GSUdfREVCVUdfU0xBQiBpcyBub3Qgc2V0DQojIENPTkZJR19ERUJV
R19TUElOTE9DSyBpcyBub3Qgc2V0DQojIENPTkZJR19ERUJVR19NVVRFWEVTIGlzIG5vdCBzZXQN
CiMgQ09ORklHX0RFQlVHX1JXU0VNUyBpcyBub3Qgc2V0DQojIENPTkZJR19ERUJVR19MT0NLX0FM
TE9DIGlzIG5vdCBzZXQNCiMgQ09ORklHX1BST1ZFX0xPQ0tJTkcgaXMgbm90IHNldA0KIyBDT05G
SUdfREVCVUdfU1BJTkxPQ0tfU0xFRVAgaXMgbm90IHNldA0KIyBDT05GSUdfREVCVUdfTE9DS0lO
R19BUElfU0VMRlRFU1RTIGlzIG5vdCBzZXQNCiMgQ09ORklHX0RFQlVHX0tPQkpFQ1QgaXMgbm90
IHNldA0KIyBDT05GSUdfREVCVUdfSU5GTyBpcyBub3Qgc2V0DQojIENPTkZJR19ERUJVR19WTSBp
cyBub3Qgc2V0DQojIENPTkZJR19ERUJVR19MSVNUIGlzIG5vdCBzZXQNCkNPTkZJR19GT1JDRURf
SU5MSU5JTkc9eQ0KIyBDT05GSUdfUkNVX1RPUlRVUkVfVEVTVCBpcyBub3Qgc2V0DQpDT05GSUdf
Q1JPU1NDT01QSUxFPXkNCkNPTkZJR19DTURMSU5FPSJjb25zb2xlPXR0eVMwIHJvb3Q9L2Rldi9u
ZnMgaXA9ZGhjcCINCiMgQ09ORklHX0RFQlVHX1NUQUNLX1VTQUdFIGlzIG5vdCBzZXQNCiMgQ09O
RklHX0tHREIgaXMgbm90IHNldA0KQ09ORklHX1JVTlRJTUVfREVCVUc9eQ0KIyBDT05GSUdfTUlQ
U19VTkNBQ0hFRCBpcyBub3Qgc2V0DQoNCiMNCiMgU2VjdXJpdHkgb3B0aW9ucw0KIw0KIyBDT05G
SUdfS0VZUyBpcyBub3Qgc2V0DQojIENPTkZJR19TRUNVUklUWSBpcyBub3Qgc2V0DQoNCiMNCiMg
Q3J5cHRvZ3JhcGhpYyBvcHRpb25zDQojDQojIENPTkZJR19DUllQVE8gaXMgbm90IHNldA0KDQoj
DQojIExpYnJhcnkgcm91dGluZXMNCiMNCkNPTkZJR19CSVRSRVZFUlNFPXkNCiMgQ09ORklHX0NS
Q19DQ0lUVCBpcyBub3Qgc2V0DQojIENPTkZJR19DUkMxNiBpcyBub3Qgc2V0DQpDT05GSUdfQ1JD
MzI9eQ0KIyBDT05GSUdfTElCQ1JDMzJDIGlzIG5vdCBzZXQNCkNPTkZJR19JT01BUF9DT1BZPXkN
Cm==


--=-7g/3cxzQffsJDqhryWgC
Content-Disposition: attachment; filename=dmesg.txt
Content-Type: text/plain; name=dmesg.txt; charset=ANSI_X3.4-1968
Content-Transfer-Encoding: base64

TGludXggdmVyc2lvbiAyLjYuMjAgKG1heEBzYWt1cmEpIChnY2MgdmVyc2lvbiA0LjEuMikgIzQw
IE1vbiBNYXIgNSAxNzoxNTo1NyBDRVQgMjAwNw0KcHJvbSBjb25zb2xlIHJlZ2lzdGVyZWQNCkNQ
VSByZXZpc2lvbiBpczogMDAwMTkwNjgNCkRldGVybWluZWQgcGh5c2ljYWwgUkFNIG1hcDoNCiBt
ZW1vcnk6IDAyMDAwMDAwIEAgMTAwMDAwMDAgKHVzYWJsZSkNCkRFQlVHOiByZXNlcnZlZF9lbmQ6
IDB4MDAwMjAxZDUNCkRFQlVHOiBpbml0X2Jvb3RtZW1fbm9kZTogbWFwc3RhcnQ6MHhmZmZmZmZm
ZiBtaW5fbG93X3BmbjoweDAwMDEwMDAwIG1heF9sb3dfcGZuOjB4MDAwMTIwMDANCg==


--=-7g/3cxzQffsJDqhryWgC
Content-Disposition: attachment; filename=dmesg-manual-reserved_end.txt
Content-Type: text/plain; name=dmesg-manual-reserved_end.txt; charset=ANSI_X3.4-1968
Content-Transfer-Encoding: base64

TGludXggdmVyc2lvbiAyLjYuMjAgKG1heEBzYWt1cmEpIChnY2MgdmVyc2lvbiA0LjEuMikgIzQx
IE1vbiBNYXIgNSAxNzoxODowNCBDRVQgMjAwNw0KcHJvbSBjb25zb2xlIHJlZ2lzdGVyZWQNCkNQ
VSByZXZpc2lvbiBpczogMDAwMTkwNjgNCkRldGVybWluZWQgcGh5c2ljYWwgUkFNIG1hcDoNCiBt
ZW1vcnk6IDAyMDAwMDAwIEAgMTAwMDAwMDAgKHVzYWJsZSkNCkRFQlVHOiByZXNlcnZlZF9lbmQ6
IDB4MDAwMTAxZDUNCkRFQlVHOiBpbml0X2Jvb3RtZW1fbm9kZTogbWFwc3RhcnQ6MHgwMDAxMDFk
NSBtaW5fbG93X3BmbjoweDAwMDEwMDAwIG1heF9sb3dfcGZuOjB4MDAwMTIwMDANCk9uIG5vZGUg
MCB0b3RhbHBhZ2VzOiA4MTkyDQogIERNQSB6b25lOiA2NCBwYWdlcyB1c2VkIGZvciBtZW1tYXAN
CiAgRE1BIHpvbmU6IDAgcGFnZXMgcmVzZXJ2ZWQNCiAgRE1BIHpvbmU6IDgxMjggcGFnZXMsIExJ
Rk8gYmF0Y2g6MA0KICBOb3JtYWwgem9uZTogMCBwYWdlcyB1c2VkIGZvciBtZW1tYXANCkJ1aWx0
IDEgem9uZWxpc3RzLiAgVG90YWwgcGFnZXM6IDgxMjgNCktlcm5lbCBjb21tYW5kIGxpbmU6IGNv
bnNvbGU9dHR5UzAgcm9vdD0vZGV2L25mcyBpcD1kaGNwDQpQcmltYXJ5IGluc3RydWN0aW9uIGNh
Y2hlIDE2a0IsIHBoeXNpY2FsbHkgdGFnZ2VkLCAyLXdheSwgbGluZXNpemUgMTYgYnl0ZXMuDQpQ
cmltYXJ5IGRhdGEgY2FjaGUgMTZrQiwgMi13YXksIGxpbmVzaXplIDE2IGJ5dGVzLg0KU3ludGhl
c2l6ZWQgVExCIHJlZmlsbCBoYW5kbGVyICgyMCBpbnN0cnVjdGlvbnMpLg0KU3ludGhlc2l6ZWQg
VExCIGxvYWQgaGFuZGxlciBmYXN0cGF0aCAoMzIgaW5zdHJ1Y3Rpb25zKS4NClN5bnRoZXNpemVk
IFRMQiBzdG9yZSBoYW5kbGVyIGZhc3RwYXRoICgzMiBpbnN0cnVjdGlvbnMpLg0KU3ludGhlc2l6
ZWQgVExCIG1vZGlmeSBoYW5kbGVyIGZhc3RwYXRoICgzMSBpbnN0cnVjdGlvbnMpLg0KUElEIGhh
c2ggdGFibGUgZW50cmllczogMTI4IChvcmRlcjogNywgNTEyIGJ5dGVzKQ0KVXNpbmcgMTUwLjc1
MCBNSHogaGlnaCBwcmVjaXNpb24gdGltZXIuDQpEZW50cnkgY2FjaGUgaGFzaCB0YWJsZSBlbnRy
aWVzOiA0MDk2IChvcmRlcjogMiwgMTYzODQgYnl0ZXMpDQpJbm9kZS1jYWNoZSBoYXNoIHRhYmxl
IGVudHJpZXM6IDIwNDggKG9yZGVyOiAxLCA4MTkyIGJ5dGVzKQ0KQmFkIHBhZ2Ugc3RhdGUgaW4g
cHJvY2VzcyAnc3dhcHBlcicNCnBhZ2U6ODEwMDAwMDAgZmxhZ3M6MHgwMDAwMDAwMCBtYXBwaW5n
OjAwMDAwMDAwIG1hcGNvdW50OjEgY291bnQ6MA0KVHJ5aW5nIHRvIGZpeCBpdCB1cCwgYnV0IGEg
cmVib290IGlzIG5lZWRlZA0KQmFja3RyYWNlOg0KQ2FsbCBUcmFjZToNCls8OTAwMjlmMTA+XSBk
dW1wX3N0YWNrKzB4OC8weDM0DQpbPDkwMDZhYzU4Pl0gYmFkX3BhZ2UrMHg2OC8weGE4DQpbPDkw
MDZiMGE0Pl0gX19mcmVlX3BhZ2VzX29rKzB4MzU4LzB4MzdjDQpbPDkwMTNkMmQwPl0gZnJlZV9h
bGxfYm9vdG1lbV9jb3JlKzB4MjRjLzB4MjcwDQpbPDkwMTM0ZThjPl0gbWVtX2luaXQrMHg0MC8w
eDE5Yw0KWzw5MDEyZDgyOD5dIHN0YXJ0X2tlcm5lbCsweDFkNC8weDM2Yw0KDQpCYWQgcGFnZSBz
dGF0ZSBpbiBwcm9jZXNzICdzd2FwcGVyJw0KcGFnZTo4MTAwMDAyMCBmbGFnczoweDAwMDAwMDAw
IG1hcHBpbmc6MDAwMDAwMDAgbWFwY291bnQ6MSBjb3VudDowDQpUcnlpbmcgdG8gZml4IGl0IHVw
LCBidXQgYSByZWJvb3QgaXMgbmVlZGVkDQpCYWNrdHJhY2U6DQpDYWxsIFRyYWNlOg0KWzw5MDAy
OWYxMD5dIGR1bXBfc3RhY2srMHg4LzB4MzQNCls8OTAwNmFjNTg+XSBiYWRfcGFnZSsweDY4LzB4
YTgNCls8OTAwNmIwYTQ+XSBfX2ZyZWVfcGFnZXNfb2srMHgzNTgvMHgzN2MNCls8OTAxM2QyZDA+
XSBmcmVlX2FsbF9ib290bWVtX2NvcmUrMHgyNGMvMHgyNzANCls8OTAxMzRlOGM+XSBtZW1faW5p
dCsweDQwLzB4MTljDQpbPDkwMTJkODI4Pl0gc3RhcnRfa2VybmVsKzB4MWQ0LzB4MzZjDQo=


--=-7g/3cxzQffsJDqhryWgC--

From djohnson@sw.starentnetworks.com Mon Mar  5 16:52:56 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 16:53:02 +0000 (GMT)
Received: from newmail.sw.starentnetworks.com ([12.33.234.78]:56990 "EHLO
	mail.sw.starentnetworks.com") by ftp.linux-mips.org with ESMTP
	id S20037605AbXCEQw4 (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 16:52:56 +0000
Received: from zeus.sw.starentnetworks.com (zeus.sw.starentnetworks.com [12.33.233.46])
	by mail.sw.starentnetworks.com (Postfix) with ESMTP id BD0F63E15F
	for <linux-mips@linux-mips.org>; Mon,  5 Mar 2007 11:52:05 -0500 (EST)
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Message-ID: <17900.19125.660006.553487@zeus.sw.starentnetworks.com>
Date:	Mon, 5 Mar 2007 11:52:05 -0500
From:	Dave Johnson <djohnson+linux-mips@sw.starentnetworks.com>
To:	linux-mips@linux-mips.org
Subject: Re: SMP+PREEMPT causes NULL dereference in khelper on startup
In-Reply-To: <17897.48239.366047.442797@zeus.sw.starentnetworks.com>
References: <17897.48239.366047.442797@zeus.sw.starentnetworks.com>
X-Mailer: VM 7.17 under 21.4 (patch 17) "Jumbo Shrimp" XEmacs Lucid
Return-Path: <djohnson@sw.starentnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14362
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: djohnson+linux-mips@sw.starentnetworks.com
Precedence: bulk
X-list: linux-mips

Dave Johnson writes:
> It appears a0 to detach_pid (*task) points to somewhere wrong as
> 'link' (now in a1) is a valid pointer, but points to a bunch of
> zeros.

I found the issue.  This appears to be a compiler bug in
__unhash_process().

SMP (works):
-----------

ffffffff8013c940:       0220f809        jalr    s1
ffffffff8013c944:       0080802d        move    s0,a0
ffffffff8013c948:       24050001        li      a1,1
ffffffff8013c94c:       de020170        ld      v0,368(s0)
ffffffff8013c950:       12020015        beq     s0,v0,ffffffff8013c9a8 <$L10>
ffffffff8013c954:       0200202d        move    a0,s0

[...]

ffffffff8013c9a8 <$L10>:
ffffffff8013c9a8:       0220f809        jalr    s1    <<< detach_pid(p, PIDTYPE_PGID);
ffffffff8013c9ac:       00000000        nop
ffffffff8013c9b0:       0200202d        move    a0,s0
ffffffff8013c9b4:       0220f809        jalr    s1    <<< detach_pid(p, PIDTYPE_SID);
ffffffff8013c9b8:       24050002        li      a1,2


SMP+PREEMPT (fails):
-------------------

ffffffff8013e62c:       0220f809        jalr    s1
ffffffff8013e630:       0080802d        move    s0,a0
ffffffff8013e634:       24050001        li      a1,1
ffffffff8013e638:       de020170        ld      v0,368(s0)
ffffffff8013e63c:       12020016        beq     s0,v0,ffffffff8013e698 <$L10>
ffffffff8013e640:       0200202d        move    a0,s0

[...]
ffffffff8013e698 <$L10>:
ffffffff8013e698:       0220f809        jalr    s1    <<< detach_pid(p, PIDTYPE_PGID);
ffffffff8013e69c:       0200202d        move    a0,s0
ffffffff8013e6a0:       0220f809        jalr    s1    <<< detach_pid(p, PIDTYPE_SID);
ffffffff8013e6a4:       24050002        li      a1,2


The delay slot is missing after the first call causing a0 to not
get set for the second call.



-- 
Dave Johnson
Starent Networks


From ddaney@avtrex.com Mon Mar  5 17:04:27 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 17:04:32 +0000 (GMT)
Received: from smtp1.dnsmadeeasy.com ([205.234.170.134]:23989 "EHLO
	smtp1.dnsmadeeasy.com") by ftp.linux-mips.org with ESMTP
	id S20037640AbXCERE1 (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 17:04:27 +0000
Received: from smtp1.dnsmadeeasy.com (localhost [127.0.0.1])
	by smtp1.dnsmadeeasy.com (Postfix) with ESMTP id 33BCD29A020;
	Mon,  5 Mar 2007 12:03:39 -0500 (EST)
X-Authenticated-Name: js.dnsmadeeasy
X-Transit-System: In case of SPAM please contact abuse@dnsmadeeasy.com
Received: from avtrex.com (unknown [67.116.42.147])
	by smtp1.dnsmadeeasy.com (Postfix) with ESMTP;
	Mon,  5 Mar 2007 12:03:38 -0500 (EST)
Received: from [192.168.7.26] ([192.168.7.26]) by avtrex.com with Microsoft SMTPSVC(6.0.3790.1830);
	 Mon, 5 Mar 2007 09:03:33 -0800
Message-ID: <45EC4D64.5050803@avtrex.com>
Date:	Mon, 05 Mar 2007 09:03:32 -0800
From:	David Daney <ddaney@avtrex.com>
User-Agent: Thunderbird 1.5.0.9 (X11/20070212)
MIME-Version: 1.0
To:	Dave Johnson <djohnson+linux-mips@sw.starentnetworks.com>
Cc:	linux-mips@linux-mips.org
Subject: Re: SMP+PREEMPT causes NULL dereference in khelper on startup
References: <17897.48239.366047.442797@zeus.sw.starentnetworks.com> <17900.19125.660006.553487@zeus.sw.starentnetworks.com>
In-Reply-To: <17900.19125.660006.553487@zeus.sw.starentnetworks.com>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-OriginalArrivalTime: 05 Mar 2007 17:03:33.0412 (UTC) FILETIME=[34F53E40:01C75F48]
Return-Path: <ddaney@avtrex.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14363
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@avtrex.com
Precedence: bulk
X-list: linux-mips

Dave Johnson wrote:
> Dave Johnson writes:
>> It appears a0 to detach_pid (*task) points to somewhere wrong as
>> 'link' (now in a1) is a valid pointer, but points to a bunch of
>> zeros.
> 
> I found the issue.  This appears to be a compiler bug in
> __unhash_process().

Perhaps you could tell us the compiler/binutils versions you are using.

It is not unheard of that compiler bugs get fixed.  So if the problem 
can still be reproduced with GCC 4.1 or 4.2, you could file a bug report 
here:

http://gcc.gnu.org/bugzilla/

Thanks,
David Daney

From djohnson@sw.starentnetworks.com Mon Mar  5 18:19:01 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Mar 2007 18:19:08 +0000 (GMT)
Received: from newmail.sw.starentnetworks.com ([12.33.234.78]:54912 "EHLO
	mail.sw.starentnetworks.com") by ftp.linux-mips.org with ESMTP
	id S20037619AbXCESTB (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Mar 2007 18:19:01 +0000
Received: from zeus.sw.starentnetworks.com (zeus.sw.starentnetworks.com [12.33.233.46])
	by mail.sw.starentnetworks.com (Postfix) with ESMTP id ED3F63E357;
	Mon,  5 Mar 2007 13:18:23 -0500 (EST)
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Message-ID: <17900.24303.861861.342312@zeus.sw.starentnetworks.com>
Date:	Mon, 5 Mar 2007 13:18:23 -0500
From:	Dave Johnson <djohnson+linux-mips@sw.starentnetworks.com>
To:	linux-mips@linux-mips.org, David Daney <ddaney@avtrex.com>
Subject: Re: SMP+PREEMPT causes NULL dereference in khelper on startup
In-Reply-To: <45EC4D64.5050803@avtrex.com>
References: <17897.48239.366047.442797@zeus.sw.starentnetworks.com>
	<17900.19125.660006.553487@zeus.sw.starentnetworks.com>
	<45EC4D64.5050803@avtrex.com>
X-Mailer: VM 7.17 under 21.4 (patch 17) "Jumbo Shrimp" XEmacs Lucid
Return-Path: <djohnson@sw.starentnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14364
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: djohnson+linux-mips@sw.starentnetworks.com
Precedence: bulk
X-list: linux-mips

David Daney writes:
> Dave Johnson wrote:
> > I found the issue.  This appears to be a compiler bug in
> > __unhash_process().
> 
> Perhaps you could tell us the compiler/binutils versions you are using.

Very old:

sbtools-2.7.1 (a.k.a. '3.2.3 with SiByte modifications')

We've found other problems in sbtools-2.5.11 (a.k.a. '3.0.3 with
SiByte modifications') relating to incorrect structure offset
calculations, but this is the first problem we've found in 3.2.3.

I'll probably look into upgrading again...

-- 
Dave Johnson
Starent Networks


From djohnson@sw.starentnetworks.com Tue Mar  6 01:51:06 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 01:51:08 +0000 (GMT)
Received: from newmail.sw.starentnetworks.com ([12.33.234.78]:40113 "EHLO
	mail.sw.starentnetworks.com") by ftp.linux-mips.org with ESMTP
	id S20021315AbXCFBvG (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Mar 2007 01:51:06 +0000
Received: from zeus.sw.starentnetworks.com (zeus.sw.starentnetworks.com [12.33.233.46])
	by mail.sw.starentnetworks.com (Postfix) with ESMTP id 0D0BB3E267;
	Mon,  5 Mar 2007 20:50:27 -0500 (EST)
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Message-ID: <17900.51427.895657.607267@zeus.sw.starentnetworks.com>
Date:	Mon, 5 Mar 2007 20:50:27 -0500
From:	Dave Johnson <djohnson+linux-mips@sw.starentnetworks.com>
To:	linux-mips@linux-mips.org, Ralf Baechle <ralf@linux-mips.org>
Subject: [PATCH] Fix __raw_read_trylock() to allow multiple readers
X-Mailer: VM 7.17 under 21.4 (patch 17) "Jumbo Shrimp" XEmacs Lucid
Return-Path: <djohnson@sw.starentnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14365
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: djohnson+linux-mips@sw.starentnetworks.com
Precedence: bulk
X-list: linux-mips


Code is from linux-mips.org's git tree at 2.6.18 plus some patches
from 2.6.18.7.

I've run into a deadlock that occurs with the following config:

CONFIG_SMP
CONFIG_PREEMPT

An individual call to __raw_read_trylock() will just return failure if
there is already a reader.

Any code that tries to take a read lock by looping around
__raw_read_trylock() can deadlock if there is already a reader and the
lock in question has a mix of irq and non-irq readers.

This is the case in the _read_lock() from BUILD_LOCK_OPS() in
kernel/spinlock.c.

Perhaps someone can confirm this bug by a code inspection, but I
think the below patch will fix the issue.

Patch should apply ok to 2.6.18.7 (and a similar one to >= 2.6.19)

-- 
Dave Johnson
Starent Networks

========================  PATCH FOLLOWS  ========================

Fix __raw_read_trylock() to allow multiple readers.

A deadlock can occur for mixed irq and non-irq rwlock readers if
a 2nd reader attempts to take lock by looping around __raw_read_trylock().

Signed-off-by: Dave Johnson <djohnson+linux-mips@sw.starentnetworks.com>

--- old/include/asm-mips/spinlock.h	2007-03-05 20:34:51.000000000 -0500
+++ new/include/asm-mips/spinlock.h	2007-03-05 20:35:18.000000000 -0500
@@ -249,7 +249,7 @@
 		"	.set	noreorder	# __raw_read_trylock	\n"
 		"	li	%2, 0					\n"
 		"1:	ll	%1, %3					\n"
-		"	bnez	%1, 2f					\n"
+		"	bltz	%1, 2f					\n"
 		"	 addu	%1, 1					\n"
 		"	sc	%1, %0					\n"
 		"	beqzl	%1, 1b					\n"
@@ -267,7 +267,7 @@
 		"	.set	noreorder	# __raw_read_trylock	\n"
 		"	li	%2, 0					\n"
 		"1:	ll	%1, %3					\n"
-		"	bnez	%1, 2f					\n"
+		"	bltz	%1, 2f					\n"
 		"	 addu	%1, 1					\n"
 		"	sc	%1, %0					\n"
 		"	beqz	%1, 1b					\n"


From marco.braga@gmail.com Tue Mar  6 08:16:06 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 08:16:33 +0000 (GMT)
Received: from an-out-0708.google.com ([209.85.132.249]:29691 "EHLO
	an-out-0708.google.com") by ftp.linux-mips.org with ESMTP
	id S20021344AbXCFIQG (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Mar 2007 08:16:06 +0000
Received: by an-out-0708.google.com with SMTP id c8so1598998ana
        for <linux-mips@linux-mips.org>; Tue, 06 Mar 2007 00:16:03 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:references;
        b=XS3/oSqi6gX/1KKa+gg9Vs7NmAf/Y9AiX7wKrzpYickd8dB3F4DdwxlyUU+rGt/XctnqZl5kAzyXYLHTgT0Czdd8Rm1ukTk4tR54RXl9izuNKff5vAlKP5Zluo3+jBVw1GHi7yIqDAznxDDKQXAjS9cQnxzuISv/vjJc7npxi28=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:references;
        b=BTIsMbt0ReEYY0If9SvLT+C4AOBQnRHODvaAlqcp4Wwow/EN+lJdzr4Yc237rDOcvDBpdA8evZSM+XdBwfiLPtoslUq7PM/Aw0Kxue9qw9D38M7Kp9BymD0gTE4WUsCvEiM4pgwTdaLHEtetNEpTuNslNpZa3VW4lNZXpQnZtjY=
Received: by 10.114.193.1 with SMTP id q1mr1634889waf.1173168963406;
        Tue, 06 Mar 2007 00:16:03 -0800 (PST)
Received: by 10.114.80.18 with HTTP; Tue, 6 Mar 2007 00:16:03 -0800 (PST)
Message-ID: <d459bb380703060016o350e4070w77d2954071f3c40a@mail.gmail.com>
Date:	Tue, 6 Mar 2007 09:16:03 +0100
From:	"Marco Braga" <marco.braga@gmail.com>
To:	"Sergei Shtylyov" <sshtylyov@ru.mvista.com>
Subject: Re: Linux kernel 2.6.20, PCI and hpt266
Cc:	linux-mips@linux-mips.org
In-Reply-To: <45EC101D.8050600@ru.mvista.com>
MIME-Version: 1.0
Content-Type: multipart/alternative; 
	boundary="----=_Part_156766_29971928.1173168963355"
References: <d459bb380703040427g4a8cad08kd8e3190f7d109c86@mail.gmail.com>
	 <45EC101D.8050600@ru.mvista.com>
Return-Path: <marco.braga@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14366
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: marco.braga@gmail.com
Precedence: bulk
X-list: linux-mips

------=_Part_156766_29971928.1173168963355
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hello,

I have a quick update on the situation. I've compiled kernel 2.6.17.14 for
the same architecture and the hard disk controller works. Moreover I've
imported the new hpt366.c driver from kernel 2.6.20 into kernel 2.6.17 and
it works perfectly, managing the "missing first channel" issue with 371N
without a problem. Still I'd like to understand where is the problem with
kernel 2.6.20. It seems to me that resource and pci mamagement has changed a
lot, sadly I'm not experienced enough to understand the exact details or
follow up the problem. My only clue here is that "inb" does not work
correctly on PCI I/O mapped registers.

Thank you for any help on this issue!

------=_Part_156766_29971928.1173168963355
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hello,<br><br>I have a quick update on the situation. I&#39;ve compiled kernel <a href="http://2.6.17.14">2.6.17.14</a> for the same architecture and the hard disk controller works. Moreover I&#39;ve imported the new hpt366.c
 driver from kernel 2.6.20 into kernel 2.6.17 and it works perfectly, managing the &quot;missing first channel&quot; issue with 371N without a problem. Still I&#39;d like to understand where is the problem with kernel 2.6.20
. It seems to me that resource and pci mamagement has changed a lot, sadly I&#39;m not experienced enough to understand the exact details or follow up the problem. My only clue here is that &quot;inb&quot; does not work correctly on PCI I/O mapped registers.
<br><br>Thank you for any help on this issue!<br><br><br>

------=_Part_156766_29971928.1173168963355--

From Mile.Davidovic@micronasnit.com Tue Mar  6 08:59:53 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 08:59:57 +0000 (GMT)
Received: from krt.tmd.ns.ac.yu ([147.91.177.65]:52629 "HELO krt.neobee.net")
	by ftp.linux-mips.org with SMTP id S20021350AbXCFI7x (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Tue, 6 Mar 2007 08:59:53 +0000
Received: from localhost (localhost [127.0.0.1])
	by krt.neobee.net (Postfix) with ESMTP id E19C7278040
	for <linux-mips@linux-mips.org>; Tue,  6 Mar 2007 09:59:22 +0100 (CET)
X-Virus-Scanned: amavisd-new at krt.neobee.net
Received: from krt.neobee.net ([127.0.0.1])
	by localhost (krt.neobee.net [127.0.0.1]) (amavisd-new, port 10024)
	with LMTP id hNFLOumUtyZn for <linux-mips@linux-mips.org>;
	Tue,  6 Mar 2007 09:59:22 +0100 (CET)
Received: from had (unknown [192.168.193.90])
	by krt.neobee.net (Postfix) with ESMTP id CAE52278031
	for <linux-mips@linux-mips.org>; Tue,  6 Mar 2007 09:59:21 +0100 (CET)
From:	"Mile Davidovic" <Mile.Davidovic@micronasnit.com>
To:	<linux-mips@linux-mips.org>
References: <20070305162826.GC786@linux-mips.org>
In-Reply-To: <20070305162826.GC786@linux-mips.org>
Subject: RE: Encrypt user file system
Date:	Tue, 6 Mar 2007 10:02:13 +0100
Message-ID: <023501c75fce$21c37db0$654a7910$@Davidovic@micronasnit.com>
MIME-Version: 1.0
Content-Type: text/plain;
	charset="Windows-1252"
Content-Transfer-Encoding: 7bit
X-Mailer: Microsoft Office Outlook 12.0
Thread-Index: AcdfQ6udbicM6h1fR36sutkqSTaAdAAiRUJw
Content-Language: sr
x-cr-hashedpuzzle: ASXg Axsp C2ol DPT5 DRKr E08S FM9F FlPs GAii GPAt GQqv G68Y HeOJ H/1w IVER IiXz;1;bABpAG4AdQB4AC0AbQBpAHAAcwBAAGwAaQBuAHUAeAAtAG0AaQBwAHMALgBvAHIAZwA=;Sosha1_v1;7;{2D5F0227-1C15-44F8-95FF-AE49686C1945};bQBpAGwAZQAuAGQAYQB2AGkAZABvAHYAaQBjAEAAbQBpAGMAcgBvAG4AYQBzAG4AaQB0AC4AYwBvAG0A;Tue, 06 Mar 2007 09:02:06 GMT;UgBFADoAIABFAG4AYwByAHkAcAB0ACAAdQBzAGUAcgAgAGYAaQBsAGUAIABzAHkAcwB0AGUAbQA=
x-cr-puzzleid: {2D5F0227-1C15-44F8-95FF-AE49686C1945}
Return-Path: <Mile.Davidovic@micronasnit.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14367
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: Mile.Davidovic@micronasnit.com
Precedence: bulk
X-list: linux-mips

Thanks a lot, it make sense. But my question is not precise, 
I am wonder if MTD block device could be encrypted with dm-crypt.
But this is questions for MTD mailing list.

Best regards Mile


But if I want to crypt MTD device 
> 
> > What is mips way for encrypting user file system?
> > On intel we can use combination dm-crypt and we could crypt complete user
> FS I
> > suppose that should work on MIPS too?
> 
> Yes, of course.
> 
>   Ralf


From demiourgos@gmail.com Tue Mar  6 11:07:25 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 11:07:27 +0000 (GMT)
Received: from nf-out-0910.google.com ([64.233.182.186]:37764 "EHLO
	nf-out-0910.google.com") by ftp.linux-mips.org with ESMTP
	id S20021344AbXCFLHZ (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Mar 2007 11:07:25 +0000
Received: by nf-out-0910.google.com with SMTP id l24so2325694nfc
        for <linux-mips@linux-mips.org>; Tue, 06 Mar 2007 03:06:25 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=odHefe32hztH4osQHubEk7v7CPspyKT0sF1X6iX8zZmyWJ4OGTadmuVFXACxvFr786pCf46Ab04i7D5np2YkioyehCK8fGj/gXnt7A+8eDMaAxVpicsVjDRMo+U+F+fpCwMeMH31bfeaxb25X3L1LafNovFiE1uKuZlDFhe1Tuc=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=AB8aF3E56A72N+hsI6kGuBGEA+MrYrvCgWOPu5DVyf9rj5vCRcAUgOc0MESaouJhrdB89IPSo/X2WrDZ47ysT8tyfSqwo82wvh2caUgVgGUXYJpnpc8DTsyVlyVyPkjp1sf6R8sBQujh4te9QE5ogaku7QGI/hh6emId41dlUa8=
Received: by 10.78.138.6 with SMTP id l6mr765057hud.1173179185385;
        Tue, 06 Mar 2007 03:06:25 -0800 (PST)
Received: by 10.78.44.13 with HTTP; Tue, 6 Mar 2007 03:06:25 -0800 (PST)
Message-ID: <c4357ccd0703060306x6135cf22p39d55ff79ed7ad45@mail.gmail.com>
Date:	Tue, 6 Mar 2007 13:06:25 +0200
From:	"Alexander Sirotkin" <demiourgos@gmail.com>
To:	linux-mips@linux-mips.org
Subject: Re: 0 function size
In-Reply-To: <20070305162745.GB786@linux-mips.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
References: <c4357ccd0703050619r6b5a7452j6b582687bf1794d3@mail.gmail.com>
	 <b115cb5f0703050821v50667580oa8dfa26412c05b08@mail.gmail.com>
	 <20070305162745.GB786@linux-mips.org>
Return-Path: <demiourgos@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14368
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: demiourgos@gmail.com
Precedence: bulk
X-list: linux-mips

On 3/5/07, Ralf Baechle <ralf@linux-mips.org> wrote:
> On Mon, Mar 05, 2007 at 09:51:25PM +0530, Rajat Jain wrote:
>
> > Are you using a native compiler or a cross compiler?
> >
> > If you are using a cross compiler, then you need to use the "cross
> > compiler" version of objdump / readelf  utilities as well. For
> > instance if you are using mips-linux-gcc to compile, then you need
> > mips-linux-readelf / mips-linux-objdump etc.
>
> In general your're right but for this particular purpose for example an
> i386-linux-objdump will do the job for 32-bit big and little endian
> MIPS ELF.  It will - depending on the exact binutils configuration - fail
> with an error message for 64-bit ELF.
>
>   Ralf
>

Apparently it is a bug in MIPS SDE toolchain, even in the latest version 6.05.
With emdebian toolchain it works just fine.

From jeff@garzik.org Tue Mar  6 11:23:19 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 11:23:22 +0000 (GMT)
Received: from srv5.dvmed.net ([207.36.208.214]:48592 "EHLO mail.dvmed.net")
	by ftp.linux-mips.org with ESMTP id S20021358AbXCFLXT (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Tue, 6 Mar 2007 11:23:19 +0000
Received: from cpe-065-190-194-075.nc.res.rr.com ([65.190.194.75] helo=[10.10.10.10])
	by mail.dvmed.net with esmtpsa (Exim 4.63 #1 (Red Hat Linux))
	id 1HOXi8-0002Ma-SC; Tue, 06 Mar 2007 11:20:05 +0000
Message-ID: <45ED4E64.5030404@garzik.org>
Date:	Tue, 06 Mar 2007 06:20:04 -0500
From:	Jeff Garzik <jeff@garzik.org>
User-Agent: Thunderbird 1.5.0.10 (X11/20070302)
MIME-Version: 1.0
To:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
CC:	linux-mips@linux-mips.org, ralf@linux-mips.org,
	netdev@vger.kernel.org, sshtylyov@ru.mvista.com
Subject: Re: [PATCH] tc35815 driver update (take 2)
References: <20070303.235459.25478204.anemo@mba.ocn.ne.jp>
In-Reply-To: <20070303.235459.25478204.anemo@mba.ocn.ne.jp>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <jeff@garzik.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14369
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: jeff@garzik.org
Precedence: bulk
X-list: linux-mips

Atsushi Nemoto wrote:
> Current tc35815 driver is very obsolete and less maintained for a long
> time.  Replace it with a new driver based on one from CELF patch
> archive.
> 
> Major advantages of CELF version (version 1.23, for kernel 2.6.10) are:
> 
> * Independent of JMR3927.
>   (Actually independent of MIPS, but AFAIK the chip is used only on
>    MIPS platforms)
> * TX4938 support.
> * 64-bit proof.
> * Asynchronous and on-demand auto negotiation.
> * High performance on non-coherent architecture.
> * ethtool support.
> * Many bugfixes and cleanups.
> 
> And improvoments since version 1.23 are:
> 
> * TX4939 support.
> * NETPOLL support.
> * NAPI support. (disabled by default)
> * Reduce memcpy on receiving.
> * PM support.
> * Many cleanups and bugfixes.
> 
> Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
> 
>  drivers/net/Kconfig     |    3 
>  drivers/net/tc35815.c   | 2587 ++++++++++++++++++++++++++++++++++------------
>  include/linux/pci_ids.h |    2 
>  3 files changed, 1917 insertions(+), 675 deletions(-)

applied to #upstream, let's give it a good review while it hangs out in 
libata-dev.git#ALL and -mm



From yoichi_yuasa@tripeaks.co.jp Tue Mar  6 12:36:12 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 12:36:15 +0000 (GMT)
Received: from mo31.po.2iij.net ([210.128.50.54]:60959 "EHLO mo31.po.2iij.net")
	by ftp.linux-mips.org with ESMTP id S20021367AbXCFMgM (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Tue, 6 Mar 2007 12:36:12 +0000
Received: by mo.po.2iij.net (mo31) id l26CYo3G041416; Tue, 6 Mar 2007 21:34:50 +0900 (JST)
Received: from localhost.localdomain (70.27.30.125.dy.iij4u.or.jp [125.30.27.70])
	by mbox.po.2iij.net (mbox32) id l26CYi0I014215
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT);
	Tue, 6 Mar 2007 21:34:45 +0900 (JST)
Date:	Tue, 6 Mar 2007 21:34:44 +0900
From:	Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	yoichi_yuasa@tripeaks.co.jp, linux-mips <linux-mips@linux-mips.org>
Subject: [PATCH][MIPS] clean up include files for Cobalt
Message-Id: <20070306213444.7b826d1d.yoichi_yuasa@tripeaks.co.jp>
Organization: TriPeaks Corporation
X-Mailer: Sylpheed version 1.0.6 (GTK+ 1.2.10; i486-pc-linux-gnu)
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Return-Path: <yoichi_yuasa@tripeaks.co.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14370
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: yoichi_yuasa@tripeaks.co.jp
Precedence: bulk
X-list: linux-mips

Hi Ralf,

This patch has cleaned up include files for Cobalt.

Yoichi

Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>

diff -pruN -X mips/Documentation/dontdiff mips-orig/arch/mips/cobalt/console.c mips/arch/mips/cobalt/console.c
--- mips-orig/arch/mips/cobalt/console.c	2007-03-05 06:51:23.517795750 +0900
+++ mips/arch/mips/cobalt/console.c	2007-03-05 06:54:18.104706750 +0900
@@ -1,13 +1,11 @@
 /*
  * (C) P. Horton 2006
  */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/console.h>
 #include <linux/serial_reg.h>
+
 #include <asm/addrspace.h>
-#include <asm/mach-cobalt/cobalt.h>
+
+#include <cobalt.h>
 
 void prom_putchar(char c)
 {
diff -pruN -X mips/Documentation/dontdiff mips-orig/arch/mips/cobalt/irq.c mips/arch/mips/cobalt/irq.c
--- mips-orig/arch/mips/cobalt/irq.c	2007-03-05 06:51:23.517795750 +0900
+++ mips/arch/mips/cobalt/irq.c	2007-03-05 06:54:18.104706750 +0900
@@ -17,7 +17,7 @@
 #include <asm/irq_cpu.h>
 #include <asm/gt64120.h>
 
-#include <asm/mach-cobalt/cobalt.h>
+#include <cobalt.h>
 
 /*
  * We have two types of interrupts that we handle, ones that come in through
diff -pruN -X mips/Documentation/dontdiff mips-orig/arch/mips/cobalt/reset.c mips/arch/mips/cobalt/reset.c
--- mips-orig/arch/mips/cobalt/reset.c	2007-03-05 06:51:23.521796000 +0900
+++ mips/arch/mips/cobalt/reset.c	2007-03-05 06:54:18.104706750 +0900
@@ -8,15 +8,12 @@
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv)
  */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/cacheflush.h>
+#include <linux/jiffies.h>
+
 #include <asm/io.h>
-#include <asm/processor.h>
 #include <asm/reboot.h>
-#include <asm/system.h>
-#include <asm/mipsregs.h>
-#include <asm/mach-cobalt/cobalt.h>
+
+#include <cobalt.h>
 
 void cobalt_machine_halt(void)
 {
diff -pruN -X mips/Documentation/dontdiff mips-orig/arch/mips/cobalt/setup.c mips/arch/mips/cobalt/setup.c
--- mips-orig/arch/mips/cobalt/setup.c	2007-03-05 06:56:04.679367250 +0900
+++ mips/arch/mips/cobalt/setup.c	2007-03-05 06:54:18.120707750 +0900
@@ -19,12 +19,10 @@
 #include <asm/bootinfo.h>
 #include <asm/time.h>
 #include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/processor.h>
 #include <asm/reboot.h>
 #include <asm/gt64120.h>
 
-#include <asm/mach-cobalt/cobalt.h>
+#include <cobalt.h>
 
 extern void cobalt_machine_restart(char *command);
 extern void cobalt_machine_halt(void);

From ralf@linux-mips.org Tue Mar  6 14:25:18 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 14:25:20 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:60858 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20021392AbXCFOZS (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Mar 2007 14:25:18 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l26ENPiB022459;
	Tue, 6 Mar 2007 14:23:25 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l26ENNwS022458;
	Tue, 6 Mar 2007 14:23:23 GMT
Date:	Tue, 6 Mar 2007 14:23:23 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Dave Johnson <djohnson+linux-mips@sw.starentnetworks.com>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH] Fix __raw_read_trylock() to allow multiple readers
Message-ID: <20070306142323.GA20948@linux-mips.org>
References: <17900.51427.895657.607267@zeus.sw.starentnetworks.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <17900.51427.895657.607267@zeus.sw.starentnetworks.com>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14371
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Mon, Mar 05, 2007 at 08:50:27PM -0500, Dave Johnson wrote:

> Perhaps someone can confirm this bug by a code inspection, but I
> think the below patch will fix the issue.

You're right, thanks!

Patch applied,

  Ralf

From anemo@mba.ocn.ne.jp Tue Mar  6 15:02:50 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 15:02:55 +0000 (GMT)
Received: from mba.ocn.ne.jp ([122.1.175.29]:16620 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20021392AbXCFPCu (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Tue, 6 Mar 2007 15:02:50 +0000
Received: from localhost (p5247-ipad28funabasi.chiba.ocn.ne.jp [220.107.204.247])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id A91F7BB2D; Tue,  6 Mar 2007 23:13:18 +0900 (JST)
Date:	Tue, 06 Mar 2007 23:13:18 +0900 (JST)
Message-Id: <20070306.231318.05599238.anemo@mba.ocn.ne.jp>
To:	jeff@garzik.org
Cc:	linux-mips@linux-mips.org, ralf@linux-mips.org,
	netdev@vger.kernel.org, sshtylyov@ru.mvista.com
Subject: Re: [PATCH] tc35815 driver update (take 2)
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
In-Reply-To: <45ED4E64.5030404@garzik.org>
References: <20070303.235459.25478204.anemo@mba.ocn.ne.jp>
	<45ED4E64.5030404@garzik.org>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14372
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

On Tue, 06 Mar 2007 06:20:04 -0500, Jeff Garzik <jeff@garzik.org> wrote:
> applied to #upstream, let's give it a good review while it hangs out in 
> libata-dev.git#ALL and -mm

Thank you.  I believe you mean netdev-2.6.git :)

---
Atsushi Nemoto

From michael@ozlabs.org Tue Mar  6 15:07:29 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 15:07:33 +0000 (GMT)
Received: from ozlabs.org ([203.10.76.45]:1669 "EHLO ozlabs.org")
	by ftp.linux-mips.org with ESMTP id S20021393AbXCFPH3 (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Tue, 6 Mar 2007 15:07:29 +0000
Received: by ozlabs.org (Postfix, from userid 1034)
	id C0234DDF0E; Wed,  7 Mar 2007 02:06:48 +1100 (EST)
To:	Greg Kroah-Hartman <greg@kroah.com>
CC:	linux-pci@atrey.karlin.mff.cuni.cz, <linuxppc-dev@ozlabs.org>,
	<dev-etrax@axis.com>, <ink@jurassic.park.msu.ru>,
	<rth@twiddle.net>, <kernel@wantstofly.org>,
	<linux-ia64@vger.kernel.org>, <linux-m68k@lists.linux-m68k.org>,
	<gerg@uclinux.org>, <linux-mips@linux-mips.org>,
	<parisc-linux@parisc-linux.org>, <sparclinux@vger.kernel.org>,
	<uclinux-v850@lsi.nec.co.jp>, <discuss@x86-64.org>,
	<chris@zankel.net>, <dhowells@redhat.com>
From:	Michael Ellerman <michael@ellerman.id.au>
Date:	Tue, 06 Mar 2007 16:06:08 +0100
Subject: [PATCH 1/2] Use a weak symbol for the empty version of pcibios_add_platform_entries()
Message-Id: <1173193568.89821.610708199943.qpush@concordia>
Return-Path: <michael@ozlabs.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14373
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: michael@ellerman.id.au
Precedence: bulk
X-list: linux-mips

I'm not sure if this is going to fly, weak symbols work on the compilers I'm
using, but whether they work for all of the affected architectures I can't say.
I've cc'ed as many arch maintainers/lists as I could find.

But assuming they do, we can use a weak empty definition of
pcibios_add_platform_entries() to avoid having an empty definition on every
arch.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/ppc/kernel/pci.c       |    6 ------
 drivers/pci/pci-sysfs.c     |    5 +++++
 include/asm-alpha/pci.h     |    5 -----
 include/asm-arm/pci.h       |    4 ----
 include/asm-cris/pci.h      |    4 ----
 include/asm-frv/pci.h       |    4 ----
 include/asm-h8300/pci.h     |    4 ----
 include/asm-i386/pci.h      |    4 ----
 include/asm-ia64/pci.h      |    4 ----
 include/asm-m68k/pci.h      |    4 ----
 include/asm-m68knommu/pci.h |    4 ----
 include/asm-mips/pci.h      |    4 ----
 include/asm-parisc/pci.h    |    4 ----
 include/asm-powerpc/pci.h   |    2 --
 include/asm-ppc/pci.h       |    2 --
 include/asm-sh/pci.h        |    4 ----
 include/asm-sh64/pci.h      |    4 ----
 include/asm-sparc/pci.h     |    4 ----
 include/asm-sparc64/pci.h   |    4 ----
 include/asm-v850/pci.h      |    4 ----
 include/asm-x86_64/pci.h    |    4 ----
 include/asm-xtensa/pci.h    |    4 ----
 include/linux/pci.h         |    2 ++
 23 files changed, 7 insertions(+), 83 deletions(-)

Index: msi-new/arch/ppc/kernel/pci.c
===================================================================
--- msi-new.orig/arch/ppc/kernel/pci.c
+++ msi-new/arch/ppc/kernel/pci.c
@@ -633,12 +633,6 @@ void pcibios_make_OF_bus_map(void)
 {
 }
 
-/* Add sysfs properties */
-void pcibios_add_platform_entries(struct pci_dev *pdev)
-{
-}
-
-
 static int __init
 pcibios_init(void)
 {
Index: msi-new/drivers/pci/pci-sysfs.c
===================================================================
--- msi-new.orig/drivers/pci/pci-sysfs.c
+++ msi-new/drivers/pci/pci-sysfs.c
@@ -600,6 +600,11 @@ static struct bin_attribute pcie_config_
 	.write = pci_write_config,
 };
 
+void __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
+{
+	return;
+}
+
 int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
 {
 	struct bin_attribute *rom_attr = NULL;
Index: msi-new/include/asm-alpha/pci.h
===================================================================
--- msi-new.orig/include/asm-alpha/pci.h
+++ msi-new/include/asm-alpha/pci.h
@@ -275,11 +275,6 @@ static inline int pci_proc_domain(struct
 	return hose->need_domain_info;
 }
 
-static inline void
-pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 struct pci_dev *alpha_gendev_to_pci(struct device *dev);
 
 #endif /* __KERNEL__ */
Index: msi-new/include/asm-arm/pci.h
===================================================================
--- msi-new.orig/include/asm-arm/pci.h
+++ msi-new/include/asm-arm/pci.h
@@ -76,10 +76,6 @@ pcibios_select_root(struct pci_dev *pdev
 	return root;
 }
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
  
 #endif
Index: msi-new/include/asm-cris/pci.h
===================================================================
--- msi-new.orig/include/asm-cris/pci.h
+++ msi-new/include/asm-cris/pci.h
@@ -89,10 +89,6 @@ extern int pci_mmap_page_range(struct pc
 			       enum pci_mmap_state mmap_state, int write_combine);
 
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
 
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
Index: msi-new/include/asm-frv/pci.h
===================================================================
--- msi-new.orig/include/asm-frv/pci.h
+++ msi-new/include/asm-frv/pci.h
@@ -22,10 +22,6 @@ struct pci_dev;
 
 #define pcibios_assign_all_busses()	0
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 extern void pcibios_set_master(struct pci_dev *dev);
 
 extern void pcibios_penalize_isa_irq(int irq);
Index: msi-new/include/asm-h8300/pci.h
===================================================================
--- msi-new.orig/include/asm-h8300/pci.h
+++ msi-new/include/asm-h8300/pci.h
@@ -22,8 +22,4 @@ static inline void pcibios_penalize_isa_
 
 #define PCI_DMA_BUS_IS_PHYS	(1)
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* _ASM_H8300_PCI_H */
Index: msi-new/include/asm-i386/pci.h
===================================================================
--- msi-new.orig/include/asm-i386/pci.h
+++ msi-new/include/asm-i386/pci.h
@@ -94,10 +94,6 @@ extern int pci_mmap_page_range(struct pc
 			       enum pci_mmap_state mmap_state, int write_combine);
 
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 					enum pci_dma_burst_strategy *strat,
Index: msi-new/include/asm-ia64/pci.h
===================================================================
--- msi-new.orig/include/asm-ia64/pci.h
+++ msi-new/include/asm-ia64/pci.h
@@ -142,10 +142,6 @@ static inline int pci_proc_domain(struct
 	return (pci_domain_nr(bus) != 0);
 }
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 extern void pcibios_resource_to_bus(struct pci_dev *dev,
 		struct pci_bus_region *region, struct resource *res);
 
Index: msi-new/include/asm-m68k/pci.h
===================================================================
--- msi-new.orig/include/asm-m68k/pci.h
+++ msi-new/include/asm-m68k/pci.h
@@ -54,8 +54,4 @@ static inline void pcibios_penalize_isa_
  */
 #define PCI_DMA_BUS_IS_PHYS	(1)
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* _ASM_M68K_PCI_H */
Index: msi-new/include/asm-m68knommu/pci.h
===================================================================
--- msi-new.orig/include/asm-m68knommu/pci.h
+++ msi-new/include/asm-m68knommu/pci.h
@@ -30,10 +30,6 @@ static inline int pci_dma_supported(stru
  */
 #define pci_dac_dma_supported(pci_dev, mask) (0)
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* CONFIG_COMEMPCI */
 
 #endif /* M68KNOMMU_PCI_H */
Index: msi-new/include/asm-mips/pci.h
===================================================================
--- msi-new.orig/include/asm-mips/pci.h
+++ msi-new/include/asm-mips/pci.h
@@ -181,10 +181,6 @@ static inline int pci_proc_domain(struct
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 /* Do platform specific device initialization at pci_enable_device() time */
 extern int pcibios_plat_dev_init(struct pci_dev *dev);
 
Index: msi-new/include/asm-parisc/pci.h
===================================================================
--- msi-new.orig/include/asm-parisc/pci.h
+++ msi-new/include/asm-parisc/pci.h
@@ -284,10 +284,6 @@ pcibios_select_root(struct pci_dev *pdev
 	return root;
 }
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 static inline void pcibios_penalize_isa_irq(int irq, int active)
 {
 	/* We don't need to penalize isa irq's */
Index: msi-new/include/asm-powerpc/pci.h
===================================================================
--- msi-new.orig/include/asm-powerpc/pci.h
+++ msi-new/include/asm-powerpc/pci.h
@@ -237,8 +237,6 @@ extern void of_scan_bus(struct device_no
 
 extern int pci_read_irq_line(struct pci_dev *dev);
 
-extern void pcibios_add_platform_entries(struct pci_dev *dev);
-
 struct file;
 extern pgprot_t	pci_phys_mem_access_prot(struct file *file,
 					 unsigned long pfn,
Index: msi-new/include/asm-ppc/pci.h
===================================================================
--- msi-new.orig/include/asm-ppc/pci.h
+++ msi-new/include/asm-ppc/pci.h
@@ -145,8 +145,6 @@ pcibios_select_root(struct pci_dev *pdev
 	return root;
 }
 
-extern void pcibios_add_platform_entries(struct pci_dev *dev);
-
 struct file;
 extern pgprot_t	pci_phys_mem_access_prot(struct file *file,
 					 unsigned long pfn,
Index: msi-new/include/asm-sh/pci.h
===================================================================
--- msi-new.orig/include/asm-sh/pci.h
+++ msi-new/include/asm-sh/pci.h
@@ -134,10 +134,6 @@ int pcibios_map_platform_irq(struct pci_
 int pciauto_assign_resources(int busno, struct pci_channel *hose);
 #endif
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
 
 /* generic pci stuff */
Index: msi-new/include/asm-sh64/pci.h
===================================================================
--- msi-new.orig/include/asm-sh64/pci.h
+++ msi-new/include/asm-sh64/pci.h
@@ -104,10 +104,6 @@ extern void pcibios_fixup_irqs(void);
 extern int pciauto_assign_resources(int busno, struct pci_channel *hose);
 #endif
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
 
 /* generic pci stuff */
Index: msi-new/include/asm-sparc/pci.h
===================================================================
--- msi-new.orig/include/asm-sparc/pci.h
+++ msi-new/include/asm-sparc/pci.h
@@ -154,10 +154,6 @@ static inline void pci_dma_burst_advice(
 }
 #endif
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #define PCI_DMA_ERROR_CODE      (~(dma_addr_t)0x0)
 
 static inline int pci_dma_mapping_error(dma_addr_t dma_addr)
Index: msi-new/include/asm-sparc64/pci.h
===================================================================
--- msi-new.orig/include/asm-sparc64/pci.h
+++ msi-new/include/asm-sparc64/pci.h
@@ -303,10 +303,6 @@ pcibios_bus_to_resource(struct pci_dev *
 
 extern struct resource *pcibios_select_root(struct pci_dev *, struct resource *);
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 {
 	return PCI_IRQ_NONE;
Index: msi-new/include/asm-v850/pci.h
===================================================================
--- msi-new.orig/include/asm-v850/pci.h
+++ msi-new/include/asm-v850/pci.h
@@ -116,8 +116,4 @@ static inline void pci_dma_burst_advice(
 extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 extern void pci_iounmap (struct pci_dev *dev, void __iomem *addr);
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __V850_PCI_H__ */
Index: msi-new/include/asm-x86_64/pci.h
===================================================================
--- msi-new.orig/include/asm-x86_64/pci.h
+++ msi-new/include/asm-x86_64/pci.h
@@ -135,10 +135,6 @@ static inline void pci_dma_burst_advice(
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 			       enum pci_mmap_state mmap_state, int write_combine);
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
 
 /* generic pci stuff */
Index: msi-new/include/asm-xtensa/pci.h
===================================================================
--- msi-new.orig/include/asm-xtensa/pci.h
+++ msi-new/include/asm-xtensa/pci.h
@@ -74,10 +74,6 @@ int pci_mmap_page_range(struct pci_dev *
 /* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
 #define HAVE_PCI_MMAP	1
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
 
 /* Implement the pci_ DMA API in terms of the generic device dma_ one */
Index: msi-new/include/linux/pci.h
===================================================================
--- msi-new.orig/include/linux/pci.h
+++ msi-new/include/linux/pci.h
@@ -857,5 +857,7 @@ extern int pci_pci_problems;
 extern unsigned long pci_cardbus_io_size;
 extern unsigned long pci_cardbus_mem_size;
 
+extern void pcibios_add_platform_entries(struct pci_dev *dev);
+
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */

From michael@ozlabs.org Tue Mar  6 15:08:15 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 15:08:19 +0000 (GMT)
Received: from ozlabs.org ([203.10.76.45]:60038 "EHLO ozlabs.org")
	by ftp.linux-mips.org with ESMTP id S20021391AbXCFPIP (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Tue, 6 Mar 2007 15:08:15 +0000
Received: by ozlabs.org (Postfix, from userid 1034)
	id 68D97DDF36; Wed,  7 Mar 2007 02:07:25 +1100 (EST)
To:	Greg Kroah-Hartman <greg@kroah.com>
CC:	linux-pci@atrey.karlin.mff.cuni.cz, <linuxppc-dev@ozlabs.org>,
	<dev-etrax@axis.com>, <ink@jurassic.park.msu.ru>,
	<rth@twiddle.net>, <kernel@wantstofly.org>,
	<linux-ia64@vger.kernel.org>, <linux-m68k@lists.linux-m68k.org>,
	<gerg@uclinux.org>, <linux-mips@linux-mips.org>,
	<parisc-linux@parisc-linux.org>, <sparclinux@vger.kernel.org>,
	<uclinux-v850@lsi.nec.co.jp>, <discuss@x86-64.org>,
	<chris@zankel.net>, <dhowells@redhat.com>
From:	Michael Ellerman <michael@ellerman.id.au>
Date:	Tue, 06 Mar 2007 16:06:49 +0100
Subject: [PATCH 2/2] Make pcibios_add_platform_entries() return errors
In-Reply-To: <1173193568.89821.610708199943.qpush@concordia>
Message-Id: <20070306150725.68D97DDF36@ozlabs.org>
Return-Path: <michael@ozlabs.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14374
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: michael@ellerman.id.au
Precedence: bulk
X-list: linux-mips

Currently pcibios_add_platform_entries() returns void, but could fail,
so instead have it return an int and propagate errors up to
pci_create_sysfs_dev_files().

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/kernel/pci_32.c |    4 ++--
 arch/powerpc/kernel/pci_64.c |    4 ++--
 drivers/pci/pci-sysfs.c      |    9 ++++++---
 include/linux/pci.h          |    2 +-
 4 files changed, 11 insertions(+), 8 deletions(-)

Index: msi-new/arch/powerpc/kernel/pci_32.c
===================================================================
--- msi-new.orig/arch/powerpc/kernel/pci_32.c
+++ msi-new/arch/powerpc/kernel/pci_32.c
@@ -1037,10 +1037,10 @@ void pcibios_make_OF_bus_map(void)
 #endif /* CONFIG_PPC_OF */
 
 /* Add sysfs properties */
-void pcibios_add_platform_entries(struct pci_dev *pdev)
+int pcibios_add_platform_entries(struct pci_dev *pdev)
 {
 #ifdef CONFIG_PPC_OF
-	device_create_file(&pdev->dev, &dev_attr_devspec);
+	return device_create_file(&pdev->dev, &dev_attr_devspec);
 #endif /* CONFIG_PPC_OF */
 }
 
Index: msi-new/arch/powerpc/kernel/pci_64.c
===================================================================
--- msi-new.orig/arch/powerpc/kernel/pci_64.c
+++ msi-new/arch/powerpc/kernel/pci_64.c
@@ -863,9 +863,9 @@ static ssize_t pci_show_devspec(struct d
 }
 static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
 
-void pcibios_add_platform_entries(struct pci_dev *pdev)
+int pcibios_add_platform_entries(struct pci_dev *pdev)
 {
-	device_create_file(&pdev->dev, &dev_attr_devspec);
+	return device_create_file(&pdev->dev, &dev_attr_devspec);
 }
 
 #define ISA_SPACE_MASK 0x1
Index: msi-new/drivers/pci/pci-sysfs.c
===================================================================
--- msi-new.orig/drivers/pci/pci-sysfs.c
+++ msi-new/drivers/pci/pci-sysfs.c
@@ -600,9 +600,9 @@ static struct bin_attribute pcie_config_
 	.write = pci_write_config,
 };
 
-void __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
+int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
 {
-	return;
+	return 0;
 }
 
 int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
@@ -644,10 +644,13 @@ int __must_check pci_create_sysfs_dev_fi
 		}
 	}
 	/* add platform-specific attributes */
-	pcibios_add_platform_entries(pdev);
+	if (pcibios_add_platform_entries(pdev))
+		goto err_rom_attr;
 
 	return 0;
 
+err_rom_attr:
+	sysfs_remove_bin_file(&pdev->dev.kobj, rom_attr);
 err_rom:
 	kfree(rom_attr);
 err_bin_file:
Index: msi-new/include/linux/pci.h
===================================================================
--- msi-new.orig/include/linux/pci.h
+++ msi-new/include/linux/pci.h
@@ -857,7 +857,7 @@ extern int pci_pci_problems;
 extern unsigned long pci_cardbus_io_size;
 extern unsigned long pci_cardbus_mem_size;
 
-extern void pcibios_add_platform_entries(struct pci_dev *dev);
+extern int pcibios_add_platform_entries(struct pci_dev *dev);
 
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */

From anemo@mba.ocn.ne.jp Tue Mar  6 15:34:06 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 15:34:11 +0000 (GMT)
Received: from mba.ocn.ne.jp ([122.1.175.29]:34248 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20021399AbXCFPeG (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Tue, 6 Mar 2007 15:34:06 +0000
Received: from localhost (p5247-ipad28funabasi.chiba.ocn.ne.jp [220.107.204.247])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP id D4016B9AE
	for <linux-mips@linux-mips.org>; Wed,  7 Mar 2007 00:32:45 +0900 (JST)
Date:	Wed, 07 Mar 2007 00:32:45 +0900 (JST)
Message-Id: <20070307.003245.82352388.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Subject: Re: fadvise on MIPS
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
In-Reply-To: <20070217.004812.03978264.anemo@mba.ocn.ne.jp>
References: <20070217.004329.108739438.anemo@mba.ocn.ne.jp>
	<20070217.004812.03978264.anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14375
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

On Sat, 17 Feb 2007 00:48:12 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote:
> > 2) On O32, glibc pass a 'long long' argument by hi and lo words, but
> > kernel needs padding word between 'fd' and 'offset' argument.
> > 
> > 3) On N32, glibc pass a 'long long' argument by hi and lo words, but
> > kernel expects a single register value for 'long long' argument.
> 
> And sync_file_range() has some problem too.

And readahead() too ...

From anemo@mba.ocn.ne.jp Tue Mar  6 15:37:14 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 15:37:19 +0000 (GMT)
Received: from mba.ocn.ne.jp ([122.1.175.29]:34293 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20021405AbXCFPhO (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Tue, 6 Mar 2007 15:37:14 +0000
Received: from localhost (p5247-ipad28funabasi.chiba.ocn.ne.jp [220.107.204.247])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP id 14594BA90
	for <linux-mips@linux-mips.org>; Wed,  7 Mar 2007 00:35:54 +0900 (JST)
Date:	Wed, 07 Mar 2007 00:35:53 +0900 (JST)
Message-Id: <20070307.003553.48531257.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Subject: Re: fadvise on MIPS
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
In-Reply-To: <20070303.012914.15243240.anemo@mba.ocn.ne.jp>
References: <20070217.004329.108739438.anemo@mba.ocn.ne.jp>
	<20070217.004812.03978264.anemo@mba.ocn.ne.jp>
	<20070303.012914.15243240.anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14376
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

On Sat, 03 Mar 2007 01:29:14 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote:
> > For N32 and O32, kernel should be fixed anyway, but which syscall
> > should be supported?  And whether kernel or libc should take care of
> > 'long long' issue?
> 
> Then how about this absolutely untested patch?

I had forgotten changing __NR_Linux_syscalls, etc.  And I found
readahead() has same problem, and sys32_readahead() and
sys32_sync_file_range() does not match with glibc.  I'll send a new
patch, fixing them all in kernel side.

---
Atsushi Nemoto

From anemo@mba.ocn.ne.jp Tue Mar  6 16:02:48 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 16:02:53 +0000 (GMT)
Received: from mba.ocn.ne.jp ([122.1.175.29]:50139 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20021413AbXCFQCs (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Tue, 6 Mar 2007 16:02:48 +0000
Received: from localhost (p5247-ipad28funabasi.chiba.ocn.ne.jp [220.107.204.247])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id BF949BA90; Wed,  7 Mar 2007 00:39:31 +0900 (JST)
Date:	Wed, 07 Mar 2007 00:39:31 +0900 (JST)
Message-Id: <20070307.003931.25235381.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org, kraj@mvista.com
Subject: [PATCH] Fix some system calls with long long arguments
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14377
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

fadvise64(), readahead(), sync_file_range() have long long argument(s)
but glibc passes it by hi/lo pair without padding, on both O32 and
N32.

Also wire up fadvise64_64() and fixup confusion of it with
fadvise64().

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
 arch/mips/kernel/linux32.c     |   16 ----------------
 arch/mips/kernel/scall32-o32.S |    7 ++++---
 arch/mips/kernel/scall64-n32.S |    5 +++--
 arch/mips/kernel/scall64-o32.S |    3 ++-
 arch/mips/kernel/syscall.c     |   33 +++++++++++++++++++++++++++++++++
 include/asm-mips/unistd.h      |   10 ++++++----
 6 files changed, 48 insertions(+), 26 deletions(-)

diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 30d433f..71e1524 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -528,22 +528,6 @@ asmlinkage int sys32_sendfile(int out_fd
 	return ret;
 }
 
-asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3,
-                                   size_t count)
-{
-	return sys_readahead(fd, merge_64(a2, a3), count);
-}
-
-asmlinkage long sys32_sync_file_range(int fd, int __pad,
-	unsigned long a2, unsigned long a3,
-	unsigned long a4, unsigned long a5,
-	int flags)
-{
-	return sys_sync_file_range(fd,
-			merge_64(a2, a3), merge_64(a4, a5),
-			flags);
-}
-
 save_static_function(sys32_clone);
 __attribute_used__ noinline static int
 _sys32_clone(nabi_no_regargs struct pt_regs regs)
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 7c0b393..b898a7c 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -554,7 +554,7 @@ einval:	li	v0, -EINVAL
 	sys	sys_fcntl64		3	/* 4220 */
 	sys	sys_ni_syscall		0
 	sys	sys_gettid		0
-	sys	sys_readahead		5
+	sys	sys32_readahead		4
 	sys	sys_setxattr		5
 	sys	sys_lsetxattr		5	/* 4225 */
 	sys	sys_fsetxattr		5
@@ -596,7 +596,7 @@ einval:	li	v0, -EINVAL
 	sys	sys_remap_file_pages	5
 	sys	sys_set_tid_address	1
 	sys	sys_restart_syscall	0
-	sys	sys_fadvise64_64	7
+	sys	sys32_fadvise64		5
 	sys	sys_statfs64		3	/* 4255 */
 	sys	sys_fstatfs64		2
 	sys	sys_timer_create	3
@@ -647,7 +647,7 @@ einval:	li	v0, -EINVAL
 	sys	sys_ppoll		5
 	sys	sys_unshare		1
 	sys	sys_splice		4
-	sys	sys_sync_file_range	7	/* 4305 */
+	sys	sys32_sync_file_range	6	/* 4305 */
 	sys	sys_tee			4
 	sys	sys_vmsplice		4
 	sys	sys_move_pages		6
@@ -656,6 +656,7 @@ einval:	li	v0, -EINVAL
 	sys	sys_kexec_load		4
 	sys	sys_getcpu		3
 	sys	sys_epoll_pwait		6
+	sys	sys32_fadvise64_64	6
 	.endm
 
 	/* We pre-compute the number of _instruction_ bytes needed to
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index f17e31e..c554f28 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -336,7 +336,7 @@ EXPORT(sysn32_call_table)
 	PTR	sys_set_tid_address
 	PTR	sys_restart_syscall
 	PTR	compat_sys_semtimedop			/* 6215 */
-	PTR	sys_fadvise64_64
+	PTR	sys32_fadvise64
 	PTR	compat_sys_statfs64
 	PTR	compat_sys_fstatfs64
 	PTR	sys_sendfile64
@@ -388,7 +388,7 @@ EXPORT(sysn32_call_table)
 	PTR	sys_ppoll			/* 6265 */
 	PTR	sys_unshare
 	PTR	sys_splice
-	PTR	sys_sync_file_range
+	PTR	sys32_sync_file_range
 	PTR	sys_tee
 	PTR	sys_vmsplice			/* 6270 */
 	PTR	sys_move_pages
@@ -397,3 +397,4 @@ EXPORT(sysn32_call_table)
 	PTR	compat_sys_kexec_load
 	PTR	sys_getcpu
 	PTR	compat_sys_epoll_pwait
+	PTR	sys32_fadvise64_64
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 142c9b7..5b7ca00 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -459,7 +459,7 @@ sys_call_table:
 	PTR	sys_remap_file_pages
 	PTR	sys_set_tid_address
 	PTR	sys_restart_syscall
-	PTR	sys_fadvise64_64
+	PTR	sys32_fadvise64
 	PTR	compat_sys_statfs64		/* 4255 */
 	PTR	compat_sys_fstatfs64
 	PTR	compat_sys_timer_create
@@ -519,4 +519,5 @@ sys_call_table:
 	PTR	compat_sys_kexec_load
 	PTR	sys_getcpu
 	PTR	compat_sys_epoll_pwait
+	PTR	sys32_fadvise64_64
 	.size	sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 26e1a7e..6e107fc 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -435,3 +435,36 @@ int kernel_execve(const char *filename,
 
 	return -__v0;
 }
+
+#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_COMPAT)
+#ifdef __BIG_ENDIAN
+#define merge_64(r1,r2)	(((u64)(r1) << 32) + ((u32)(r2)))
+#else
+#define merge_64(r1,r2)	(((u64)(r2) << 32) + ((u32)(r1)))
+#endif
+asmlinkage long sys32_fadvise64_64(int fd, long a1, long a2, long a3, long a4,
+	int advice)
+{
+	return sys_fadvise64_64(fd, merge_64(a1, a2), merge_64(a3, a4),
+				advice);
+}
+
+asmlinkage long sys32_fadvise64(int fd, long a1, long a2, size_t len,
+	int advice)
+{
+	return sys_fadvise64_64(fd, merge_64(a1, a2), len, advice);
+}
+
+asmlinkage ssize_t sys32_readahead(int fd, long a1, long a2, size_t count)
+{
+	return sys_readahead(fd, merge_64(a1, a2), count);
+}
+
+asmlinkage long sys32_sync_file_range(int fd, long a1, long a2,
+	long a3, long a4, unsigned int flags)
+{
+	return sys_sync_file_range(fd, merge_64(a1, a2), merge_64(a3, a4),
+				   flags);
+}
+
+#endif
diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h
index 696cff3..949e956 100644
--- a/include/asm-mips/unistd.h
+++ b/include/asm-mips/unistd.h
@@ -334,16 +334,17 @@
 #define __NR_kexec_load			(__NR_Linux + 311)
 #define __NR_getcpu			(__NR_Linux + 312)
 #define __NR_epoll_pwait		(__NR_Linux + 313)
+#define __NR_fadvise64_64		(__NR_Linux + 314)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls		313
+#define __NR_Linux_syscalls		314
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux			4000
-#define __NR_O32_Linux_syscalls		313
+#define __NR_O32_Linux_syscalls		314
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
@@ -918,16 +919,17 @@
 #define __NR_kexec_load			(__NR_Linux + 274)
 #define __NR_getcpu			(__NR_Linux + 275)
 #define __NR_epoll_pwait		(__NR_Linux + 276)
+#define __NR_fadvise64_64		(__NR_Linux + 277)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls		276
+#define __NR_Linux_syscalls		277
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux			6000
-#define __NR_N32_Linux_syscalls		276
+#define __NR_N32_Linux_syscalls		277
 
 #ifdef __KERNEL__
 

From James.Bottomley@SteelEye.com Tue Mar  6 18:02:15 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 18:02:19 +0000 (GMT)
Received: from hancock.steeleye.com ([71.30.118.248]:64204 "EHLO
	hancock.sc.steeleye.com") by ftp.linux-mips.org with ESMTP
	id S20021429AbXCFSCP (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Mar 2007 18:02:15 +0000
Received: from [172.17.6.40] (midgard.sc.steeleye.com [172.17.6.40])
	by hancock.sc.steeleye.com (8.11.6/8.11.6) with ESMTP id l26I10x10975;
	Tue, 6 Mar 2007 13:01:00 -0500
Subject: Re: [parisc-linux] [PATCH 1/2] Use a weak symbol for the empty
	version of pcibios_add_platform_entries()
From:	James Bottomley <James.Bottomley@SteelEye.com>
To:	Michael Ellerman <michael@ellerman.id.au>
Cc:	Greg Kroah-Hartman <greg@kroah.com>, linux-mips@linux-mips.org,
	dev-etrax@axis.com, linux-ia64@vger.kernel.org, discuss@x86-64.org,
	chris@zankel.net, dhowells@redhat.com, linuxppc-dev@ozlabs.org,
	linux-m68k@vger.kernel.org, ink@jurassic.park.msu.ru,
	gerg@uclinux.org, sparclinux@vger.kernel.org,
	uclinux-v850@lsi.nec.co.jp, linux-pci@atrey.karlin.mff.cuni.cz,
	parisc-linux@parisc-linux.org, kernel@wantstofly.org,
	rth@twiddle.net
In-Reply-To: <1173193568.89821.610708199943.qpush@concordia>
References: <1173193568.89821.610708199943.qpush@concordia>
Content-Type: text/plain
Date:	Tue, 06 Mar 2007 12:01:00 -0600
Message-Id: <1173204060.3379.28.camel@mulgrave.il.steeleye.com>
Mime-Version: 1.0
X-Mailer: Evolution 2.8.3 (2.8.3-1.fc6) 
Content-Transfer-Encoding: 7bit
Return-Path: <James.Bottomley@SteelEye.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14378
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: James.Bottomley@SteelEye.com
Precedence: bulk
X-list: linux-mips

On Tue, 2007-03-06 at 16:06 +0100, Michael Ellerman wrote:
> I'm not sure if this is going to fly, weak symbols work on the compilers I'm
> using, but whether they work for all of the affected architectures I can't say.
> I've cc'ed as many arch maintainers/lists as I could find.

Well, for your use, PCI already uses weak symbols, so it must work on
every architecture that you want to do it on ...

James



From James.Bottomley@SteelEye.com Tue Mar  6 18:06:13 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 18:06:17 +0000 (GMT)
Received: from hancock.steeleye.com ([71.30.118.248]:13261 "EHLO
	hancock.sc.steeleye.com") by ftp.linux-mips.org with ESMTP
	id S20021427AbXCFSGN (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Mar 2007 18:06:13 +0000
Received: from [172.17.6.40] (midgard.sc.steeleye.com [172.17.6.40])
	by hancock.sc.steeleye.com (8.11.6/8.11.6) with ESMTP id l26I51x11230;
	Tue, 6 Mar 2007 13:05:01 -0500
Subject: Re: [parisc-linux] [PATCH 2/2] Make pcibios_add_platform_entries()
	return errors
From:	James Bottomley <James.Bottomley@SteelEye.com>
To:	Michael Ellerman <michael@ellerman.id.au>
Cc:	Greg Kroah-Hartman <greg@kroah.com>, linux-mips@linux-mips.org,
	dev-etrax@axis.com, linux-ia64@vger.kernel.org, discuss@x86-64.org,
	chris@zankel.net, dhowells@redhat.com, linuxppc-dev@ozlabs.org,
	linux-m68k@vger.kernel.org, ink@jurassic.park.msu.ru,
	gerg@uclinux.org, sparclinux@vger.kernel.org,
	uclinux-v850@lsi.nec.co.jp, linux-pci@atrey.karlin.mff.cuni.cz,
	parisc-linux@parisc-linux.org, kernel@wantstofly.org,
	rth@twiddle.net
In-Reply-To: <20070306150725.68D97DDF36@ozlabs.org>
References: <20070306150725.68D97DDF36@ozlabs.org>
Content-Type: text/plain
Date:	Tue, 06 Mar 2007 12:05:01 -0600
Message-Id: <1173204301.3379.33.camel@mulgrave.il.steeleye.com>
Mime-Version: 1.0
X-Mailer: Evolution 2.8.3 (2.8.3-1.fc6) 
Content-Transfer-Encoding: 7bit
Return-Path: <James.Bottomley@SteelEye.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14379
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: James.Bottomley@SteelEye.com
Precedence: bulk
X-list: linux-mips

On Tue, 2007-03-06 at 16:06 +0100, Michael Ellerman wrote:
>  int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
> @@ -644,10 +644,13 @@ int __must_check pci_create_sysfs_dev_fi
>  		}
>  	}
>  	/* add platform-specific attributes */
> -	pcibios_add_platform_entries(pdev);
> +	if (pcibios_add_platform_entries(pdev))
> +		goto err_rom_attr;
>  
>  	return 0;
>  
> +err_rom_attr:
> +	sysfs_remove_bin_file(&pdev->dev.kobj, rom_attr);

This file is only created if the rom resource has a non-zero length.  If
you unconditionally call sysfs_remove_bin_file() it's going to spit
scary warnings and dump traces in this error leg if the rom resource
doesn't exist.

James


>  err_rom:
>  	kfree(rom_attr);
>  err_bin_file:
> Index: msi-new/include/linux/pci.h
> ===================================================================
> --- msi-new.orig/include/linux/pci.h
> +++ msi-new/include/linux/pci.h
> @@ -857,7 +857,7 @@ extern int pci_pci_problems;
>  extern unsigned long pci_cardbus_io_size;
>  extern unsigned long pci_cardbus_mem_size;
>  
> -extern void pcibios_add_platform_entries(struct pci_dev *dev);
> +extern int pcibios_add_platform_entries(struct pci_dev *dev);
>  
>  #endif /* __KERNEL__ */
>  #endif /* LINUX_PCI_H */
> _______________________________________________
> parisc-linux mailing list
> parisc-linux@lists.parisc-linux.org
> http://lists.parisc-linux.org/mailman/listinfo/parisc-linux


From vagabon.xyz@gmail.com Tue Mar  6 21:41:01 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Mar 2007 21:41:05 +0000 (GMT)
Received: from ug-out-1314.google.com ([66.249.92.168]:65315 "EHLO
	ug-out-1314.google.com") by ftp.linux-mips.org with ESMTP
	id S20021464AbXCFVlB (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Mar 2007 21:41:01 +0000
Received: by ug-out-1314.google.com with SMTP id 40so381497uga
        for <linux-mips@linux-mips.org>; Tue, 06 Mar 2007 13:40:00 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=fmjpq7/0xHprfcrTUTTGSC2bdv4u0CPmd6KW4jjEzlQr90EnEJ5UIoMvAnWElc6elGD3tlIV6APLcBVV2A6CIEIStXoLyo8Yi1xViJUc4OsV0+ENDiQUujWNIuUjP222MU3vU1kDdZX8qabZO3H2lbvdg7MZIbEjsDrQWrGgLPE=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=sncSyUexe5zNMFUb5nUY7ZAkG91Dm04gTD4fZRkeKxs+UxNy0Jumw5QzbzM+FpNoKTn+Q3VPVcBJFxX6dAVZ5eTJ8L468Ma9M/tcMainnbeCbCAAnRG5aqHuJm8XQBWB8gmS/fXboryZ82oTRf7bYQbIPBhojJnN0oUgWJTYuzs=
Received: by 10.114.131.2 with SMTP id e2mr1900573wad.1173217199336;
        Tue, 06 Mar 2007 13:39:59 -0800 (PST)
Received: by 10.114.136.11 with HTTP; Tue, 6 Mar 2007 13:39:59 -0800 (PST)
Message-ID: <cda58cb80703061339l2f8cfc09m5823b090b69a7aa7@mail.gmail.com>
Date:	Tue, 6 Mar 2007 22:39:59 +0100
From:	"Franck Bui-Huu" <vagabon.xyz@gmail.com>
To:	mbizon@freebox.fr
Subject: Re: [PATCH 0/2] FLATMEM: allow memory to start at pfn != 0 [take #2]
Cc:	linux-mips <linux-mips@linux-mips.org>
In-Reply-To: <1173112433.7093.36.camel@sakura.staff.proxad.net>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
References: <116841864595-git-send-email-fbuihuu@gmail.com>
	 <1172879147.964.65.camel@sakura.staff.proxad.net>
	 <cda58cb80703050615r4e559ca1u78517634ac23a27@mail.gmail.com>
	 <1173112433.7093.36.camel@sakura.staff.proxad.net>
Return-Path: <vagabon.xyz@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14380
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: vagabon.xyz@gmail.com
Precedence: bulk
X-list: linux-mips

On 3/5/07, Maxime Bizon <mbizon@freebox.fr> wrote:
> I dug a little and found the following.
>
> My kernel is loaded at 0x9012d000, '&_end' value is 0x901d4020. In
> bootmem_init(), we try to compute reserved_end by using
> __pa_symbol(&_end), which adds PHYS_OFFSET to it, though it was already
> accounted.
>

I think you missed PAGE_OFFSET meaning...

PAGE_OFFSET is the start of the kernel virtual address space and
before this patchset pa(PAGE_OFFSET) was always 0.

In your case, you said:

        PAGE_OFFSET = 0x80000000
        PHYS_OFFSET = 0x10000000

this means that the first kernel virtual address is 0x80000000 and the
corresponding physical address is 0x10000000. If you load your kernel
at 0x9000xxxx, it will be loaded in physical memory located at
0x2000xxxx which is obviously not what you want.

So to fix this you have 2 possibilities:

    - load your kernel at 0x8000xxxx addresses,
    - set PAGE_OFFSET to 0x90000000.

You said that you already tried the second solution but it fails. I
don't see why though...

> The loop in setup.c is thus unable to compute a correct 'map_start'
> value since 'reserved_end' is way above all declared memory.
>
> init_bootmem_node() is then called with a 'map_start' default value of
> ~0. Maybe that case should fall in the invalid memory map panic ?
>

well maybe some sanity checkings are missing here.

Sorry for responding lately but life sometimes triggers NMIs ;)
-- 
               Franck

From michael@ellerman.id.au Wed Mar  7 08:56:05 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Mar 2007 08:56:07 +0000 (GMT)
Received: from ozlabs.org ([203.10.76.45]:15288 "EHLO ozlabs.org")
	by ftp.linux-mips.org with ESMTP id S20021567AbXCGI4F (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Wed, 7 Mar 2007 08:56:05 +0000
Received: from [127.0.0.1] (localhost [127.0.0.1])
	by ozlabs.org (Postfix) with ESMTP id DCADBDDF17;
	Wed,  7 Mar 2007 19:55:19 +1100 (EST)
Subject: Re: [parisc-linux] [PATCH 2/2] Make pcibios_add_platform_entries()
	return errors
From:	Michael Ellerman <michael@ellerman.id.au>
Reply-To: michael@ellerman.id.au
To:	James Bottomley <James.Bottomley@SteelEye.com>
Cc:	Greg Kroah-Hartman <greg@kroah.com>, linux-mips@linux-mips.org,
	dev-etrax@axis.com, linux-ia64@vger.kernel.org, discuss@x86-64.org,
	chris@zankel.net, dhowells@redhat.com, linuxppc-dev@ozlabs.org,
	linux-m68k@vger.kernel.org, ink@jurassic.park.msu.ru,
	gerg@uclinux.org, sparclinux@vger.kernel.org,
	uclinux-v850@lsi.nec.co.jp, linux-pci@atrey.karlin.mff.cuni.cz,
	parisc-linux@parisc-linux.org, kernel@wantstofly.org,
	rth@twiddle.net
In-Reply-To: <1173204301.3379.33.camel@mulgrave.il.steeleye.com>
References: <20070306150725.68D97DDF36@ozlabs.org>
	 <1173204301.3379.33.camel@mulgrave.il.steeleye.com>
Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="=-BgsAG7SQX+bolLlRm7kx"
Date:	Wed, 07 Mar 2007 09:55:18 +0100
Message-Id: <1173257718.5101.16.camel@concordia.ozlabs.ibm.com>
Mime-Version: 1.0
X-Mailer: Evolution 2.8.1 
Return-Path: <michael@ellerman.id.au>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14381
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: michael@ellerman.id.au
Precedence: bulk
X-list: linux-mips


--=-BgsAG7SQX+bolLlRm7kx
Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable

On Tue, 2007-03-06 at 12:05 -0600, James Bottomley wrote:
> On Tue, 2007-03-06 at 16:06 +0100, Michael Ellerman wrote:
> >  int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
> > @@ -644,10 +644,13 @@ int __must_check pci_create_sysfs_dev_fi
> >  		}
> >  	}
> >  	/* add platform-specific attributes */
> > -	pcibios_add_platform_entries(pdev);
> > +	if (pcibios_add_platform_entries(pdev))
> > +		goto err_rom_attr;
> > =20
> >  	return 0;
> > =20
> > +err_rom_attr:
> > +	sysfs_remove_bin_file(&pdev->dev.kobj, rom_attr);
>=20
> This file is only created if the rom resource has a non-zero length.  If
> you unconditionally call sysfs_remove_bin_file() it's going to spit
> scary warnings and dump traces in this error leg if the rom resource
> doesn't exist.

Ah crud, don't write patches during meetings. I'll send a fixed version.

cheers

--=20
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

--=-BgsAG7SQX+bolLlRm7kx
Content-Type: application/pgp-signature; name=signature.asc
Content-Description: This is a digitally signed message part

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.3 (GNU/Linux)

iD8DBQBF7n32dSjSd0sB4dIRAn5sAKDLKRSrFBG7U5Cd40rDmTlteEGzOgCgsZhx
xnxBaUCAjUOpUDo/Iyyq50o=
=Lg0a
-----END PGP SIGNATURE-----

--=-BgsAG7SQX+bolLlRm7kx--


From freddy@dusktilldawn.nl Wed Mar  7 10:50:15 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Mar 2007 10:50:19 +0000 (GMT)
Received: from tool.snarl.nl ([82.95.241.19]:62156 "EHLO tool.snarl.nl")
	by ftp.linux-mips.org with ESMTP id S20021572AbXCGKuP (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Wed, 7 Mar 2007 10:50:15 +0000
Received: from localhost (tool.local.snarl.nl [127.0.0.1])
	by tool.snarl.nl (Postfix) with ESMTP id A3FC85DF46;
	Wed,  7 Mar 2007 11:49:31 +0100 (CET)
Received: from tool.snarl.nl ([127.0.0.1])
	by localhost (tool.local.snarl.nl [127.0.0.1]) (amavisd-new, port 10024)
	with LMTP id zUKxGWHbzVhE; Wed,  7 Mar 2007 11:49:31 +0100 (CET)
Received: by tool.snarl.nl (Postfix, from userid 1000)
	id 31C1A5DF3D; Wed,  7 Mar 2007 11:49:31 +0100 (CET)
Date:	Wed, 7 Mar 2007 11:49:30 +0100
From:	Freddy Spierenburg <freddy@dusktilldawn.nl>
To:	Charles Eidsness <charles@cooper-street.com>
Cc:	linux-mips@linux-mips.org
Subject: Trouble with sound/mips/au1x00.c AC97 driver
Message-ID: <20070307104930.GD25248@dusktilldawn.nl>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="lf0NQ8GVTdtriwpn"
Content-Disposition: inline
X-User-Agent-Feature: All mail clients suck. This one just sucks less.
X-GPG-Key: http://snarl.nl/~freddy/keys/freddyPublicKey.gpg
User-Agent: Mutt/1.5.13 (2006-08-11)
Return-Path: <freddy@dusktilldawn.nl>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14382
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: freddy@dusktilldawn.nl
Precedence: bulk
X-list: linux-mips


--lf0NQ8GVTdtriwpn
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi Charles,

I'm experiencing strange behaviour with the sound/mips/au1x00.c
AC97 driver. I'm using kernel 2.6.16, but 2.6.20 gives me the
same results.

When I load the driver sometimes (frequently enough that it's a
serious problem) I do not get all 38 simple mixer controls.
Sometimes I'm missing one or more controls, but in a more rare
situation it also happens that a control holds the wrong min/max
values. And in an even more rare situation I get the error below
while loading the driver:

	AC'97 0 access error (not audio or modem codec)

I have tried to track it down and it all boils down to the
snd_au1000_ac97_read() routine, I think. When I try to debug the
problem, I see that most of the time the res and val variables
compared in snd_ac97_try_bit() from sound/pci/ac97/ac97_codec.c
do not appear to be equal. Hence the missing controls. It looks
to me that snd_au1000_ac97_read() is not returning a value
expected.

When I look at the snd_au1000_ac97_read() implementation it looks
good to me. I've read the AU1100 Processor Data Book and your
routine does exactly the thing needed to read data from the AC97
controller. I've also inspected the whole thing a little bit and
I never receive a 'au1000 AC97: AC97 command read timeout'. Never
is a command still pending before you stop try to poll for the
sane situation and never is an answer not yet received from the
codec before you stop polling for it. And the poll values are
never close to the 0x5000 max you specify. For the latter test
(the test if the data is available) I have also checked if the
data is available right away (i=3D=3D0). This happens rarely and does
not cause trouble if it happens.

So there is not much that I understand that goes wrong in this
routine. I might be wrong of course. Any insight from real kernel
hackers?

I really do get the feeling that it's a hardware thing. But my
hardware engineer doesn't yet believe that. And I'm afraid he has
sound (sic :) reasoning. I've tested this code on two different platforms.
The first is an official AMD SYRAH DbAu1100 board with a Sigmatel
STAC9752T audio codec and the second is our own Balvenie board
(based on the DbAu1100 design) with an Wolfson WM9705 audio
codec. Both platforms experience the same problems.

We have also checked all the timings to and from the codec with
an oscilloscope and they are up to spec. Nothing strange
happening over there.

What I've also done is play a sound file constantly over the
course of several days. During that playing I constantly did some
muting/unmuting of the 'Master', 'Master Mono' and 'Headphone'
output. I connected some speakers and the small shell-script I
wrote rotated the audio in a nice loop around the speakers. This
happened like every second or so. No error messages from the
amixer utility over that course of days and no error message from
aplay whatsoever. I have also never heard any strange glitch in
the playing of audio, but if only a few samples are missing or
tampered it might be impossible to hear.

Anyway, does anyone have ever experienced this trouble and have
any clue what might causes it?


--=20
$ cat ~/.signature
Freddy Spierenburg <freddy@dusktilldawn.nl>  http://freddy.snarl.nl/
GnuPG: 0x7941D1E1=3DC948 5851 26D2 FA5C 39F1  E588 6F17 FD5D 7941 D1E1
$ # Please read http://www.ietf.org/rfc/rfc2015.txt before complain!

--lf0NQ8GVTdtriwpn
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQFF7pi6bxf9XXlB0eERAua6AJ9QZDnNIy0g5vG7ETzvYfobbUrbRACg7GPa
UJWUR2SgCsaxD6w0CI6OlOU=
=9dai
-----END PGP SIGNATURE-----

--lf0NQ8GVTdtriwpn--

From ralf@linux-mips.org Wed Mar  7 13:01:12 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Mar 2007 13:01:14 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:53636 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20021585AbXCGNBM (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Wed, 7 Mar 2007 13:01:12 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.13.8/8.13.8) with ESMTP id l27CxG3d017974;
	Wed, 7 Mar 2007 12:59:17 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.13.8/8.13.8/Submit) id l27CxFHe017973;
	Wed, 7 Mar 2007 12:59:15 GMT
Date:	Wed, 7 Mar 2007 12:59:15 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Cc:	linux-mips <linux-mips@linux-mips.org>
Subject: Re: [PATCH][MIPS] clean up include files for Cobalt
Message-ID: <20070307125915.GA17956@linux-mips.org>
References: <20070306213444.7b826d1d.yoichi_yuasa@tripeaks.co.jp>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20070306213444.7b826d1d.yoichi_yuasa@tripeaks.co.jp>
User-Agent: Mutt/1.4.2.2i
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14383
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Tue, Mar 06, 2007 at 09:34:44PM +0900, Yoichi Yuasa wrote:

> This patch has cleaned up include files for Cobalt.

Thanks, queued for 2.6.22.

  Ralf

From tsbogend@alpha.franken.de Wed Mar  7 13:23:21 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Mar 2007 13:23:23 +0000 (GMT)
Received: from elvis.franken.de ([193.175.24.41]:22214 "EHLO elvis.franken.de")
	by ftp.linux-mips.org with ESMTP id S20021589AbXCGNXV (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Wed, 7 Mar 2007 13:23:21 +0000
Received: from uucp (helo=solo.franken.de)
	by elvis.franken.de with local-bsmtp (Exim 3.36 #1)
	id 1HOw3u-0007wL-00; Wed, 07 Mar 2007 14:20:10 +0100
Received: by solo.franken.de (Postfix, from userid 1000)
	id 04481C2349; Wed,  7 Mar 2007 14:18:42 +0100 (CET)
Date:	Wed, 7 Mar 2007 14:18:42 +0100
To:	Franck Bui-Huu <vagabon.xyz@gmail.com>
Cc:	mbizon@freebox.fr, linux-mips <linux-mips@linux-mips.org>
Subject: Re: [PATCH 0/2] FLATMEM: allow memory to start at pfn != 0 [take #2]
Message-ID: <20070307131842.GA9361@alpha.franken.de>
References: <116841864595-git-send-email-fbuihuu@gmail.com> <1172879147.964.65.camel@sakura.staff.proxad.net> <cda58cb80703050615r4e559ca1u78517634ac23a27@mail.gmail.com> <1173112433.7093.36.camel@sakura.staff.proxad.net> <cda58cb80703061339l2f8cfc09m5823b090b69a7aa7@mail.gmail.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <cda58cb80703061339l2f8cfc09m5823b090b69a7aa7@mail.gmail.com>
User-Agent: Mutt/1.5.9i
From:	tsbogend@alpha.franken.de (Thomas Bogendoerfer)
Return-Path: <tsbogend@alpha.franken.de>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14384
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: tsbogend@alpha.franken.de
Precedence: bulk
X-list: linux-mips

On Tue, Mar 06, 2007 at 10:39:59PM +0100, Franck Bui-Huu wrote:
> I think you missed PAGE_OFFSET meaning...
> 
> PAGE_OFFSET is the start of the kernel virtual address space and
> before this patchset pa(PAGE_OFFSET) was always 0.
> 
> In your case, you said:
> 
>        PAGE_OFFSET = 0x80000000
>        PHYS_OFFSET = 0x10000000
> 
> this means that the first kernel virtual address is 0x80000000 and the
> corresponding physical address is 0x10000000. If you load your kernel
> at 0x9000xxxx, it will be loaded in physical memory located at
> 0x2000xxxx which is obviously not what you want.

which sound like a very bogus setup for at leat 32bit MIPS. The mapping
virtual 0x80000000 to physical 0x00000000 is a CPU thing and can't
be changed.

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessary a
good idea.                                                [ RFC1925, 2.3 ]

From anemo@mba.ocn.ne.jp Wed Mar  7 14:15:31 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Mar 2007 14:15:37 +0000 (GMT)
Received: from mba.ocn.ne.jp ([122.1.175.29]:59867 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20021589AbXCGOPb (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Wed, 7 Mar 2007 14:15:31 +0000
Received: from localhost (p5052-ipad01funabasi.chiba.ocn.ne.jp [61.207.79.52])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id D096BBA90; Wed,  7 Mar 2007 23:14:09 +0900 (JST)
Date:	Wed, 07 Mar 2007 23:14:10 +0900 (JST)
Message-Id: <20070307.231410.15268922.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org, kraj@mvista.com
Subject: Re: [PATCH] Fix some system calls with long long arguments
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
In-Reply-To: <20070307.003931.25235381.anemo@mba.ocn.ne.jp>
References: <20070307.003931.25235381.anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14385
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

Revised, renumbering __NR_fadvise64_64.


Subject: [PATCH] Fix some system calls with long long arguments

fadvise64(), readahead(), sync_file_range() have long long argument(s)
but glibc passes it by hi/lo pair without padding, on both O32 and
N32.

Also wire up fadvise64_64() and fixup confusion of it with
fadvise64().

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
 arch/mips/kernel/linux32.c     |   16 ----------------
 arch/mips/kernel/scall32-o32.S |    7 ++++---
 arch/mips/kernel/scall64-n32.S |    5 +++--
 arch/mips/kernel/scall64-o32.S |    3 ++-
 arch/mips/kernel/syscall.c     |   33 +++++++++++++++++++++++++++++++++
 include/asm-mips/unistd.h      |   10 ++++++----
 6 files changed, 48 insertions(+), 26 deletions(-)

diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 30d433f..71e1524 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -528,22 +528,6 @@ asmlinkage int sys32_sendfile(int out_fd
 	return ret;
 }
 
-asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3,
-                                   size_t count)
-{
-	return sys_readahead(fd, merge_64(a2, a3), count);
-}
-
-asmlinkage long sys32_sync_file_range(int fd, int __pad,
-	unsigned long a2, unsigned long a3,
-	unsigned long a4, unsigned long a5,
-	int flags)
-{
-	return sys_sync_file_range(fd,
-			merge_64(a2, a3), merge_64(a4, a5),
-			flags);
-}
-
 save_static_function(sys32_clone);
 __attribute_used__ noinline static int
 _sys32_clone(nabi_no_regargs struct pt_regs regs)
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 0c9a9ff..aa02a68 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -554,7 +554,7 @@ einval:	li	v0, -EINVAL
 	sys	sys_fcntl64		3	/* 4220 */
 	sys	sys_ni_syscall		0
 	sys	sys_gettid		0
-	sys	sys_readahead		5
+	sys	sys32_readahead		4
 	sys	sys_setxattr		5
 	sys	sys_lsetxattr		5	/* 4225 */
 	sys	sys_fsetxattr		5
@@ -596,7 +596,7 @@ einval:	li	v0, -EINVAL
 	sys	sys_remap_file_pages	5
 	sys	sys_set_tid_address	1
 	sys	sys_restart_syscall	0
-	sys	sys_fadvise64_64	7
+	sys	sys32_fadvise64		5
 	sys	sys_statfs64		3	/* 4255 */
 	sys	sys_fstatfs64		2
 	sys	sys_timer_create	3
@@ -647,7 +647,7 @@ einval:	li	v0, -EINVAL
 	sys	sys_ppoll		5
 	sys	sys_unshare		1
 	sys	sys_splice		4
-	sys	sys_sync_file_range	7	/* 4305 */
+	sys	sys32_sync_file_range	6	/* 4305 */
 	sys	sys_tee			4
 	sys	sys_vmsplice		4
 	sys	sys_move_pages		6
@@ -658,6 +658,7 @@ einval:	li	v0, -EINVAL
 	sys	sys_epoll_pwait		6
 	sys	sys_ioprio_set		3
 	sys	sys_ioprio_get		2
+	sys	sys32_fadvise64_64	6
 	.endm
 
 	/* We pre-compute the number of _instruction_ bytes needed to
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 6eac283..e65dbf6 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -336,7 +336,7 @@ EXPORT(sysn32_call_table)
 	PTR	sys_set_tid_address
 	PTR	sys_restart_syscall
 	PTR	compat_sys_semtimedop			/* 6215 */
-	PTR	sys_fadvise64_64
+	PTR	sys32_fadvise64
 	PTR	compat_sys_statfs64
 	PTR	compat_sys_fstatfs64
 	PTR	sys_sendfile64
@@ -388,7 +388,7 @@ EXPORT(sysn32_call_table)
 	PTR	sys_ppoll			/* 6265 */
 	PTR	sys_unshare
 	PTR	sys_splice
-	PTR	sys_sync_file_range
+	PTR	sys32_sync_file_range
 	PTR	sys_tee
 	PTR	sys_vmsplice			/* 6270 */
 	PTR	sys_move_pages
@@ -399,4 +399,5 @@ EXPORT(sysn32_call_table)
 	PTR	compat_sys_epoll_pwait
 	PTR	sys_ioprio_set
 	PTR	sys_ioprio_get
+	PTR	sys32_fadvise64_64
 	.size	sysn32_call_table,.-sysn32_call_table
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 7e74b41..7d797da 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -459,7 +459,7 @@ sys_call_table:
 	PTR	sys_remap_file_pages
 	PTR	sys_set_tid_address
 	PTR	sys_restart_syscall
-	PTR	sys_fadvise64_64
+	PTR	sys32_fadvise64
 	PTR	compat_sys_statfs64		/* 4255 */
 	PTR	compat_sys_fstatfs64
 	PTR	compat_sys_timer_create
@@ -521,4 +521,5 @@ sys_call_table:
 	PTR	compat_sys_epoll_pwait
 	PTR	sys_ioprio_set
 	PTR	sys_ioprio_get			/* 4315 */
+	PTR	sys32_fadvise64_64
 	.size	sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 26e1a7e..6e107fc 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -435,3 +435,36 @@ int kernel_execve(const char *filename,
 
 	return -__v0;
 }
+
+#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_COMPAT)
+#ifdef __BIG_ENDIAN
+#define merge_64(r1,r2)	(((u64)(r1) << 32) + ((u32)(r2)))
+#else
+#define merge_64(r1,r2)	(((u64)(r2) << 32) + ((u32)(r1)))
+#endif
+asmlinkage long sys32_fadvise64_64(int fd, long a1, long a2, long a3, long a4,
+	int advice)
+{
+	return sys_fadvise64_64(fd, merge_64(a1, a2), merge_64(a3, a4),
+				advice);
+}
+
+asmlinkage long sys32_fadvise64(int fd, long a1, long a2, size_t len,
+	int advice)
+{
+	return sys_fadvise64_64(fd, merge_64(a1, a2), len, advice);
+}
+
+asmlinkage ssize_t sys32_readahead(int fd, long a1, long a2, size_t count)
+{
+	return sys_readahead(fd, merge_64(a1, a2), count);
+}
+
+asmlinkage long sys32_sync_file_range(int fd, long a1, long a2,
+	long a3, long a4, unsigned int flags)
+{
+	return sys_sync_file_range(fd, merge_64(a1, a2), merge_64(a3, a4),
+				   flags);
+}
+
+#endif
diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h
index 2f1087b..93b17ac 100644
--- a/include/asm-mips/unistd.h
+++ b/include/asm-mips/unistd.h
@@ -336,16 +336,17 @@
 #define __NR_epoll_pwait		(__NR_Linux + 313)
 #define __NR_ioprio_set			(__NR_Linux + 314)
 #define __NR_ioprio_get			(__NR_Linux + 315)
+#define __NR_fadvise64_64		(__NR_Linux + 316)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls		315
+#define __NR_Linux_syscalls		316
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux			4000
-#define __NR_O32_Linux_syscalls		315
+#define __NR_O32_Linux_syscalls		316
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
@@ -924,16 +925,17 @@
 #define __NR_epoll_pwait		(__NR_Linux + 276)
 #define __NR_ioprio_set			(__NR_Linux + 277)
 #define __NR_ioprio_get			(__NR_Linux + 278)
+#define __NR_fadvise64_64		(__NR_Linux + 279)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls		278
+#define __NR_Linux_syscalls		279
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux			6000
-#define __NR_N32_Linux_syscalls		278
+#define __NR_N32_Linux_syscalls		279
 
 #ifdef __KERNEL__
 

From mbizon@freebox.fr Wed Mar  7 17:01:37 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Mar 2007 17:01:41 +0000 (GMT)
Received: from sakura.staff.proxad.net ([213.228.1.107]:58546 "EHLO
	sakura.staff.proxad.net") by ftp.linux-mips.org with ESMTP
	id S20021603AbXCGRBh (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Wed, 7 Mar 2007 17:01:37 +0000
Received: from max by sakura.staff.proxad.net with local (Exim 3.36 #1 (Debian))
	id 1HOzT2-0008O3-00; Wed, 07 Mar 2007 17:58:20 +0100
Subject: Re: [PATCH 0/2] FLATMEM: allow memory to start at pfn != 0 [take
	#2]
From:	Maxime Bizon <mbizon@freebox.fr>
Reply-To: mbizon@freebox.fr
To:	Franck Bui-Huu <vagabon.xyz@gmail.com>
Cc:	linux-mips <linux-mips@linux-mips.org>, ralf <ralf@linux-mips.org>
In-Reply-To: <cda58cb80703061339l2f8cfc09m5823b090b69a7aa7@mail.gmail.com>
References: <116841864595-git-send-email-fbuihuu@gmail.com>
	 <1172879147.964.65.camel@sakura.staff.proxad.net>
	 <cda58cb80703050615r4e559ca1u78517634ac23a27@mail.gmail.com>
	 <1173112433.7093.36.camel@sakura.staff.proxad.net>
	 <cda58cb80703061339l2f8cfc09m5823b090b69a7aa7@mail.gmail.com>
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Organization: Freebox
Date:	Wed, 07 Mar 2007 17:58:20 +0100
Message-Id: <1173286700.6970.24.camel@sakura.staff.proxad.net>
Mime-Version: 1.0
X-Mailer: Evolution 2.8.1 
Return-Path: <mbizon@freebox.fr>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14386
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: mbizon@freebox.fr
Precedence: bulk
X-list: linux-mips


On Tue, 2007-03-06 at 22:39 +0100, Franck Bui-Huu wrote:

>     - set PAGE_OFFSET to 0x90000000.
> 
> You said that you already tried the second solution but it fails. I
> don't see why though...

Ok that makes sense for me now.

Though on the opposite of other arch, on 32bits mips you will always
have PAGE_OFFSET == PHYS_OFFSET + 0x80000000 because of fixed KSEG.
Making it possible to change both confused me.

I found the problem, I think these two liners are missing from your
patch. My board now works correctly, with 2MB more free memory, thanks
for this ! (and for the free tour in mm/ ;)




Commit 6f284a2ce7b8bc49cb8455b1763357897a899abb introduced PHYS_OFFSET,
but missed some virtual to physical address conversion. The following
patch fixes it.


Signed-off-by: Maxime Bizon <mbizon@freebox.fr>

--- linux-2.6.20/include/asm-mips/pgtable.h	2007-02-04 21:22:45.000000000 +0100
+++ linux/include/asm-mips/pgtable.h	2007-03-07 17:28:20.000000000 +0100
@@ -75,7 +75,7 @@
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-#define pmd_phys(pmd)		(pmd_val(pmd) - PAGE_OFFSET)
+#define pmd_phys(pmd)		(pmd_val(pmd) - PAGE_OFFSET + PHYS_OFFSET)
 #define pmd_page(pmd)		(pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
 #define pmd_page_vaddr(pmd)	pmd_val(pmd)
 
--- linux-2.6.20/include/asm-mips/pgtable-64.h	2007-02-04 21:22:45.000000000 +0100
+++ linux/include/asm-mips/pgtable-64.h	2007-03-07 17:28:47.000000000 +0100
@@ -199,7 +199,7 @@
 {
 	return pud_val(pud);
 }
-#define pud_phys(pud)		(pud_val(pud) - PAGE_OFFSET)
+#define pud_phys(pud)		(pud_val(pud) - PAGE_OFFSET + PHYS_OFFSET)
 #define pud_page(pud)		(pfn_to_page(pud_phys(pud) >> PAGE_SHIFT))
 
 /* Find an entry in the second-level page table.. */


-- 
Maxime


From stjeanma@pmc-sierra.com Wed Mar  7 18:02:18 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Mar 2007 18:02:23 +0000 (GMT)
Received: from mother.pmc-sierra.com ([216.241.224.12]:57237 "HELO
	mother.pmc-sierra.bc.ca") by ftp.linux-mips.org with SMTP
	id S20021611AbXCGSCS (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Wed, 7 Mar 2007 18:02:18 +0000
Received: (qmail 13975 invoked by uid 101); 7 Mar 2007 18:01:01 -0000
Received: from unknown (HELO pmxedge2.pmc-sierra.bc.ca) (216.241.226.184)
  by mother.pmc-sierra.com with SMTP; 7 Mar 2007 18:01:01 -0000
Received: from pasqua.pmc-sierra.bc.ca (pasqua.pmc-sierra.bc.ca [134.87.183.161])
	by pmxedge2.pmc-sierra.bc.ca (8.13.4/8.12.7) with ESMTP id l27I0pA2024577
	for <linux-mips@linux-mips.org>; Wed, 7 Mar 2007 10:00:58 -0800
From:	Marc St-Jean <stjeanma@pmc-sierra.com>
Received: (from stjeanma@localhost)
	by pasqua.pmc-sierra.bc.ca (8.13.4/8.12.11) id l27I0ppH012662
	for linux-mips@linux-mips.org; Wed, 7 Mar 2007 12:00:51 -0600
Date:	Wed, 7 Mar 2007 12:00:51 -0600
Message-Id: <200703071800.l27I0ppH012662@pasqua.pmc-sierra.bc.ca>
To:	linux-mips@linux-mips.org
Subject: [PATCH 1/5] mips: PMC MSP71xx core platform
Return-Path: <stjeanma@pmc-sierra.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14387
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: stjeanma@pmc-sierra.com
Precedence: bulk
X-list: linux-mips

[PATCH 1/5] mips: PMC MSP71xx core platform

Patch to add core platform support for the PMC-Sierra
MSP71xx devices.

These 5 patches along with the previously posted serial patch
will boot the PMC-Sierra MSP7120 Residential Gateway board.

Thanks,
Marc

Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
---
Re-posting patch with recommended changes:
-Cleanup on style and formatting for comments, macros, etc.
-Dropped a5000.S and wrote prom_put/get_char() functions.
-Removed CONFIG_CHECKOVERLAP support.
-Removed unnecessary __KERNEL__ tests.
-Moved 34k errata testing to mips-common patch.
-Modified CIC/SLP management code to use new set_irq_chip() and callbacks.
-Rewrote msp7120_reset in assembly but reverted to 'C' when I discovered
that inline assembly can reference labels in other blocks.
-Modified prom_free_prom_memory to use new free_init_pages().
-Changed usb_setup code to use DMA_32BIT_MASK.
-Changed dvpe() test to CONFIG_SYS_SUPPORTS_MULTITHREADING.
-Other odds and ends.

 arch/mips/pmc-sierra/msp71xx/Makefile                 |   11 
 arch/mips/pmc-sierra/msp71xx/msp_elb.c                |   46 +
 arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c           |  177 ++++
 arch/mips/pmc-sierra/msp71xx/msp_irq.c                |  124 +++
 arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c            |  140 +++
 arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c            |  115 +++
 arch/mips/pmc-sierra/msp71xx/msp_prom.c               |  597 ++++++++++++++++
 arch/mips/pmc-sierra/msp71xx/msp_setup.c              |  257 ++++++
 arch/mips/pmc-sierra/msp71xx/msp_time.c               |   94 ++
 arch/mips/pmc-sierra/msp71xx/msp_usb.c                |  146 +++
 include/asm-mips/pmc-sierra/msp71xx/msp_cic_int.h     |  151 ++++
 include/asm-mips/pmc-sierra/msp71xx/msp_gpio_macros.h |  309 ++++++++
 include/asm-mips/pmc-sierra/msp71xx/msp_int.h         |   43 +
 include/asm-mips/pmc-sierra/msp71xx/msp_prom.h        |  176 ++++
 include/asm-mips/pmc-sierra/msp71xx/msp_regs.h        |  661 ++++++++++++++++++
 include/asm-mips/pmc-sierra/msp71xx/msp_slp_int.h     |  141 +++
 16 files changed, 3188 insertions(+)

diff --git a/arch/mips/pmc-sierra/msp71xx/Makefile b/arch/mips/pmc-sierra/msp71xx/Makefile
new file mode 100644
index 0000000..209d0d0
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the PMC-Sierra MSP SOCs
+#
+obj-y += msp_prom.o msp_setup.o msp_irq.o \
+	 msp_time.o msp_serial.o msp_elb.o
+obj-$(CONFIG_PMC_MSP7120_GW) += msp_hwbutton.o
+obj-$(CONFIG_IRQ_MSP_SLP) += msp_irq_slp.o
+obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o
+obj-$(CONFIG_PCI) += msp_pci.o
+obj-$(CONFIG_PMC_MSP_ETH) += msp_eth.o
+obj-$(CONFIG_MSP_USB) += msp_usb.o
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_elb.c b/arch/mips/pmc-sierra/msp71xx/msp_elb.c
new file mode 100644
index 0000000..3e96410
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_elb.c
@@ -0,0 +1,46 @@
+/*
+ * Sets up the proper Chip Select configuration registers.  It is assumed that
+ * PMON sets up the ADDR and MASK registers properly.
+ *
+ * Copyright 2005-2006 PMC-Sierra, Inc.
+ * Author: Marc St-Jean, Marc_St-Jean@pmc-sierra.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <msp_regs.h>
+
+static int __init msp_elb_setup(void)
+{
+#if defined(CONFIG_PMC_MSP7120_GW) \
+ || defined(CONFIG_PMC_MSP7120_EVAL)
+	/*
+	 * Force all CNFG to be identical and equal to CS0,
+	 * according to OPS doc
+	 */
+	*CS1_CNFG_REG = *CS2_CNFG_REG = *CS3_CNFG_REG = *CS0_CNFG_REG;
+#endif
+	return 0;
+}
+
+subsys_initcall(msp_elb_setup);
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
new file mode 100644
index 0000000..d23ef37
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
@@ -0,0 +1,177 @@
+/*
+ * Sets up interrupt handlers for various hardware switches which are
+ * connected to interrupt lines.
+ *
+ * Copyright 2005 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <msp_int.h>
+#include <msp_regs.h>
+#ifdef CONFIG_SENSORS_PMCTWILED
+#include <msp_led_macros.h>
+#endif
+
+/* For hwbutton_interrupt->initial_state */
+#define HWBUTTON_HI	0x1
+#define HWBUTTON_LO	0x2
+
+/*
+ * This struct describes a hardware button
+ */
+struct hwbutton_interrupt {
+	char *name;			/* Name of button */
+	int irq;			/* Actual LINUX IRQ */
+	int eirq;			/* Extended IRQ number (0-7) */
+	int initial_state;		/* The "normal" state of the switch */
+	void (*handle_hi)(void*);	/* Handler: switch input has gone HI */
+	void (*handle_lo)(void*);	/* Handler: switch input has gone LO */
+	void *data;			/* Optional data to pass to handler */
+};
+
+#ifdef CONFIG_PMC_MSP7120_GW
+extern void msp_restart(char *);
+
+static void softreset_push(void *data)
+{
+	printk(KERN_WARNING "SOFTRESET switch was pushed\n");
+
+	/*
+	 * In the future you could move this to the release handler,
+	 * timing the difference between the 'push' and 'release', and only
+	 * doing this ungraceful restart if the button has been down for
+	 * a certain amount of time; otherwise doing a graceful restart.
+	 */
+
+	msp_restart(NULL);
+}
+
+static void softreset_release(void *data)
+{
+	printk(KERN_WARNING "SOFTRESET switch was released\n");
+
+	/* Do nothing */
+}
+
+static void standby_on(void *data)
+{
+	printk(KERN_WARNING "STANDBY switch was set to ON (not implemented)\n");
+
+	/* TODO: Put board in standby mode */
+#ifdef CONFIG_SENSORS_PMCTWILED
+	msp_led_turn_off(MSP_LED_PWRSTANDBY_GREEN); 
+	msp_led_turn_on(MSP_LED_PWRSTANDBY_RED); 
+#endif
+}
+
+static void standby_off(void *data)
+{
+	printk(KERN_WARNING "STANDBY switch was set to OFF (not implemented)\n");
+
+	/* TODO: Take out of standby mode */
+#ifdef CONFIG_SENSORS_PMCTWILED
+	msp_led_turn_on(MSP_LED_PWRSTANDBY_GREEN); 
+	msp_led_turn_off(MSP_LED_PWRSTANDBY_RED); 
+#endif
+}
+
+static struct hwbutton_interrupt softreset_sw = {
+	.name = "Softreset button",
+	.irq = MSP_INT_EXT0,
+	.eirq = 0,
+	.initial_state = HWBUTTON_HI,
+	.handle_hi = softreset_release,
+	.handle_lo = softreset_push,
+	.data = NULL,
+};
+
+static struct hwbutton_interrupt standby_sw = {
+	.name = "Standby switch",
+	.irq = MSP_INT_EXT1,
+	.eirq = 1,
+	.initial_state = HWBUTTON_HI,
+	.handle_hi = standby_off,
+	.handle_lo = standby_on,
+	.data = NULL,
+};
+#endif /* CONFIG_PMC_MSP7120_GW */
+
+static irqreturn_t hwbutton_handler(int irq, void* data)
+{
+	struct hwbutton_interrupt *hirq = data;
+	unsigned long cic_ext = *CIC_EXT_CFG_REG;
+
+	if (irq != hirq->irq)
+		return IRQ_NONE;
+
+	if (CIC_EXT_IS_ACTIVE_HI(cic_ext, hirq->eirq)) {
+		/* Interrupt: pin is now HI */
+		CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
+		hirq->handle_hi(hirq->data);
+	} else {
+		/* Interrupt: pin is now LO */
+		CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
+		hirq->handle_lo(hirq->data);
+	}
+
+	/* 
+	 * Invert the POLARITY of this level interrupt to ack the interrupt
+	 * Thus next state change will invoke the opposite message
+	 */
+	*CIC_EXT_CFG_REG = cic_ext;
+
+	return IRQ_HANDLED;
+}
+
+static int msp_hwbutton_register(struct hwbutton_interrupt *hirq)
+{
+	unsigned long cic_ext;
+
+	if (hirq->handle_hi == NULL || hirq->handle_lo == NULL)
+		return -EINVAL;
+       
+	cic_ext = *CIC_EXT_CFG_REG;
+	CIC_EXT_SET_TRIGGER_LEVEL(cic_ext, hirq->eirq);
+	if (hirq->initial_state == HWBUTTON_HI)
+		CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
+	else
+		CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
+	*CIC_EXT_CFG_REG = cic_ext;
+
+	return request_irq(hirq->irq, hwbutton_handler, SA_INTERRUPT,
+				hirq->name, (void*)hirq);
+}
+
+static int __init msp_hwbutton_setup(void)
+{
+#ifdef CONFIG_PMC_MSP7120_GW
+	msp_hwbutton_register(&softreset_sw);
+	msp_hwbutton_register(&standby_sw);
+#endif
+	return 0;
+}
+
+subsys_initcall(msp_hwbutton_setup);
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq.c b/arch/mips/pmc-sierra/msp71xx/msp_irq.c
new file mode 100644
index 0000000..3b78f81
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_irq.c
@@ -0,0 +1,124 @@
+/*
+ * IRQ vector handles
+ *
+ * Copyright (C) 1995, 1996, 1997, 2003 by Ralf Baechle
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/ptrace.h>
+#include <asm/time.h>
+
+#include <msp_int.h>
+
+extern void msp_int_handle(void);
+
+/* SLP bases systems */
+extern void msp_slp_irq_init(void);
+extern void msp_slp_irq_dispatch(void);
+
+/* CIC based systems */
+extern void msp_cic_irq_init(void);
+extern void msp_cic_irq_dispatch(void);
+
+/*
+ * The PMC-Sierra MSP interrupts are arranged in a 3 level cascaded
+ * hierarchical system.  The first level are the direct MIPS interrupts
+ * and are assigned the interrupt range 0-7.  The second level is the SLM
+ * interrupt controller and is assigned the range 8-39.  The third level
+ * comprises the Peripherial block, the PCI block, the PCI MSI block and
+ * the SLP.  The PCI interrupts and the SLP errors are handled by the
+ * relevant subsystems so the core interrupt code needs only concern
+ * itself with the Peripheral block.  These are assigned interrupts in
+ * the range 40-71.
+ */
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+	u32 pending;
+
+	pending = read_c0_status() & read_c0_cause();
+	
+	/*
+	 * jump to the correct interrupt routine
+	 * These are arranged in priority order and the timer
+	 * comes first!
+	 */
+
+#ifdef CONFIG_IRQ_MSP_CIC	/* break out the CIC stuff for now */
+	if (pending & C_IRQ4)	/* do the peripherals first, that's the timer */
+		msp_cic_irq_dispatch();
+		
+	else if (pending & C_IRQ0)
+		do_IRQ(MSP_INT_MAC0);
+		
+	else if (pending & C_IRQ1)
+		do_IRQ(MSP_INT_MAC1);
+
+	else if (pending & C_IRQ2)
+		do_IRQ(MSP_INT_USB);
+	
+	else if (pending & C_IRQ3)
+		do_IRQ(MSP_INT_SAR);
+
+	else if (pending & C_IRQ5)
+		do_IRQ(MSP_INT_SEC);
+
+#else
+	if (pending & C_IRQ5)
+		do_IRQ(MSP_INT_TIMER);
+	
+	else if (pending & C_IRQ0)
+		do_IRQ(MSP_INT_MAC0);
+
+	else if (pending & C_IRQ1)
+		do_IRQ(MSP_INT_MAC1);
+	
+	else if (pending & C_IRQ3)
+		do_IRQ(MSP_INT_VE);
+
+	else if (pending & C_IRQ4)
+		msp_slp_irq_dispatch();
+#endif
+
+	else if (pending & C_SW0)	/* do software after hardware */
+		do_IRQ(MSP_INT_SW0);
+
+	else if (pending & C_SW1)
+		do_IRQ(MSP_INT_SW1);
+}
+
+static struct irqaction cascade_msp = {
+	.handler = no_action,
+	.name	 = "MSP cascade"
+};
+
+
+void __init arch_init_irq(void)
+{
+	/* initialize the 1st-level CPU based interrupt controller */
+	mips_cpu_irq_init();
+
+#ifdef CONFIG_IRQ_MSP_CIC
+	msp_cic_irq_init();
+
+	/* setup the cascaded interrupts */
+	setup_irq(MSP_INT_CIC, &cascade_msp);
+	setup_irq(MSP_INT_PER, &cascade_msp);
+#else
+	/* setup the 2nd-level SLP register based interrupt controller */
+	msp_slp_irq_init();
+
+	/* setup the cascaded SLP/PER interrupts */
+	setup_irq(MSP_INT_SLP, &cascade_msp);
+	setup_irq(MSP_INT_PER, &cascade_msp);
+#endif
+}
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c
new file mode 100644
index 0000000..3b713f2
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c
@@ -0,0 +1,140 @@
+/*
+ * This file define the irq handler for MSP SLM subsystem interrupts.
+ *
+ * Copyright 2005-2007 PMC-Sierra, Inc, derived from irq_cpu.c
+ * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.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.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <msp_cic_int.h>
+#include <msp_regs.h>
+
+/*
+ * NOTE: We are only enabling support for VPE0 right now.
+ */
+
+static inline void unmask_msp_cic_irq(unsigned int irq)
+{
+
+	/* check for PER interrupt range */
+	if (irq < MSP_PER_INTBASE)
+		*CIC_VPE0_MSK_REG |= (1 << (irq - MSP_CIC_INTBASE));
+	else
+		*PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
+}
+
+static inline void mask_msp_cic_irq(unsigned int irq)
+{
+	/* check for PER interrupt range */
+	if (irq < MSP_PER_INTBASE)
+		*CIC_VPE0_MSK_REG &= ~(1 << (irq - MSP_CIC_INTBASE));
+	else
+		*PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
+}
+
+/*
+ * While we ack the interrupt interrupts are disabled and thus we don't need
+ * to deal with concurrency issues.  Same for msp_cic_irq_end.
+ */
+static inline void ack_msp_cic_irq(unsigned int irq)
+{
+	mask_msp_cic_irq(irq);
+
+	/*
+	 * only really necessary for 18, 16-14 and sometimes 3:0 (since
+	 * these can be edge sensitive) but it doesn't hurt for the others.
+	 */ 
+
+	/* check for PER interrupt range */
+	if (irq < MSP_PER_INTBASE)
+		*CIC_STS_REG = (1 << (irq - MSP_CIC_INTBASE));
+	else
+		*PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
+}
+
+static void end_msp_cic_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		unmask_msp_cic_irq(irq);
+}
+
+static struct irq_chip msp_cic_irq_controller = {
+	.typename = "MSP_CIC",
+	.ack = ack_msp_cic_irq,
+	.mask = ack_msp_cic_irq,
+	.mask_ack = ack_msp_cic_irq,
+	.unmask = unmask_msp_cic_irq,
+	.end = end_msp_cic_irq,
+};
+
+
+void __init msp_cic_irq_init(void)
+{
+ 	int i;
+
+	/* Mask/clear interrupts. */
+	*CIC_VPE0_MSK_REG = 0x00000000;
+	*PER_INT_MSK_REG  = 0x00000000;	
+	*CIC_STS_REG      = 0xFFFFFFFF;
+	*PER_INT_STS_REG  = 0xFFFFFFFF;
+ 
+#if defined(CONFIG_PMC_MSP7120_GW) \
+ || defined(CONFIG_PMC_MSP7120_EVAL)
+	/* 
+	 * The MSP7120 RG and EVBD boards use IRQ[6:4] for PCI.
+	 * These inputs map to EXT_INT_POL[6:4] inside the CIC.
+	 * They are to be active low, level sensitive.
+	 */
+	*CIC_EXT_CFG_REG &= 0xFFFF8F8F;
+#endif
+
+	/* initialize all the IRQ descriptors */
+	for (i = MSP_CIC_INTBASE; i < MSP_PER_INTBASE + 32; i++)
+		set_irq_chip(i, &msp_cic_irq_controller);
+}
+
+void msp_cic_irq_dispatch(void)
+{
+	u32 pending;
+	int intbase;
+
+	intbase = MSP_CIC_INTBASE;
+	pending = *CIC_STS_REG & *CIC_VPE0_MSK_REG;
+
+	/* check for PER interrupt */
+	if (pending == (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) {
+		intbase = MSP_PER_INTBASE;
+		pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
+	}
+
+	/* check for spurious interrupt */
+	if (pending == 0x00000000) {
+		printk(KERN_ERR
+			"Spurious %s interrupt? status %08x, mask %08x\n",
+			(intbase == MSP_CIC_INTBASE) ? "CIC" : "PER",
+			(intbase == MSP_CIC_INTBASE) ?
+				*CIC_STS_REG : *PER_INT_STS_REG,
+			(intbase == MSP_CIC_INTBASE) ?
+				*CIC_VPE0_MSK_REG : *PER_INT_MSK_REG);
+		return;
+	}
+
+	/* check for the timer and dispatch it first */
+	if ((intbase == MSP_CIC_INTBASE) &&
+	    (pending & (1 << (MSP_INT_VPE0_TIMER - MSP_CIC_INTBASE))))
+		do_IRQ(MSP_INT_VPE0_TIMER);
+	else
+		do_IRQ(ffs(pending) + intbase - 1);
+}
+
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c
new file mode 100644
index 0000000..abd15b6
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c
@@ -0,0 +1,115 @@
+/*
+ * This file define the irq handler for MSP SLM subsystem interrupts.
+ *
+ * Copyright 2005-2006 PMC-Sierra, Inc, derived from irq_cpu.c
+ * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.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.
+ */
+ 
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <msp_slp_int.h>
+#include <msp_regs.h>
+
+static inline void unmask_msp_slp_irq(unsigned int irq)
+{
+	/* check for PER interrupt range */
+	if (irq < MSP_PER_INTBASE)
+		*SLP_INT_MSK_REG |= (1 << (irq - MSP_SLP_INTBASE));
+	else
+		*PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
+}
+
+static inline void mask_msp_slp_irq(unsigned int irq)
+{
+	/* check for PER interrupt range */
+	if (irq < MSP_PER_INTBASE)
+		*SLP_INT_MSK_REG &= ~(1 << (irq - MSP_SLP_INTBASE));
+	else
+		*PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
+}
+
+/*
+ * While we ack the interrupt interrupts are disabled and thus we don't need
+ * to deal with concurrency issues.  Same for msp_slp_irq_end.
+ */
+static inline void ack_msp_slp_irq(unsigned int irq)
+{
+	mask_slp_irq(irq);
+
+	/*
+	 * only really necessary for 18, 16-14 and sometimes 3:0 (since
+	 * these can be edge sensitive) but it doesn't hurt  for the others.
+	 */
+
+	/* check for PER interrupt range */
+	if (irq < MSP_PER_INTBASE)
+		*SLP_INT_STS_REG = (1 << (irq - MSP_SLP_INTBASE));
+	else
+		*PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
+}
+
+static void end_msp_slp_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		unmask_slp_irq(irq);
+}
+
+static struct irq_chip msp_slp_irq_controller = {
+	.typename = "MSP_SLP",
+	.ack = ack_msp_slp_irq,
+	.mask = ack_msp_slp_irq,
+	.mask_ack = ack_msp_slp_irq,
+	.unmask = unmask_msp_slp_irq,
+	.end = end_msp_slp_irq,
+};
+
+void __init msp_slp_irq_init(void)
+{
+	int i;
+
+	/* Mask/clear interrupts. */
+	*SLP_INT_MSK_REG = 0x00000000;
+	*PER_INT_MSK_REG = 0x00000000;	
+	*SLP_INT_STS_REG = 0xFFFFFFFF;
+	*PER_INT_STS_REG = 0xFFFFFFFF;
+
+	/* initialize all the IRQ descriptors */
+	for (i = MSP_SLP_INTBASE; i < MSP_PER_INTBASE + 32; i++)
+		set_irq_chip(i, &msp_slp_irq_controller);
+}
+
+void msp_slp_irq_dispatch(void)
+{
+	u32 pending;
+	int intbase;
+
+	intbase = MSP_SLP_INTBASE;
+	pending = *SLP_INT_STS_REG & *SLP_INT_MSK_REG;
+
+	/* check for PER interrupt */
+	if (pending == (1 << (MSP_INT_PER - MSP_SLP_INTBASE))) {
+		intbase = MSP_PER_INTBASE;
+		pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
+	}
+
+	/* check for spurious interrupt */
+	if (pending == 0x00000000) {
+		printk(KERN_ERR "Spurious %s interrupt?\n",
+			(intbase == MSP_SLP_INTBASE) ? "SLP" : "PER");
+		return;
+	}
+
+	/* dispatch the irq */
+	do_IRQ(ffs(pending) + intbase - 1);
+}
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_prom.c b/arch/mips/pmc-sierra/msp71xx/msp_prom.c
new file mode 100644
index 0000000..cf521c0
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_prom.c
@@ -0,0 +1,597 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *    PROM library initialisation code, assuming a version of
+ *    pmon is the boot code.
+ *
+ * Copyright 2000,2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ * This file was derived from Carsten Langgaard's
+ * arch/mips/mips-boards/xx files.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#ifdef CONFIG_CRAMFS
+#include <linux/cramfs_fs.h>
+#endif
+#ifdef CONFIG_SQUASHFS
+#include <linux/squashfs_fs.h>
+#endif
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <asm-generic/sections.h>
+#include <asm/page.h>
+
+#include <msp_prom.h>
+#include <msp_regs.h>
+
+/* console uses serial port 0 */
+#define CONSOLE_PORT_BASE KSEG1ADDR(MSP_UART0_BASE)
+
+/* global PROM environment variables and pointers */
+int prom_argc;
+char **prom_argv, **prom_envp;
+int *prom_vec;
+
+/* debug flag */
+int init_debug = 1;
+
+/* memory blocks */
+struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
+
+/* default feature sets */
+static char msp_default_features[] = 
+#if defined(CONFIG_PMC_MSP4200_EVAL) \
+ || defined(CONFIG_PMC_MSP4200_GW)
+	"ERER";
+#elif defined(CONFIG_PMC_MSP7120_EVAL) \
+ || defined(CONFIG_PMC_MSP7120_GW)
+	"EMEMSP";
+#elif defined(CONFIG_PMC_MSP7120_FPGA)
+	"EMEM";
+#endif
+
+/* conversion functions */
+static inline unsigned char str2hexnum(unsigned char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	return 0; /* foo */
+}
+
+static inline int str2eaddr(unsigned char *ea, unsigned char *str)
+{
+	int index = 0;
+	unsigned char num = 0;
+
+	while (*str != '\0') {
+		if ((*str == '.') || (*str == ':')) {
+			ea[index++] = num;
+			num = 0;
+			str++;
+		} else {
+			num = num << 4;
+			num |= str2hexnum(*str++);
+		}
+	}
+
+	if (index == 5)	{
+		ea[index++] = num;
+		return 0;
+	} else
+		return -1;
+}
+
+static inline unsigned long str2hex(unsigned char *str)
+{
+	int value = 0;
+
+	while (*str) {
+		value = value << 4;
+		value |= str2hexnum(*str++);
+	}
+
+	return value;
+}
+
+/* function to query the system information */
+const char *get_system_type(void)
+{
+#if defined(CONFIG_PMC_MSP4200_EVAL)
+	return "PMC-Sierra MSP4200 Eval Board";
+#elif defined(CONFIG_PMC_MSP4200_GW)
+	return "PMC-Sierra MSP4200 VoIP Gateway";
+#elif defined(CONFIG_PMC_MSP7120_EVAL)
+	return "PMC-Sierra MSP7120 Eval Board";
+#elif defined(CONFIG_PMC_MSP7120_GW)
+	return "PMC-Sierra MSP7120 Residential Gateway";
+#elif defined(CONFIG_PMC_MSP7120_FPGA)
+	return "PMC-Sierra MSP7120 FPGA";
+#else
+	#error "What is the type of *your* MSP?"
+#endif
+}
+
+int get_ethernet_addr(char * ethaddr_name, char *ethernet_addr)
+{
+	char *ethaddr_str;
+
+	ethaddr_str = prom_getenv(ethaddr_name);
+	if (!ethaddr_str) {
+		printk(KERN_WARNING "%s not set in boot prom\n", ethaddr_name);
+		return -1;
+	}
+		
+	if (str2eaddr(ethernet_addr, ethaddr_str) == -1) {
+		printk(KERN_WARNING "%s badly formatted-<%s>\n",
+			ethaddr_name, ethaddr_str);
+		return -1;
+	}
+
+	if (init_debug > 1) {
+		int i;
+		printk(KERN_DEBUG "get_ethernet_addr: for %s ", ethaddr_name);
+		for (i=0; i<5; i++)
+			printk(KERN_DEBUG "%02x:",
+				(unsigned char)*(ethernet_addr+i));
+		printk(KERN_DEBUG "%02x\n", *(ethernet_addr+i));
+	}
+
+	return 0;
+}
+
+static char *get_features(void)
+{
+	char *feature = prom_getenv(FEATURES);
+
+	if (feature == NULL) {
+		/* default features based on MACHINE_TYPE */
+		feature = msp_default_features;
+	}
+
+	return feature;
+}
+
+static char test_feature(char c)
+{
+	char *feature = get_features();
+
+	while (*feature) {
+		if (*feature++ == c)
+			return *feature;
+		feature++;
+	}
+
+	return FEATURE_NOEXIST;
+}
+
+unsigned long get_deviceid(void)
+{
+	char *deviceid = prom_getenv(DEVICEID);
+
+	if (deviceid == NULL)
+		return *DEV_ID_REG;
+	else
+		return str2hex(deviceid);
+}
+
+char identify_pci(void)
+{
+	return test_feature(PCI_KEY);
+}
+
+char identify_pcimux(void)
+{
+	return test_feature(PCIMUX_KEY);
+}
+
+char identify_sec(void)
+{
+	return test_feature(SEC_KEY);
+}
+
+char identify_spad(void)
+{
+	return test_feature(SPAD_KEY);
+}
+
+char identify_tdm(void)
+{
+	return test_feature(TDM_KEY);
+}
+
+char identify_zsp(void)
+{
+	return test_feature(ZSP_KEY);
+}
+
+static char identify_enetfeature(char key, unsigned long interface_num)
+{
+	char *feature = get_features();
+
+	while (*feature) {
+		if (*feature++ == key && interface_num-- == 0)
+			return *feature;
+		feature++;
+	}
+
+	return FEATURE_NOEXIST;
+}
+
+char identify_enet(unsigned long interface_num)
+{
+	return identify_enetfeature(ENET_KEY, interface_num);
+}
+
+char identify_enetTxD(unsigned long interface_num)
+{
+	return identify_enetfeature(ENETTXD_KEY, interface_num);
+}
+
+unsigned long identify_family(void)
+{
+	unsigned long deviceid;
+
+	deviceid = get_deviceid();
+
+	return deviceid & CPU_DEVID_FAMILY;
+}
+
+unsigned long identify_revision(void)
+{
+	unsigned long deviceid;
+
+	deviceid = get_deviceid();
+
+	return deviceid & CPU_DEVID_REVISION;
+}
+
+
+/* PROM environment functions */
+char *prom_getenv(char *env_name)
+{
+	/*
+	 * Return a pointer to the given environment variable.  prom_envp
+	 * points to a null terminated array of pointers to variables.
+	 * Environment variables are stored in the form of "memsize=64"
+	 */
+
+	char **var = prom_envp;
+	int i = strlen(env_name);
+
+	while (*var) {
+		if (strncmp(env_name, *var, i) == 0) {
+			return (*var + strlen(env_name) + 1);
+		}
+		var++;
+	}
+	
+	return NULL;
+}
+
+/* PROM commandline functions */
+char * prom_getcmdline(void)
+{
+	return &(arcs_cmdline[0]);
+}
+
+void  __init prom_init_cmdline(void)
+{
+	char *cp;
+	int actr;
+
+	actr = 1; /* Always ignore argv[0] */
+
+	cp = &(arcs_cmdline[0]);
+	while (actr < prom_argc) {
+		strcpy(cp, prom_argv[actr]);
+		cp += strlen(prom_argv[actr]);
+		*cp++ = ' ';
+		actr++;
+	}
+	if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+		--cp;
+	*cp = '\0';
+}
+
+/* PROM printing functions */
+void prom_putchar(char c)
+{
+	volatile uint32_t *uart = (volatile uint32_t *)CONSOLE_PORT_BASE;
+	uint32_t val = (uint32_t)c;
+	
+	local_irq_disable();
+	while (!(uart[5] & 0x20)); /* Wait for TXRDY */
+	uart[0] = val;
+	while (!(uart[5] & 0x20)); /* Wait for TXRDY */
+	local_irq_enable();
+}
+
+char prom_getchar(void)
+{
+	volatile uint32_t *uart = (volatile uint32_t *)CONSOLE_PORT_BASE;
+	uint32_t val;
+	
+	while (!(uart[5] & 0x01)); /* Wait for RXRDY */
+	val = uart[0];
+	
+	return (char)val;
+}
+
+/* memory allocation functions */
+static int __init prom_memtype_classify(unsigned int type)
+{
+	switch (type) {
+	case yamon_free:
+		return BOOT_MEM_RAM;
+	case yamon_prom:
+		return BOOT_MEM_ROM_DATA;
+	default:
+		return BOOT_MEM_RESERVED;
+	}
+}
+
+void __init prom_meminit(void)
+{
+	struct prom_pmemblock *p;
+
+	p = prom_getmdesc();
+
+	while (p->size) {
+		long type;
+		unsigned long base, size;
+
+		type = prom_memtype_classify(p->type);
+		base = p->base;
+		size = p->size;
+
+		add_memory_region(base, size, type);
+		p++; 
+	}
+}
+
+void __init prom_free_prom_memory(void)
+{
+	int	argc;
+	char	**argv;
+	char	**envp;
+	char	*ptr;
+	int	len = 0;
+	int	i;
+	unsigned long addr;
+
+	/*
+	 * preserve environment variables and command line from pmon/bbload
+	 * first preserve the command line
+	 */
+	for (argc = 0; argc < prom_argc; argc++) {
+		len += sizeof(char *);			/* length of pointer */
+		len += strlen(prom_argv[argc]) + 1;	/* length of string */
+	}
+	len += sizeof(char *);		/* plus length of null pointer */
+
+	argv = kmalloc(len, GFP_KERNEL);
+	ptr = (char *) &argv[prom_argc + 1];	/* strings follow array */
+
+	for (argc = 0; argc < prom_argc; argc++) {
+		argv[argc] = ptr;
+		strcpy(ptr, prom_argv[argc]);
+		ptr += strlen(prom_argv[argc]) + 1;
+	}
+	argv[prom_argc] = NULL;		/* end array with null pointer */
+	prom_argv = argv;
+
+	/* next preserve the environment variables */
+	len = 0;
+	i = 0;
+	for (envp = prom_envp; *envp != NULL; envp++) {
+		i++;		/* count number of environment variables */
+		len += sizeof(char *);		/* length of pointer */
+		len += strlen(*envp) + 1;	/* length of string */
+	}
+	len += sizeof(char *);		/* plus length of null pointer */
+
+	envp = kmalloc(len, GFP_KERNEL);
+	ptr = (char *) &envp[i+1];
+
+	for (argc = 0; argc < i; argc++) {
+		envp[argc] = ptr;
+		strcpy(ptr, prom_envp[argc]);
+		ptr += strlen(prom_envp[argc]) + 1;
+	}
+	envp[i] = NULL;			/* end array with null pointer */
+	prom_envp = envp;
+
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
+			continue;
+
+		addr = boot_mem_map.map[i].addr;
+		free_init_pages("prom memory",
+				addr, addr + boot_mem_map.map[i].size);
+	}
+}
+
+struct prom_pmemblock * __init prom_getmdesc(void)
+{
+	static char	memsz_env[] __initdata = "memsize";
+	static char	heaptop_env[] __initdata = "heaptop";
+	char		*str;
+	unsigned int	memsize;
+	unsigned int	heaptop;
+#ifdef CONFIG_MTD_PMC_MSP_RAMROOT
+	void		*ramroot_start;
+	unsigned long	ramroot_size;
+#endif
+	int i;
+
+	str = prom_getenv(memsz_env);
+	if (!str) {
+		ppfinit("memsize not set in boot prom, "
+			"set to default (32Mb)\n");
+		memsize = 0x02000000;
+	} else {
+		memsize = simple_strtol(str, NULL, 0);
+
+		if (memsize == 0) {
+			/* if memsize is a bad size, use reasonable default */
+			memsize = 0x02000000;
+		}
+
+		/* convert to physical address (removing caching bits, etc) */
+		memsize = CPHYSADDR(memsize);
+	}
+
+	str = prom_getenv(heaptop_env);
+	if (!str) {
+		heaptop = CPHYSADDR((u32)&_text);
+		ppfinit("heaptop not set in boot prom, "
+			"set to default 0x%08x\n", heaptop);
+	} else {
+		heaptop = simple_strtol(str, NULL, 16);
+		if (heaptop == 0) {
+			/* heaptop conversion bad, might have 0xValue */
+			heaptop = simple_strtol(str, NULL, 0);
+
+			if (heaptop == 0) {
+				/* heaptop still bad, use reasonable default */
+				heaptop = CPHYSADDR((u32)&_text);
+			}
+		}
+
+		/* convert to physical address (removing caching bits, etc) */
+		heaptop = CPHYSADDR((u32)heaptop);
+	}
+
+	/* the base region */
+	i = 0;
+	mdesc[i].type = BOOT_MEM_RESERVED;
+	mdesc[i].base = 0x00000000;
+	mdesc[i].size = PAGE_ALIGN(0x300 + 0x80);
+		/* jtag interrupt vector + sizeof vector */
+
+	/* PMON data */
+	if (heaptop > mdesc[i].base + mdesc[i].size) {
+		i++;			/* 1 */
+		mdesc[i].type = BOOT_MEM_ROM_DATA;
+		mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
+		mdesc[i].size = heaptop - mdesc[i].base;
+	}
+
+	/* end of PMON data to start of kernel -- probably zero .. */
+	if (heaptop != CPHYSADDR((u32)_text)) {
+		i++;	/* 2 */
+		mdesc[i].type = BOOT_MEM_RAM;
+		mdesc[i].base = heaptop;
+		mdesc[i].size = CPHYSADDR((u32)_text) - mdesc[i].base;
+	}
+
+	/*  kernel proper */
+	i++;			/* 3 */
+	mdesc[i].type = BOOT_MEM_RESERVED;
+	mdesc[i].base = CPHYSADDR((u32)_text);
+#ifdef CONFIG_MTD_PMC_MSP_RAMROOT
+	if (get_ramroot(&ramroot_start, &ramroot_size)) {
+		/*
+		 * Rootfs in RAM -- follows kernel
+		 * Combine rootfs image with kernel block so a
+		 * page (4k) isn't wasted between memory blocks
+		 */
+		mdesc[i].size = CPHYSADDR(PAGE_ALIGN(
+			(u32)ramroot_start + ramroot_size)) - mdesc[i].base;
+	} else
+#endif
+		mdesc[i].size = CPHYSADDR(PAGE_ALIGN(
+			(u32)_end)) - mdesc[i].base;
+
+	/* Remainder of RAM -- under memsize */
+	i++;			/* 5 */				
+	mdesc[i].type = yamon_free;
+	mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
+	mdesc[i].size = memsize - mdesc[i].base;
+
+	return &mdesc[0];
+}
+
+/* rootfs functions */
+#ifdef CONFIG_MTD_PMC_MSP_RAMROOT
+bool get_ramroot(void **start, unsigned long *size)
+{
+	extern char _end[];
+	
+	/* Check for start following the end of the kernel */
+	void *check_start = (void *)_end;
+
+	/* Check for supported rootfs types */
+#ifdef CONFIG_CRAMFS
+	if (*(__u32 *)check_start == CRAMFS_MAGIC) {
+		/* Get CRAMFS size */
+		*start = check_start;
+		*size = PAGE_ALIGN(((struct cramfs_super *)
+				   check_start)->size);
+		
+		return true;
+	}
+#endif
+#ifdef CONFIG_SQUASHFS
+	if (*((unsigned int *)check_start) == SQUASHFS_MAGIC) {
+		/* Get SQUASHFS size */
+		*start = check_start;
+		*size = PAGE_ALIGN(((struct squashfs_super_block *)
+				   check_start)->bytes_used);
+		
+		return true;
+	}
+#endif
+
+	return false;
+}
+
+EXPORT_SYMBOL(get_ramroot);
+#endif
+
+EXPORT_SYMBOL(get_ethernet_addr);
+EXPORT_SYMBOL(identify_pci);
+EXPORT_SYMBOL(identify_sec);
+EXPORT_SYMBOL(identify_spad);
+EXPORT_SYMBOL(identify_tdm);
+EXPORT_SYMBOL(identify_zsp);
+EXPORT_SYMBOL(identify_enet);
+EXPORT_SYMBOL(identify_enetTxD);
+EXPORT_SYMBOL(identify_family);
+EXPORT_SYMBOL(identify_revision);
+
+EXPORT_SYMBOL(prom_getcmdline);
+EXPORT_SYMBOL(str2eaddr);
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_setup.c b/arch/mips/pmc-sierra/msp71xx/msp_setup.c
new file mode 100644
index 0000000..fb6d76d
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_setup.c
@@ -0,0 +1,257 @@
+/*
+ * The generic setup file for PMC-Sierra MSP processors
+ *
+ * Copyright 2005-2007 PMC-Sierra, Inc,
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * 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.
+ */
+
+#include <asm/bootinfo.h>
+#include <asm/r4kcache.h>
+#include <asm/reboot.h>
+#include <asm/time.h>
+
+#include <msp_prom.h>
+#include <msp_regs.h>
+
+#if defined(CONFIG_PMC_MSP7120_GW)
+#include <msp_gpio_macros.h>
+#endif
+
+extern void msp_timer_init(void);
+extern void msp_serial_setup(void);
+extern void pmctwiled_setup(void);
+
+#if defined(CONFIG_PMC_MSP7120_EVAL) || \
+    defined(CONFIG_PMC_MSP7120_GW) || \
+    defined(CONFIG_PMC_MSP7120_FPGA)
+/*
+ * Performs the reset for MSP7120-based boards
+ */
+void msp7120_reset(void)
+{
+	void *start, *end, *iptr;
+	int i;
+
+	/* Diasble all interrupts */
+	local_irq_disable();
+#ifdef CONFIG_SYS_SUPPORTS_MULTITHREADING
+	dvpe();
+#endif
+
+	/* Cache the reset code of this function */
+	__asm__ __volatile__ (
+		"	.set	push				\n"
+		"	.set	mips3				\n"
+		"	la	%0,startpoint			\n"
+		"	la	%1,endpoint			\n"
+		"	.set	pop				\n"
+		: "=r" (start), "=r" (end)
+		: 
+	);
+	;
+	for (iptr = (void *)((unsigned int)start & ~(L1_CACHE_BYTES - 1));
+	     iptr < end; iptr += L1_CACHE_BYTES)
+		cache_op(Fill, iptr);
+	
+	__asm__ __volatile__ (
+		"startpoint:					\n"
+	);
+
+	/* Put the DDRC into self-refresh mode */
+	DDRC_INDIRECT_WRITE(DDRC_CTL(10), 0xb, (1<<16));
+	
+	/*
+	 * IMPORTANT! 
+	 * DO NOT do anything from here on out that might even
+	 * think about fetching from RAM - i.e., don't call any 
+	 * non-inlined functions, and be VERY sure that any inline 
+	 * functions you do call do NOT access any sort of RAM
+	 * anywhere!
+	 */
+
+	/* Wait a bit for the DDRC to settle */
+	for (i = 0; i < 100000000; i++);
+
+#if defined(CONFIG_PMC_MSP7120_GW)
+	/*
+	 * Set GPIO 9 HI, (tied to board reset logic)
+	 * GPIO 9 is the 4th GPIO of register 3
+	 *
+	 * Note, we cannot use the higher-level 'msp_gpio_pin_...'
+	 * functions as they look up data in a static table somewhere
+	 * else in RAM!
+	 */
+	set_value_reg32(GPIO_CFG3_REG,
+			BASIC_MODE_REG_MASK(3),
+			BASIC_MODE_REG_VALUE(MSP_GPIO_OUTPUT, 3));
+	set_reg32(GPIO_DATA3_REG, 
+			BASIC_DATA_REG_MASK(3));
+
+	/*
+	 * In case GPIO9 doesn't reset the board (jumper configurable!)
+	 * fallback to device reset below.
+	 */
+#endif
+	/* Set bit 1 of the MSP7120 reset register */
+	*RST_SET_REG = 0x00000001;
+
+	__asm__ __volatile__ (
+		"endpoint:					\n"
+	);
+}
+#endif
+
+void msp_restart(char *command)
+{
+	printk(KERN_WARNING "Now rebooting .......\n");
+
+#if defined(CONFIG_PMC_MSP7120_EVAL) || \
+    defined(CONFIG_PMC_MSP7120_GW) || \
+    defined(CONFIG_PMC_MSP7120_FPGA)
+	msp7120_reset();
+#else
+	/* No chip-specific reset code, just jump to the ROM reset vector */
+	set_c0_status(ST0_BEV | ST0_ERL);
+	change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+	flush_cache_all();
+	write_c0_wired(0);
+
+	__asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
+#endif
+}
+
+void msp_halt(void)
+{
+	printk(KERN_WARNING "\n** You can safely turn off the power\n");
+	while (1)
+		/* If possible call official function to get CPU WARs */
+		if (cpu_wait)
+			(*cpu_wait)();
+		else
+			__asm__(".set\tmips3\n\t" "wait\n\t" ".set\tmips0");
+}
+
+void msp_power_off(void)
+{
+	msp_halt();
+}
+
+void __init plat_mem_setup(void)
+{
+	_machine_restart = msp_restart;
+	_machine_halt = msp_halt;
+	pm_power_off = msp_power_off;
+
+	board_time_init   = msp_timer_init;
+}
+
+void __init prom_init(void)
+{
+	unsigned long family;
+	unsigned long revision;
+
+	prom_argc = fw_arg0;
+	prom_argv = (char **)fw_arg1;
+	prom_envp = (char **)fw_arg2;
+
+	/* 
+	 * someday we can use this with PMON2000 to get a
+	 * platform call prom routines for output etc. without
+	 * having to use grody hacks.  For now it's unused.
+	 */
+	/*struct callvectors *cv = (struct callvectors *) fw_arg3;*/
+
+	family = identify_family();
+	revision = identify_revision();
+
+	switch (family)	{
+	case FAMILY_FPGA:
+		if (FPGA_IS_MSP4200(revision)) {
+			/* Old-style revision ID */
+			mips_machgroup = MACH_GROUP_MSP;
+			mips_machtype = MACH_MSP4200_FPGA;
+		} else { 
+			mips_machgroup = MACH_GROUP_MSP;
+			mips_machtype = MACH_MSP_OTHER;
+		}
+		break;
+
+	case FAMILY_MSP4200:
+		mips_machgroup = MACH_GROUP_MSP;
+#if defined(CONFIG_PMC_MSP4200_EVAL)
+		mips_machtype  = MACH_MSP4200_EVAL;
+#elif defined(CONFIG_PMC_MSP4200_GW)
+		mips_machtype  = MACH_MSP4200_GW;
+#else
+		mips_machtype = MACH_MSP_OTHER;
+#endif
+		break;
+
+	case FAMILY_MSP4200_FPGA:
+		mips_machgroup = MACH_GROUP_MSP;
+		mips_machtype  = MACH_MSP4200_FPGA;
+		break;
+
+	case FAMILY_MSP7100:
+		mips_machgroup = MACH_GROUP_MSP;
+#if defined(CONFIG_PMC_MSP7120_EVAL)
+		mips_machtype = MACH_MSP7120_EVAL;
+#elif defined(CONFIG_PMC_MSP7120_GW)
+		mips_machtype = MACH_MSP7120_GW;
+#else
+		mips_machtype = MACH_MSP_OTHER;
+#endif
+		break;
+
+	case FAMILY_MSP7100_FPGA:
+		mips_machgroup = MACH_GROUP_MSP;
+		mips_machtype  = MACH_MSP7120_FPGA;
+		break;
+
+	default:
+		/* we don't recognize the machine */
+		mips_machgroup = MACH_GROUP_UNKNOWN;
+		mips_machtype  = MACH_UNKNOWN;
+		break;
+	}
+
+	prom_printf("\nLINUX started...\n");
+
+	/* make sure we have the right initialization routine - sanity */
+	if (mips_machgroup != MACH_GROUP_MSP) {
+		prom_printf("Unknown machine group in a "
+			    "MSP initialization routine\n");
+		panic("***Bogosity factor five***, exiting\n");
+	}
+
+	/* setup the serial console */
+	msp_serial_setup();
+	prom_init_cmdline();
+	
+	/* setup memory regions */
+	prom_meminit();
+
+	/*
+	 * Sub-system setup follows.
+	 * Setup functions can  either be called here or using the
+	 * subsys_initcall mechanism (i.e. see msp_pci). The order
+	 * in which they are called can be changed by using the link
+	 * order in arch/mips/pmc-sierra/msp71xx/Makefile.
+	 * 
+	 * NOTE: Please keep sub-system specific initialization code
+	 * in separate specific files.
+	 */
+	 
+#ifdef CONFIG_SENSORS_PMCTWILED
+	/*
+	 * Setup LED states before the subsys_initcall loads other
+	 * dependant drivers/modules.
+	 */
+	pmctwiled_setup();
+#endif
+}
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_time.c b/arch/mips/pmc-sierra/msp71xx/msp_time.c
new file mode 100644
index 0000000..73a5ac5
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_time.c
@@ -0,0 +1,94 @@
+/*
+ * Setting up the clock on MSP SOCs.  No RTC typically.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ */
+
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <asm/mipsregs.h>
+#include <asm/ptrace.h>
+#include <asm/time.h>
+
+#include <msp_prom.h>
+#include <msp_int.h>
+#include <msp_regs.h>
+
+void __init msp_timer_init(void)
+{
+	char    *endp,*s;
+	unsigned long cpu_rate = 0;
+    
+	if (cpu_rate == 0) {
+		s = prom_getenv("clkfreqhz");
+		cpu_rate = simple_strtoul(s,&endp,10);
+		if (endp != NULL && *endp != 0) {
+			printk(KERN_ERR
+				"Clock rate in Hz parse error: %s\n", s);
+			cpu_rate = 0;
+		}
+	}
+	
+	if (cpu_rate == 0) {
+		s = prom_getenv("clkfreq");
+		cpu_rate = 1000*simple_strtoul(s,&endp,10);        
+		if (endp != NULL && *endp != 0) {
+			printk(KERN_ERR
+				"Clock rate in MHz parse error: %s\n", s);
+			cpu_rate = 0;
+		}
+	}
+	
+	if (cpu_rate == 0) {
+#if defined(CONFIG_PMC_MSP7120_EVAL) \
+ || defined(CONFIG_PMC_MSP7120_GW)
+		cpu_rate = 400000000;
+#elif defined(CONFIG_PMC_MSP7120_FPGA)
+		cpu_rate = 25000000;
+#else                
+		cpu_rate = 150000000;
+#endif
+		printk(KERN_ERR
+			"Failed to determine CPU clock rate, "
+			"assuming %ld hz ...\n", cpu_rate);
+	}
+	
+	printk(KERN_WARNING "Clock rate set to %ld\n",cpu_rate);
+	
+	/* timer frequency is 1/2 clock rate */
+	mips_hpt_frequency = cpu_rate/2;
+}
+
+
+void __init plat_timer_setup(struct irqaction *irq)
+{
+#ifdef CONFIG_IRQ_MSP_CIC
+	/* we are using the vpe0 counter for timer interrupts */
+	setup_irq(MSP_INT_VPE0_TIMER, irq);
+#else
+	/* we are using the mips counter for timer interrupts */
+	setup_irq(MSP_INT_TIMER, irq);
+#endif
+}
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_usb.c b/arch/mips/pmc-sierra/msp71xx/msp_usb.c
new file mode 100644
index 0000000..2aa13f0
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_usb.c
@@ -0,0 +1,146 @@
+/*
+ * The setup file for USB related hardware on PMC-Sierra MSP processors.
+ *
+ * Copyright 2006-2007 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+#include <asm/mipsregs.h>
+
+#include <msp_regs.h>
+#include <msp_int.h>
+#include <msp_prom.h>
+
+#if defined (CONFIG_USB_EHCI_HCD)
+static struct resource msp_usbhost_resources [] = {
+	[0] = {
+		.start	= MSP_USB_BASE_START,
+		.end	= MSP_USB_BASE_END,
+		.flags 	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= MSP_INT_USB,
+		.end	= MSP_INT_USB,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 msp_usbhost_dma_mask = DMA_32BIT_MASK;
+
+static struct platform_device msp_usbhost_device = {
+	.name	= "pmcmsp-ehci",
+	.id	= 0,
+	.dev	= {
+		.dma_mask = &msp_usbhost_dma_mask,
+		.coherent_dma_mask = DMA_32BIT_MASK,
+	},
+	.num_resources 	= ARRAY_SIZE (msp_usbhost_resources),
+	.resource	= msp_usbhost_resources,
+};
+#endif /* CONFIG_USB_EHCI_HCD */
+
+#if defined (CONFIG_USB_GADGET)
+static struct resource msp_usbdev_resources [] = {
+	[0] = {
+		.start	= MSP_USB_BASE,
+		.end	= MSP_USB_BASE_END,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= MSP_INT_USB,
+		.end	= MSP_INT_USB,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 msp_usbdev_dma_mask = DMA_32BIT_MASK;
+
+static struct platform_device msp_usbdev_device = {
+	.name	= "msp71xx_udc",
+	.id	= 0,
+	.dev	= {
+		.dma_mask = &msp_usbdev_dma_mask,
+		.coherent_dma_mask = DMA_32BIT_MASK,
+	},
+	.num_resources	= ARRAY_SIZE (msp_usbdev_resources),
+	.resource	= msp_usbdev_resources,
+};
+#endif /* CONFIG_USB_GADGET */
+
+#if defined (CONFIG_USB_EHCI_HCD) || defined (CONFIG_USB_GADGET)
+static struct platform_device *msp_devs[1];
+#endif
+
+
+static int __init msp_usb_setup(void)
+{
+#if defined (CONFIG_USB_EHCI_HCD) || defined (CONFIG_USB_GADGET)
+	char *strp;
+	char envstr[32];
+	unsigned int val;
+	
+	/*
+	 * construct environment name usbmode
+	 * set usbmode <host/device> as pmon environment var
+	 */
+	snprintf((char *)&envstr[0], sizeof(envstr), "usbmode");
+
+	/* default to host mode */
+	val = 1;
+
+	/* get environment string */
+	strp = prom_getenv((char *)&envstr[0]);
+	if (strp) {
+		if (!strcmp(strp, "device"))
+			val = 0;
+	}
+
+	if (val) {
+#if defined (CONFIG_USB_EHCI_HCD)
+		/* get host mode device */
+		msp_devs[0] = &msp_usbhost_device;
+		prom_printf("platform add USB HOST done %s.\n",
+			    msp_devs[0]->name);
+
+		platform_add_devices (msp_devs, ARRAY_SIZE (msp_devs));
+#endif /* CONFIG_USB_EHCI_HCD */
+	}
+#if defined (CONFIG_USB_GADGET)
+	else {
+		/* get device mode structure */
+		msp_devs[0] = &msp_usbdev_device;
+		prom_printf("platform add USB DEVICE done %s.\n",
+			    msp_devs[0]->name);
+
+		platform_add_devices (msp_devs, ARRAY_SIZE (msp_devs));
+	}
+#endif /* CONFIG_USB_GADGET */
+#endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */
+
+	return 0;
+}
+
+subsys_initcall(msp_usb_setup);
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_cic_int.h b/include/asm-mips/pmc-sierra/msp71xx/msp_cic_int.h
new file mode 100644
index 0000000..8e5fd9f
--- /dev/null
+++ b/include/asm-mips/pmc-sierra/msp71xx/msp_cic_int.h
@@ -0,0 +1,151 @@
+/*
+ * Defines for the MSP interrupt controller.
+ *
+ * Copyright (C) 1999 MIPS Technologies, Inc.  All rights reserved.
+ * Author: Carsten Langgaard, carstenl@mips.com
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ */
+
+#ifndef _MSP_CIC_INT_H
+#define _MSP_CIC_INT_H
+
+/*
+ * The PMC-Sierra CIC interrupts are all centrally managed by the
+ * CIC sub-system.
+ * We attempt to keep the interrupt numbers as consistent as possible
+ * across all of the MSP devices, but some differences will creep in ...
+ * The interrupts which are directly forwarded to the MIPS core interrupts
+ * are assigned interrupts in the range 0-7, interrupts cascaded through
+ * the CIC are assigned interrupts 8-39.  The cascade occurs on C_IRQ4
+ * (MSP_INT_CIC).  Currently we don't really distinguish between VPE1 
+ * and VPE0 (or thread contexts for that matter).  Will have to fix.
+ * The PER interrupts are assigned interrupts in the range 40-71.
+*/
+
+
+/*
+ * IRQs directly forwarded to the CPU
+ */
+#define MSP_MIPS_INTBASE	0
+#define MSP_INT_SW0		0	/* IRQ for swint0,       C_SW0  */
+#define MSP_INT_SW1		1	/* IRQ for swint1,       C_SW1  */
+#define MSP_INT_MAC0		2	/* IRQ for MAC 0,        C_IRQ0 */
+#define MSP_INT_MAC1		3	/* IRQ for MAC 1,        C_IRQ1 */
+#define MSP_INT_USB		4	/* IRQ for USB,          C_IRQ2 */
+#define MSP_INT_SAR		5	/* IRQ for ADSL2+ SAR,   C_IRQ3 */
+#define MSP_INT_CIC		6	/* IRQ for CIC block,    C_IRQ4 */
+#define MSP_INT_SEC		7	/* IRQ for Sec engine,   C_IRQ5 */
+
+/*
+ * IRQs cascaded on CPU interrupt 4 (CAUSE bit 12, C_IRQ4)
+ * These defines should be tied to the register definitions for the CIC
+ * interrupt routine.  For now, just use hard-coded values.
+ */
+#define MSP_CIC_INTBASE		(MSP_MIPS_INTBASE + 8) 
+#define MSP_INT_EXT0		(MSP_CIC_INTBASE + 0)  
+					/* External interrupt 0         */
+#define MSP_INT_EXT1		(MSP_CIC_INTBASE + 1)  
+					/* External interrupt 1         */
+#define MSP_INT_EXT2		(MSP_CIC_INTBASE + 2)
+					/* External interrupt 2         */
+#define MSP_INT_EXT3		(MSP_CIC_INTBASE + 3)  
+					/* External interrupt 3         */
+#define MSP_INT_CPUIF		(MSP_CIC_INTBASE + 4)  
+					/* CPU interface interrupt      */
+#define MSP_INT_EXT4		(MSP_CIC_INTBASE + 5)  
+					/* External interrupt 4         */
+#define MSP_INT_CIC_USB		(MSP_CIC_INTBASE + 6)
+					/* Cascaded IRQ for USB         */
+#define MSP_INT_MBOX		(MSP_CIC_INTBASE + 7)
+					/* Sec engine mailbox IRQ       */
+#define MSP_INT_EXT5		(MSP_CIC_INTBASE + 8)
+					/* External interrupt 5         */
+#define MSP_INT_TDM		(MSP_CIC_INTBASE + 9)
+					/* TDM interrupt                */
+#define MSP_INT_CIC_MAC0	(MSP_CIC_INTBASE + 10)
+					/* Cascaded IRQ for MAC 0       */
+#define MSP_INT_CIC_MAC1	(MSP_CIC_INTBASE + 11)
+					/* Cascaded IRQ for MAC 1       */
+#define MSP_INT_CIC_SEC		(MSP_CIC_INTBASE + 12)
+					/* Cascaded IRQ for sec engine  */
+#define	MSP_INT_PER		(MSP_CIC_INTBASE + 13)
+					/* Peripheral interrupt         */
+#define	MSP_INT_TIMER0		(MSP_CIC_INTBASE + 14)
+					/* SLP timer 0                  */
+#define	MSP_INT_TIMER1		(MSP_CIC_INTBASE + 15)
+					/* SLP timer 1                  */
+#define	MSP_INT_TIMER2		(MSP_CIC_INTBASE + 16)
+					/* SLP timer 2                  */
+#define	MSP_INT_VPE0_TIMER	(MSP_CIC_INTBASE + 17)
+					/* VPE0 MIPS timer              */
+#define MSP_INT_BLKCP		(MSP_CIC_INTBASE + 18)
+					/* Block Copy                   */
+#define MSP_INT_UART0		(MSP_CIC_INTBASE + 19)
+					/* UART 0                       */
+#define MSP_INT_PCI		(MSP_CIC_INTBASE + 20)
+					/* PCI subsystem                */
+#define MSP_INT_EXT6		(MSP_CIC_INTBASE + 21)
+					/* External interrupt 5         */
+#define MSP_INT_PCI_MSI		(MSP_CIC_INTBASE + 22) 
+					/* PCI Message Signal           */
+#define MSP_INT_CIC_SAR		(MSP_CIC_INTBASE + 23)
+					/* Cascaded ADSL2+ SAR IRQ      */
+#define MSP_INT_DSL		(MSP_CIC_INTBASE + 24)
+					/* ADSL2+ IRQ                   */
+#define MSP_INT_CIC_ERR		(MSP_CIC_INTBASE + 25)
+					/* SLP error condition          */
+#define MSP_INT_VPE1_TIMER	(MSP_CIC_INTBASE + 26)
+					/* VPE1 MIPS timer              */
+#define MSP_INT_VPE0_PC		(MSP_CIC_INTBASE + 27)
+					/* VPE0 Performance counter     */
+#define MSP_INT_VPE1_PC		(MSP_CIC_INTBASE + 28)
+					/* VPE1 Performance counter     */
+#define MSP_INT_EXT7		(MSP_CIC_INTBASE + 29)
+					/* External interrupt 5         */
+#define MSP_INT_VPE0_SW		(MSP_CIC_INTBASE + 30)
+					/* VPE0 Software interrupt      */
+#define MSP_INT_VPE1_SW		(MSP_CIC_INTBASE + 31)
+					/* VPE0 Software interrupt      */
+
+/* 
+ * IRQs cascaded on CIC PER interrupt (MSP_INT_PER)
+ */
+#define MSP_PER_INTBASE		(MSP_CIC_INTBASE + 32)
+/* Reserved					   0-1                  */
+#define MSP_INT_UART1		(MSP_PER_INTBASE + 2) 
+					/* UART 1                       */
+/* Reserved					   3-5                  */
+#define MSP_INT_2WIRE		(MSP_PER_INTBASE + 6)
+					/* 2-wire                       */
+#define MSP_INT_TM0		(MSP_PER_INTBASE + 7)
+					/* Peripheral timer block out 0 */
+#define MSP_INT_TM1		(MSP_PER_INTBASE + 8)
+					/* Peripheral timer block out 1 */
+/* Reserved					   9                    */
+#define MSP_INT_SPRX		(MSP_PER_INTBASE + 10)
+					/* SPI RX complete              */
+#define MSP_INT_SPTX		(MSP_PER_INTBASE + 11)
+					/* SPI TX complete              */
+#define MSP_INT_GPIO		(MSP_PER_INTBASE + 12)
+					/* GPIO                         */
+#define MSP_INT_PER_ERR		(MSP_PER_INTBASE + 13)
+					/* Peripheral error             */
+/* Reserved					   14-31                */
+
+#endif /* !_MSP_CIC_INT_H */
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_gpio_macros.h b/include/asm-mips/pmc-sierra/msp71xx/msp_gpio_macros.h
new file mode 100644
index 0000000..1e06c3b
--- /dev/null
+++ b/include/asm-mips/pmc-sierra/msp71xx/msp_gpio_macros.h
@@ -0,0 +1,309 @@
+/*
+ * Macros for external SMP-safe access to the PMC Athena (MSP7120) reference
+ * board GPIO pins
+ *
+ * Copyright 2005-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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MSP_GPIO_MACROS_H__
+#define __MSP_GPIO_MACROS_H__
+
+#include <asm/regops.h>
+
+#include <msp_regs.h>
+
+/* -- GPIO Enumerations -- */
+typedef enum {
+	MSP_GPIO_LO = 0,
+	MSP_GPIO_HI = 1,
+	MSP_GPIO_NONE,		/* Special - Means pin is out of range */
+	MSP_GPIO_TOGGLE,	/* Special - Sets pin to opposite */
+} msp_gpio_data_t;
+
+typedef enum {
+	MSP_GPIO_INPUT		= 0x0,
+	/* MSP_GPIO_ INTERRUPT	= 0x1,	Not supported yet */
+	MSP_GPIO_UART_INPUT	= 0x2,	/* Only GPIO 4 or 5 */
+	MSP_GPIO_OUTPUT		= 0x8,
+	MSP_GPIO_UART_OUTPUT	= 0x9,	/* Only GPIO 2 or 3 */
+	MSP_GPIO_PERIF_TIMERA	= 0x9,	/* Only GPIO 0 or 1 */
+	MSP_GPIO_PERIF_TIMERB	= 0xa,	/* Only GPIO 0 or 1 */
+	MSP_GPIO_UNKNOWN	= 0xb,  /* No such GPIO or mode */
+} msp_gpio_mode_t;
+
+/* -- Static Tables -- */
+
+/* Maps pins to data register */
+static volatile u32 * const MSP_GPIO_DATA_REGISTER[] = {
+	/* GPIO 0 and 1 on the first register */
+GPIO_DATA1_REG, GPIO_DATA1_REG,
+	/* GPIO 2, 3, 4, and 5 on the second register */
+	GPIO_DATA2_REG, GPIO_DATA2_REG, GPIO_DATA2_REG, GPIO_DATA2_REG,
+	/* GPIO 6, 7, 8, and 9 on the third register */
+	GPIO_DATA3_REG, GPIO_DATA3_REG, GPIO_DATA3_REG, GPIO_DATA3_REG,
+	/* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */
+	GPIO_DATA4_REG, GPIO_DATA4_REG, GPIO_DATA4_REG, GPIO_DATA4_REG,
+	GPIO_DATA4_REG, GPIO_DATA4_REG,
+	/* GPIO 16, 17, 18, and 19 on the strange EXTENDED register */
+	EXTENDED_GPIO_REG, EXTENDED_GPIO_REG,
+	EXTENDED_GPIO_REG, EXTENDED_GPIO_REG,
+};
+
+/* Maps pins to mode register */
+static volatile u32 * const MSP_GPIO_MODE_REGISTER[] = {
+	/* GPIO 0 and 1 on the first register */
+	GPIO_CFG1_REG, GPIO_CFG1_REG,
+	/* GPIO 2, 3, 4, and 5 on the second register */
+	GPIO_CFG2_REG, GPIO_CFG2_REG, GPIO_CFG2_REG, GPIO_CFG2_REG,
+	/* GPIO 6, 7, 8, and 9 on the third register */
+	GPIO_CFG3_REG, GPIO_CFG3_REG, GPIO_CFG3_REG, GPIO_CFG3_REG,
+	/* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */
+	GPIO_CFG4_REG, GPIO_CFG4_REG, GPIO_CFG4_REG, GPIO_CFG4_REG,
+	GPIO_CFG4_REG, GPIO_CFG4_REG,
+	/* GPIO 16, 17, 18, and 19 on the strange EXTENDED register */
+	EXTENDED_GPIO_REG, EXTENDED_GPIO_REG,
+	EXTENDED_GPIO_REG, EXTENDED_GPIO_REG,
+};
+
+/* Maps 'basic' pins to relative offset from 0 per register */
+static int MSP_GPIO_OFFSET[] = {
+	/* GPIO 0 and 1 on the first register */
+	0, 0,
+	/* GPIO 2, 3, 4, and 5 on the second register */
+	2, 2, 2, 2,
+	/* GPIO 6, 7, 8, and 9 on the third register */
+	6, 6, 6, 6,
+	/* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */
+	10, 10, 10, 10, 10, 10,
+};
+
+/* Maps MODE to allowed pin mask */
+static unsigned int MSP_GPIO_MODE_ALLOWED[] = {
+	0xfffff,	/* Mode 0 - INPUT */
+	0x00000,	/* Mode 1 - INTERRUPT */
+	0x00030,	/* Mode 2 - UART_INPUT (GPIO 4, 5)*/
+	0, 0, 0, 0, 0,	/* Modes 3, 4, 5, 6, and 7 are reserved */
+	0xfffff,	/* Mode 8 - OUTPUT */
+	0x0000f,	/* Mode 9 - UART_OUTPUT/PERF_TIMERA (GPIO 0,1,2,3) */
+	0x00003,	/* Mode a - PERF_TIMERB (GPIO 0, 1) */
+	0x00000,	/* Mode b - Not really a mode! */
+};
+
+/* -- Bit masks -- */
+
+/* This gives you the 'register relative offlet gpio' number */
+#define OFFSET_GPIO_NUMBER(gpio)	(gpio - MSP_GPIO_OFFSET[gpio])
+
+/* These take the 'register relative offset gpio' number */
+#define BASIC_DATA_REG_MASK(ogpio)		(1 << ogpio)
+#define BASIC_MODE_REG_VALUE(mode, ogpio) \
+			(mode << BASIC_MODE_REG_SHIFT(ogpio))
+#define BASIC_MODE_REG_MASK(ogpio) \
+			BASIC_MODE_REG_VALUE(0xf, ogpio)
+#define BASIC_MODE_REG_SHIFT(ogpio)		(ogpio * 4)
+#define BASIC_MODE_REG_FROM_REG(data, ogpio) \
+			((data & BASIC_MODE_REG_MASK(ogpio)) >> \
+			BASIC_MODE_REG_SHIFT(ogpio))
+
+/* These take the actual GPIO number (0 through 15) */
+#define BASIC_DATA_MASK(gpio) \
+		BASIC_DATA_REG_MASK(OFFSET_GPIO_NUMBER(gpio))
+#define BASIC_MODE_MASK(gpio) \
+		BASIC_MODE_REG_MASK(OFFSET_GPIO_NUMBER(gpio))
+#define BASIC_MODE(mode, gpio) \
+		BASIC_MODE_REG_VALUE(mode, OFFSET_GPIO_NUMBER(gpio))
+#define BASIC_MODE_SHIFT(gpio) \
+		BASIC_MODE_REG_SHIFT(OFFSET_GPIO_NUMBER(gpio))
+#define BASIC_MODE_FROM_REG(data, gpio)	\
+		BASIC_MODE_REG_FROM_REG(data,OFFSET_GPIO_NUMBER(gpio))
+
+/* This gives you the 'register relative offset gpio' number */
+#define EXTENDED_OFFSET_GPIO(gpio)	(gpio - 16)
+
+/* These take the 'register relative offset gpio' number */
+#define EXTENDED_REG_DISABLE(ogpio)	(0x2 << ((ogpio * 2) + 16))
+#define EXTENDED_REG_ENABLE(ogpio)	(0x1 << ((ogpio * 2) + 16))
+#define EXTENDED_REG_SET(ogpio)		(0x2 << (ogpio * 2))
+#define EXTENDED_REG_CLR(ogpio)		(0x1 << (ogpio * 2))
+
+/* These take the actual GPIO number (16 through 19) */
+#define EXTENDED_DISABLE(gpio) \
+		EXTENDED_REG_DISABLE(EXTENDED_OFFSET_GPIO(gpio))
+#define EXTENDED_ENABLE(gpio) \
+		EXTENDED_REG_ENABLE(EXTENDED_OFFSET_GPIO(gpio))
+#define EXTENDED_SET(gpio) \
+		EXTENDED_REG_SET(EXTENDED_OFFSET_GPIO(gpio))
+#define EXTENDED_CLR(gpio) \
+		EXTENDED_REG_CLR(EXTENDED_OFFSET_GPIO(gpio))
+		
+#define EXTENDED_FULL_MASK	0xffffffff
+
+/* -- API inline-functions -- */
+
+/*
+ * Gets the current value of the specified pin
+ */
+static inline msp_gpio_data_t msp_gpio_pin_get(unsigned int gpio)
+{
+	u32 pinhi_mask = 0, pinhi_mask2 = 0;
+
+	if (gpio >= 20)
+		return MSP_GPIO_NONE;
+
+	if (gpio < 16) {
+		pinhi_mask = BASIC_DATA_MASK(gpio);
+	} else {
+		/*
+		 * Two cases are possible with the EXTENDED register:
+		 *  - In output mode (ENABLED flag set), check the CLR bit
+		 *  - In input mode (ENABLED flag not set), check the SET bit
+		 */
+		pinhi_mask = EXTENDED_ENABLE(gpio) | EXTENDED_CLR(gpio);
+		pinhi_mask2 = EXTENDED_SET(gpio);
+	}
+	if ((*MSP_GPIO_DATA_REGISTER[gpio] & pinhi_mask) ||
+	    (*MSP_GPIO_DATA_REGISTER[gpio] & pinhi_mask2))
+		return MSP_GPIO_HI;
+	else
+		return MSP_GPIO_LO;
+}
+
+/* Sets the specified pin to the specified value */
+static inline void msp_gpio_pin_set(msp_gpio_data_t data, unsigned int gpio)
+{
+	if (gpio >= 20)
+		return;
+
+	if (gpio < 16) {
+		if (data == MSP_GPIO_TOGGLE)
+			toggle_reg32(MSP_GPIO_DATA_REGISTER[gpio],
+					BASIC_DATA_MASK(gpio));
+		else if (data == MSP_GPIO_HI)
+			set_reg32(MSP_GPIO_DATA_REGISTER[gpio],
+					BASIC_DATA_MASK(gpio));
+		else
+			clear_reg32(MSP_GPIO_DATA_REGISTER[gpio],
+					BASIC_DATA_MASK(gpio));
+	} else {
+		if (data == MSP_GPIO_TOGGLE) {
+			/*
+			 * Special ugly case:
+			 *   We have to read the CLR bit.
+			 *   If set, we write the CLR bit.
+			 *   If not, we write the SET bit.
+			 */
+			u32 tmpdata;
+			custom_reg32_read(MSP_GPIO_DATA_REGISTER[gpio],
+					  tmpdata);
+			if (tmpdata & EXTENDED_CLR(gpio))
+				tmpdata = EXTENDED_CLR(gpio);
+			else
+				tmpdata = EXTENDED_SET(gpio);
+			custom_reg32_write(MSP_GPIO_DATA_REGISTER[gpio],
+					   tmpdata);
+		} else {
+			u32 newdata;
+			if (data == MSP_GPIO_HI)
+				newdata = EXTENDED_SET(gpio);
+			else
+				newdata = EXTENDED_CLR(gpio);
+			set_value_reg32(MSP_GPIO_DATA_REGISTER[gpio],
+					EXTENDED_FULL_MASK, newdata);
+		}
+	}
+}
+
+/* Sets the specified pin to the specified value */
+static inline void msp_gpio_pin_hi(unsigned int gpio)
+{
+	msp_gpio_pin_set(MSP_GPIO_HI, gpio);
+}
+
+/* Sets the specified pin to the specified value */
+static inline void msp_gpio_pin_lo(unsigned int gpio)
+{
+	msp_gpio_pin_set(MSP_GPIO_LO, gpio);
+}
+
+/* Sets the specified pin to the opposite value */
+static inline void msp_gpio_pin_toggle(unsigned int gpio)
+{
+	msp_gpio_pin_set(MSP_GPIO_TOGGLE, gpio);
+}
+
+/* Gets the mode of the specified pin */
+static inline msp_gpio_mode_t msp_gpio_pin_get_mode(unsigned int gpio)
+{
+	msp_gpio_mode_t retval = MSP_GPIO_UNKNOWN;
+	uint32_t data;
+
+	if (gpio >= 20)
+		return retval;
+
+	data = *MSP_GPIO_MODE_REGISTER[gpio];
+
+	if (gpio < 16) {
+		retval = BASIC_MODE_FROM_REG(data, gpio);
+	} else {
+		/* Extended pins can only be either INPUT or OUTPUT */
+		if (data & EXTENDED_ENABLE(gpio))
+			retval = MSP_GPIO_OUTPUT;
+		else
+			retval = MSP_GPIO_INPUT;
+	}
+
+	return retval;
+}
+
+/*
+ * Sets the specified mode on the requested pin
+ * Returns 0 on success, or -1 if that mode is not allowed on this pin
+ */
+static inline int msp_gpio_pin_mode(msp_gpio_mode_t mode, unsigned int gpio)
+{
+	u32 modemask, newmode;
+
+	if ((1 << gpio) & ~MSP_GPIO_MODE_ALLOWED[mode])
+		return -1;
+
+	if (gpio >= 20)
+		return -1;
+
+	if (gpio < 16) {
+		modemask = BASIC_MODE_MASK(gpio);
+		newmode =  BASIC_MODE(mode, gpio);
+	} else {
+		modemask = EXTENDED_FULL_MASK;
+		if (mode == MSP_GPIO_INPUT)
+			newmode = EXTENDED_DISABLE(gpio);
+		else
+			newmode = EXTENDED_ENABLE(gpio);
+	}
+	
+	/* Do the set atomically */
+	set_value_reg32(MSP_GPIO_MODE_REGISTER[gpio], modemask, newmode);
+
+	return 0;
+}
+
+#endif /* !__MSP_GPIO_MACROS_H__ */
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_int.h b/include/asm-mips/pmc-sierra/msp71xx/msp_int.h
new file mode 100644
index 0000000..28e1bb5
--- /dev/null
+++ b/include/asm-mips/pmc-sierra/msp71xx/msp_int.h
@@ -0,0 +1,43 @@
+/*
+ * Defines for the MSP interrupt handlers.
+ * 
+ * Copyright (C) 2005, PMC-Sierra, Inc.  All rights reserved.
+ * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com
+ * 
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ */
+
+#ifndef _MSP_INT_H
+#define _MSP_INT_H
+
+/*
+ * The PMC-Sierra MSP product line has at least two different interrupt
+ * controllers, the SLP register based scheme and the CIC interrupt
+ * controller block mechanism.  This file distinguishes between them
+ * so that devices see a uniform interface.
+ */
+
+#if defined(CONFIG_IRQ_MSP_SLP)
+        #include "msp_slp_int.h"
+#elif defined(CONFIG_IRQ_MSP_CIC)
+        #include "msp_cic_int.h"
+#else
+        #error "What sort of interrupt controller does *your* MSP have?"
+#endif
+
+#endif /* !_MSP_INT_H */
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_prom.h b/include/asm-mips/pmc-sierra/msp71xx/msp_prom.h
new file mode 100644
index 0000000..964361f
--- /dev/null
+++ b/include/asm-mips/pmc-sierra/msp71xx/msp_prom.h
@@ -0,0 +1,176 @@
+/*
+ * MIPS boards bootprom interface for the Linux kernel.
+ * 
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ * Author: Carsten Langgaard, carstenl@mips.com
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ */
+
+#ifndef _ASM_MSP_PROM_H
+#define _ASM_MSP_PROM_H
+
+#include <linux/types.h>
+
+#define DEVICEID			"deviceid"
+#define FEATURES			"features"
+#define PROM_ENV			"prom_env"
+#define PROM_ENV_FILE			"/proc/"PROM_ENV
+#define PROM_ENV_SIZE			256
+
+#define CPU_DEVID_FAMILY		0x0000ff00
+#define CPU_DEVID_REVISION		0x000000ff
+
+#define FPGA_IS_POLO(revision) \
+		(((revision >= 0xb0) && (revision < 0xd0)))
+#define FPGA_IS_5000(revision) \
+		((revision >= 0x80) && (revision <= 0x90))
+#define	FPGA_IS_ZEUS(revision)		((revision < 0x7f))
+#define FPGA_IS_DUET(revision) \
+		(((revision >= 0xa0) && (revision < 0xb0)))
+#define FPGA_IS_MSP4200(revision)	((revision >= 0xd0))
+#define FPGA_IS_MSP7100(revision)	((revision >= 0xd0))
+
+#define MACHINE_TYPE_POLO		"POLO"
+#define MACHINE_TYPE_DUET		"DUET"
+#define	MACHINE_TYPE_ZEUS		"ZEUS"
+#define MACHINE_TYPE_MSP2000REVB	"MSP2000REVB"
+#define MACHINE_TYPE_MSP5000		"MSP5000"
+#define MACHINE_TYPE_MSP4200		"MSP4200"
+#define MACHINE_TYPE_MSP7120		"MSP7120"
+#define MACHINE_TYPE_MSP7130		"MSP7130"
+#define MACHINE_TYPE_OTHER		"OTHER"
+
+#define MACHINE_TYPE_POLO_FPGA		"POLO-FPGA"
+#define MACHINE_TYPE_DUET_FPGA		"DUET-FPGA"
+#define	MACHINE_TYPE_ZEUS_FPGA		"ZEUS_FPGA"
+#define MACHINE_TYPE_MSP2000REVB_FPGA	"MSP2000REVB-FPGA"
+#define MACHINE_TYPE_MSP5000_FPGA	"MSP5000-FPGA"
+#define MACHINE_TYPE_MSP4200_FPGA	"MSP4200-FPGA"
+#define MACHINE_TYPE_MSP7100_FPGA	"MSP7100-FPGA"
+#define MACHINE_TYPE_OTHER_FPGA		"OTHER-FPGA"
+
+/* Device Family definitions */
+#define FAMILY_FPGA			0x0000
+#define FAMILY_ZEUS			0x1000
+#define FAMILY_POLO			0x2000
+#define FAMILY_DUET			0x4000
+#define FAMILY_TRIAD			0x5000
+#define FAMILY_MSP4200			0x4200
+#define FAMILY_MSP4200_FPGA		0x4f00
+#define FAMILY_MSP7100			0x7100
+#define FAMILY_MSP7100_FPGA		0x7f00
+
+/* Device Type definitions */
+#define TYPE_MSP7120			0x7120
+#define TYPE_MSP7130			0x7130
+
+#define ENET_KEY		'E'
+#define ENETTXD_KEY		'e'
+#define PCI_KEY			'P'
+#define PCIMUX_KEY		'p'
+#define SEC_KEY			'S'
+#define SPAD_KEY		'D'
+#define TDM_KEY			'T'
+#define ZSP_KEY			'Z'
+
+#define FEATURE_NOEXIST		'-'
+#define FEATURE_EXIST		'+'
+
+#define ENET_MII		'M'
+#define ENET_RMII		'R'
+
+#define	ENETTXD_FALLING		'F'
+#define ENETTXD_RISING		'R'
+
+#define PCI_HOST		'H'
+#define PCI_PERIPHERAL		'P'
+
+#define PCIMUX_FULL		'F'
+#define PCIMUX_SINGLE		'S'
+
+#define SEC_DUET		'D'
+#define SEC_POLO		'P'
+#define SEC_SLOW		'S'
+#define SEC_TRIAD		'T'
+
+#define SPAD_POLO		'P'
+
+#define TDM_DUET		'D'	/* DUET TDMs might exist */
+#define TDM_POLO		'P'	/* POLO TDMs might exist */
+#define TDM_TRIAD		'T'	/* TRIAD TDMs might exist */
+
+#define ZSP_DUET		'D'	/* one DUET zsp engine */
+#define ZSP_TRIAD		'T'	/* two TRIAD zsp engines */
+
+extern char *prom_getcmdline(void);
+extern char *prom_getenv(char *name);
+extern void prom_init_cmdline(void);
+extern void prom_printf(char *fmt, ...);
+extern void prom_putchar(char c);
+extern char prom_getchar(void);
+extern void prom_meminit(void);
+extern void prom_fixup_mem_map(unsigned long start_mem,
+			       unsigned long end_mem);
+
+#ifdef CONFIG_MTD_PMC_MSP_RAMROOT
+extern bool get_ramroot(void **start, unsigned long *size);
+#endif
+
+extern int get_ethernet_addr(char *ethaddr_name, char *ethernet_addr);
+extern unsigned long get_deviceid(void);
+extern char identify_enet(unsigned long interfaceNum);
+extern char identify_enetTxD(unsigned long interfaceNum);
+extern char identify_pci(void);
+extern char identify_sec(void);
+extern char identify_spad(void);
+extern char identify_sec(void);
+extern char identify_tdm(void);
+extern char identify_zsp(void);
+extern unsigned long identify_family(void);
+extern unsigned long identify_revision(void);
+
+/*
+ * The following macro calls prom_printf and puts the format string
+ * into an init section so it can be reclaimed.
+ */
+#define ppfinit(f, x...) do { static char _f[] __initdata = f; \
+        prom_printf(_f, ## x); } while (0)
+
+/* Memory descriptor management. */
+#define PROM_MAX_PMEMBLOCKS    7	/* 6 used */
+
+enum yamon_memtypes {
+        yamon_dontuse,
+        yamon_prom,
+        yamon_free,
+};
+
+struct prom_pmemblock {
+        unsigned long base; /* Within KSEG0. */
+        unsigned int size;  /* In bytes. */
+        unsigned int type;  /* free or prom memory */
+};
+
+extern int prom_argc;
+extern char **prom_argv;
+extern char **prom_envp;
+extern int *prom_vec;
+extern struct prom_pmemblock *prom_getmdesc(void);
+
+#endif /* !_ASM_MSP_PROM_H */
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_regs.h b/include/asm-mips/pmc-sierra/msp71xx/msp_regs.h
new file mode 100644
index 0000000..a0ca83a
--- /dev/null
+++ b/include/asm-mips/pmc-sierra/msp71xx/msp_regs.h
@@ -0,0 +1,661 @@
+/*
+ * Defines for the address space, registers and register configuration
+ * (bit masks, access macros etc) for the PMC-Sierra line of MSP products.
+ * This file contains addess maps for all the devices in the line of
+ * products but only has register definitions and configuration masks for
+ * registers which aren't definitely associated with any device.  Things
+ * like clock settings, reset access, the ELB etc.  Individual device
+ * drivers will reference the appropriate XXX_BASE value defined here
+ * and have individual registers offset from that.
+ * 
+ * Copyright (C) 2005-2007 PMC-Sierra, Inc.  All rights reserved.
+ * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com
+ * 
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ */
+
+#include <asm/addrspace.h>
+#include <linux/types.h>
+
+#ifndef _ASM_MSP_REGS_H
+#define _ASM_MSP_REGS_H
+
+/*
+ ########################################################################
+ #  Address space and device base definitions                           #
+ ########################################################################
+ */
+
+/*
+ ***************************************************************************
+ * System Logic and Peripherals (ELB, UART0, etc) device address space     *
+ ***************************************************************************
+ */
+#define MSP_SLP_BASE		0x1c000000
+					/* System Logic and Peripherals */
+#define MSP_WTIMER_BASE		(MSP_SLP_BASE + 0x04C)
+					/* watchdog timer base          */
+#define MSP_ITIMER_BASE		(MSP_SLP_BASE + 0x054)
+					/* internal timer base          */
+#define MSP_UART0_BASE		(MSP_SLP_BASE + 0x100)
+					/* UART0 controller base        */
+#define MSP_BCPY_CTRL_BASE	(MSP_SLP_BASE + 0x120)
+					/* Block Copy controller base   */
+#define MSP_BCPY_DESC_BASE	(MSP_SLP_BASE + 0x160)
+					/* Block Copy descriptor base   */
+
+/*
+ ***************************************************************************
+ * PCI address space                                                       *
+ ***************************************************************************
+ */
+#define MSP_PCI_BASE		0x19000000
+
+/*
+ ***************************************************************************
+ * MSbus device address space                                              *
+ ***************************************************************************
+ */
+#define MSP_MSB_BASE		0x18000000
+					/* MSbus address start          */
+#define MSP_PER_BASE		(MSP_MSB_BASE + 0x400000)
+					/* Peripheral device registers  */
+#define MSP_MAC0_BASE		(MSP_MSB_BASE + 0x600000)
+					/* MAC A device registers       */
+#define MSP_MAC1_BASE		(MSP_MSB_BASE + 0x700000)
+					/* MAC B device registers       */
+#define MSP_SEC_BASE		(MSP_MSB_BASE + 0x800000)
+					/* Security Engine registers    */
+#define MSP_MAC2_BASE		(MSP_MSB_BASE + 0x900000)
+					/* MAC C device registers       */
+#define MSP_ADSL2_BASE		(MSP_MSB_BASE + 0xA80000)
+					/* ADSL2 device registers       */
+#define MSP_USB_BASE		(MSP_MSB_BASE + 0xB40000)
+					/* USB device registers         */
+#define MSP_USB_BASE_START	(MSP_MSB_BASE + 0xB40100)
+					/* USB device registers         */
+#define MSP_USB_BASE_END	(MSP_MSB_BASE + 0xB401FF)
+					/* USB device registers         */
+#define MSP_CPUIF_BASE		(MSP_MSB_BASE + 0xC00000)
+					/* CPU interface registers      */
+
+/* Devices within the MSbus peripheral block */
+#define MSP_UART1_BASE		(MSP_PER_BASE + 0x030)
+					/* UART1 controller base        */
+#define MSP_SPI_BASE		(MSP_PER_BASE + 0x058)
+					/* SPI/MPI control registers    */
+#define MSP_TWI_BASE		(MSP_PER_BASE + 0x090)
+					/* Two-wire control registers   */
+#define MSP_PTIMER_BASE		(MSP_PER_BASE + 0x0F0)
+					/* Programmable timer control   */
+
+/*
+ ***************************************************************************
+ * Physical Memory configuration address space                             *
+ ***************************************************************************
+ */
+#define MSP_MEM_CFG_BASE	0x17f00000
+
+#define MSP_MEM_INDIRECT_CTL_10	0x10
+
+/*
+ * Notes:
+ *  1) The SPI registers are split into two blocks, one offset from the
+ *     MSP_SPI_BASE by 0x00 and the other offset from the MSP_SPI_BASE by
+ *     0x68.  The SPI driver definitions for the register must be aware
+ *     of this.
+ *  2) The block copy engine register are divided into two regions, one
+ *     for the control/configuration of the engine proper and one for the
+ *     values of the descriptors used in the copy process.  These have
+ *     different base defines (CTRL_BASE vs DESC_BASE)
+ *  3) These constants are for physical addresses which means that they
+ *     work correctly with "ioremap" and friends.  This means that device
+ *     drivers will need to remap these addresses using ioremap and perhaps
+ *     the readw/writew macros.  Or they could use the regptr() macro
+ *     defined below, but the readw/writew calls are the correct thing.
+ *  4) The UARTs have an additional status register offset from the base
+ *     address.  This register isn't used in the standard 8250 driver but
+ *     may be used in other software.  Consult the hardware datasheet for
+ *     offset details.
+ *  5) For some unknown reason the security engine (MSP_SEC_BASE) registers
+ *     start at an offset of 0x84 from the base address but the block of
+ *     registers before this is reserved for the security engine.  The
+ *     driver will have to be aware of this but it makes the register
+ *     definitions line up better with the documentation.
+ */
+
+/*
+ ########################################################################
+ #  System register definitions.  Not associated with a specific device #
+ ########################################################################
+ */
+
+/*
+ * This macro maps the physical register number into uncached space
+ * and (for C code) casts it into a u32 pointer so it can be dereferenced
+ * Normally these would be accessed with ioremap and readX/writeX, but
+ * these are convenient for a lot of internal kernel code.
+ */
+#ifdef __ASSEMBLER__
+        #define regptr(addr) (KSEG1ADDR(addr))
+#else
+        #define regptr(addr) ((volatile u32 * const)(KSEG1ADDR(addr)))
+#endif
+
+/*
+ ***************************************************************************
+ * System Logic and Peripherals (RESET, ELB, etc) registers                *
+ ***************************************************************************
+ */
+
+/* System Control register definitions */
+#define	DEV_ID_REG	regptr(MSP_SLP_BASE + 0x00)
+					/* Device-ID                 RO */
+#define	FWR_ID_REG	regptr(MSP_SLP_BASE + 0x04)
+					/* Firmware-ID Register      RW */
+#define	SYS_ID_REG0	regptr(MSP_SLP_BASE + 0x08)
+					/* System-ID Register-0      RW */
+#define	SYS_ID_REG1	regptr(MSP_SLP_BASE + 0x0C)
+					/* System-ID Register-1      RW */
+
+/* System Reset register definitions */
+#define	RST_STS_REG	regptr(MSP_SLP_BASE + 0x10)
+					/* System Reset Status       RO */
+#define	RST_SET_REG	regptr(MSP_SLP_BASE + 0x14)
+					/* System Set Reset          WO */
+#define	RST_CLR_REG	regptr(MSP_SLP_BASE + 0x18)
+					/* System Clear Reset        WO */
+
+/* System Clock Registers */
+#define PCI_SLP_REG	regptr(MSP_SLP_BASE + 0x1C)
+					/* PCI clock generator       RW */
+#define URT_SLP_REG	regptr(MSP_SLP_BASE + 0x20)
+					/* UART clock generator      RW */
+/* reserved		      (MSP_SLP_BASE + 0x24)                     */
+/* reserved		      (MSP_SLP_BASE + 0x28)                     */
+#define PLL1_SLP_REG	regptr(MSP_SLP_BASE + 0x2C)
+					/* PLL1 clock generator      RW */
+#define PLL0_SLP_REG	regptr(MSP_SLP_BASE + 0x30)
+					/* PLL0 clock generator      RW */
+#define MIPS_SLP_REG	regptr(MSP_SLP_BASE + 0x34)
+					/* MIPS clock generator      RW */
+#define	VE_SLP_REG	regptr(MSP_SLP_BASE + 0x38)
+					/* Voice Eng clock generator RW */
+/* reserved		      (MSP_SLP_BASE + 0x3C)                     */
+#define MSB_SLP_REG	regptr(MSP_SLP_BASE + 0x40)
+					/* MS-Bus clock generator    RW */
+#define SMAC_SLP_REG	regptr(MSP_SLP_BASE + 0x44)
+					/* Sec & MAC clock generator RW */
+#define PERF_SLP_REG	regptr(MSP_SLP_BASE + 0x48)
+					/* Per & TDM clock generator RW */
+
+/* Interrupt Controller Registers */
+#define SLP_INT_STS_REG regptr(MSP_SLP_BASE + 0x70)
+					/* Interrupt status register RW */
+#define SLP_INT_MSK_REG regptr(MSP_SLP_BASE + 0x74)
+					/* Interrupt enable/mask     RW */
+#define SE_MBOX_REG	regptr(MSP_SLP_BASE + 0x78)
+					/* Security Engine mailbox   RW */
+#define VE_MBOX_REG	regptr(MSP_SLP_BASE + 0x7C)
+					/* Voice Engine mailbox      RW */
+
+/* ELB Controller Registers */
+#define CS0_CNFG_REG	regptr(MSP_SLP_BASE + 0x80)
+					/* ELB CS0 Configuration Reg    */
+#define CS0_ADDR_REG	regptr(MSP_SLP_BASE + 0x84) 
+					/* ELB CS0 Base Address Reg     */
+#define CS0_MASK_REG	regptr(MSP_SLP_BASE + 0x88)
+					/* ELB CS0 Mask Register        */
+#define CS0_ACCESS_REG	regptr(MSP_SLP_BASE + 0x8C)
+					/* ELB CS0 access register      */
+
+#define CS1_CNFG_REG	regptr(MSP_SLP_BASE + 0x90)
+					/* ELB CS1 Configuration Reg    */
+#define CS1_ADDR_REG	regptr(MSP_SLP_BASE + 0x94)
+					/* ELB CS1 Base Address Reg     */
+#define CS1_MASK_REG	regptr(MSP_SLP_BASE + 0x98)
+					/* ELB CS1 Mask Register        */
+#define CS1_ACCESS_REG	regptr(MSP_SLP_BASE + 0x9C)
+					/* ELB CS1 access register      */
+
+#define CS2_CNFG_REG	regptr(MSP_SLP_BASE + 0xA0)
+					/* ELB CS2 Configuration Reg    */
+#define CS2_ADDR_REG	regptr(MSP_SLP_BASE + 0xA4)
+					/* ELB CS2 Base Address Reg     */
+#define CS2_MASK_REG	regptr(MSP_SLP_BASE + 0xA8)
+					/* ELB CS2 Mask Register        */
+#define CS2_ACCESS_REG	regptr(MSP_SLP_BASE + 0xAC)
+					/* ELB CS2 access register      */
+
+#define CS3_CNFG_REG	regptr(MSP_SLP_BASE + 0xB0)
+					/* ELB CS3 Configuration Reg    */
+#define CS3_ADDR_REG	regptr(MSP_SLP_BASE + 0xB4)
+					/* ELB CS3 Base Address Reg     */
+#define CS3_MASK_REG	regptr(MSP_SLP_BASE + 0xB8)
+					/* ELB CS3 Mask Register        */
+#define CS3_ACCESS_REG	regptr(MSP_SLP_BASE + 0xBC)
+					/* ELB CS3 access register      */
+
+#define CS4_CNFG_REG	regptr(MSP_SLP_BASE + 0xC0)
+					/* ELB CS4 Configuration Reg    */
+#define CS4_ADDR_REG	regptr(MSP_SLP_BASE + 0xC4)
+					/* ELB CS4 Base Address Reg     */
+#define CS4_MASK_REG	regptr(MSP_SLP_BASE + 0xC8)
+					/* ELB CS4 Mask Register        */
+#define CS4_ACCESS_REG	regptr(MSP_SLP_BASE + 0xCC)
+					/* ELB CS4 access register      */
+
+#define CS5_CNFG_REG	regptr(MSP_SLP_BASE + 0xD0)
+					/* ELB CS5 Configuration Reg    */
+#define CS5_ADDR_REG	regptr(MSP_SLP_BASE + 0xD4)
+					/* ELB CS5 Base Address Reg     */
+#define CS5_MASK_REG	regptr(MSP_SLP_BASE + 0xD8)
+					/* ELB CS5 Mask Register        */
+#define CS5_ACCESS_REG	regptr(MSP_SLP_BASE + 0xDC)
+					/* ELB CS5 access register      */
+
+/* reserved			       0xE0 - 0xE8                      */
+#define ELB_1PC_EN_REG	regptr(MSP_SLP_BASE + 0xEC)
+					/* ELB single PC card detect    */
+
+/* reserved			       0xF0 - 0xF8                      */
+#define ELB_CLK_CFG_REG	regptr(MSP_SLP_BASE + 0xFC)
+					/* SDRAM read/ELB timing Reg    */
+
+/* Extended UART status registers */
+#define UART0_STATUS_REG	regptr(MSP_UART0_BASE + 0x0c0)
+					/* UART Status Register 0       */
+#define UART1_STATUS_REG	regptr(MSP_UART1_BASE + 0x170)
+					/* UART Status Register 1       */
+
+/* Performance monitoring registers */
+#define PERF_MON_CTRL_REG	regptr(MSP_SLP_BASE + 0x140)
+					/* Performance monitor control  */
+#define PERF_MON_CLR_REG	regptr(MSP_SLP_BASE + 0x144)
+					/* Performance monitor clear    */
+#define PERF_MON_CNTH_REG	regptr(MSP_SLP_BASE + 0x148)
+					/* Perf monitor counter high    */
+#define PERF_MON_CNTL_REG	regptr(MSP_SLP_BASE + 0x14C)
+					/* Perf monitor counter low     */
+
+/* System control registers */
+#define SYS_CTRL_REG		regptr(MSP_SLP_BASE + 0x150)
+					/* System control register      */
+#define SYS_ERR1_REG		regptr(MSP_SLP_BASE + 0x154)
+					/* System Error status 1        */
+#define SYS_ERR2_REG		regptr(MSP_SLP_BASE + 0x158)
+					/* System Error status 2        */
+#define SYS_INT_CFG_REG		regptr(MSP_SLP_BASE + 0x15C)
+					/* System Interrupt config      */
+
+/* Voice Engine Memory configuration */
+#define VE_MEM_REG		regptr(MSP_SLP_BASE + 0x17C)
+					/* Voice engine memory config   */
+
+/* CPU/SLP Error Status registers */
+#define CPU_ERR1_REG		regptr(MSP_SLP_BASE + 0x180)
+					/* CPU/SLP Error status 1       */
+#define CPU_ERR2_REG		regptr(MSP_SLP_BASE + 0x184)
+					/* CPU/SLP Error status 1       */
+
+#define EXTENDED_GPIO_REG	regptr(MSP_SLP_BASE + 0x188)
+					/* Extended GPIO register       */
+
+/* System Error registers */
+#define SLP_ERR_STS_REG		regptr(MSP_SLP_BASE + 0x190)
+					/* Int status for SLP errors    */
+#define SLP_ERR_MSK_REG		regptr(MSP_SLP_BASE + 0x194)
+					/* Int mask for SLP errors      */
+#define SLP_ELB_ERST_REG	regptr(MSP_SLP_BASE + 0x198)
+					/* External ELB reset           */
+#define SLP_BOOT_STS_REG	regptr(MSP_SLP_BASE + 0x19C)
+					/* Boot Status                  */
+
+/* Extended ELB addressing */
+#define CS0_EXT_ADDR_REG	regptr(MSP_SLP_BASE + 0x1A0)
+					/* CS0 Extended address         */
+#define CS1_EXT_ADDR_REG	regptr(MSP_SLP_BASE + 0x1A4)
+					/* CS1 Extended address         */
+#define CS2_EXT_ADDR_REG	regptr(MSP_SLP_BASE + 0x1A8)
+					/* CS2 Extended address         */
+#define CS3_EXT_ADDR_REG	regptr(MSP_SLP_BASE + 0x1AC)
+					/* CS3 Extended address         */
+/* reserved					      0x1B0             */  
+#define CS5_EXT_ADDR_REG	regptr(MSP_SLP_BASE + 0x1B4)
+					/* CS5 Extended address         */
+
+/* PLL Adjustment registers */
+#define PLL_LOCK_REG		regptr(MSP_SLP_BASE + 0x200)
+					/* PLL0 lock status             */
+#define PLL_ARST_REG		regptr(MSP_SLP_BASE + 0x204)
+					/* PLL Analog reset status      */
+#define PLL0_ADJ_REG		regptr(MSP_SLP_BASE + 0x208)
+					/* PLL0 Adjustment value        */
+#define PLL1_ADJ_REG		regptr(MSP_SLP_BASE + 0x20C)
+					/* PLL1 Adjustment value        */
+
+/*
+ ***************************************************************************
+ * Peripheral Register definitions                                         *
+ ***************************************************************************
+ */
+
+/* Peripheral status */
+#define PER_CTRL_REG		regptr(MSP_PER_BASE + 0x50)
+					/* Peripheral control register  */
+#define PER_STS_REG		regptr(MSP_PER_BASE + 0x54)
+					/* Peripheral status register   */
+
+/* SPI/MPI Registers */
+#define SMPI_TX_SZ_REG		regptr(MSP_PER_BASE + 0x58)
+					/* SPI/MPI Tx Size register     */
+#define SMPI_RX_SZ_REG		regptr(MSP_PER_BASE + 0x5C)
+					/* SPI/MPI Rx Size register     */
+#define SMPI_CTL_REG		regptr(MSP_PER_BASE + 0x60)
+					/* SPI/MPI Control register     */
+#define SMPI_MS_REG		regptr(MSP_PER_BASE + 0x64)
+					/* SPI/MPI Chip Select reg      */
+#define SMPI_CORE_DATA_REG	regptr(MSP_PER_BASE + 0xC0)
+					/* SPI/MPI Core Data reg        */
+#define SMPI_CORE_CTRL_REG	regptr(MSP_PER_BASE + 0xC4)
+					/* SPI/MPI Core Control reg     */
+#define SMPI_CORE_STAT_REG	regptr(MSP_PER_BASE + 0xC8)
+					/* SPI/MPI Core Status reg      */
+#define SMPI_CORE_SSEL_REG	regptr(MSP_PER_BASE + 0xCC)
+					/* SPI/MPI Core Ssel reg        */
+#define SMPI_FIFO_REG		regptr(MSP_PER_BASE + 0xD0)
+					/* SPI/MPI Data FIFO reg        */
+
+/* Peripheral Block Error Registers           */
+#define PER_ERR_STS_REG		regptr(MSP_PER_BASE + 0x70)
+					/* Error Bit Status Register    */
+#define PER_ERR_MSK_REG		regptr(MSP_PER_BASE + 0x74)
+					/* Error Bit Mask Register      */
+#define PER_HDR1_REG		regptr(MSP_PER_BASE + 0x78)
+					/* Error Header 1 Register      */
+#define PER_HDR2_REG		regptr(MSP_PER_BASE + 0x7C)
+					/* Error Header 2 Register      */
+
+/* Peripheral Block Interrupt Registers       */
+#define PER_INT_STS_REG		regptr(MSP_PER_BASE + 0x80)
+					/* Interrupt status register    */
+#define PER_INT_MSK_REG		regptr(MSP_PER_BASE + 0x84)
+					/* Interrupt Mask Register      */
+#define GPIO_INT_STS_REG	regptr(MSP_PER_BASE + 0x88)
+					/* GPIO interrupt status reg    */
+#define GPIO_INT_MSK_REG	regptr(MSP_PER_BASE + 0x8C)
+					/* GPIO interrupt MASK Reg      */
+
+/* POLO GPIO registers                        */
+#define POLO_GPIO_DAT1_REG	regptr(MSP_PER_BASE + 0x0E0)  
+					/* Polo GPIO[8:0]  data reg     */
+#define POLO_GPIO_CFG1_REG	regptr(MSP_PER_BASE + 0x0E4)
+					/* Polo GPIO[7:0]  config reg   */
+#define POLO_GPIO_CFG2_REG	regptr(MSP_PER_BASE + 0x0E8)
+					/* Polo GPIO[15:8] config reg   */
+#define POLO_GPIO_OD1_REG	regptr(MSP_PER_BASE + 0x0EC)
+					/* Polo GPIO[31:0] output drive */
+#define POLO_GPIO_CFG3_REG	regptr(MSP_PER_BASE + 0x170)
+					/* Polo GPIO[23:16] config reg  */
+#define POLO_GPIO_DAT2_REG	regptr(MSP_PER_BASE + 0x174)
+					/* Polo GPIO[15:9]  data reg    */
+#define POLO_GPIO_DAT3_REG	regptr(MSP_PER_BASE + 0x178)
+					/* Polo GPIO[23:16]  data reg   */
+#define POLO_GPIO_DAT4_REG	regptr(MSP_PER_BASE + 0x17C)
+					/* Polo GPIO[31:24]  data reg   */
+#define POLO_GPIO_DAT5_REG	regptr(MSP_PER_BASE + 0x180)
+					/* Polo GPIO[39:32]  data reg   */
+#define POLO_GPIO_DAT6_REG	regptr(MSP_PER_BASE + 0x184)
+					/* Polo GPIO[47:40]  data reg   */
+#define POLO_GPIO_DAT7_REG	regptr(MSP_PER_BASE + 0x188)
+					/* Polo GPIO[54:48]  data reg   */
+#define POLO_GPIO_CFG4_REG	regptr(MSP_PER_BASE + 0x18C)
+					/* Polo GPIO[31:24] config reg  */
+#define POLO_GPIO_CFG5_REG	regptr(MSP_PER_BASE + 0x190)
+					/* Polo GPIO[39:32] config reg  */
+#define POLO_GPIO_CFG6_REG	regptr(MSP_PER_BASE + 0x194)
+					/* Polo GPIO[47:40] config reg  */
+#define POLO_GPIO_CFG7_REG	regptr(MSP_PER_BASE + 0x198)
+					/* Polo GPIO[54:48] config reg  */
+#define POLO_GPIO_OD2_REG	regptr(MSP_PER_BASE + 0x19C)
+					/* Polo GPIO[54:32] output drive */
+
+/* Generic GPIO registers                     */
+#define GPIO_DATA1_REG		regptr(MSP_PER_BASE + 0x170)
+					/* GPIO[1:0] data register      */
+#define GPIO_DATA2_REG		regptr(MSP_PER_BASE + 0x174)
+					/* GPIO[5:2] data register      */
+#define GPIO_DATA3_REG		regptr(MSP_PER_BASE + 0x178)
+					/* GPIO[9:6] data register      */
+#define GPIO_DATA4_REG		regptr(MSP_PER_BASE + 0x17C)
+					/* GPIO[15:10] data register    */
+#define GPIO_CFG1_REG		regptr(MSP_PER_BASE + 0x180)
+					/* GPIO[1:0] config register    */
+#define GPIO_CFG2_REG		regptr(MSP_PER_BASE + 0x184)
+					/* GPIO[5:2] config register    */
+#define GPIO_CFG3_REG		regptr(MSP_PER_BASE + 0x188)
+					/* GPIO[9:6] config register    */
+#define GPIO_CFG4_REG		regptr(MSP_PER_BASE + 0x18C)
+					/* GPIO[15:10] config register  */
+#define GPIO_OD_REG		regptr(MSP_PER_BASE + 0x190)
+					/* GPIO[15:0] output drive      */
+
+/*
+ ***************************************************************************
+ * CPU Interface register definitions                                      *
+ ***************************************************************************
+ */
+#define PCI_FLUSH_REG		regptr(MSP_CPUIF_BASE + 0x00)
+					/* PCI-SDRAM queue flush trigger */
+#define OCP_ERR1_REG		regptr(MSP_CPUIF_BASE + 0x04)
+					/* OCP Error Attribute 1        */
+#define OCP_ERR2_REG		regptr(MSP_CPUIF_BASE + 0x08)
+					/* OCP Error Attribute 2        */
+#define OCP_STS_REG		regptr(MSP_CPUIF_BASE + 0x0C)
+					/* OCP Error Status             */
+#define CPUIF_PM_REG		regptr(MSP_CPUIF_BASE + 0x10)
+					/* CPU policy configuration     */
+#define CPUIF_CFG_REG		regptr(MSP_CPUIF_BASE + 0x10)
+					/* Misc configuration options   */
+
+/* Central Interrupt Controller Registers */
+#define MSP_CIC_BASE		(MSP_CPUIF_BASE + 0x8000)
+					/* Central Interrupt registers  */
+#define CIC_EXT_CFG_REG		regptr(MSP_CIC_BASE + 0x00)
+					/* External interrupt config    */
+#define CIC_STS_REG		regptr(MSP_CIC_BASE + 0x04)
+					/* CIC Interrupt Status         */
+#define CIC_VPE0_MSK_REG	regptr(MSP_CIC_BASE + 0x08)
+					/* VPE0 Interrupt Mask          */
+#define CIC_VPE1_MSK_REG	regptr(MSP_CIC_BASE + 0x0C)
+					/* VPE1 Interrupt Mask          */
+#define CIC_TC0_MSK_REG		regptr(MSP_CIC_BASE + 0x10)
+					/* Thread Context 0 Int Mask    */
+#define CIC_TC1_MSK_REG		regptr(MSP_CIC_BASE + 0x14)
+					/* Thread Context 1 Int Mask    */
+#define CIC_TC2_MSK_REG		regptr(MSP_CIC_BASE + 0x18)
+					/* Thread Context 2 Int Mask    */
+#define CIC_TC3_MSK_REG		regptr(MSP_CIC_BASE + 0x18)
+					/* Thread Context 3 Int Mask    */
+#define CIC_TC4_MSK_REG		regptr(MSP_CIC_BASE + 0x18)
+					/* Thread Context 4 Int Mask    */
+#define CIC_PCIMSI_STS_REG	regptr(MSP_CIC_BASE + 0x18)
+#define CIC_PCIMSI_MSK_REG	regptr(MSP_CIC_BASE + 0x18)
+#define CIC_PCIFLSH_REG		regptr(MSP_CIC_BASE + 0x18)
+#define CIC_VPE0_SWINT_REG	regptr(MSP_CIC_BASE + 0x08)
+
+
+/*
+ ***************************************************************************
+ * Memory controller registers                                             *
+ ***************************************************************************
+ */
+#define MEM_CFG1_REG		regptr(MSP_MEM_CFG_BASE + 0x00)
+#define MEM_SS_ADDR		regptr(MSP_MEM_CFG_BASE + 0x00)
+#define MEM_SS_DATA		regptr(MSP_MEM_CFG_BASE + 0x04)
+#define MEM_SS_WRITE		regptr(MSP_MEM_CFG_BASE + 0x08)
+
+/*
+ ***************************************************************************
+ * PCI controller registers                                                *
+ ***************************************************************************
+ */
+#define PCI_BASE_REG		regptr(MSP_PCI_BASE + 0x00)
+#define PCI_CONFIG_SPACE_REG	regptr(MSP_PCI_BASE + 0x800)
+#define PCI_JTAG_DEVID_REG	regptr(MSP_SLP_BASE + 0x13c)
+
+/* 
+ ########################################################################
+ #  Register content & macro definitions                                #
+ ########################################################################
+ */
+
+/*
+ ***************************************************************************
+ * DEV_ID defines                                                          *
+ ***************************************************************************
+ */
+#define DEV_ID_PCI_DIS		(1 << 26)       /* Set if PCI disabled */
+#define DEV_ID_PCI_HOST		(1 << 20)       /* Set if PCI host */
+#define DEV_ID_SINGLE_PC	(1 << 19)       /* Set if single PC Card */
+#define DEV_ID_FAMILY		(0xff << 8)     /* family ID code */
+#define POLO_ZEUS_SUB_FAMILY	(0x7  << 16)    /* sub family for Polo/Zeus */
+
+#define MSPFPGA_ID		(0x00  << 8)    /* you are on your own here */
+#define MSP5000_ID		(0x50  << 8)
+#define MSP4F00_ID		(0x4f  << 8)    /* FPGA version of MSP4200 */
+#define MSP4E00_ID		(0x4f  << 8)    /* FPGA version of MSP7120 */
+#define MSP4200_ID		(0x42  << 8)
+#define MSP4000_ID		(0x40  << 8)
+#define MSP2XXX_ID		(0x20  << 8)
+#define MSPZEUS_ID		(0x10  << 8)
+
+#define MSP2004_SUB_ID		(0x0   << 16)
+#define MSP2005_SUB_ID		(0x1   << 16)
+#define MSP2006_SUB_ID		(0x1   << 16)
+#define MSP2007_SUB_ID		(0x2   << 16)
+#define MSP2010_SUB_ID		(0x3   << 16)
+#define MSP2015_SUB_ID		(0x4   << 16)
+#define MSP2020_SUB_ID		(0x5   << 16)
+#define MSP2100_SUB_ID		(0x6   << 16)
+
+/*
+ ***************************************************************************
+ * RESET defines                                                           *
+ ***************************************************************************
+ */
+#define MSP_GR_RST		(0x01 << 0)     /* Global reset bit     */
+#define MSP_MR_RST		(0x01 << 1)     /* MIPS reset bit       */
+#define MSP_PD_RST		(0x01 << 2)     /* PVC DMA reset bit    */
+#define MSP_PP_RST		(0x01 << 3)     /* PVC reset bit        */
+/* reserved                                                             */
+#define MSP_EA_RST		(0x01 << 6)     /* Mac A reset bit      */
+#define MSP_EB_RST		(0x01 << 7)     /* Mac B reset bit      */
+#define MSP_SE_RST		(0x01 << 8)     /* Security Eng reset bit */
+#define MSP_PB_RST		(0x01 << 9)     /* Per block reset bit  */
+#define MSP_EC_RST		(0x01 << 10)    /* Mac C reset bit      */
+#define MSP_TW_RST		(0x01 << 11)    /* TWI reset bit        */
+#define MSP_SPI_RST		(0x01 << 12)    /* SPI/MPI reset bit    */
+#define MSP_U1_RST		(0x01 << 13)    /* UART1 reset bit      */
+#define MSP_U0_RST		(0x01 << 14)    /* UART0 reset bit      */
+
+/*
+ ***************************************************************************
+ * UART defines                                                            *
+ ***************************************************************************
+ */
+#ifndef CONFIG_MSP_FPGA
+#define MSP_BASE_BAUD		25000000
+#else
+#define MSP_BASE_BAUD		6000000
+#endif
+#define MSP_UART_REG_LEN	0x20
+
+/*
+ ***************************************************************************
+ * ELB defines                                                             *
+ ***************************************************************************
+ */
+#define PCCARD_32		0x02    /* Set if is PCCARD 32 (Cardbus) */
+#define SINGLE_PCCARD		0x01    /* Set to enable single PC card */
+
+/*
+ ***************************************************************************
+ * CIC defines                                                             *
+ ***************************************************************************
+ */
+
+/* CIC_EXT_CFG_REG */
+#define EXT_INT_POL(eirq)			(1 << (eirq + 8))
+#define EXT_INT_EDGE(eirq)			(1 << eirq)
+
+#define CIC_EXT_SET_TRIGGER_LEVEL(reg, eirq)	reg &= ~EXT_INT_EDGE(eirq)
+#define CIC_EXT_SET_TRIGGER_EDGE(reg, eirq)	reg |= EXT_INT_EDGE(eirq)
+#define CIC_EXT_SET_ACTIVE_HI(reg, eirq)	reg |= EXT_INT_POL(eirq)
+#define CIC_EXT_SET_ACTIVE_LO(reg, eirq)	reg &= ~EXT_INT_POL(eirq)
+#define CIC_EXT_SET_ACTIVE_RISING		CIC_EXT_SET_ACTIVE_HI
+#define CIC_EXT_SET_ACTIVE_FALLING		CIC_EXT_SET_ACTIVE_LO
+
+#define CIC_EXT_IS_TRIGGER_LEVEL(reg, eirq) \
+				((reg & EXT_INT_EDGE(eirq)) == 0)
+#define CIC_EXT_IS_TRIGGER_EDGE(reg, eirq)	(reg & EXT_INT_EDGE(eirq))
+#define CIC_EXT_IS_ACTIVE_HI(reg, eirq)		(reg & EXT_INT_POL(eirq))
+#define CIC_EXT_IS_ACTIVE_LO(reg, eirq) \
+				((reg & EXT_INT_POL(eirq)) == 0)
+#define CIC_EXT_IS_ACTIVE_RISING		CIC_EXT_IS_ACTIVE_HI
+#define CIC_EXT_IS_ACTIVE_FALLING		CIC_EXT_IS_ACTIVE_LO
+
+/*
+ ***************************************************************************
+ * Memory Controller defines                                               *
+ ***************************************************************************
+ */
+
+/* Indirect memory controller registers */
+#define DDRC_CFG(n)		(n)
+#define DDRC_DEBUG(n)		(0x04 + n)
+#define DDRC_CTL(n)		(0x40 + n)
+
+/* Macro to perform DDRC indirect write */
+#define DDRC_INDIRECT_WRITE(reg, mask, value) \
+({ \
+	*MEM_SS_ADDR = ((mask & 0xf) << 8) | (reg & 0xff); \
+	*MEM_SS_DATA = value; \
+	*MEM_SS_WRITE = 1; \
+})
+
+/*
+ ***************************************************************************
+ * SPI/MPI Mode                                                            *
+ ***************************************************************************
+ */
+#define SPI_MPI_RX_BUSY		0x00008000	/* SPI/MPI Receive Busy */
+#define SPI_MPI_FIFO_EMPTY	0x00004000	/* SPI/MPI Fifo Empty   */
+#define SPI_MPI_TX_BUSY		0x00002000	/* SPI/MPI Transmit Busy */
+#define SPI_MPI_FIFO_FULL	0x00001000	/* SPI/MPU FIFO full    */
+
+/*
+ ***************************************************************************
+ * SPI/MPI Control Register                                                *
+ ***************************************************************************
+ */
+#define SPI_MPI_RX_START	0x00000004	/* Start receive command */
+#define SPI_MPI_FLUSH_Q		0x00000002	/* Flush SPI/MPI Queue */
+#define SPI_MPI_TX_START	0x00000001	/* Start Transmit Command */
+
+#endif /* !_ASM_MSP_REGS_H */
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_slp_int.h b/include/asm-mips/pmc-sierra/msp71xx/msp_slp_int.h
new file mode 100644
index 0000000..2ca3f56
--- /dev/null
+++ b/include/asm-mips/pmc-sierra/msp71xx/msp_slp_int.h
@@ -0,0 +1,141 @@
+/*
+ * Defines for the MSP interrupt controller.
+ * 
+ * Copyright (C) 1999 MIPS Technologies, Inc.  All rights reserved.
+ * Author: Carsten Langgaard, carstenl@mips.com
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ */
+
+#ifndef _MSP_SLP_INT_H
+#define _MSP_SLP_INT_H
+
+/* 
+ * The PMC-Sierra SLP interrupts are arranged in a 3 level cascaded
+ * hierarchical system.  The first level are the direct MIPS interrupts
+ * and are assigned the interrupt range 0-7.  The second level is the SLM
+ * interrupt controller and is assigned the range 8-39.  The third level
+ * comprises the Peripherial block, the PCI block, the PCI MSI block and
+ * the SLP.  The PCI interrupts and the SLP errors are handled by the
+ * relevant subsystems so the core interrupt code needs only concern
+ * itself with the Peripheral block.  These are assigned interrupts in
+ * the range 40-71. 
+ */
+
+/*
+ * IRQs directly connected to CPU
+ */
+#define MSP_MIPS_INTBASE	0
+#define MSP_INT_SW0		0  /* IRQ for swint0,         C_SW0  */
+#define MSP_INT_SW1		1  /* IRQ for swint1,         C_SW1  */
+#define MSP_INT_MAC0 		2  /* IRQ for MAC 0,          C_IRQ0 */
+#define MSP_INT_MAC1		3  /* IRQ for MAC 1,          C_IRQ1 */
+#define MSP_INT_C_IRQ2		4  /* Wired off,              C_IRQ2 */
+#define MSP_INT_VE		5  /* IRQ for Voice Engine,   C_IRQ3 */
+#define MSP_INT_SLP		6  /* IRQ for SLM block,      C_IRQ4 */
+#define MSP_INT_TIMER		7  /* IRQ for the MIPS timer, C_IRQ5 */
+
+/*
+ * IRQs cascaded on CPU interrupt 4 (CAUSE bit 12, C_IRQ4)
+ * These defines should be tied to the register definition for the SLM
+ * interrupt routine.  For now, just use hard-coded values.
+ */
+#define MSP_SLP_INTBASE		(MSP_MIPS_INTBASE + 8)
+#define MSP_INT_EXT0		(MSP_SLP_INTBASE + 0) 
+					/* External interrupt 0         */
+#define MSP_INT_EXT1		(MSP_SLP_INTBASE + 1) 
+					/* External interrupt 1         */
+#define MSP_INT_EXT2		(MSP_SLP_INTBASE + 2)
+					/* External interrupt 2         */
+#define MSP_INT_EXT3		(MSP_SLP_INTBASE + 3)
+					/* External interrupt 3         */
+/* Reserved					   4-7                  */
+
+/*
+ *************************************************************************
+ * DANGER/DANGER/DANGER/DANGER/DANGER/DANGER/DANGER/DANGER/DANGER/DANGER *
+ * Some MSP produces have this interrupt labelled as Voice and some are  *
+ * SEC mbox ...                                                          *
+ *************************************************************************
+ */
+#define MSP_INT_SLP_VE		(MSP_SLP_INTBASE + 8)
+					/* Cascaded IRQ for Voice Engine*/
+#define MSP_INT_SLP_TDM		(MSP_SLP_INTBASE + 9)
+					/* TDM interrupt                */
+#define MSP_INT_SLP_MAC0	(MSP_SLP_INTBASE + 10)
+					/* Cascaded IRQ for MAC 0       */
+#define MSP_INT_SLP_MAC1	(MSP_SLP_INTBASE + 11)
+					/* Cascaded IRQ for MAC 1       */
+#define MSP_INT_SEC		(MSP_SLP_INTBASE + 12)
+					/* IRQ for security engine      */
+#define	MSP_INT_PER		(MSP_SLP_INTBASE + 13)
+					/* Peripheral interrupt         */
+#define	MSP_INT_TIMER0		(MSP_SLP_INTBASE + 14)
+					/* SLP timer 0                  */
+#define	MSP_INT_TIMER1		(MSP_SLP_INTBASE + 15)
+					/* SLP timer 1                  */
+#define	MSP_INT_TIMER2		(MSP_SLP_INTBASE + 16)
+					/* SLP timer 2                  */
+#define	MSP_INT_SLP_TIMER	(MSP_SLP_INTBASE + 17)
+					/* Cascaded MIPS timer          */
+#define MSP_INT_BLKCP		(MSP_SLP_INTBASE + 18)
+					/* Block Copy                   */
+#define MSP_INT_UART0		(MSP_SLP_INTBASE + 19)
+					/* UART 0                       */
+#define MSP_INT_PCI		(MSP_SLP_INTBASE + 20)
+					/* PCI subsystem                */
+#define MSP_INT_PCI_DBELL	(MSP_SLP_INTBASE + 21)
+					/* PCI doorbell                 */
+#define MSP_INT_PCI_MSI		(MSP_SLP_INTBASE + 22)
+					/* PCI Message Signal           */
+#define MSP_INT_PCI_BC0		(MSP_SLP_INTBASE + 23)
+					/* PCI Block Copy 0             */
+#define MSP_INT_PCI_BC1		(MSP_SLP_INTBASE + 24)
+					/* PCI Block Copy 1             */
+#define MSP_INT_SLP_ERR		(MSP_SLP_INTBASE + 25)
+					/* SLP error condition          */
+#define MSP_INT_MAC2		(MSP_SLP_INTBASE + 26)
+					/* IRQ for MAC2                 */
+/* Reserved					   26-31                */
+
+/* 
+ * IRQs cascaded on SLP PER interrupt (MSP_INT_PER)
+ */
+#define MSP_PER_INTBASE		(MSP_SLP_INTBASE + 32)
+/* Reserved					   0-1                  */
+#define MSP_INT_UART1		(MSP_PER_INTBASE + 2)
+					/* UART 1                       */
+/* Reserved					   3-5                  */
+#define MSP_INT_2WIRE		(MSP_PER_INTBASE + 6) 
+					/* 2-wire                       */
+#define MSP_INT_TM0		(MSP_PER_INTBASE + 7)
+					/* Peripheral timer block out 0 */
+#define MSP_INT_TM1		(MSP_PER_INTBASE + 8)
+					/* Peripheral timer block out 1 */
+/* Reserved					   9                    */
+#define MSP_INT_SPRX		(MSP_PER_INTBASE + 10)
+					/* SPI RX complete              */
+#define MSP_INT_SPTX		(MSP_PER_INTBASE + 11)
+					/* SPI TX complete              */
+#define MSP_INT_GPIO		(MSP_PER_INTBASE + 12)
+					/* GPIO                         */
+#define MSP_INT_PER_ERR		(MSP_PER_INTBASE + 13)
+					/* Peripheral error             */
+/* Reserved					   14-31                */
+
+#endif /* !_MSP_SLP_INT_H */

From stjeanma@pmc-sierra.com Wed Mar  7 18:03:12 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Mar 2007 18:03:17 +0000 (GMT)
Received: from mother.pmc-sierra.com ([216.241.224.12]:6294 "HELO
	mother.pmc-sierra.bc.ca") by ftp.linux-mips.org with SMTP
	id S20021611AbXCGSDM (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Wed, 7 Mar 2007 18:03:12 +0000
Received: (qmail 14417 invoked by uid 101); 7 Mar 2007 18:01:56 -0000
Received: from unknown (HELO pmxedge2.pmc-sierra.bc.ca) (216.241.226.184)
  by mother.pmc-sierra.com with SMTP; 7 Mar 2007 18:01:56 -0000
Received: from pasqua.pmc-sierra.bc.ca (pasqua.pmc-sierra.bc.ca [134.87.183.161])
	by pmxedge2.pmc-sierra.bc.ca (8.13.4/8.12.7) with ESMTP id l27I1YCG024662
	for <linux-mips@linux-mips.org>; Wed, 7 Mar 2007 10:01:54 -0800
From:	Marc St-Jean <stjeanma@pmc-sierra.com>
Received: (from stjeanma@localhost)
	by pasqua.pmc-sierra.bc.ca (8.13.4/8.12.11) id l27I1Yfs012803
	for linux-mips@linux-mips.org; Wed, 7 Mar 2007 12:01:34 -0600
Date:	Wed, 7 Mar 2007 12:01:34 -0600
Message-Id: <200703071801.l27I1Yfs012803@pasqua.pmc-sierra.bc.ca>
To:	linux-mips@linux-mips.org
Subject: [PATCH 2/5] mips: PMC MSP71xx mips common
Return-Path: <stjeanma@pmc-sierra.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14388
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: stjeanma@pmc-sierra.com
Precedence: bulk
X-list: linux-mips

[PATCH 2/5] mips: PMC MSP71xx mips common

Patch to add mips common support for the PMC-Sierra
MSP71xx devices.

These 5 patches along with the previously posted serial patch
will boot the PMC-Sierra MSP7120 Residential Gateway board.

Thanks,
Marc

Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
---
Re-posting patch with recommended changes:
-Moved 34K errata checking from platfrom patch to an check_errata
function called from check_bugs32().
(arch/mips/kernel/cpu-probe.c, include/asm-mips/cpu.h,
include/asm-mips/mipsregs.h)

 arch/mips/Kconfig            |   87 ++++++++++++++++++++++
 arch/mips/Makefile           |   11 ++
 arch/mips/kernel/cpu-probe.c |   20 +++++
 arch/mips/kernel/head.S      |    5 +
 arch/mips/kernel/traps.c     |    6 +
 include/asm-mips/bootinfo.h  |   12 +++
 include/asm-mips/cpu.h       |    2 
 include/asm-mips/mipsregs.h  |   33 ++++++++
 include/asm-mips/regops.h    |  166 +++++++++++++++++++++++++++++++++++++++++++
 include/asm-mips/war.h       |   11 ++
 10 files changed, 351 insertions(+), 2 deletions(-)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 5da6b0d..899c528 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -354,6 +354,7 @@ config MIPS_SIM
 	bool 'MIPS simulator (MIPSsim)'
 	select DMA_NONCOHERENT
 	select IRQ_CPU
+	select BOOT_RAW
 	select SYS_HAS_CPU_MIPS32_R1
 	select SYS_HAS_CPU_MIPS32_R2
 	select SYS_SUPPORTS_32BIT_KERNEL
@@ -504,6 +505,27 @@ config MACH_VR41XX
 	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
 	select GENERIC_HARDIRQS_NO__DO_IRQ
 
+config PMC_MSP
+	bool "PMC-Sierra MSP chipsets"
+	depends on EXPERIMENTAL
+	select DMA_NONCOHERENT
+	select SWAP_IO_SPACE
+	select NO_EXCEPT_FILL
+	select BOOT_RAW
+	select SYS_HAS_CPU_MIPS32_R1
+	select SYS_HAS_CPU_MIPS32_R2
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select SYS_SUPPORTS_BIG_ENDIAN
+	select SYS_SUPPORTS_KGDB
+	select IRQ_CPU
+	select SERIAL_8250
+	select SERIAL_8250_CONSOLE
+	help
+	  This adds support for the PMC-Sierra family of Multi-Service
+	  Processor System-On-A-Chips.  These parts include a number
+	  of integrated peripherals, interfaces and DSPs in addition to
+	  a variety of MIPS cores.
+
 config PMC_YOSEMITE
 	bool "PMC-Sierra Yosemite eval board"
 	select DMA_COHERENT
@@ -815,6 +837,55 @@ config TOSHIBA_RBTX4938
 
 endchoice
 
+choice
+	prompt "PMC-Sierra MSP SOC type"
+	depends on PMC_MSP
+
+config PMC_MSP4200_EVAL
+	bool "PMC-Sierra MSP4200 Eval Board"
+	select IRQ_MSP_SLP
+	select HW_HAS_PCI
+
+config PMC_MSP4200_GW
+	bool "PMC-Sierra MSP4200 VoIP Gateway"
+	select IRQ_MSP_SLP
+	select HW_HAS_PCI
+
+config PMC_MSP7120_EVAL
+	bool "PMC-Sierra MSP7120 Eval Board"
+	select SYS_SUPPORTS_MULTITHREADING
+	select IRQ_MSP_CIC
+	select HW_HAS_PCI
+	select MSP_USB
+
+config PMC_MSP7120_GW
+	bool "PMC-Sierra MSP7120 Residential Gateway"
+	select SYS_SUPPORTS_MULTITHREADING
+	select IRQ_MSP_CIC
+	select HW_HAS_PCI
+	select MSP_USB
+
+config PMC_MSP7120_FPGA
+	bool "PMC-Sierra MSP7120 FPGA"
+	select SYS_SUPPORTS_MULTITHREADING
+	select IRQ_MSP_CIC
+	select HW_HAS_PCI
+	select MSP_USB
+
+endchoice
+
+menu "Options for PMC-Sierra MSP chipsets"
+	depends on PMC_MSP
+
+config PMC_MSP_EMBEDDED_ROOTFS
+	bool "Root filesystem embedded in kernel image"
+	select MTD
+	select MTD_BLOCK
+	select MTD_PMC_MSP_RAMROOT
+	select MTD_RAM
+
+endmenu
+
 source "arch/mips/ddb5xxx/Kconfig"
 source "arch/mips/gt64120/ev64120/Kconfig"
 source "arch/mips/jazz/Kconfig"
@@ -879,6 +950,9 @@ config ARC
 config ARCH_MAY_HAVE_PC_FDC
 	bool
 
+config BOOT_RAW
+	bool
+
 config DMA_COHERENT
 	bool
 
@@ -924,6 +998,9 @@ config MIPS_DISABLE_OBSOLETE_IDE
 
 config GENERIC_ISA_DMA_SUPPORT_BROKEN
 	bool
+	
+config NO_EXCEPT_FILL
+	bool
 
 #
 # Endianess selection.  Sufficiently obscure so many users don't know what to
@@ -971,6 +1048,15 @@ config IRQ_CPU_RM9K
 config IRQ_MV64340
 	bool
 
+config IRQ_MSP_SLP
+	bool
+
+config IRQ_MSP_CIC
+	bool
+
+config MSP_USB
+	bool
+
 config DDB5XXX_COMMON
 	bool
 	select SYS_SUPPORTS_KGDB
@@ -1086,6 +1172,7 @@ config MIPS_L1_CACHE_SHIFT
 	int
 	default "4" if MACH_DECSTATION || SNI_RM
 	default "7" if SGI_IP27
+	default "4" if PMC_MSP4200_EVAL
 	default "5"
 
 config HAVE_STD_PC_SERIAL_PORT
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 92bca6a..1c38332 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -360,6 +360,14 @@ core-$(CONFIG_MOMENCO_OCELOT_C)	+= arch/mips/momentum/ocelot_c/
 load-$(CONFIG_MOMENCO_OCELOT_C)	+= 0xffffffff80100000
 
 #
+# PMC-Sierra MSP SOCs
+#
+core-$(CONFIG_PMC_MSP)		+= arch/mips/pmc-sierra/msp71xx/
+cflags-$(CONFIG_PMC_MSP)	+= -Iinclude/asm-mips/pmc-sierra/msp71xx \
+					-mno-branch-likely
+load-$(CONFIG_PMC_MSP)		+= 0xffffffff80100000
+
+#
 # PMC-Sierra Yosemite
 #
 core-$(CONFIG_PMC_YOSEMITE)	+= arch/mips/pmc-sierra/yosemite/
@@ -619,7 +627,8 @@ JIFFIES			= jiffies_64
 endif
 
 AFLAGS		+= $(cflags-y)
-CFLAGS		+= $(cflags-y)
+CFLAGS		+= $(cflags-y) \
+			-D"VMLINUX_LOAD_ADDRESS=$(load-y)"
 
 LDFLAGS			+= -m $(ld-emul)
 
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 6f57ca4..27366f6 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/threads.h>
 
+#include <asm/addrspace.h>
 #include <asm/asm.h>
 #include <asm/asmmacro.h>
 #include <asm/irqflags.h>
@@ -129,16 +130,18 @@
 #endif
 	.endm
 
+#ifndef CONFIG_NO_EXCEPT_FILL
 	/*
 	 * Reserved space for exception handlers.
 	 * Necessary for machines which link their kernels at KSEG0.
 	 */
 	.fill	0x400
+#endif
 
 EXPORT(stext)					# used for profiling
 EXPORT(_stext)
 
-#ifdef CONFIG_MIPS_SIM
+#ifdef CONFIG_BOOT_RAW
 	/*
 	 * Give us a fighting chance of running if execution beings at the
 	 * kernel load address.  This is needed because this platform does
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index ab755ea..ce8c9c7 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -165,9 +165,29 @@ static inline void check_wait(void)
 	}
 }
 
+static inline void check_errata(void)
+{
+	struct cpuinfo_mips *c = &current_cpu_data;
+
+	switch (c->cputype) {
+	case CPU_34K:
+		/*
+		 * Erratum "RPS May Cause Incorrect Instruction Execution"
+		 * This code only handles VPE0, any SMP/SMTC/RTOS code
+		 * making use of VPE1 will be responsable for that VPE.
+		 */
+		if ((c->processor_id & PRID_REV_MASK) <= PRID_REV_34K_V1_0_2)
+			write_c0_config7(read_c0_config7() | MIPS_CONF7_RPS);
+		break;
+	default:
+		break;
+	}
+}
+
 void __init check_bugs32(void)
 {
 	check_wait();
+	check_errata();
 }
 
 /*
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 18f56a9..2c812c2 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -70,6 +70,7 @@ extern asmlinkage void handle_reserved(void);
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
 	struct mips_fpu_struct *ctx, int has_fpu);
 
+void (*board_watchpoint_handler)(struct pt_regs *regs);
 void (*board_be_init)(void);
 int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
 void (*board_nmi_handler_setup)(void);
@@ -860,6 +861,11 @@ asmlinkage void do_mdmx(struct pt_regs *regs)
 
 asmlinkage void do_watch(struct pt_regs *regs)
 {
+	if (board_watchpoint_handler) {
+		(*board_watchpoint_handler)(regs);
+		return;
+	}
+	
 	/*
 	 * We use the watch exception where available to detect stack
 	 * overflows.
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index c7c945b..7fc52c7 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -213,6 +213,18 @@
 #define MACH_GROUP_NEC_EMMA2RH 25	/* NEC EMMA2RH (was 23)		*/
 #define  MACH_NEC_MARKEINS	0	/* NEC EMMA2RH Mark-eins	*/
 
+/*
+ * Valid machtype for group PMC-MSP
+ */
+#define MACH_GROUP_MSP         26	/* PMC-Sierra MSP boards/CPUs    */
+#define MACH_MSP4200_EVAL       0	/* PMC-Sierra MSP4200 Evaluation board */
+#define MACH_MSP4200_GW         1	/* PMC-Sierra MSP4200 Gateway demo board */
+#define MACH_MSP4200_FPGA       2	/* PMC-Sierra MSP4200 Emulation board */
+#define MACH_MSP7120_EVAL       3	/* PMC-Sierra MSP7120 Evaluation board */
+#define MACH_MSP7120_GW         4	/* PMC-Sierra MSP7120 Residential Gateway board */
+#define MACH_MSP7120_FPGA       5	/* PMC-Sierra MSP7120 Emulation board */
+#define MACH_MSP_OTHER        255	/* PMC-Sierra unknown board type */
+
 #define CL_SIZE			COMMAND_LINE_SIZE
 
 const char *get_system_type(void);
diff --git a/include/asm-mips/cpu.h b/include/asm-mips/cpu.h
index d38fdbf..9415dc2 100644
--- a/include/asm-mips/cpu.h
+++ b/include/asm-mips/cpu.h
@@ -107,6 +107,7 @@
  * Definitions for 7:0 on legacy processors
  */
 
+#define PRID_REV_MASK		0x00ff
 
 #define PRID_REV_TX4927		0x0022
 #define PRID_REV_TX4937		0x0030
@@ -123,6 +124,7 @@
 #define PRID_REV_VR4122		0x0070
 #define PRID_REV_VR4181A	0x0070	/* Same as VR4122 */
 #define PRID_REV_VR4130		0x0080
+#define PRID_REV_34K_V1_0_2	0x0022
 
 /*
  * FPU implementation/revision register (CP1 control register 0).
diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h
index 9985cb7..fb3c76e 100644
--- a/include/asm-mips/mipsregs.h
+++ b/include/asm-mips/mipsregs.h
@@ -15,6 +15,7 @@
 
 #include <linux/linkage.h>
 #include <asm/hazards.h>
+#include <asm/war.h>
 
 /*
  * The following macros are especially useful for __asm__
@@ -534,6 +535,9 @@
 #define MIPS_CONF3_LPA		(_ULCAST_(1) <<  7)
 #define MIPS_CONF3_DSP		(_ULCAST_(1) << 10)
 
+#define MIPS_CONF7_RPS		(_ULCAST_(1) << 2)
+
+
 /*
  * Bits in the MIPS32/64 coprocessor 1 (FPU) revision register.
  */
@@ -1292,10 +1296,39 @@ static inline void tlb_probe(void)
 
 static inline void tlb_read(void)
 {
+#if MIPS34K_MISSED_ITLB_WAR
+	int res = 0;
+
+	__asm__ __volatile__(
+	"	.set	push						\n"
+	"	.set	noreorder					\n"
+	"	.set	noat						\n"
+	"	.set	mips32r2					\n"
+	"	.word	0x41610001		# dvpe $1		\n"
+	"	move	%0, $1						\n"
+	"	ehb							\n"
+	"	.set	pop						\n"
+	: "=r" (res));
+
+	instruction_hazard();
+#endif
+
 	__asm__ __volatile__(
 		".set noreorder\n\t"
 		"tlbr\n\t"
 		".set reorder");
+
+#if MIPS34K_MISSED_ITLB_WAR
+	if ((res & _ULCAST_(1)))
+		__asm__ __volatile__(
+		"	.set	push						\n"
+		"	.set	noreorder					\n"
+		"	.set	noat						\n"
+		"	.set	mips32r2					\n"
+		"	.word	0x41600021		# evpe			\n"
+		"	ehb							\n"
+		"	.set	pop						\n");
+#endif
 }
 
 static inline void tlb_write_indexed(void)
diff --git a/include/asm-mips/war.h b/include/asm-mips/war.h
index 13a3502..74c08e6 100644
--- a/include/asm-mips/war.h
+++ b/include/asm-mips/war.h
@@ -196,6 +196,14 @@
 #endif
 
 /*
+ * 34K core erratum: "Problems Executing the TLBR Instruction"
+ */
+#if defined(CONFIG_PMC_MSP7120_EVAL) || defined(CONFIG_PMC_MSP7120_GW) || \
+	defined(CONFIG_PMC_MSP7120_FPGA)
+#define MIPS34K_MISSED_ITLB_WAR		1
+#endif
+
+/*
  * Workarounds default to off
  */
 #ifndef ICACHE_REFILLS_WORKAROUND_WAR
@@ -234,5 +242,8 @@
 #ifndef R10000_LLSC_WAR
 #define R10000_LLSC_WAR			0
 #endif
+#ifndef MIPS34K_MISSED_ITLB_WAR
+#define MIPS34K_MISSED_ITLB_WAR		0
+#endif
 
 #endif /* _ASM_WAR_H */
diff --git a/include/asm-mips/regops.h b/include/asm-mips/regops.h
new file mode 100644
index 0000000..375c667
--- /dev/null
+++ b/include/asm-mips/regops.h
@@ -0,0 +1,166 @@
+/*
+ * VPE/SMP-safe functions to access registers.  They use ll/sc instructions, so
+ * it is your responsibility to ensure these are available on your platform
+ * before including this file.
+ *
+ * In addition, there is a bug on the R10000 chips which has a workaround.  If
+ * you are affected by this bug, make sure to define the symbol
+ * 'R10000_LLSC_WAR' to be non-zero.  If you are using this header from within
+ * linux, you may include <asm/war.h> before including this file to have this
+ * defined appropriately for you.
+ *
+ * Copyright 2005 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
+ *  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF USE,
+ *  DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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., 675
+ *  Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_REGOPS_H__
+#define __ASM_REGOPS_H__
+
+#ifndef R10000_LLSC_WAR
+#define R10000_LLSC_WAR 0
+#endif
+
+#if R10000_LLSC_WAR == 1
+#define __beqz	"beqzl	"
+#else
+#define __beqz	"beqz	"
+#endif
+
+#ifndef _LINUX_TYPES_H
+typedef unsigned int uint32_t;
+#endif
+
+/*
+ * Sets all the masked bits to the corresponding value bits
+ */
+static inline void set_value_reg32( volatile uint32_t * const addr,
+					uint32_t const mask,
+					uint32_t const value )
+{
+	uint32_t temp;
+
+	__asm__ __volatile__(
+	"	.set	mips3				\n"
+	"1:	ll	%0, %1	# set_value_reg32	\n"
+	"	and	%0, %2				\n"
+	"	or	%0, %3				\n"
+	"	sc	%0, %1				\n"
+	"	"__beqz"%0, 1b				\n"
+	"	.set	mips0				\n"
+	: "=&r" (temp), "=m" (*addr)
+	: "ir" (~mask), "ir" (value), "m" (*addr) );
+}
+
+/*
+ * Sets all the masked bits to '1'
+ */
+static inline void set_reg32( volatile uint32_t * const addr,
+				uint32_t const mask )
+{
+	uint32_t temp;
+
+	__asm__ __volatile__(
+	"	.set	mips3				\n"
+	"1:	ll	%0, %1		# set_reg32	\n"
+	"	or	%0, %2				\n"
+	"	sc	%0, %1				\n"
+	"	"__beqz"%0, 1b				\n"
+	"	.set	mips0				\n"
+	: "=&r" (temp), "=m" (*addr)
+	: "ir" (mask), "m" (*addr) );
+}
+
+/*
+ * Sets all the masked bits to '0'
+ */
+static inline void clear_reg32( volatile uint32_t * const addr,
+				uint32_t const mask )
+{
+	uint32_t temp;
+
+	__asm__ __volatile__(
+	"	.set	mips3				\n"
+	"1:	ll	%0, %1		# clear_reg32	\n"
+	"	and	%0, %2				\n"
+	"	sc	%0, %1				\n"
+	"	"__beqz"%0, 1b				\n"
+	"	.set	mips0				\n"
+	: "=&r" (temp), "=m" (*addr)
+	: "ir" (~mask), "m" (*addr) );
+}
+
+/*
+ * Toggles all masked bits from '0' to '1' and '1' to '0'
+ */
+static inline void toggle_reg32( volatile uint32_t * const addr,
+				uint32_t const mask )
+{
+	uint32_t temp;
+
+	__asm__ __volatile__(
+	"	.set	mips3				\n"
+	"1:	ll	%0, %1		# toggle_reg32	\n"
+	"	xor	%0, %2				\n"
+	"	sc	%0, %1				\n"
+	"	"__beqz"%0, 1b				\n"
+	"	.set	mips0				\n"
+	: "=&r" (temp), "=m" (*addr)
+	: "ir" (mask), "m" (*addr) );
+}
+
+/* For special strange cases only:
+ *
+ * If you need custom processing within a ll/sc loop, use the following macros
+ * VERY CAREFULLY:
+ *
+ *   uint32_t tmp;                      <-- Define a variable to hold the data
+ *
+ *   custom_reg32_start(address, tmp);	<-- Reads the address and puts the value
+ *						in the 'tmp' variable given
+ *
+ *	< From here on out, you are (basicly) atomic, so don't do anything too
+ *	< fancy!
+ *	< Also, this code may loop if the end of this block fails to write
+ *	< everything back safely due do the other CPU, so do NOT do anything
+ *	< with side-effects!
+ *
+ *   custom_reg32_stop(address, tmp);	<-- Writes back 'tmp' safely. 
+ *
+ */
+#define custom_reg32_read(address, tmp)				\
+	__asm__ __volatile__(					\
+	"	.set	mips3				\n"	\
+	"1:	ll	%0, %1	#custom_reg32_read	\n"	\
+	"	.set	mips0				\n"	\
+	: "=r" (tmp), "=m" (*address)				\
+	: "m" (*address) )
+
+#define custom_reg32_write(address, tmp)			\
+	__asm__ __volatile__(					\
+	"	.set	mips3				\n"	\
+	"	sc	%0, %1	#custom_reg32_write	\n"	\
+	"	"__beqz"%0, 1b				\n"	\
+	"	.set	mips0				\n"	\
+	: "=&r" (tmp), "=m" (*address)				\
+	: "0" (tmp), "m" (*address) )
+
+#endif  /* __ASM_REGOPS_H__ */

From Marc_St-Jean@pmc-sierra.com Wed Mar  7 23:49:08 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Mar 2007 23:49:13 +0000 (GMT)
Received: from father.pmc-sierra.com ([216.241.224.13]:14320 "HELO
	father.pmc-sierra.bc.ca") by ftp.linux-mips.org with SMTP
	id S20021662AbXCGXtI (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Wed, 7 Mar 2007 23:49:08 +0000
Received: (qmail 13091 invoked by uid 101); 7 Mar 2007 23:47:45 -0000
Received: from unknown (HELO pmxedge2.pmc-sierra.bc.ca) (216.241.226.184)
  by father.pmc-sierra.com with SMTP; 7 Mar 2007 23:47:45 -0000
Received: from bby1exi01.pmc_nt.nt.pmc-sierra.bc.ca (bby1exi01.pmc-sierra.bc.ca [216.241.231.251])
	by pmxedge2.pmc-sierra.bc.ca (8.13.4/8.12.7) with ESMTP id l27NleTc024449;
	Wed, 7 Mar 2007 15:47:45 -0800
Received: by bby1exi01.pmc-sierra.bc.ca with Internet Mail Service (5.5.2657.72)
	id <FGCP3JFP>; Wed, 7 Mar 2007 15:47:40 -0800
Message-ID: <45EF4F0E.50303@pmc-sierra.com>
From:	Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
To:	Andrew Morton <akpm@linux-foundation.org>
Cc:	Marc St-Jean <stjeanma@pmc-sierra.com>,
	linux-kernel@vger.kernel.org, linux-mips@linux-mips.org
Subject: Re: [PATCH] drivers: PMC MSP71xx GPIO char driver
Date:	Wed, 7 Mar 2007 15:47:26 -0800 
MIME-Version: 1.0
X-Mailer: Internet Mail Service (5.5.2657.72)
x-originalarrivaltime: 07 Mar 2007 23:47:36.0611 (UTC) FILETIME=[FBDB5730:01C76112]
user-agent: Thunderbird 1.5.0.10 (X11/20070221)
Content-Type: text/plain;
	charset="iso-8859-1"
Return-Path: <Marc_St-Jean@pmc-sierra.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14389
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: Marc_St-Jean@pmc-sierra.com
Precedence: bulk
X-list: linux-mips

Andrew Morton wrote:
>  > On Fri, 23 Feb 2007 17:28:19 -0600 Marc St-Jean 
> <stjeanma@pmc-sierra.com> wrote:
>  > [PATCH] drivers: PMC MSP71xx GPIO char driver
>  >
>  > Patch to add a GPIO char driver for the PMC-Sierra
>  > MSP71xx devices.
>  >
>  > This patch references some platform support files previously
>  > submitted to the linux-mips@linux-mips.org list.
>  >

Thanks for the feedback Andrew. I've implemented all your recommendations
other than the kernel thread handling, which I still have to look into.

[...]

> 
>  > +/* -- Module functions -- */
>  > +
>  > +static int msp_gpio_blinkthread( void *none )
> 
> Why is this a "module function"?

The reason is likely because it's only called by msp_gpio_init so it was
considered part of the module code. I'll move the comment to only cover
msp_gpio_init/exit.

[...]

>  > +module_init(msp_gpio_init);
>  > +module_exit(msp_gpio_exit);
>  > +
>  > +EXPORT_SYMBOL(msp_gpio_in);
>  > +EXPORT_SYMBOL(msp_gpio_out);
>  > +EXPORT_SYMBOL(msp_gpio_mode);
>  > +EXPORT_SYMBOL(msp_gpio_blink);
>  > +EXPORT_SYMBOL(msp_gpio_noblink);
> 
> What uses these exports?

These exports are needed for other drivers compiled as modules can control
the GPIO pins through this driver.

[...]

Marc

From maillist@jg555.com Thu Mar  8 06:13:16 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Mar 2007 06:13:18 +0000 (GMT)
Received: from rrcs-64-183-102-11.west.biz.rr.com ([64.183.102.11]:41411 "EHLO
	jg555.com") by ftp.linux-mips.org with ESMTP id S20021535AbXCHGNQ
	(ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 8 Mar 2007 06:13:16 +0000
Received: from [192.168.55.157] ([::ffff:192.168.55.157])
  (AUTH: PLAIN root, TLS: TLSv1/SSLv3,256bits,AES256-SHA)
  by jg555.com with esmtp; Wed, 07 Mar 2007 22:12:14 -0800
  id 004600EC.45EFA93E.00000872
Message-ID: <45EFA92C.3070203@jg555.com>
Date:	Wed, 07 Mar 2007 22:11:56 -0800
From:	Jim Gifford <maillist@jg555.com>
User-Agent: Thunderbird 1.5.0.10 (Windows/20070221)
MIME-Version: 1.0
To:	Ralf Baechle <ralf@linux-mips.org>
CC:	Linux MIPS List <linux-mips@linux-mips.org>
Subject: Re: Building 64 bit kernel on Cobalt
References: <45EB53D5.8060007@jg555.com> <20070304232731.GA25039@linux-mips.org>
In-Reply-To: <20070304232731.GA25039@linux-mips.org>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <maillist@jg555.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14390
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: maillist@jg555.com
Precedence: bulk
X-list: linux-mips

Ralf Baechle wrote:
> On Sun, Mar 04, 2007 at 03:18:45PM -0800, Jim Gifford wrote:
>
>   
>> Last working Kernel was 2.6.19 series.
>>
>> Some changes from 2.6.19 and the 2.6.20 make it impossible to build a 64 
>> bit kernel to boot on the cobalt. Ya, I know why, building a N32 
>> actually but need a 64 bit kernel in order to do that. Anyone got any 
>> suggestions. Looking through the difference between the kernels to 
>> figure this out, but it's like looking for a needle in a haystack. Any 
>> suggestions as to a starting point?
>>     
>
> Try git-bisect to track down the changeset that broke things.
>
>   Ralf
>
>   
We got it nailed down to arch/mips/kernel /setup.c. But we have not 
isolated which change is actually causing it.

We do know that reverting back to the 2.6.19.x arch/mips/kernel /setup.c 
will fix the issue. We will continue to dwindle it down until we come up 
with the offender.

From maillist@jg555.com Thu Mar  8 08:48:14 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Mar 2007 08:48:17 +0000 (GMT)
Received: from rrcs-64-183-102-11.west.biz.rr.com ([64.183.102.11]:61583 "EHLO
	jg555.com") by ftp.linux-mips.org with ESMTP id S20021510AbXCHIsO
	(ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 8 Mar 2007 08:48:14 +0000
Received: from [192.168.55.157] ([::ffff:192.168.55.157])
  (AUTH: PLAIN root, TLS: TLSv1/SSLv3,256bits,AES256-SHA)
  by jg555.com with esmtp; Thu, 08 Mar 2007 00:46:56 -0800
  id 0045019D.45EFCD80.00001566
Message-ID: <45EFCD73.2010404@jg555.com>
Date:	Thu, 08 Mar 2007 00:46:43 -0800
From:	Jim Gifford <maillist@jg555.com>
User-Agent: Thunderbird 1.5.0.10 (Windows/20070221)
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="=_server-5478-1173343616-0001-2"
To:	Jim Gifford <maillist@jg555.com>
CC:	Ralf Baechle <ralf@linux-mips.org>,
	Linux MIPS List <linux-mips@linux-mips.org>
Subject: Re: Building 64 bit kernel on Cobalt
References: <45EB53D5.8060007@jg555.com> <20070304232731.GA25039@linux-mips.org> <45EFA92C.3070203@jg555.com>
In-Reply-To: <45EFA92C.3070203@jg555.com>
Return-Path: <maillist@jg555.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14391
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: maillist@jg555.com
Precedence: bulk
X-list: linux-mips

This is a MIME-formatted message.  If you see this text it means that your
E-mail software does not support MIME-formatted messages.

--=_server-5478-1173343616-0001-2
Content-Type: text/plain; charset=iso-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Here's what we isolated it to.

The problem looks like this

inflate: decompressing
elf64: 00080000 - 0037701f (ffffffff.80326000) (ffffffff.80000000)
elf64: ffffffff.80080000 (80080000) 2957446t + 151450t
net: interface down

If we apply the patch that's attached we can boot all the way up, but we 
do get some errors. I'm hoping one of these errors might shed the light 
on what the actual issue is.

VFS: Mounted root (nfs filesystem) readonly.
Unhandled kernel unaligned access[#1]:
Cpu 0
$ 0   : 0000000000000000 ffffffff802adc60 0000000000000000 0000000000000000
$ 4   : ffffffff80089eec ffffffffde020000 ffffffff8008c588 0000000000000000
$ 8   : 0000000000561024 996bffffff40b050 0000000000000000 000000000000f6f8
$12   : ffffffff94004ce0 000000001000001e 0000000000000000 ffffffff80300000
$16   : 9800000000387df0 ffffffff80326000 0000000000000000 00067ffffff80326
$20   : 00067ffffff80326 000000000000002d fffffffffffffbff 67ffffff80353000
$24   : 0000000000000010 ffffffff801768d8
$28   : 9800000000384000 9800000000387dc0 67ffffff80326000 ffffffff80081e28
Hi    : 0000000000000000
Lo    : 0000000000000000
epc   : ffffffff80089f04 do_ade+0x3a4/0x4c0     Not tainted
ra    : ffffffff80081e28 ret_from_exception+0x0/0x1c
Status: 94004ce2    KX SX UX KERNEL EXL
Cause : 00808010
BadVA : 996bffffff40b057
PrId  : 000028a0
Process swapper (pid: 1, threadinfo=9800000000384000, task=9800000000381828)
Stack : 996bffffff40b050 ffffffff80326000 016bfffffe40b050 00067ffffff80326
        ffffffff80081e28 0000000000000000 0000000000000000 ffffffff94004ce0
        9800000001000000 019ffffffe00c980 ffffffff94004ce1 00067ffffff80353
        6800000000000000 9800000000381828 98000000013e9a40 98000000003b3000
        ffffffff80309758 000000000000f6f8 0000000000000001 ffffffff801b9388
        0000000000000000 ffffffff80300000 996bffffff40b050 ffffffff80326000
        016bfffffe40b050 00067ffffff80326 00067ffffff80326 000000000000002d
        fffffffffffffbff 67ffffff80353000 0000000000000010 ffffffff801768d8
        ffffffff800fb5ac ffffffff800fb5ac 9800000000384000 9800000000387f20
        67ffffff80326000 ffffffff8008c4d0 ffffffff94004ce2 0000000000000000
        ...
Call Trace:
[<ffffffff80089f04>] do_ade+0x3a4/0x4c0
[<ffffffff80081e28>] ret_from_exception+0x0/0x1c
[<ffffffff8008c588>] free_initmem+0xe8/0x218
[<ffffffff80080688>] init+0x248/0x510
[<ffffffff80084420>] kernel_thread_helper+0x10/0x18


Code: 00431024  5440ff77  de020100 <69230007> 6d230000  24020000  
1440ffba  00051402  08022760
Kernel panic - not syncing: Attempted to kill init!

patch - at http://ftp.jg555.com/revert.working.diff


--=_server-5478-1173343616-0001-2
Content-Type: text/x-patch; name="revert.working.diff"; charset=iso-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="revert.working.diff"

--- linux-2.6.19.2/arch/mips/kernel/setup.c	2007-01-10 11:10:37.000000000 -0800
+++ linux-2.6.20.1/arch/mips/kernel/setup.c	2007-03-07 20:59:28.000000000 -0800
@@ -145,13 +145,12 @@
 	unsigned long start = memparse(p, &p);
 
 #ifdef CONFIG_64BIT
-	/* HACK: Guess if the sign extension was forgotten */
-	if (start > 0x0000000080000000 && start < 0x00000000ffffffff)
-		start |= 0xffffffff00000000UL;
+	/* Guess if the sign extension was forgotten by bootloader */
+	if (start < XKPHYS)
+		start = (int)start;
 #endif
 	initrd_start = start;
 	initrd_end += start;
-
 	return 0;
 }
 early_param("rd_start", rd_start_early);
@@ -159,41 +158,64 @@
 static int __init rd_size_early(char *p)
 {
 	initrd_end += memparse(p, &p);
-
 	return 0;
 }
 early_param("rd_size", rd_size_early);
 
+/* it returns the next free pfn after initrd */
 static unsigned long __init init_initrd(void)
 {
-	unsigned long tmp, end, size;
+	unsigned long end;
 	u32 *initrd_header;
 
-	ROOT_DEV = Root_RAM0;
-
 	/*
 	 * Board specific code or command line parser should have
 	 * already set up initrd_start and initrd_end. In these cases
 	 * perfom sanity checks and use them if all looks good.
 	 */
-	size = initrd_end - initrd_start;
-	if (initrd_end == 0 || size == 0) {
-		initrd_start = 0;
-		initrd_end = 0;
-	} else
-		return initrd_end;
-
-	end = (unsigned long)&_end;
-	tmp = PAGE_ALIGN(end) - sizeof(u32) * 2;
-	if (tmp < end)
-		tmp += PAGE_SIZE;
-
-	initrd_header = (u32 *)tmp;
-	if (initrd_header[0] == 0x494E5244) {
-		initrd_start = (unsigned long)&initrd_header[2];
-		initrd_end = initrd_start + initrd_header[1];
+	if (initrd_start && initrd_end > initrd_start)
+		goto sanitize;
+
+	/*
+	 * See if initrd has been added to the kernel image by
+	 * arch/mips/boot/addinitrd.c. In that case a header is
+	 * prepended to initrd and is made up by 8 bytes. The fisrt
+	 * word is a magic number and the second one is the size of
+	 * initrd.  Initrd start must be page aligned in any cases.
+	 */
+	initrd_header = __va(PAGE_ALIGN(__pa_symbol(&_end) + 8)) - 8;
+	if (initrd_header[0] != 0x494E5244)
+		goto disable;
+	initrd_start = (unsigned long)(initrd_header + 2);
+	initrd_end = initrd_start + initrd_header[1];
+
+sanitize:
+	if (initrd_start & ~PAGE_MASK) {
+		printk(KERN_ERR "initrd start must be page aligned\n");
+		goto disable;
 	}
-	return initrd_end;
+	if (initrd_start < PAGE_OFFSET) {
+		printk(KERN_ERR "initrd start < PAGE_OFFSET\n");
+		goto disable;
+	}
+
+	/*
+	 * Sanitize initrd addresses. For example firmware
+	 * can't guess if they need to pass them through
+	 * 64-bits values if the kernel has been built in pure
+	 * 32-bit. We need also to switch from KSEG0 to XKPHYS
+	 * addresses now, so the code can now safely use __pa().
+	 */
+	end = __pa(initrd_end);
+	initrd_end = (unsigned long)__va(end);
+	initrd_start = (unsigned long)__va(__pa(initrd_start));
+
+	ROOT_DEV = Root_RAM0;
+	return PFN_UP(end);
+disable:
+	initrd_start = 0;
+	initrd_end = 0;
+	return 0;
 }
 
 static void __init finalize_initrd(void)
@@ -204,12 +226,12 @@
 		printk(KERN_INFO "Initrd not found or empty");
 		goto disable;
 	}
-	if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) {
+	if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) {
 		printk("Initrd extends beyond end of memory");
 		goto disable;
 	}
 
-	reserve_bootmem(CPHYSADDR(initrd_start), size);
+	reserve_bootmem(__pa(initrd_start), size);
 	initrd_below_start_ok = 1;
 
 	printk(KERN_INFO "Initial ramdisk at: 0x%lx (%lu bytes)\n",
@@ -259,8 +281,7 @@
 	 * not selected. Once that done we can determine the low bound
 	 * of usable memory.
 	 */
-	reserved_end = init_initrd();
-	reserved_end = PFN_UP(CPHYSADDR(max(reserved_end, (unsigned long)&_end)));
+	reserved_end = max(init_initrd(), PFN_UP(__pa_symbol(&_end)));
 
 	/*
 	 * Find the highest page frame number we have available.
@@ -432,10 +453,10 @@
 	if (UNCAC_BASE != IO_BASE)
 		return;
 
-	code_resource.start = virt_to_phys(&_text);
-	code_resource.end = virt_to_phys(&_etext) - 1;
-	data_resource.start = virt_to_phys(&_etext);
-	data_resource.end = virt_to_phys(&_edata) - 1;
+	code_resource.start = __pa_symbol(&_text);
+	code_resource.end = __pa_symbol(&_etext) - 1;
+	data_resource.start = __pa_symbol(&_etext);
+	data_resource.end = __pa_symbol(&_edata) - 1;
 
 	/*
 	 * Request address space for all standard RAM.
@@ -500,7 +521,7 @@
 #endif
 }
 
-int __init fpu_disable(char *s)
+static int __init fpu_disable(char *s)
 {
 	int i;
 
@@ -512,7 +533,7 @@
 
 __setup("nofpu", fpu_disable);
 
-int __init dsp_disable(char *s)
+static int __init dsp_disable(char *s)
 {
 	cpu_data[0].ases &= ~MIPS_ASE_DSP;
 

--=_server-5478-1173343616-0001-2--

From vagabon.xyz@gmail.com Thu Mar  8 08:56:02 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Mar 2007 08:56:06 +0000 (GMT)
Received: from qb-out-0506.google.com ([72.14.204.231]:51050 "EHLO
	qb-out-0506.google.com") by ftp.linux-mips.org with ESMTP
	id S20021514AbXCHI4C (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 8 Mar 2007 08:56:02 +0000
Received: by qb-out-0506.google.com with SMTP id e12so707409qba
        for <linux-mips@linux-mips.org>; Thu, 08 Mar 2007 00:54:52 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=N9pAsqiOkX7099d3ztDO5h2Dl3u8dmE63IMyiHPG22MIzc2TPBEMUG+z/9zfQ4nUhzurzromrefU6SKlxQQLFyKTM3QnsA9XRUg8mnQRJbUyZRfZu2v6dPsQk6E/sTUqivF+jY8CjrCyGBL5OY84OotiGZ55HqLTYhpa7/xgPK8=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=Ha2HVnpBEpHjcTJLCstRVpL+7Ij8ahf2bsjpd5VFE7i1XUyYrZDzC0QtIXnLbcOF9KFO4Ve29nv1fcCbQZyWDWAVNsT/CDaHXmuO8woBFvO3y2usCWqPShTujKt4ibKFVbaZWjCYdY4e4Y6WmVzjK7HoJ204KRsrHzM8KetcUVE=
Received: by 10.114.137.2 with SMTP id k2mr47542wad.1173344091894;
        Thu, 08 Mar 2007 00:54:51 -0800 (PST)
Received: by 10.114.136.11 with HTTP; Thu, 8 Mar 2007 00:54:51 -0800 (PST)
Message-ID: <cda58cb80703080054q52f9977cm2ee43f381816a348@mail.gmail.com>
Date:	Thu, 8 Mar 2007 09:54:51 +0100
From:	"Franck Bui-Huu" <vagabon.xyz@gmail.com>
To:	mbizon@freebox.fr
Subject: Re: [PATCH 0/2] FLATMEM: allow memory to start at pfn != 0 [take #2]
Cc:	linux-mips <linux-mips@linux-mips.org>
In-Reply-To: <cda58cb80703061339l2f8cfc09m5823b090b69a7aa7@mail.gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
References: <116841864595-git-send-email-fbuihuu@gmail.com>
	 <1172879147.964.65.camel@sakura.staff.proxad.net>
	 <cda58cb80703050615r4e559ca1u78517634ac23a27@mail.gmail.com>
	 <1173112433.7093.36.camel@sakura.staff.proxad.net>
	 <cda58cb80703061339l2f8cfc09m5823b090b69a7aa7@mail.gmail.com>
Return-Path: <vagabon.xyz@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14392
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: vagabon.xyz@gmail.com
Precedence: bulk
X-list: linux-mips

On 3/6/07, Franck Bui-Huu <vagabon.xyz@gmail.com> wrote:
> So to fix this you have 2 possibilities:
>
>     - load your kernel at 0x8000xxxx addresses,

OMG, this is totaly crap ! That's what happen when I try to answer and
my brain is not working ! Even if you play with VMA/LMA in your linker
script it won't work...

So forget about this point.
-- 
               Franck

From vagabon.xyz@gmail.com Thu Mar  8 09:02:32 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Mar 2007 09:02:36 +0000 (GMT)
Received: from qb-out-0506.google.com ([72.14.204.232]:60570 "EHLO
	qb-out-0506.google.com") by ftp.linux-mips.org with ESMTP
	id S20021516AbXCHJCc (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 8 Mar 2007 09:02:32 +0000
Received: by qb-out-0506.google.com with SMTP id a33so2119394qbd
        for <linux-mips@linux-mips.org>; Thu, 08 Mar 2007 01:01:22 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=uRX5mmpbwY5tnDEmiPF7WbWDefexyu3Y1qFURrX24Xu0Dvy3ag7Do5/S2awjYPjKUQVqrTt66qt7QQxbvjfY8Tb+Mkl7G3Y61ZXiLRTQHdTmQTa1vPjCKar8vdjSr1KZ/fZ+ifUg0aH5nurxYetC5eE2dcC8SwIqyMw8sqbzaOA=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=DFHPH18E2ivqTnIck4+EaeZRqZCUuJGh02FqnKl/tptrfTbk90mx3iBFDy3mRRH6tpQmkQt4ImHs7P6zt8nIUZbXTg+PpwXT2kl6+hybgehQEsyx72F6p6kQwj6fWXw/fZmIOTYmvANaNpy8WaLfs+W16sPr6kHjG7pedPZpA3w=
Received: by 10.115.111.1 with SMTP id o1mr62957wam.1173344481815;
        Thu, 08 Mar 2007 01:01:21 -0800 (PST)
Received: by 10.114.136.11 with HTTP; Thu, 8 Mar 2007 01:01:21 -0800 (PST)
Message-ID: <cda58cb80703080101g41b4242cu76692d604e83d7ab@mail.gmail.com>
Date:	Thu, 8 Mar 2007 10:01:21 +0100
From:	"Franck Bui-Huu" <vagabon.xyz@gmail.com>
To:	mbizon@freebox.fr
Subject: Re: [PATCH 0/2] FLATMEM: allow memory to start at pfn != 0 [take #2]
Cc:	linux-mips <linux-mips@linux-mips.org>, ralf <ralf@linux-mips.org>
In-Reply-To: <1173286700.6970.24.camel@sakura.staff.proxad.net>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
References: <116841864595-git-send-email-fbuihuu@gmail.com>
	 <1172879147.964.65.camel@sakura.staff.proxad.net>
	 <cda58cb80703050615r4e559ca1u78517634ac23a27@mail.gmail.com>
	 <1173112433.7093.36.camel@sakura.staff.proxad.net>
	 <cda58cb80703061339l2f8cfc09m5823b090b69a7aa7@mail.gmail.com>
	 <1173286700.6970.24.camel@sakura.staff.proxad.net>
Return-Path: <vagabon.xyz@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14393
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: vagabon.xyz@gmail.com
Precedence: bulk
X-list: linux-mips

Hi

On 3/7/07, Maxime Bizon <mbizon@freebox.fr> wrote:
> I found the problem, I think these two liners are missing from your

good catch ! I dunno why this is missing from the original patch since
I have this in my own tree.

> patch. My board now works correctly, with 2MB more free memory, thanks
> for this ! (and for the free tour in mm/ ;)
>

yeah 2MB is quite a lot for embedded system.

>
>
>
> Commit 6f284a2ce7b8bc49cb8455b1763357897a899abb introduced PHYS_OFFSET,
> but missed some virtual to physical address conversion. The following
> patch fixes it.
>
>
> Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
>
> --- linux-2.6.20/include/asm-mips/pgtable.h     2007-02-04 21:22:45.000000000 +0100
> +++ linux/include/asm-mips/pgtable.h    2007-03-07 17:28:20.000000000 +0100
> @@ -75,7 +75,7 @@
>   * Conversion functions: convert a page and protection to a page entry,
>   * and a page entry and page directory to the page they refer to.
>   */
> -#define pmd_phys(pmd)          (pmd_val(pmd) - PAGE_OFFSET)
> +#define pmd_phys(pmd)          (pmd_val(pmd) - PAGE_OFFSET + PHYS_OFFSET)

please use virt_to_phys() instead plain translation...

>  #define pmd_page(pmd)          (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
>  #define pmd_page_vaddr(pmd)    pmd_val(pmd)
>
> --- linux-2.6.20/include/asm-mips/pgtable-64.h  2007-02-04 21:22:45.000000000 +0100
> +++ linux/include/asm-mips/pgtable-64.h 2007-03-07 17:28:47.000000000 +0100
> @@ -199,7 +199,7 @@
>  {
>         return pud_val(pud);
>  }
> -#define pud_phys(pud)          (pud_val(pud) - PAGE_OFFSET)
> +#define pud_phys(pud)          (pud_val(pud) - PAGE_OFFSET + PHYS_OFFSET)

ditto

Ralf, could this patch reach ASAP your main tree ?

thanks
-- 
               Franck

From vagabon.xyz@gmail.com Thu Mar  8 12:49:21 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Mar 2007 12:49:25 +0000 (GMT)
Received: from qb-out-0506.google.com ([72.14.204.230]:40872 "EHLO
	qb-out-0506.google.com") by ftp.linux-mips.org with ESMTP
	id S20021734AbXCHMtV (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 8 Mar 2007 12:49:21 +0000
Received: by qb-out-0506.google.com with SMTP id e12so822992qba
        for <linux-mips@linux-mips.org>; Thu, 08 Mar 2007 04:48:11 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=gJetEInnqI2PnzRBo5AC6cqG7Sv9wXgcJGM3dR51WrhDjRSDTWKvrEugMGb9xD7ZkAySHqR7hHOOQCgLRZV/TSsK7uOwCgCHfR8hLoVcEKOfvl+qL/QHBZPtWEz1tz7CfEmq3O/CO7oQEaGPkQS5Rq0PQj/NqHD3HffMhxZG+L8=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=qmvQkhAYNHcfweufxYnF5KcHynR8ugJdk2LuPE9eI6rNHMixxJ8LwgH8bXnkM7RrtC+Rynqv5kkPoIvrt1Z1mDWY5IIMCSyUwL+o8HiVAZYW+xGhm7KTVD23ZGxexH10L+0rTxJ8+GG+VhObXJPpQWZJ1YiwE9M66GZmVAwtIxM=
Received: by 10.114.152.17 with SMTP id z17mr133140wad.1173358090775;
        Thu, 08 Mar 2007 04:48:10 -0800 (PST)
Received: by 10.114.136.11 with HTTP; Thu, 8 Mar 2007 04:48:10 -0800 (PST)
Message-ID: <cda58cb80703080448yca7fa21xb005e0685d42d318@mail.gmail.com>
Date:	Thu, 8 Mar 2007 13:48:10 +0100
From:	"Franck Bui-Huu" <vagabon.xyz@gmail.com>
To:	"Jim Gifford" <maillist@jg555.com>
Subject: Re: Building 64 bit kernel on Cobalt
Cc:	"Ralf Baechle" <ralf@linux-mips.org>,
	"Linux MIPS List" <linux-mips@linux-mips.org>
In-Reply-To: <45EFA92C.3070203@jg555.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
References: <45EB53D5.8060007@jg555.com>
	 <20070304232731.GA25039@linux-mips.org> <45EFA92C.3070203@jg555.com>
Return-Path: <vagabon.xyz@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14394
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: vagabon.xyz@gmail.com
Precedence: bulk
X-list: linux-mips

Hi,

On 3/8/07, Jim Gifford <maillist@jg555.com> wrote:
> Ralf Baechle wrote:
> > On Sun, Mar 04, 2007 at 03:18:45PM -0800, Jim Gifford wrote:
> >
> >
> >> Last working Kernel was 2.6.19 series.
> >>

It seems that I broke things again :(

> >> Some changes from 2.6.19 and the 2.6.20 make it impossible to build a 64
> >> bit kernel to boot on the cobalt. Ya, I know why, building a N32
> >> actually but need a 64 bit kernel in order to do that. Anyone got any
> >> suggestions. Looking through the difference between the kernels to
> >> figure this out, but it's like looking for a needle in a haystack. Any
> >> suggestions as to a starting point?
> >>
> >
> > Try git-bisect to track down the changeset that broke things.
> >
> >   Ralf
> >
> >
> We got it nailed down to arch/mips/kernel /setup.c. But we have not
> isolated which change is actually causing it.
>

Do you use any initrd ? If so how do you pass its address to the kernel ?

What is your kernel load address ?

can you send your .config file you're using ?

> We do know that reverting back to the 2.6.19.x arch/mips/kernel /setup.c
> will fix the issue. We will continue to dwindle it down until we come up
> with the offender.
>
>

What did the console say ? If nothing early console may help if available.

thanks
-- 
               Franck

From anemo@mba.ocn.ne.jp Thu Mar  8 15:39:11 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Mar 2007 15:39:16 +0000 (GMT)
Received: from mba.ocn.ne.jp ([122.1.175.29]:14785 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20021756AbXCHPjL (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Mar 2007 15:39:11 +0000
Received: from localhost (p8013-ipad201funabasi.chiba.ocn.ne.jp [222.146.71.13])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id 0007CBA41; Fri,  9 Mar 2007 00:37:49 +0900 (JST)
Date:	Fri, 09 Mar 2007 00:37:49 +0900 (JST)
Message-Id: <20070309.003749.39154822.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org, kraj@mvista.com, libc-ports@sourceware.org
Subject: Re: [PATCH] Fix some system calls with long long arguments
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
In-Reply-To: <20070307.231410.15268922.anemo@mba.ocn.ne.jp>
References: <20070307.003931.25235381.anemo@mba.ocn.ne.jp>
	<20070307.231410.15268922.anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14395
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

On Wed, 07 Mar 2007 23:14:10 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote:
> fadvise64(), readahead(), sync_file_range() have long long argument(s)
> but glibc passes it by hi/lo pair without padding, on both O32 and
> N32.
> 
> Also wire up fadvise64_64() and fixup confusion of it with
> fadvise64().

If best performance was preferred, the O32 readahead and
sync_file_range should not changed and libc should provide MIPS
specific syscall wrappers, like pread64.  The N32 can also use
standard sys_readahead(), etc. and libc should provide wrappers, too.

Anyway fadvice64() needs to be fixed.

Any comments from libc side?  Original patch is here:
http://www.linux-mips.org/archives/linux-mips/2007-03/msg00092.html

---
Atsushi Nemoto

From maillist@jg555.com Thu Mar  8 16:12:21 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Mar 2007 16:12:25 +0000 (GMT)
Received: from rrcs-64-183-102-11.west.biz.rr.com ([64.183.102.11]:55498 "EHLO
	jg555.com") by ftp.linux-mips.org with ESMTP id S20021759AbXCHQMV
	(ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 8 Mar 2007 16:12:21 +0000
Received: from [192.168.55.157] ([::ffff:192.168.55.157])
  (AUTH: PLAIN root, TLS: TLSv1/SSLv3,256bits,AES256-SHA)
  by jg555.com with esmtp; Thu, 08 Mar 2007 08:11:17 -0800
  id 00340293.45F035A5.00003B40
Message-ID: <45F0359A.105@jg555.com>
Date:	Thu, 08 Mar 2007 08:11:06 -0800
From:	Jim Gifford <maillist@jg555.com>
User-Agent: Thunderbird 1.5.0.10 (Windows/20070221)
MIME-Version: 1.0
To:	Franck Bui-Huu <vagabon.xyz@gmail.com>
CC:	Ralf Baechle <ralf@linux-mips.org>,
	Linux MIPS List <linux-mips@linux-mips.org>
Subject: Re: Building 64 bit kernel on Cobalt
References: <45EB53D5.8060007@jg555.com>	 <20070304232731.GA25039@linux-mips.org> <45EFA92C.3070203@jg555.com> <cda58cb80703080448yca7fa21xb005e0685d42d318@mail.gmail.com>
In-Reply-To: <cda58cb80703080448yca7fa21xb005e0685d42d318@mail.gmail.com>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <maillist@jg555.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14396
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: maillist@jg555.com
Precedence: bulk
X-list: linux-mips

Franck Bui-Huu wrote:
> Hi,
>
> On 3/8/07, Jim Gifford <maillist@jg555.com> wrote:
>> Ralf Baechle wrote:
>> > On Sun, Mar 04, 2007 at 03:18:45PM -0800, Jim Gifford wrote:
>> >
>> >
>> >> Last working Kernel was 2.6.19 series.
>> >>
>
> It seems that I broke things again :(
>
>> >> Some changes from 2.6.19 and the 2.6.20 make it impossible to 
>> build a 64
>> >> bit kernel to boot on the cobalt. Ya, I know why, building a N32
>> >> actually but need a 64 bit kernel in order to do that. Anyone got any
>> >> suggestions. Looking through the difference between the kernels to
>> >> figure this out, but it's like looking for a needle in a haystack. 
>> Any
>> >> suggestions as to a starting point?
>> >>
>> >
>> > Try git-bisect to track down the changeset that broke things.
>> >
>> >   Ralf
>> >
>> >
>> We got it nailed down to arch/mips/kernel /setup.c. But we have not
>> isolated which change is actually causing it.
>>
>
> Do you use any initrd ? If so how do you pass its address to the kernel ?
No.
>
> What is your kernel load address ?
Not sure
>
> can you send your .config file you're using ?
I'll send it to you later, since I'm not at the office right now.
>
>> We do know that reverting back to the 2.6.19.x arch/mips/kernel /setup.c
>> will fix the issue. We will continue to dwindle it down until we come up
>> with the offender.
>>
>>
>
> What did the console say ? If nothing early console may help if 
> available.
All I get is this
inflate: decompressing
elf64: 00080000 - 0037701f (ffffffff.80326000) (ffffffff.80000000)
elf64: ffffffff.80080000 (80080000) 2957446t + 151450t
net: interface down

>
> thanks


From stjeanma@pmc-sierra.com Thu Mar  8 20:20:16 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Mar 2007 20:20:22 +0000 (GMT)
Received: from father.pmc-sierra.com ([216.241.224.13]:57337 "HELO
	father.pmc-sierra.bc.ca") by ftp.linux-mips.org with SMTP
	id S20021763AbXCHUUQ (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 8 Mar 2007 20:20:16 +0000
Received: (qmail 11340 invoked by uid 101); 8 Mar 2007 20:19:04 -0000
Received: from unknown (HELO pmxedge1.pmc-sierra.bc.ca) (216.241.226.183)
  by father.pmc-sierra.com with SMTP; 8 Mar 2007 20:19:04 -0000
Received: from pasqua.pmc-sierra.bc.ca (pasqua.pmc-sierra.bc.ca [134.87.183.161])
	by pmxedge1.pmc-sierra.bc.ca (8.13.4/8.12.7) with ESMTP id l28KItoM004994;
	Thu, 8 Mar 2007 12:18:55 -0800
From:	Marc St-Jean <stjeanma@pmc-sierra.com>
Received: (from stjeanma@localhost)
	by pasqua.pmc-sierra.bc.ca (8.13.4/8.12.11) id l28KIeqt017408;
	Thu, 8 Mar 2007 14:18:40 -0600
Date:	Thu, 8 Mar 2007 14:18:40 -0600
Message-Id: <200703082018.l28KIeqt017408@pasqua.pmc-sierra.bc.ca>
To:	linux-kernel@vger.kernel.org
Subject: [PATCH] drivers: PMC MSP71xx GPIO char driver
Cc:	linux-mips@linux-mips.org
Return-Path: <stjeanma@pmc-sierra.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14397
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: stjeanma@pmc-sierra.com
Precedence: bulk
X-list: linux-mips

[PATCH] drivers: PMC MSP71xx GPIO char driver

Patch to add a GPIO char driver for the PMC-Sierra
MSP71xx devices.

This patch references some platform support files previously
submitted to the linux-mips@linux-mips.org list.

Thanks,
Marc

Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
---
Re-posting patch with recommended changes:
-Cleanup on style and formatting for comments, macros, etc.
-Moved some driver private data structures from .h to .c.
-Eliminated MSP_GPIO_BIT macro.
-Added call to new read_reg32 function to eliminate need
for use of volatile keyword.
-Made use of schedule_timeout_interruptible() call instead
of multiple calls.
-Added calls to kthread_should_stop and try_to_freeze().

 drivers/char/Kconfig                           |    4 
 drivers/char/Makefile                          |    1 
 drivers/char/pmcmsp_gpio.c                     |  644 +++++++++++++++++++++++++
 include/asm-mips/pmc-sierra/msp71xx/msp_gpio.h |   98 +++
 4 files changed, 747 insertions(+)

diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index ed5453f..dea96a0 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -372,6 +372,10 @@ config ISTALLION
 	  To compile this driver as a module, choose M here: the
 	  module will be called istallion.
 
+config PMCMSP_GPIO
+	tristate "PMC MSP 7120 GPIO device support"
+	depends on MIPS && (PMC_MSP7120_EVAL || PMC_MSP7120_GW || PMC_MSP7120_FPGA)
+	  
 config AU1X00_GPIO
 	tristate "Alchemy Au1000 GPIO device support"
 	depends on MIPS && SOC_AU1X00
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 3ed7647..9abbcc1 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_DS1620)		+= ds1620.o
 obj-$(CONFIG_HW_RANDOM)		+= hw_random/
 obj-$(CONFIG_COBALT_LCD)	+= lcd.o
 obj-$(CONFIG_AU1000_GPIO)	+= au1000_gpio.o
+obj-$(CONFIG_PMCMSP_GPIO)	+= pmcmsp_gpio.o
 obj-$(CONFIG_PPDEV)		+= ppdev.o
 obj-$(CONFIG_NWBUTTON)		+= nwbutton.o
 obj-$(CONFIG_NWFLASH)		+= nwflash.o
diff --git a/drivers/char/pmcmsp_gpio.c b/drivers/char/pmcmsp_gpio.c
new file mode 100644
index 0000000..e2d65bd
--- /dev/null
+++ b/drivers/char/pmcmsp_gpio.c
@@ -0,0 +1,644 @@
+/*
+ * Driver for the PMC MSP7120 reference board GPIO pins
+ *
+ * Copyright 2005-2007 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+
+#include <asm/io.h>
+#include <asm/war.h>
+#include <asm/regops.h>
+
+#include <msp_regs.h>
+#include <msp_gpio.h>
+
+/* -- Private definitions -- */
+
+/* Special bitflags and whatnot for the driver's convenience */
+#define GPIO_REG_COUNT		4
+const u32 GPIO_DATA_COUNT[] = { 2, 4, 4, 6 };
+const u32 GPIO_DATA_SHIFT[] = { 0, 2, 6, 10 };
+const u32 GPIO_DATA_MASK[] = { 0x03, 0x0f, 0x0f, 0x3f };
+u32 * const GPIO_DATA_REG[] = {
+	(u32 *)GPIO_DATA1_REG, (u32 *)GPIO_DATA2_REG,
+	(u32 *)GPIO_DATA3_REG, (u32 *)GPIO_DATA4_REG,
+};
+const u32 GPIO_CFG_MASK[] = { 0x0000ff, 0x00ffff, 0x00ffff, 0xffffff };
+u32 * const GPIO_CFG_REG[] = {
+	(u32 *)GPIO_CFG1_REG, (u32 *)GPIO_CFG2_REG,
+	(u32 *)GPIO_CFG3_REG, (u32 *)GPIO_CFG4_REG,
+};
+
+#define GPIO_CFG_SHIFT(i)	(i * 4)
+#define GPIO_CFG_PINMASK	0xf
+
+/* The extended gpio register */
+
+#define EXTENDED_GPIO_COUNT	4
+#define EXTENDED_GPIO_SHIFT	16
+#define EXTENDED_GPIO_MASK	0x0f
+
+#define EXTENDED_GPIO_DATA_SHIFT(i)	(i * 2)
+#define EXTENDED_GPIO_DATA_MASK(i)	(0x3 << (i*2))
+#define EXTENDED_GPIO_DATA_SET		0x2
+#define EXTENDED_GPIO_DATA_CLR		0x1
+#define EXTENDED_GPIO_CFG_SHIFT(i)	((i * 2) + 16)
+#define EXTENDED_GPIO_CFG_MASK(i)	(0x3 << ((i*2)+16))
+#define EXTENDED_GPIO_CFG_DISABLE	0x2
+#define EXTENDED_GPIO_CFG_ENABLE	0x1
+
+/* -- Data structures -- */
+
+static DEFINE_SPINLOCK(msp_gpio_spinlock);
+
+static struct task_struct *msp_blinkthread;
+static DEFINE_SPINLOCK(msp_blink_lock);
+static DECLARE_COMPLETION(msp_blink_wait);
+
+struct blink_table {
+	u32 count;
+	u32 period;
+	u32 dcycle;
+};
+
+static struct blink_table blink_table[MSP_NUM_GPIOS];
+
+/* -- Utility functions -- */
+
+/* Define the following for extra debug output */
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...) do {} while (0)
+#endif
+
+/* Reads the data bits from a single register set */
+static u32 msp_gpio_read_data_basic(int reg)
+{
+	return read_reg32(GPIO_DATA_REG[reg], GPIO_DATA_MASK[reg]);
+}
+
+/* Reads the data bits from the extended register set */
+static u32 msp_gpio_read_data_extended(void)
+{
+	int pin;
+	u32 tmp = *EXTENDED_GPIO_REG;
+	u32 retval = 0;
+	
+	for (pin = 0; pin < EXTENDED_GPIO_COUNT; pin++) {
+		u32 bit = 0;
+		
+		/*
+		 * In output mode, read CLR bit
+		 * In input mode, read SET bit
+		 */
+		if (tmp & (EXTENDED_GPIO_CFG_ENABLE <<
+				EXTENDED_GPIO_CFG_SHIFT(pin)))
+			bit = EXTENDED_GPIO_DATA_CLR <<
+				EXTENDED_GPIO_DATA_SHIFT(pin);
+		else
+			bit = EXTENDED_GPIO_DATA_SET <<
+				EXTENDED_GPIO_DATA_SHIFT(pin);
+
+		if (tmp & bit)
+			retval |= 1 << pin;
+	}
+	
+	return retval;
+}
+
+/*
+ * Reads the current state of all 20 pins, putting the values in
+ * the lowest 20 bits (1=HI, 0=LO)
+ */
+static u32 msp_gpio_read_data(void)
+{
+	int reg;
+	u32 retval = 0;
+	
+	spin_lock(&msp_gpio_spinlock);
+	for (reg = 0; reg < GPIO_REG_COUNT; reg++)
+		retval |= msp_gpio_read_data_basic(reg) <<
+				GPIO_DATA_SHIFT[reg];
+	retval |= msp_gpio_read_data_extended() << EXTENDED_GPIO_SHIFT;
+	spin_unlock(&msp_gpio_spinlock);
+	
+	DBG("%s: 0x%08x\n", __FUNCTION__, retval);
+	return retval;
+}
+
+/*
+ * This assumes both data and mask are register-ready, and does
+ * the set atomically
+ */
+static void msp_gpio_write_data_basic(int reg, u32 data, u32 mask)
+{
+	set_value_reg32(GPIO_DATA_REG[reg], mask, data);
+}
+
+/*
+ * The four lowest bits of 'data' and 'mask' are used, and the set
+ * is done atomically
+ */
+static void msp_gpio_write_data_extended(u32 data, u32 mask)
+{
+	int i;
+	u32 tmpmask = 0xffffffff, tmpdata = 0;
+
+	/* Set all SET/CLR values based on data bits passed in */
+	for (i = 0; i < EXTENDED_GPIO_COUNT; i++) {
+		if (mask & (1 << i)) {
+			if (data & (1 << i))
+				/* Set the bit HI */
+				tmpdata |= EXTENDED_GPIO_DATA_SET <<
+					   EXTENDED_GPIO_DATA_SHIFT(i);
+			else
+				/* Set the bit LO */
+				tmpdata |= EXTENDED_GPIO_DATA_CLR <<
+					   EXTENDED_GPIO_DATA_SHIFT(i);
+		}
+	}
+	
+	set_value_reg32(EXTENDED_GPIO_REG, tmpmask, tmpdata);
+}
+
+/*
+ * Sets all masked GPIOs based on the first 20 bits of the data
+ * passed in (1=HI, 0=LO)
+ */
+static void msp_gpio_write_data(u32 data, u32 mask)
+{
+	int reg;
+	
+	spin_lock(&msp_gpio_spinlock);
+	for (reg = 0; reg < GPIO_REG_COUNT; reg++) {
+		u32 tmpdata = (data >> GPIO_DATA_SHIFT[reg]) &
+					GPIO_DATA_MASK[reg];
+		u32 tmpmask = (mask >> GPIO_DATA_SHIFT[reg]) &
+					GPIO_DATA_MASK[reg];
+		if (tmpmask > 0)
+			msp_gpio_write_data_basic(reg, tmpdata, tmpmask);
+	}
+	msp_gpio_write_data_extended(data >> EXTENDED_GPIO_SHIFT,
+					mask >> EXTENDED_GPIO_SHIFT);
+	spin_unlock(&msp_gpio_spinlock);
+}
+
+/* Reads the config bits from a single register set */
+static u32 msp_gpio_read_cfg_basic(int reg)
+{
+	return read_reg32(GPIO_CFG_REG[reg], GPIO_CFG_MASK[reg]);
+}
+
+/*
+ * This assumes both data and mask are register-ready, and does
+ * the write atomically
+ */
+static void msp_gpio_write_cfg_basic(int reg, u32 data, u32 mask)
+{
+	set_value_reg32(GPIO_CFG_REG[reg], mask, data);
+}
+
+/*
+ * Reads the configuration of the extended pins, returning the current
+ * configuration in the lowest 4 bits (1-output, 0-input)
+ */
+static u32 msp_gpio_read_cfg_extended(void)
+{
+	int i;
+	u32 tmp = *EXTENDED_GPIO_REG;
+	u32 retval = 0;
+
+	/* Read all ENABLE/DISABLE values and translate to single bits */
+	for (i = 0; i < EXTENDED_GPIO_COUNT; i++) {
+		if (tmp & (EXTENDED_GPIO_CFG_ENABLE <<
+				EXTENDED_GPIO_CFG_SHIFT(i)))
+			/* Pin is OUTPUT */
+			retval |= 1 << i;
+		else
+			/* Pin is INPUT */
+			retval &= ~(1 << i);
+	}
+	
+	return retval;
+}
+
+/*
+ * Sets the masked extended pins to (1-output, 0-input)
+ * (uses 4 lowest bits of the mask)
+ * Does the write atomically
+ */
+static void msp_gpio_write_cfg_extended(u32 data, u32 mask)
+{
+	int i;
+	u32 tmpmask = 0xffffffff, tmpdata = 0;
+
+	/* Set all ENABLE/DISABLE values based on mask bits passed in */
+	for (i = 0; i < EXTENDED_GPIO_COUNT; i++) {
+		if (mask & (1 << i)) {
+			if (data & (1 << i))
+				/* Set the pin to OUTPUT */
+				tmpdata |= EXTENDED_GPIO_CFG_ENABLE <<
+					   EXTENDED_GPIO_CFG_SHIFT(i);
+			else
+				/* Set the pin to INPUT */
+				tmpdata |= EXTENDED_GPIO_CFG_DISABLE <<
+					   EXTENDED_GPIO_CFG_SHIFT(i);
+		}
+	}
+	
+	set_value_reg32(EXTENDED_GPIO_REG, tmpmask, tmpdata);
+}
+
+/*
+ * Sets all GPIOs to input/output based on the first 20 bits of the mask
+ * (1-output, 0-input)
+ */
+static void msp_gpio_write_cfg(msp_gpio_mode_t mode, u32 mask)
+{
+	int reg;
+	u32 extdata = 0, extmask = 0;
+	
+	spin_lock(&msp_gpio_spinlock);
+	for (reg = 0; reg < GPIO_REG_COUNT; reg++) {
+		int pin;
+		u32 tmpdata = 0, tmpmask = 0;
+		for (pin = 0; pin < GPIO_DATA_COUNT[reg]; pin++) {
+			if (mask & (1 << (GPIO_DATA_SHIFT[reg] + pin))) {
+				tmpmask |= GPIO_CFG_PINMASK <<
+					   GPIO_CFG_SHIFT(pin);
+				tmpdata |= (u32)mode <<
+					   GPIO_CFG_SHIFT(pin);
+			}
+		}
+		if (tmpmask)
+			msp_gpio_write_cfg_basic(reg, tmpdata, tmpmask);
+	}
+
+	extmask = mask >> EXTENDED_GPIO_SHIFT;
+	if (mode == MSP_GPIO_INPUT)
+		extdata = 0;
+	else if (mode == MSP_GPIO_OUTPUT)
+		extdata = 0xf;
+	else
+		extmask = 0;
+	if (extmask)
+		msp_gpio_write_cfg_extended(extdata, extmask);
+	spin_unlock(&msp_gpio_spinlock);
+}
+
+/*
+ * Reads all GPIO config values and checks if they match the pin mode given,
+ * placing the result in the lowest 20 bits of the result, one bit per pin
+ * (1-pin matches mode give, 0-pin does not match)
+ */
+static u32 msp_gpio_read_cfg(u32 mode)
+{
+	u32 retval = 0;
+	int reg;
+	
+	spin_lock(&msp_gpio_spinlock);
+	for (reg = 0; reg < GPIO_REG_COUNT; reg++) {
+		int pin;
+		u32 tmpdata = msp_gpio_read_cfg_basic(reg);
+		for (pin = 0; pin < GPIO_DATA_COUNT[reg]; pin++) {
+			u32 val = (tmpdata >> GPIO_CFG_SHIFT(pin)) &
+					GPIO_CFG_PINMASK;
+			if (val == mode)
+				retval |= 1 << (GPIO_DATA_SHIFT[reg] + pin);
+		}
+	}
+	
+	/* Extended pins only have INPUT or OUTPUT pins */
+	if (mode == MSP_GPIO_INPUT)
+		retval |= (~msp_gpio_read_cfg_extended() & EXTENDED_GPIO_MASK)
+			  << EXTENDED_GPIO_SHIFT;
+	else if (mode == MSP_GPIO_OUTPUT)
+		retval |= (msp_gpio_read_cfg_extended() & EXTENDED_GPIO_MASK)
+			  << EXTENDED_GPIO_SHIFT;
+	spin_unlock(&msp_gpio_spinlock);
+	
+	DBG("%s(0x%02x): 0x%08x\n", __FUNCTION__, mode, retval);
+	return retval;
+}
+
+/* -- Public functions -- */
+
+/*
+ * Reads the bits specified by the mask and puts the values in data.
+ * May include output statuses also, if in mask.
+ *
+ * Returns 0 on success
+ */
+int msp_gpio_in(u32 *data, u32 mask)
+{
+	*data = msp_gpio_read_data() & mask;
+	
+	return 0;
+}
+
+/*
+ * Sets the specified data on the masked pins
+ *
+ * Returns 0 on success or one of the following:
+ *  -EINVAL if any of the pins in the mask are not free or not already
+ *  in output mode
+ */
+int msp_gpio_out(u32 data, u32 mask)
+{
+	if ((mask & ~MSP_GPIO_FREE_MASK) != 0) {
+		printk(KERN_WARNING
+			"Invalid GPIO mask - References non-free pins\n");
+		return -EINVAL;
+	}
+	if ((mask & ~msp_gpio_read_cfg(MSP_GPIO_OUTPUT)) != 0) {
+		printk(KERN_WARNING
+			"Invalid GPIO mask - Cannot set non-output pins\n");
+		return -EINVAL;
+	}
+	
+	msp_gpio_noblink(mask);
+	msp_gpio_write_data(data, mask);
+
+	return 0;
+}
+
+/*
+ * Sets masked pins to the specified msp_gpio_mode_t
+ *
+ * Returns 0 on success or one of the following:
+ *  -EINVAL if any of the pins in the mask are not free or if any pins
+ *  are not allowed to be set to the specified mode
+ */
+int msp_gpio_mode(msp_gpio_mode_t mode, u32 mask)
+{
+	u32 allowedmask;
+
+	if ((mask & ~MSP_GPIO_FREE_MASK) != 0) {
+		printk(KERN_WARNING
+			"Invalid GPIO mask - References non-free pins\n");
+		return -EINVAL;
+	}
+	
+	/* Enforce pin-mode rules */
+	allowedmask = MSP_GPIO_MODE_ALLOWED[mode];
+	if ((mask & ~allowedmask) != 0) {
+		printk(KERN_WARNING
+			"Invalid GPIO mode for masked pins\n");
+		return -EINVAL;
+	}
+
+	msp_gpio_noblink(mask);
+	msp_gpio_write_cfg(mode, mask);
+
+	return 0;
+}
+
+/*
+ * Stops the specified GPIOs from blinking
+ */
+int msp_gpio_noblink(u32 mask)
+{
+	int i;
+
+	if ((mask & ~msp_gpio_read_cfg(MSP_GPIO_OUTPUT)) != 0)
+		return -EINVAL;
+
+	spin_lock(&msp_blink_lock);
+	for (i = 0; i < MSP_NUM_GPIOS; i++) {
+		if (mask & (1 << i)) {
+			blink_table[i].count = 0;
+			blink_table[i].period = 0;
+			blink_table[i].dcycle = 0;
+		}
+	}
+	spin_unlock(&msp_blink_lock);
+
+	msp_gpio_write_data(0, mask);
+
+	return 0;
+}
+
+/*
+ * Configures GPIO(s) to blink
+ *  - mask shows which GPIOs to blink
+ *  - period is the time in 100ths of a second for the total period
+ *    (0 disables blinking)
+ *  - dcycle is the percentage of the period where the GPIO is HI
+ */
+int msp_gpio_blink(u32 mask, u32 period, u32 dcycle)
+{
+	int i;
+
+	if ((mask & ~msp_gpio_read_cfg(MSP_GPIO_OUTPUT)) != 0) {
+		printk(KERN_WARNING
+			"Invalid GPIO mask - Cannot blink non-output pins\n");
+		return -EINVAL;
+	}
+
+	if (period == 0) 
+		return msp_gpio_noblink(mask);
+
+	spin_lock(&msp_blink_lock);
+	for (i = 0; i < MSP_NUM_GPIOS; i++) {
+		if (mask & (1 << i)) {
+			blink_table[i].count = 0;
+			blink_table[i].period = period;
+			blink_table[i].dcycle = dcycle;
+		}
+	}
+	spin_unlock(&msp_blink_lock);
+
+	complete(&msp_blink_wait);
+
+	return 0;
+}
+
+/* -- File functions -- */
+
+static int msp_gpio_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int msp_gpio_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int msp_gpio_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	static struct msp_gpio_ioctl_io_data data;
+	static struct msp_gpio_ioctl_blink_data blink;
+
+	switch (cmd) {
+	case MSP_GPIO_BLINK:
+		if (copy_from_user(&blink,
+		    (struct msp_gpio_ioctl_blink_data *)arg, sizeof(blink)))
+			return -EFAULT;
+		break;
+	default:
+		if (copy_from_user(&data,
+		    (struct msp_gpio_ioctl_io_data *)arg, sizeof(data)))
+			return -EFAULT;
+		break;
+	}
+
+	switch (cmd) {
+	case MSP_GPIO_IN:
+		if (msp_gpio_in(&data.data, data.mask))
+			return -EFAULT;
+		if (copy_to_user((struct msp_gpio_ioctl_io_data *)arg,
+		    &data, sizeof(data)))
+			return -EFAULT;
+		break;
+	case MSP_GPIO_OUT:
+		if (msp_gpio_out(data.data, data.mask))
+			return -EFAULT;
+		break;
+	case MSP_GPIO_MODE:
+		if (msp_gpio_mode( data.data, data.mask))
+			return -EFAULT;
+		break;
+	case MSP_GPIO_BLINK:
+		if (msp_gpio_blink(blink.mask, blink.period, blink.dcycle))
+			return -EFAULT;
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	
+	return 0;
+}
+
+static struct file_operations msp_gpio_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= msp_gpio_ioctl,
+	.open		= msp_gpio_open,
+	.release	= msp_gpio_release,
+};
+
+static struct miscdevice msp_gpio_miscdev = {
+	MISC_DYNAMIC_MINOR,
+	"pmcmsp_gpio",
+	&msp_gpio_fops
+};
+
+static int msp_gpio_blinkthread(void *none)
+{
+	int firstrun = 1;
+	
+	do {
+		u32 mask = 0, data = 0;
+		int i, blinking = 0;
+		spin_lock(&msp_blink_lock);
+		for (i = 0; i < MSP_NUM_GPIOS; i++) {
+			/* use blink_table[i].period as 'blink enabled' test */
+			if (blink_table[i].period) {
+				blinking = 1;
+				mask |= 1 << i;
+				blink_table[i].count++;
+
+				if (blink_table[i].count >=
+				    blink_table[i].period)
+					blink_table[i].count = 0;
+
+				if (blink_table[i].count <
+				    (blink_table[i].period *
+				    blink_table[i].dcycle / 100))
+					data |= 1 << i;
+			}
+		}
+		spin_unlock(&msp_blink_lock);
+
+		if (!firstrun || blinking)
+			msp_gpio_write_data(data, mask);
+		else
+			firstrun = 0;
+
+		if (blinking)
+			schedule_timeout_interruptible(HZ/100);
+		else
+			wait_for_completion_interruptible(&msp_blink_wait);
+		
+		/* Thread may have been woken up to freeze or to exit */
+		try_to_freeze();
+	} while (!kthread_should_stop());
+
+	return 0;
+}
+
+/* -- Module functions -- */
+
+static int __init msp_gpio_init(void)
+{
+	if (misc_register(&msp_gpio_miscdev)) {
+		printk(KERN_ERR "Device registration failed\n");
+		goto err_miscdev;
+	}
+
+	msp_blinkthread = kthread_run(msp_gpio_blinkthread,NULL, "gpio_blink");
+	if (msp_blinkthread == NULL) {
+		printk(KERN_ERR "Could not start kthread\n");
+		goto err_blinkthread;
+	}
+
+	printk(KERN_WARNING "MSP7120 GPIO subsystem initialized\n");
+	return 0;
+
+err_blinkthread:
+	misc_deregister(&msp_gpio_miscdev);
+err_miscdev:
+	return -ENOMEM;
+}
+
+static void __exit msp_gpio_exit(void)
+{
+	complete(&msp_blink_wait);
+	kthread_stop(msp_blinkthread);
+
+	misc_deregister(&msp_gpio_miscdev);
+}
+
+EXPORT_SYMBOL(msp_gpio_in);
+EXPORT_SYMBOL(msp_gpio_out);
+EXPORT_SYMBOL(msp_gpio_mode);
+EXPORT_SYMBOL(msp_gpio_blink);
+EXPORT_SYMBOL(msp_gpio_noblink);
+
+MODULE_DESCRIPTION("PMC MSP GPIO driver");
+MODULE_LICENSE("GPL");
+
+module_init(msp_gpio_init);
+module_exit(msp_gpio_exit);
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_gpio.h b/include/asm-mips/pmc-sierra/msp71xx/msp_gpio.h
new file mode 100644
index 0000000..3c930ed
--- /dev/null
+++ b/include/asm-mips/pmc-sierra/msp71xx/msp_gpio.h
@@ -0,0 +1,98 @@
+/*
+ * Character driver for the PMC Athena (MSP7120) reference board GPIO pins
+ *
+ * Copyright 2005-2007 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MSP_GPIO_H__
+#define __MSP_GPIO_H__
+
+#include <linux/ioctl.h>
+
+#include <msp_gpio_macros.h>
+
+/* IOCTL structs macros */
+
+struct msp_gpio_ioctl_io_data {
+	u32 data;
+	u32 mask;
+};
+
+struct msp_gpio_ioctl_blink_data {
+	u32 mask;
+	u32 period;
+	u32 dcycle;
+};
+
+#define MSP_GPIO_IOCTL_BASE	'Z'
+
+/* Reads the current data bits */
+#define MSP_GPIO_IN	_IOWR(MSP_GPIO_IOCTL_BASE, 0, \
+			      struct msp_gpio_ioctl_io_data)
+
+/* Writes data bits */
+#define MSP_GPIO_OUT	_IOW(MSP_GPIO_IOCTL_BASE, 1, \
+			      struct msp_gpio_ioctl_io_data)
+
+/* Sets all masked pins to the msp_gpio_mode_t given in the data field */
+#define MSP_GPIO_MODE	_IOW(MSP_GPIO_IOCTL_BASE, 2, \
+			      struct msp_gpio_ioctl_io_data)
+
+/* 
+ * Starts any masked LEDs blinking with parameters as follows:
+ *   - period - The time in 100ths of a second for a single period
+ *              (set to '0' to stop blinking)
+ *   - dcycle - The 'duty cycle' - what percentage of the period should
+ *              the gpio be on?
+ */
+#define MSP_GPIO_BLINK	_IOW(MSP_GPIO_IOCTL_BASE, 3, \
+			      struct msp_gpio_ioctl_blink_data)
+
+/* Bit flags and masks for GPIOs */
+#define MSP_NUM_GPIOS		20
+#define MSP_GPIO_ALL_MASK 	((1 << MSP_NUM_GPIOS) - 1)
+#define MSP_GPIO_NONE_MASK 	0LL
+#define MSP_GPIO_FREE_MASK	MSP_GPIO_ALL_MASK
+
+/* The following is only available to other modules */
+
+#ifdef __KERNEL__
+
+/* Reads the bits specified by the mask and puts the values in data */
+extern int msp_gpio_in(u32 *data, u32 mask);
+
+/* Sets the specified data on the masked pins */
+extern int msp_gpio_out(u32 data, u32 mask);
+
+/* Sets masked pins to the specified msp_gpio_mode_t */
+extern int msp_gpio_mode(msp_gpio_mode_t mode, u32 mask);
+
+/* Stops the specified GPIOs from blinking */
+extern int msp_gpio_noblink(u32 mask);
+
+/* Configures GPIO(s) to blink */
+int msp_gpio_blink(u32 mask, u32 period, u32 dcycle);
+
+#endif /* __KERNEL__ */
+
+#endif /* !__MSP_GPIO_H__ */

From stjeanma@pmc-sierra.com Thu Mar  8 23:25:34 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Mar 2007 23:25:40 +0000 (GMT)
Received: from mother.pmc-sierra.com ([216.241.224.12]:4552 "HELO
	mother.pmc-sierra.bc.ca") by ftp.linux-mips.org with SMTP
	id S20021288AbXCHXZe (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 8 Mar 2007 23:25:34 +0000
Received: (qmail 9053 invoked by uid 101); 8 Mar 2007 23:24:23 -0000
Received: from unknown (HELO pmxedge1.pmc-sierra.bc.ca) (216.241.226.183)
  by mother.pmc-sierra.com with SMTP; 8 Mar 2007 23:24:23 -0000
Received: from pasqua.pmc-sierra.bc.ca (pasqua.pmc-sierra.bc.ca [134.87.183.161])
	by pmxedge1.pmc-sierra.bc.ca (8.13.4/8.12.7) with ESMTP id l28NOME9018428;
	Thu, 8 Mar 2007 15:24:22 -0800
From:	Marc St-Jean <stjeanma@pmc-sierra.com>
Received: (from stjeanma@localhost)
	by pasqua.pmc-sierra.bc.ca (8.13.4/8.12.11) id l28NODOl023442;
	Thu, 8 Mar 2007 17:24:13 -0600
Date:	Thu, 8 Mar 2007 17:24:13 -0600
Message-Id: <200703082324.l28NODOl023442@pasqua.pmc-sierra.bc.ca>
To:	linux-kernel@vger.kernel.org
Subject: [PATCH] drivers: PMC MSP71xx TWI driver
Cc:	linux-mips@linux-mips.org
Return-Path: <stjeanma@pmc-sierra.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14398
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: stjeanma@pmc-sierra.com
Precedence: bulk
X-list: linux-mips

[PATCH] drivers: PMC MSP71xx TWI driver

Patch to add TWI driver for the PMC-Sierra MSP71xx devices.

This patch references some platform support files previously
submitted to the linux-mips@linux-mips.org list.

Thanks,
Marc

Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
---
Re-posting patch with recommended changes:
-Cleanup on style and formatting for comments, macros, etc.
-Moved some driver private data structures from .h to .c.
-Removed casting of RHS void *.
-Changed priv_data.lock from a semaphore to a mutex.

 drivers/i2c/algos/Kconfig           |    9 
 drivers/i2c/algos/Makefile          |    1 
 drivers/i2c/algos/i2c-algo-pmctwi.c |  197 ++++++++++++++++
 drivers/i2c/busses/Kconfig          |    7 
 drivers/i2c/busses/Makefile         |    1 
 drivers/i2c/busses/i2c-pmcmsp.c     |  419 ++++++++++++++++++++++++++++++++++++
 include/linux/i2c-algo-pmctwi.h     |  135 +++++++++++
 7 files changed, 768 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index af02034..794f7bb 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -49,5 +49,12 @@ config I2C_ALGO_SGI
 	  Supports the SGI interfaces like the ones found on SGI Indy VINO
 	  or SGI O2 MACE.
 
-endmenu
+config I2C_ALGO_PMCTWI
+	tristate "I2C PMC TWI interfaces"
+	depends on I2C && PMC_MSP
+	help
+	  Implements the PMC TWI SoC algorithm for various implementations.
 
+	  Be sure to select the proper bus for your platform below.
+
+endmenu
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
index cac1051..2645d00 100644
--- a/drivers/i2c/algos/Makefile
+++ b/drivers/i2c/algos/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
 obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
 obj-$(CONFIG_I2C_ALGOPCA)	+= i2c-algo-pca.o
 obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
+obj-$(CONFIG_I2C_ALGO_PMCTWI)	+= i2c-algo-pmctwi.o
 
 ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/algos/i2c-algo-pmctwi.c b/drivers/i2c/algos/i2c-algo-pmctwi.c
new file mode 100644
index 0000000..160f0e9
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-pmctwi.c
@@ -0,0 +1,197 @@
+/*
+ * Device-independent algorithm for using PMC-TWI SoC busses.
+ *
+ * See drivers/i2c/busses/i2c-pmcmsp.c for an example implementation.
+ *
+ * Copyright 2005-2007 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pmctwi.h>
+
+/* 
+ * Sends an i2c command out on the adapter
+ * Return -1 on error.
+ */
+static int pmctwi_master_xfer(struct i2c_adapter *adap,
+				struct i2c_msg *m, int num)
+{
+	struct pmctwi_data *busops = adap->algo_data;
+	int i, ret = 0, dual, probe;
+	struct i2c_msg *cmsg, *nmsg;
+	u8 detect_buffer[] = { 0 };
+
+	for (i = 0; i < num; i++) {
+		struct pmctwi_cmd cmd;
+		struct pmctwi_cfg oldcfg, newcfg;
+
+		probe = 0;
+		dual = 0;
+		cmsg = m + i;
+		nmsg = NULL;
+
+		if ((num - i) >= 2) {
+			/* Check for a dual write-then-read command */
+			nmsg = cmsg + 1;
+			dual = !((cmsg->flags & I2C_M_RD)) &&
+			       (nmsg->flags & I2C_M_RD) &&
+			       (cmsg->addr == nmsg->addr);
+		}
+
+		if (dual)
+			dev_dbg(&adap->dev, "Doing ops %d&%d of %d\n",
+				(i + 1), (i + 2), num);
+		else
+			dev_dbg(&adap->dev, "Doing op %d of %d\n",
+				(i + 1), num);
+
+		if (dual) {
+			cmd.type = PMCTWI_CMD_WRITE_READ;
+			cmd.write_len = cmsg->len;
+			cmd.write_data = (u8*)cmsg->buf;
+			cmd.read_len = nmsg->len;
+			cmd.read_data = (u8*)nmsg->buf;
+		} else if (cmsg->flags & I2C_M_RD) {
+			cmd.type = PMCTWI_CMD_READ;
+			cmd.read_len = cmsg->len;
+			cmd.read_data = (u8*)cmsg->buf;
+			cmd.write_len = 0;
+			cmd.write_data = NULL;
+		} else {
+			cmd.type = PMCTWI_CMD_WRITE;
+			cmd.read_len = 0;
+			cmd.read_data = NULL;
+			cmd.write_len = cmsg->len;
+			cmd.write_data = (u8*)cmsg->buf;
+		}
+
+		if (cmsg->len == 0) {
+			if (cmsg->flags & I2C_M_RD) {
+				dev_dbg(&adap->dev,
+					"Read of 0 bytes!  (illegal!)\n");
+				return -1;
+			} else {
+				dev_dbg(&adap->dev,
+					"Probing for slave at 0x%02x\n",
+					(cmsg->addr & 0xff));
+				probe = 1;
+
+				/*
+				 * Probe is a special read of 1 byte.
+				 * We don't care about the result, we just
+				 * want to see that it is successful.
+				 */
+				cmd.write_len = 1;
+				cmd.write_data = detect_buffer;
+				cmd.read_len = 1;
+				cmd.read_data = NULL;
+			}
+		}
+
+		cmd.addr = cmsg->addr;
+
+		if (probe || (cmsg->flags & I2C_M_TEN)) {
+			busops->get_twi_config(&newcfg, busops->data);
+			busops->get_twi_config(&oldcfg, busops->data);
+
+			/* For probes, we don't want any retries */
+			if (probe)
+				newcfg.nak = 0;
+
+			/* Set the special 10-bit address flag, if required */
+			if (cmsg->flags & I2C_M_TEN)
+				newcfg.add10 = 1;
+
+			busops->set_twi_config(&newcfg, busops->data);
+		}
+
+		ret = busops->xfer_cmd(&cmd, busops->data);
+
+		if (probe || (cmsg->flags & I2C_M_TEN))
+			busops->set_twi_config(&oldcfg, busops->data);
+
+		switch (ret) {
+		case PMCTWI_XFER_LOST_ARBITRATION:
+			dev_dbg(&adap->dev, "We lost arbitration: "
+				"Could not become bus master\n");
+			break;
+		case PMCTWI_XFER_NO_RESPONSE:
+			dev_dbg(&adap->dev, "No response\n");
+			break;
+		case PMCTWI_XFER_DATA_COLLISION:
+			dev_dbg(&adap->dev, "Data collision\n");
+			break;
+		case PMCTWI_XFER_BUSY:
+			dev_dbg(&adap->dev, "Port was busy\n");
+			/*
+			 *  TODO: We could potentially loop and retry
+			 *        in this case
+			 */
+			break;
+		case PMCTWI_XFER_TIMEOUT:
+			dev_dbg(&adap->dev, "Transfer timeout\n");
+			break;
+		}
+		if (ret != PMCTWI_XFER_OK) {
+			if (probe)
+				dev_dbg(&adap->dev, "Probe failed\n");
+			return -1;
+		}
+
+		if (dual) {
+			dev_dbg(&adap->dev,
+				"SMBus read 0x%02x from reg 0x%02x\n",
+				nmsg->buf[0], cmsg->buf[0]);
+
+			/* Skip one more ahead, since we just did 2 commands */
+			i++;
+		} else {
+			if (probe)
+				dev_dbg(&adap->dev, "Probe successful\n");
+			else
+				dev_dbg(&adap->dev,
+					"I2C %s %d bytes successfully\n",
+					(cmsg->flags & I2C_M_RD) ?
+						"read" : "wrote",
+					cmsg->len);
+		}
+	}
+
+	return 0;
+}
+
+static u32 pmctwi_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+struct i2c_algorithm pmctwi_algorithm = {
+	.master_xfer	= pmctwi_master_xfer,
+	.smbus_xfer	= NULL,
+	.algo_control	= NULL,	/* TODO: someday */
+	.functionality	= pmctwi_i2c_func,
+};
+
+EXPORT_SYMBOL(pmctwi_algorithm);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 4d44a2d..f2998b8 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -573,4 +573,11 @@ config I2C_PNX
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-pnx.
 
+config I2C_PMCMSP
+	tristate "PMC MSP I2C Controller"
+	depends on I2C && PMC_MSP
+	select I2C_ALGO_PMCTWI
+	help
+	  Supports the special PMC TWI SoC chip on the MSP platform
+
 endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 03505aa..8923878 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT)	+= i2c-parport-light.o
 obj-$(CONFIG_I2C_PASEMI)	+= i2c-pasemi.o
 obj-$(CONFIG_I2C_PCA_ISA)	+= i2c-pca-isa.o
 obj-$(CONFIG_I2C_PIIX4)		+= i2c-piix4.o
+obj-$(CONFIG_I2C_PMCMSP)	+= i2c-pmcmsp.o
 obj-$(CONFIG_I2C_PNX)		+= i2c-pnx.o
 obj-$(CONFIG_I2C_PROSAVAGE)	+= i2c-prosavage.o
 obj-$(CONFIG_I2C_PXA)		+= i2c-pxa.o
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
new file mode 100644
index 0000000..a8b9cfa
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -0,0 +1,419 @@
+/*
+ * Specific bus support for PMC-TWI compliant implementation on 7120 chip
+ *
+ * Copyright 2005-2007 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pmctwi.h>
+#include <linux/mutex.h>
+
+#include <asm/io.h>
+
+#include <msp_regs.h>
+#include <msp_cic_int.h>
+
+#define MSP_TW_SF_CLK_REG_OFFSET	0x00
+#define MSP_TW_HS_CLK_REG_OFFSET	0x04
+#define MSP_TW_CFG_REG_OFFSET		0x08
+#define MSP_TW_CMD_REG_OFFSET		0x0c
+#define MSP_TW_ADD_REG_OFFSET		0x10
+#define MSP_TW_DAT_0_REG_OFFSET		0x14
+#define MSP_TW_DAT_1_REG_OFFSET		0x18
+#define MSP_TW_INT_STS_REG_OFFSET	0x1c
+#define MSP_TW_INT_MSK_REG_OFFSET	0x20
+#define MSP_TW_BUSY_REG_OFFSET		0x24
+#define MSP_TW_REG_SIZE			0x28
+
+#define MSP_TW_INT_STS_DONE		(1 << 0)
+#define MSP_TW_INT_STS_LOST_ARBITRATION	(1 << 1)
+#define MSP_TW_INT_STS_NO_RESPONSE	(1 << 2)
+#define MSP_TW_INT_STS_DATA_COLLISION	(1 << 3)
+#define MSP_TW_INT_STS_BUSY		(1 << 4)
+#define MSP_TW_INT_STS_ALL		0x1f
+
+#define MSP_MAX_BYTES_PER_RW		8
+#define MSP_MAX_POLL			5
+#define MSP_POLL_DELAY			10
+#define MSP_IRQ_TIMEOUT			(MSP_MAX_POLL * MSP_POLL_DELAY)
+
+#define MSP_TW_IRQ 			MSP_INT_2WIRE
+/* Use the following instead to disable interrupt mode */
+/* #define MSP_TW_IRQ 			0 */
+
+/* IO Operation macros */
+#define pmcmsp_twi_readl	__raw_readl
+#define pmcmsp_twi_writel	__raw_writel
+
+struct pmcmsp_priv_data {
+	void __iomem *iobase;			/* iomapped base for IO */
+	enum pmctwi_xfer_result last_result;	/* result of last xfer */
+	int irq;				/* IRQ to use (0 disables) */
+	struct completion wait;			/* Completion struct for xfer */
+	struct mutex lock;			/* Used for threadsafeness */
+};
+
+static struct i2c_adapter pmcmsp_twi_adapter;
+
+/* The default settings */
+const static struct pmctwi_clockcfg pmctwi_defclockcfg = {
+	.standard = {
+		.filter = 0x3,
+		.clock = 0x1f,
+	},
+	.highspeed = {
+		.filter = 0x3,
+		.clock = 0x1f,
+	},
+};
+
+const static struct pmctwi_cfg pmctwi_deftwicfg = {
+	.arbf		= 0x03,
+	.nak		= 0x03,
+	.add10		= 0x00,
+	.mst_code	= 0x00,
+	.arb		= 0x01,
+	.highspeed	= 0x00,
+};
+
+/*
+ * Gets the current clock configuration
+ */
+static void pmcmsp_get_clock_config(struct pmctwi_clockcfg *cfg, void *data)
+{
+	struct pmcmsp_priv_data *p = data;
+	
+	mutex_lock(&p->lock);
+	pmctwi_reg_to_clock(pmcmsp_twi_readl(p->iobase +
+				MSP_TW_SF_CLK_REG_OFFSET),
+				&(cfg->standard));
+	pmctwi_reg_to_clock(pmcmsp_twi_readl(p->iobase +
+				MSP_TW_HS_CLK_REG_OFFSET),
+				&(cfg->highspeed));
+	mutex_unlock(&p->lock);
+}
+
+/*
+ * Sets the current clock configuration
+ */
+static void pmcmsp_set_clock_config(const struct pmctwi_clockcfg *cfg,
+					void *data)
+{
+	struct pmcmsp_priv_data *p = data;
+	
+	mutex_lock(&p->lock);
+	pmcmsp_twi_writel(pmctwi_clock_to_reg(&(cfg->standard)),
+				p->iobase + MSP_TW_SF_CLK_REG_OFFSET);
+	pmcmsp_twi_writel(pmctwi_clock_to_reg(&(cfg->highspeed)),
+				p->iobase + MSP_TW_HS_CLK_REG_OFFSET);
+	mutex_unlock(&p->lock);
+}
+
+/*
+ * Gets the current TWI bus configuration
+ */
+static void pmcmsp_get_twi_config(struct pmctwi_cfg *cfg, void *data)
+{
+	struct pmcmsp_priv_data *p = data;
+	
+	mutex_lock(&p->lock);
+	pmctwi_reg_to_cfg(pmcmsp_twi_readl(
+				p->iobase + MSP_TW_CFG_REG_OFFSET), cfg);
+	mutex_unlock(&p->lock);
+}
+
+/*
+ * Sets the current TWI bus configuration
+ */
+static void pmcmsp_set_twi_config(const struct pmctwi_cfg *cfg, void *data)
+{
+	struct pmcmsp_priv_data *p = data;
+	
+	mutex_lock(&p->lock);
+	pmcmsp_twi_writel(pmctwi_cfg_to_reg(cfg),
+				p->iobase + MSP_TW_CFG_REG_OFFSET);
+	mutex_unlock(&p->lock);
+}
+
+/*
+ * Parses the 'int_sts' register and returns a well-defined error code
+ */
+static enum pmctwi_xfer_result pmcmsp_get_result(u32 reg)
+{
+	if (reg & MSP_TW_INT_STS_LOST_ARBITRATION) {
+		dev_dbg(&pmcmsp_twi_adapter.dev,
+			"  Result: Lost arbitration\n");
+		return PMCTWI_XFER_LOST_ARBITRATION;
+	} else if (reg & MSP_TW_INT_STS_NO_RESPONSE) {
+		dev_dbg(&pmcmsp_twi_adapter.dev,
+			"  Result: No response\n");
+		return PMCTWI_XFER_NO_RESPONSE;
+	} else if (reg & MSP_TW_INT_STS_DATA_COLLISION) {
+		dev_dbg(&pmcmsp_twi_adapter.dev,
+			"  Result: Data collision\n");
+		return PMCTWI_XFER_DATA_COLLISION;
+	} else if (reg & MSP_TW_INT_STS_BUSY) {
+		dev_dbg(&pmcmsp_twi_adapter.dev,
+			"  Result: Bus busy\n");
+		return PMCTWI_XFER_BUSY;
+	}
+
+	dev_dbg(&pmcmsp_twi_adapter.dev, "  Result: Operation succeeded\n");
+	return PMCTWI_XFER_OK;
+}
+
+/*
+ * Polls the 'busy' register until the command is complete
+ * Note: Assumes p->lock is held.
+ */
+static void pmcmsp_poll_complete(struct pmcmsp_priv_data* p)
+{
+	int i;
+	u32 val = 0;
+	
+	for (i = 0; i < MSP_MAX_POLL; i++) {
+		val = pmcmsp_twi_readl(p->iobase + MSP_TW_BUSY_REG_OFFSET);
+		if (val == 0) {
+			u32 reason = pmcmsp_twi_readl(p->iobase +
+						MSP_TW_INT_STS_REG_OFFSET);
+			pmcmsp_twi_writel(reason, p->iobase +
+						MSP_TW_INT_STS_REG_OFFSET);
+			p->last_result = pmcmsp_get_result(reason);
+			return;
+		}
+		udelay(MSP_POLL_DELAY);
+	}
+
+	dev_dbg(&pmcmsp_twi_adapter.dev, "  Result: Poll timeout\n");
+	p->last_result = PMCTWI_XFER_TIMEOUT;
+}
+
+/*
+ * In interrupt mode, handle the interrupt
+ * Note: Assumes p->lock is held.
+ */
+static irqreturn_t pmcmsp_interrupt(int irq, void* data)
+{
+	struct pmcmsp_priv_data *p = data;
+	
+	u32 reason = pmcmsp_twi_readl(p->iobase + MSP_TW_INT_STS_REG_OFFSET);
+	pmcmsp_twi_writel(reason, p->iobase + MSP_TW_INT_STS_REG_OFFSET);
+
+	dev_dbg(&pmcmsp_twi_adapter.dev, "    Got interrupt 0x%08x\n",
+			reason);
+	if (!(reason & MSP_TW_INT_STS_DONE))
+		return IRQ_NONE;
+
+	p->last_result = pmcmsp_get_result(reason);
+	complete(&p->wait);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Do the transfer (low level):
+ *  - May use interrupt-driven or polling, depending on if an IRQ is
+ *  presently registered
+ * Note: Assumes p->lock is held
+ */
+static enum pmctwi_xfer_result pmcmsp_do_xfer(u32 reg,
+					struct pmcmsp_priv_data *p)
+{
+	dev_dbg(&pmcmsp_twi_adapter.dev, "  Writing cmd reg 0x%08x\n", reg);
+	pmcmsp_twi_writel(reg, p->iobase + MSP_TW_CMD_REG_OFFSET);
+	if (p->irq) {
+		unsigned long timeleft = wait_for_completion_timeout(
+						&p->wait, MSP_IRQ_TIMEOUT);
+		if (timeleft == 0) {
+			dev_dbg(&pmcmsp_twi_adapter.dev,
+				"  Result: IRQ timeout\n");
+			complete(&p->wait);
+			p->last_result = PMCTWI_XFER_TIMEOUT;
+		}
+	} else
+		pmcmsp_poll_complete(p);
+
+	return p->last_result;
+}
+
+/*
+ * Helper routine, converts 'pmctwi_cmd' struct to register format
+ */
+static inline u32 pmcmsp_cmd_to_reg(const struct pmctwi_cmd *cmd)
+{
+	return (u32)(((cmd->type & 0x3) << 8) |
+			(((cmd->write_len - 1) & 0x7) << 4) |
+			(((cmd->read_len - 1) & 0x7) << 0));
+}
+
+/*
+ * Do the transfer (high level)
+ */
+static enum pmctwi_xfer_result pmcmsp_xfer_cmd(struct pmctwi_cmd *cmd,
+						void *data)
+{
+	struct pmcmsp_priv_data *p = data;
+	u64 *write_data, *read_data;
+	enum pmctwi_xfer_result retval;
+
+	write_data = (u64*)cmd->write_data;
+	read_data = (u64*)cmd->read_data;
+
+	if ((cmd->type == PMCTWI_CMD_WRITE && cmd->write_len == 0) ||
+	    (cmd->type == PMCTWI_CMD_READ && cmd->read_len == 0) ||
+	    (cmd->type == PMCTWI_CMD_WRITE_READ &&
+	    (cmd->read_len == 0 || cmd->write_len == 0))) {
+		printk(KERN_ERR "%s: Cannot transfer less than 1 byte\n",
+		        __FUNCTION__);
+		return -1;
+	}
+
+	if ((cmd->read_len > MSP_MAX_BYTES_PER_RW) ||
+	    (cmd->write_len > MSP_MAX_BYTES_PER_RW)) {
+		printk(KERN_ERR "%s: Cannot transfer more than %d bytes\n",
+			__FUNCTION__, MSP_MAX_BYTES_PER_RW);
+	}
+
+	mutex_lock(&p->lock);
+	dev_dbg(&pmcmsp_twi_adapter.dev, "Setting address to 0x%08x\n",
+		cmd->addr);
+	pmcmsp_twi_writel(cmd->addr, p->iobase + MSP_TW_ADD_REG_OFFSET);
+
+	if ((cmd->type == PMCTWI_CMD_WRITE) ||
+	    (cmd->type == PMCTWI_CMD_WRITE_READ)) {
+		u64 tmp = be64_to_cpu(*write_data);
+		tmp >>= (8 - cmd->write_len) * 8;
+		dev_dbg(&pmcmsp_twi_adapter.dev, "Writing 0x%016llx\n", tmp);
+		pmcmsp_twi_writel((u32)(tmp & 0x00000000ffffffffLL),
+				p->iobase + MSP_TW_DAT_0_REG_OFFSET);
+		if (cmd->write_len > 4)
+			pmcmsp_twi_writel((u32)(tmp >> 32),
+					p->iobase + MSP_TW_DAT_1_REG_OFFSET);
+	}
+
+	retval = pmcmsp_do_xfer(pmcmsp_cmd_to_reg(cmd), p);
+
+	if ((cmd->type == PMCTWI_CMD_READ) ||
+	    (cmd->type == PMCTWI_CMD_WRITE_READ)) {
+		int i;
+		u64 rmsk = ~(0xffffffffffffffffLL << (cmd->read_len*8));
+		u64 tmp = (u64)pmcmsp_twi_readl(p->iobase +
+					MSP_TW_DAT_0_REG_OFFSET);
+		if (cmd->read_len > 4)
+			tmp |= (u64)pmcmsp_twi_readl(p->iobase +
+					MSP_TW_DAT_1_REG_OFFSET) << 32;
+		tmp &= rmsk;
+		dev_dbg(&pmcmsp_twi_adapter.dev, "Read 0x%016llx\n", tmp);
+		
+		for (i = 0; i < cmd->read_len; i++)
+			cmd->read_data[i] = (u8)((tmp >> i) & 0xff);
+	}
+	mutex_unlock(&p->lock);
+	
+	return retval;
+}
+
+static struct pmcmsp_priv_data pmcmsp_priv;
+
+static struct pmctwi_data pmcmsp_twi_algdata = {
+	.data			= (void*)&pmcmsp_priv,
+	.get_clock_config	= pmcmsp_get_clock_config,
+	.set_clock_config	= pmcmsp_set_clock_config,
+	.get_twi_config		= pmcmsp_get_twi_config,
+	.set_twi_config		= pmcmsp_set_twi_config,
+	.xfer_cmd		= pmcmsp_xfer_cmd,
+};
+
+static struct i2c_adapter pmcmsp_twi_adapter = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON,
+	.algo		= &pmctwi_algorithm,
+	.algo_data	= &pmcmsp_twi_algdata,
+	.name		= "PMC MSP TWI/SMB/I2C driver",
+};
+
+static int __init pmcmsp_twi_init(void)
+{
+	pmcmsp_priv.iobase = ioremap(MSP_TWI_BASE, MSP_TW_REG_SIZE);
+	if (pmcmsp_priv.iobase == NULL)
+		return -ENOMEM;
+
+	init_completion(&pmcmsp_priv.wait); 
+	mutex_init(&pmcmsp_priv.lock);
+	pmcmsp_priv.irq = MSP_TW_IRQ;
+
+	if (pmcmsp_priv.irq) {
+		int rc = request_irq(pmcmsp_priv.irq, pmcmsp_interrupt,
+				SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
+				"TWI", &pmcmsp_priv);
+		if (rc == 0) {
+			/*
+			 * Enable 'DONE' interrupt only
+			 *
+			 * If you enable all interrupts, you will get one on
+			 * error and another when the operation completes.
+			 * This way you only have to handle one interrupt,
+			 * but you can still check all result flags.
+			 */
+			pmcmsp_twi_writel(MSP_TW_INT_STS_DONE,
+					pmcmsp_priv.iobase +
+					MSP_TW_INT_MSK_REG_OFFSET);
+		} else {
+			printk(KERN_WARNING
+				"Could not assign TWI IRQ handler "
+				"to irq %d (continuing with poll)\n",
+				pmcmsp_priv.irq);
+			pmcmsp_priv.irq = 0;
+		}
+	}
+
+	pmcmsp_set_clock_config(&pmctwi_defclockcfg, &pmcmsp_priv);
+	pmcmsp_set_twi_config(&pmctwi_deftwicfg, &pmcmsp_priv);
+
+	printk(KERN_WARNING "Registering MSP7120 I2C adapter\n");
+
+	return i2c_add_adapter(&pmcmsp_twi_adapter);
+}
+
+static void __exit pmcmsp_twi_exit(void)
+{
+	if (pmcmsp_priv.irq) {
+		pmcmsp_twi_writel(0,
+			pmcmsp_priv.iobase + MSP_TW_INT_MSK_REG_OFFSET);
+		free_irq(pmcmsp_priv.irq, &pmcmsp_priv);
+	}
+	i2c_del_adapter(&pmcmsp_twi_adapter);
+}
+
+MODULE_DESCRIPTION("PMC MSP TWI/SMB/I2C driver");
+MODULE_LICENSE("GPL");
+
+module_init(pmcmsp_twi_init);
+module_exit(pmcmsp_twi_exit);
diff --git a/include/linux/i2c-algo-pmctwi.h b/include/linux/i2c-algo-pmctwi.h
new file mode 100644
index 0000000..7b6ca58
--- /dev/null
+++ b/include/linux/i2c-algo-pmctwi.h
@@ -0,0 +1,135 @@
+/*
+ * Device-independent algorithm for using PMC-TWI SoC busses.
+ *
+ * See drivers/i2c/busses/i2c-pmcmsp.c for an example implementation.
+ *
+ * Copyright 2005-2007 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef I2C_ALGO_PMCTWI_H
+#define I2C_ALGO_PMCTWI_H
+
+#include <linux/i2c.h>
+
+/* TWI command type */
+enum pmctwi_cmd_type {
+	PMCTWI_CMD_WRITE	= 0, /* Write only */
+	PMCTWI_CMD_READ		= 1, /* Read only */
+	PMCTWI_CMD_WRITE_READ	= 2, /* Write then Read */
+	PMCTWI_CMD_RESERVED	= 3,
+};
+
+/* Corresponds to a PMCTWI clock configuration register */
+struct pmctwi_clock {
+	u8 filter;	/* Bits 15:12,	default = 0x03 */
+	u16 clock;	/* Bits 9:0,	default = 0x001f */
+};
+
+static inline u32 pmctwi_clock_to_reg(const struct pmctwi_clock *clock) {
+	return (u32)(((clock->filter & 0xf) << 12) |
+			(clock->clock & 0x03ff));
+}
+
+static inline void pmctwi_reg_to_clock(u32 reg, struct pmctwi_clock *clock) {
+	clock->filter = (u8)((reg >> 12) & 0xf);
+	clock->clock = (u16)(reg & 0x03ff);
+}
+
+struct pmctwi_clockcfg {
+	struct pmctwi_clock standard;	/* The standard/fast clock config */
+	struct pmctwi_clock highspeed;	/* The highspeed clock config */
+};
+
+/* Corresponds to the main TWI configuration register */
+struct pmctwi_cfg {
+	u8 arbf;	/* Bits 15:12,	default=0x03 */
+	u8 nak;		/* Bits 11:8,	default=0x03 */
+	u8 add10;	/* Bit 7,	default=0x00 */
+	u8 mst_code;	/* Bits 6:4,	default=0x00 */
+	u8 arb;		/* Bit 1,	default=0x01 */
+	u8 highspeed;	/* Bit 0,	default=0x00 */
+};
+
+static inline u32 pmctwi_cfg_to_reg(const struct pmctwi_cfg *cfg) {
+	return (u32)(((cfg->arbf & 0xf) << 12) |
+			((cfg->nak & 0xf) << 8) |
+			((cfg->add10 & 0x1) << 7) |
+			((cfg->mst_code & 0x7) << 4) |
+			((cfg->arb & 0x1) << 1) |
+			((cfg->highspeed & 0x1) << 0));
+}
+
+static inline void pmctwi_reg_to_cfg(u32 reg, struct pmctwi_cfg *cfg) {
+	cfg->arbf = (u8)((reg >> 12) & 0xf);
+	cfg->nak = (u8)((reg >> 8) & 0xf);
+	cfg->add10 = (u8)((reg >> 7) & 0x1);
+	cfg->mst_code = (u8)((reg >> 4) & 0x7);
+	cfg->arb = (u8)((reg >> 1) & 0x1);
+	cfg->highspeed = (u8)(reg & 0x1);
+}
+
+/* A single pmctwi command to issue */
+struct pmctwi_cmd {
+	u16 addr;	/* The slave address (7 or 10 bits) */
+	enum pmctwi_cmd_type type;	/* The command type */
+	u8 write_len;	/* Number of bytes in the write buffer */
+	u8 read_len;	/* Number of bytes in the read buffer */
+	u8*write_data;	/* Buffer of characters to send */
+	u8 *read_data;	/* Buffer to fill with incoming data */
+};
+
+/* The possible results of the xferCmd */
+enum pmctwi_xfer_result {
+	PMCTWI_XFER_OK	= 0,
+	PMCTWI_XFER_TIMEOUT,
+	PMCTWI_XFER_BUSY,
+	PMCTWI_XFER_DATA_COLLISION,
+	PMCTWI_XFER_NO_RESPONSE,
+	PMCTWI_XFER_LOST_ARBITRATION,
+};
+
+/* The set of operations each bus must implement to use this algorithm */
+struct pmctwi_data {
+	void *data;	/* Optional bus-specific data */
+
+	/* Get both clock configuration registers */
+	void (*get_clock_config)(struct pmctwi_clockcfg *cfg, void *data);
+
+	/* Set both clock configuration registers */
+	void (*set_clock_config)(const struct pmctwi_clockcfg *cfg,
+					void *data);
+
+	/* Get the TWI configuration register */
+	void (*get_twi_config)(struct pmctwi_cfg *cfg, void *data);
+
+	/* Set the TWI configuration register */
+	void (*set_twi_config)(const struct pmctwi_cfg *cfg, void *data);
+
+	/* Send the command, reading and/or writing all data specified */
+	enum pmctwi_xfer_result (*xfer_cmd)(struct pmctwi_cmd *cmd,
+						void *data);
+};
+
+extern struct i2c_algorithm pmctwi_algorithm;
+
+#endif /* I2C_ALGO_PMCTWI_H */

From marco.braga@gmail.com Fri Mar  9 07:23:23 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 09 Mar 2007 07:23:31 +0000 (GMT)
Received: from ug-out-1314.google.com ([66.249.92.172]:43705 "EHLO
	ug-out-1314.google.com") by ftp.linux-mips.org with ESMTP
	id S20021290AbXCIHXX (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 9 Mar 2007 07:23:23 +0000
Received: by ug-out-1314.google.com with SMTP id 40so1386766uga
        for <linux-mips@linux-mips.org>; Thu, 08 Mar 2007 23:22:23 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:references;
        b=DmO4NRSxYxPdc4y6P4cNJFgf3R/MjylbtJTuLCFuRmUkoTD6A02wr+sihzt2xTdH6wNXF1AzgpSuGSD7jGC/YFGKzdM3htanxkfSe0ixPqMxmnQ6QP1NPRFnzsanoPCECYnmkkB7ad03whNToUYnf6uiHqPTqO++Ki62Sh2Lkb8=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:references;
        b=pLZQinYL7ylzAQF2AlU/cRS2SqpZyP8vVAPKDDyoAzyjOo7ZDEge4ER+mynG5Jxlj6QFH9KvGGZ3pHtFNTYLsG2LZDZRXOwvIDxv18Ml1dk9Sv2tnzps/ioxtn7jF79HdGwTSyy7DyPthn1vACNsHU60HV5omDrY45yhvjYkVx8=
Received: by 10.114.210.2 with SMTP id i2mr436247wag.1173424942164;
        Thu, 08 Mar 2007 23:22:22 -0800 (PST)
Received: by 10.114.80.18 with HTTP; Thu, 8 Mar 2007 23:22:22 -0800 (PST)
Message-ID: <d459bb380703082322r18879381ma4c57149a8b7adfe@mail.gmail.com>
Date:	Fri, 9 Mar 2007 08:22:22 +0100
From:	"Marco Braga" <marco.braga@gmail.com>
To:	"Freddy Spierenburg" <freddy@dusktilldawn.nl>
Subject: Re: Trouble with sound/mips/au1x00.c AC97 driver
Cc:	"Charles Eidsness" <charles@cooper-street.com>,
	linux-mips@linux-mips.org
In-Reply-To: <20070307104930.GD25248@dusktilldawn.nl>
MIME-Version: 1.0
Content-Type: multipart/alternative; 
	boundary="----=_Part_234590_21201112.1173424942127"
References: <20070307104930.GD25248@dusktilldawn.nl>
Return-Path: <marco.braga@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14399
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: marco.braga@gmail.com
Precedence: bulk
X-list: linux-mips

------=_Part_234590_21201112.1173424942127
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hello Freddy,

I have exactly the same problem with a custom board based on an Alchemy
Au1500, kernel 2.6.17.14 from linux-mips.org
No solution at the moment.

------=_Part_234590_21201112.1173424942127
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hello Freddy,<br><br>I have exactly the same problem with a custom board based on an Alchemy Au1500, kernel <a href="http://2.6.17.14">2.6.17.14</a> from <a href="http://linux-mips.org">linux-mips.org</a><br>No solution at the moment.
<br>

------=_Part_234590_21201112.1173424942127--

From freddy@dusktilldawn.nl Fri Mar  9 10:33:46 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 09 Mar 2007 10:34:14 +0000 (GMT)
Received: from tool.snarl.nl ([82.95.241.19]:7645 "EHLO tool.snarl.nl")
	by ftp.linux-mips.org with ESMTP id S20021333AbXCIKdq (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 9 Mar 2007 10:33:46 +0000
Received: from localhost (tool.local.snarl.nl [127.0.0.1])
	by tool.snarl.nl (Postfix) with ESMTP id 50A895DF46;
	Fri,  9 Mar 2007 11:33:08 +0100 (CET)
Received: from tool.snarl.nl ([127.0.0.1])
	by localhost (tool.local.snarl.nl [127.0.0.1]) (amavisd-new, port 10024)
	with LMTP id bdmtjwM0vt8i; Fri,  9 Mar 2007 11:33:07 +0100 (CET)
Received: by tool.snarl.nl (Postfix, from userid 1000)
	id CAF5D5DF3D; Fri,  9 Mar 2007 11:33:07 +0100 (CET)
Date:	Fri, 9 Mar 2007 11:33:07 +0100
From:	Freddy Spierenburg <freddy@dusktilldawn.nl>
To:	Marco Braga <marco.braga@gmail.com>
Cc:	linux-mips@linux-mips.org
Subject: Re: Trouble with sound/mips/au1x00.c AC97 driver
Message-ID: <20070309103307.GI25248@dusktilldawn.nl>
References: <20070307104930.GD25248@dusktilldawn.nl> <d459bb380703082322r18879381ma4c57149a8b7adfe@mail.gmail.com>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="UlgRIH+VC25VUu7I"
Content-Disposition: inline
In-Reply-To: <d459bb380703082322r18879381ma4c57149a8b7adfe@mail.gmail.com>
X-User-Agent-Feature: All mail clients suck. This one just sucks less.
X-GPG-Key: http://snarl.nl/~freddy/keys/freddyPublicKey.gpg
User-Agent: Mutt/1.5.13 (2006-08-11)
Return-Path: <freddy@dusktilldawn.nl>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14400
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: freddy@dusktilldawn.nl
Precedence: bulk
X-list: linux-mips


--UlgRIH+VC25VUu7I
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi Marco,

On Fri, Mar 09, 2007 at 08:22:22AM +0100, Marco Braga wrote:
> I have exactly the same problem with a custom board based on an Alchemy
> Au1500, kernel 2.6.17.14 from linux-mips.org
> No solution at the moment.

The only solution I have yet is a small shell-script to load the
kernel driver and checks if all 38 controls are available. If not
it removes the driver and loads it again. Most of the times it
works right away and it's a very rare case that it takes the
script 8 loads to get all controls. I did around 143.000 tests
and 120.000 times it loaded correctly the first time, 20.000 the
seconds time, it faded gradually after that and only one time it
took 8 times.

But unfortunately, this work-around is far from perfect. It's
possible for the driver to load with all 38 controls, but wrong
control data. Let's say the CD volume control has a normal range
that is 0 - 31, and it happens sometimes the range is fucked up.
Let's say 0 - 15. Again snd_au1000_ac97_read() to blame.
Anyway, you don't want that, for obvious reason!

So as a more robust work-around, I'm almost finished with a small
Python program that reads /var/lib/alsa/asound.state (the saved
mixer values) and checks these against the values received from
the ALSA layer. I've patched pyalsaaudio-0.2 (the most usable
Python ALSA bindings IMHO) a little bit, and can now ask the
ALSA layer all relevant information needed. When it's completely
finished I shall mail the patches to the maintainer in the hope
he'll include them. And if finished I'm willing to share the
small Python program too, if anyone asks.

But what does this gives us? In the long run not much, to be
honoust! Like I told in my first email, I did also do a lot of
other tests and if the driver is loaded correctly things do work
well. So in the short run this is a good workable solution for
me.

But in the long run the kernel driver needs te be fixed of
course. And unfortunately I still consider myself a fool when it
comes to kernel programming. I have already decided to dive into
this a little bit in my spare time, but I'm afraid I lack the
right kernel knowledge when it comes to solve this issue. Charles
Eidsnes nicely answered my email with some tips, but also told me
he has other priorities than to dive into this. If one is up to
the challange to fix this he is willing to answer some questions,
but he's not actively involved with mips-linux anymore. Anyway,
here is his tip to look into:

On Wed, Mar 07, 2007 at 06:48:05PM -0500, Charles Eidsness wrote:
> I'm not sure what could cause this issue. Given your results on
> different hardware I think you're right in assuming that it's
> not a hardware issue (at least not with your AC'97 Codec). It
> kind of seems like a S/W timing issue. All that I can think of
> to suggest it to try adding some delays during the read cycle
> and see if that helps. It may be that there is some lag between
> when the processor says the data register has data, and when it
> really has data. You could also try to implement an interrupt
> based read, you may have better luck with it than I did. I gave
> up because it was taking me too long to get it to work, and I
> didn't mind the extra over-head of a polled read.

Sounds like some good advice to look into. Althought I'm a little
bit confused about why the AC97 controller would state that
information is available, when it is really not yet available.
Sounds like plain wrong to me. But then again, do not forget that
I'm the fool without a lot of knowledge on the subject again. :)

Anyway, to end up this long, long writing. Within a couple of
hours I'm of to the south of France to do some serious
snowboarding, so I will not look into this for like a little more
than a week. After that I will finish the Python work-around and
in my spare time shall dive into a real solution, but not with
much hope of fixing it for real.

Thanks for your reply and maybe with this little bit of extra
information some kernel hacker has his druthers and fixes the
bloody thing. If not just wait what I come up with, but please
don't hold your breath to it.


--=20
$ cat ~/.signature
Freddy Spierenburg <freddy@dusktilldawn.nl>  http://freddy.snarl.nl/
GnuPG: 0x7941D1E1=3DC948 5851 26D2 FA5C 39F1  E588 6F17 FD5D 7941 D1E1
$ # Please read http://www.ietf.org/rfc/rfc2015.txt before complain!

--UlgRIH+VC25VUu7I
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQFF8Tfjbxf9XXlB0eERAkDpAJ4yJd5/Q72RJICSEp8+47mY8CU/cwCgo3SW
cCk3rngKG+PA34VdzgRLedI=
=66Qc
-----END PGP SIGNATURE-----

--UlgRIH+VC25VUu7I--

From post@pfrst.de Fri Mar  9 13:24:20 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 09 Mar 2007 13:24:26 +0000 (GMT)
Received: from mail1.pearl-online.net ([62.159.194.147]:28441 "EHLO
	mail1.pearl-online.net") by ftp.linux-mips.org with ESMTP
	id S20021459AbXCINYU (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 9 Mar 2007 13:24:20 +0000
Received: from SNaIlmail.Peter (unknown [77.47.7.186])
	by mail1.pearl-online.net (Postfix) with ESMTP id 4A8A4B196;
	Fri,  9 Mar 2007 14:24:03 +0100 (CET)
Received: from Indigo2.Peter (Indigo2.Peter [192.168.1.28])
	by SNaIlmail.Peter (8.12.6/8.12.6/Sendmail/Linux 2.0.32) with ESMTP id l29DIhRY000729;
	Fri, 9 Mar 2007 14:18:43 +0100
Received: from Indigo2.Peter (localhost [127.0.0.1])
	by Indigo2.Peter (8.12.6/8.12.6/Sendmail/Linux 2.6.14-rc2-ip28) with ESMTP id l29DIeup014338;
	Fri, 9 Mar 2007 14:18:40 +0100
Received: from localhost (pf@localhost)
	by Indigo2.Peter (8.12.6/8.12.6/Submit) with ESMTP id l29DIeZU014335;
	Fri, 9 Mar 2007 14:18:40 +0100
X-Authentication-Warning: Indigo2.Peter: pf owned process doing -bs
Date:	Fri, 9 Mar 2007 14:18:40 +0100 (CET)
From:	peter fuerst <post@pfrst.de>
X-X-Sender: pf@Indigo2.Peter
Reply-To: post@pfrst.de
To:	Franck Bui-Huu <vagabon.xyz@gmail.com>
Cc:	linux-mips <linux-mips@linux-mips.org>
Subject: Re: [PATCH 0/2] FLATMEM: allow memory to start at pfn != 0 [take
 #2]
In-Reply-To: <cda58cb80703061339l2f8cfc09m5823b090b69a7aa7@mail.gmail.com>
Message-ID: <Pine.LNX.4.58.0703091415250.604@Indigo2.Peter>
References: <116841864595-git-send-email-fbuihuu@gmail.com> 
 <1172879147.964.65.camel@sakura.staff.proxad.net> 
 <cda58cb80703050615r4e559ca1u78517634ac23a27@mail.gmail.com> 
 <1173112433.7093.36.camel@sakura.staff.proxad.net>
 <cda58cb80703061339l2f8cfc09m5823b090b69a7aa7@mail.gmail.com>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
Return-Path: <post@pfrst.de>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14401
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: post@pfrst.de
Precedence: bulk
X-list: linux-mips



to detail Thomas' note...

On Tue, 6 Mar 2007, Franck Bui-Huu wrote:

> Date: Tue, 6 Mar 2007 22:39:59 +0100
> From: Franck Bui-Huu <vagabon.xyz@gmail.com>
> To: mbizon@freebox.fr
> Cc: linux-mips <linux-mips@linux-mips.org>
> Subject: Re: [PATCH 0/2] FLATMEM: allow memory to start at pfn != 0 [take
>     #2]
> ...
> In your case, you said:
>
>         PAGE_OFFSET = 0x80000000
>         PHYS_OFFSET = 0x10000000
>
> this means that the first kernel virtual address is 0x80000000 and the
> corresponding physical address is 0x10000000. If you load your kernel
> at 0x9000xxxx, it will be loaded in physical memory located at
> 0x2000xxxx which is obviously not what you want.
>

Never. If the kernel virtual address is 0x80000000+off with 0 <= off <=
0x1fffffff (aka kseg0, defined by bits 31..29), the corresponding physical
address is always 0+off, no matter what PHYS_OFFSET you invent. Physical
memory at 0x20000000 is not reachable from kesg0/1.

> ...

regards

peter

From vagabon.xyz@gmail.com Fri Mar  9 13:36:35 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 09 Mar 2007 13:36:39 +0000 (GMT)
Received: from hu-out-0506.google.com ([72.14.214.239]:8865 "EHLO
	hu-out-0506.google.com") by ftp.linux-mips.org with ESMTP
	id S20021472AbXCINgf (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 9 Mar 2007 13:36:35 +0000
Received: by hu-out-0506.google.com with SMTP id 22so2199703hug
        for <linux-mips@linux-mips.org>; Fri, 09 Mar 2007 05:35:35 -0800 (PST)
DKIM-Signature:	a=rsa-sha1; c=relaxed/relaxed;
        d=gmail.com; s=beta;
        h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=UKjf6bw6t5x4tLe9xHoMnOUiqls5iR0CsWNJYy+o/ogpZUa+ynZITH9zCd18Byj2zt7BSFT2+cgtKN8UMYo13Hi8hU9oyptyFmaHS3+nYa01QLW8ut1KhYzZpbkPrAo3j6jlpwZvFo1QPlACTaY3Fgrdy4bBgPsS3yaa+72TaHw=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=beta;
        h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references;
        b=apFdCy/7V8nWos3qZ0lfkAhb5cHpJOxnxM8V2YiQlQ8eaE78k6Vkz2BVgAwI4RtC+JAviUkR4bqj5x6uIqAOFEbMqfK2rcnzkvrUgeJ0fSteFALY92c9TPn8pmWjaLEQKk/BLIYU5IFEJsY/kYgyjg2IBh/6Az0wQ5VyiJGH/HY=
Received: by 10.115.95.1 with SMTP id x1mr538691wal.1173447332746;
        Fri, 09 Mar 2007 05:35:32 -0800 (PST)
Received: by 10.114.136.11 with HTTP; Fri, 9 Mar 2007 05:35:32 -0800 (PST)
Message-ID: <cda58cb80703090535i3b039ec0x3b31198c52bcee63@mail.gmail.com>
Date:	Fri, 9 Mar 2007 14:35:32 +0100
From:	"Franck Bui-Huu" <vagabon.xyz@gmail.com>
To:	post@pfrst.de
Subject: Re: [PATCH 0/2] FLATMEM: allow memory to start at pfn != 0 [take #2]
Cc:	linux-mips <linux-mips@linux-mips.org>
In-Reply-To: <Pine.LNX.4.58.0703091415250.604@Indigo2.Peter>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
References: <116841864595-git-send-email-fbuihuu@gmail.com>
	 <1172879147.964.65.camel@sakura.staff.proxad.net>
	 <cda58cb80703050615r4e559ca1u78517634ac23a27@mail.gmail.com>
	 <1173112433.7093.36.camel@sakura.staff.proxad.net>
	 <cda58cb80703061339l2f8cfc09m5823b090b69a7aa7@mail.gmail.com>
	 <Pine.LNX.4.58.0703091415250.604@Indigo2.Peter>
Return-Path: <vagabon.xyz@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14402
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: vagabon.xyz@gmail.com
Precedence: bulk
X-list: linux-mips

On 3/9/07, peter fuerst <post@pfrst.de> wrote:
>
> Never. If the kernel virtual address is 0x80000000+off with 0 <= off <=
> 0x1fffffff (aka kseg0, defined by bits 31..29), the corresponding physical
> address is always 0+off, no matter what PHYS_OFFSET you invent. Physical
> memory at 0x20000000 is not reachable from kesg0/1.
>

I already answered that was bullshit and I took drugs before writing this...

thanks
-- 
               Franck

From anemo@mba.ocn.ne.jp Fri Mar  9 16:05:11 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 09 Mar 2007 16:05:16 +0000 (GMT)
Received: from mba.ocn.ne.jp ([122.1.175.29]:43462 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20021471AbXCIQFL (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 9 Mar 2007 16:05:11 +0000
Received: from localhost (p4160-ipad211funabasi.chiba.ocn.ne.jp [58.91.160.160])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id E4BA0BB70; Sat, 10 Mar 2007 01:03:48 +0900 (JST)
Date:	Sat, 10 Mar 2007 01:03:48 +0900 (JST)
Message-Id: <20070310.010348.72708233.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org, macro@linux-mips.org, vagabon.xyz@gmail.com
Subject: [PATCH] Check FCSR for pending interrupts, alternative version
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14403
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

The commit 6d6671066a311703bca1b91645bb1e04cc983387 is incomplete and
misses non-r4k CPUs.  This patch reverts the commit and fixes in other
way.

* Do FCSR checking in caller of restore_fp_context.
* Send SIGFPE if the signal handler set any FPU exception bits.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
This is an update of:
http://www.linux-mips.org/archives/linux-mips/2007-02/msg00215.html

 arch/mips/kernel/r4k_fpu.S       |   16 ------------
 arch/mips/kernel/signal-common.h |    3 ++
 arch/mips/kernel/signal.c        |   46 ++++++++++++++++++++++++++++++++++---
 arch/mips/kernel/signal32.c      |   27 +++++++++++++++++++--
 arch/mips/kernel/signal_n32.c    |    6 ++++
 5 files changed, 75 insertions(+), 23 deletions(-)

diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
index 59c1577..dbd42ad 100644
--- a/arch/mips/kernel/r4k_fpu.S
+++ b/arch/mips/kernel/r4k_fpu.S
@@ -114,14 +114,6 @@ LEAF(_save_fp_context32)
  */
 LEAF(_restore_fp_context)
 	EX	lw t0, SC_FPC_CSR(a0)
-
-	/* Fail if the CSR has exceptions pending */
-	srl	t1, t0, 5
-	and	t1, t0
-	andi	t1, 0x1f << 7
-	bnez	t1, fault
-	 nop
-
 #ifdef CONFIG_64BIT
 	EX	ldc1 $f1, SC_FPREGS+8(a0)
 	EX	ldc1 $f3, SC_FPREGS+24(a0)
@@ -165,14 +157,6 @@ LEAF(_restore_fp_context)
 LEAF(_restore_fp_context32)
 	/* Restore an o32 sigcontext.  */
 	EX	lw t0, SC32_FPC_CSR(a0)
-
-	/* Fail if the CSR has exceptions pending */
-	srl	t1, t0, 5
-	and	t1, t0
-	andi	t1, 0x1f << 7
-	bnez	t1, fault
-	 nop
-
 	EX	ldc1 $f0, SC32_FPREGS+0(a0)
 	EX	ldc1 $f2, SC32_FPREGS+16(a0)
 	EX	ldc1 $f4, SC32_FPREGS+32(a0)
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h
index fdbdbdc..297dfcb 100644
--- a/arch/mips/kernel/signal-common.h
+++ b/arch/mips/kernel/signal-common.h
@@ -31,4 +31,7 @@ extern void __user *get_sigframe(struct
  */
 extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall);
 
+/* Check and clear pending FPU exceptions in saved CSR */
+extern int fpcsr_pending(unsigned int __user *fpcsr);
+
 #endif	/* __SIGNAL_COMMON_H */
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index f091786..bf094fc 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -124,6 +124,37 @@ int setup_sigcontext(struct pt_regs *reg
 	return err;
 }
 
+int fpcsr_pending(unsigned int __user *fpcsr)
+{
+	int err, sig = 0;
+	unsigned int csr, enabled;
+
+	err = __get_user(csr, fpcsr);
+	enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5);
+	/*
+	 * If the signal handler set some FPU exceptions, clear it and
+	 * send SIGFPE.
+	 */
+	if (csr & enabled) {
+		csr &= ~enabled;
+		err |= __put_user(csr, fpcsr);
+		sig = SIGFPE;
+	}
+	return err ?: sig;
+}
+
+static int
+check_and_restore_fp_context(struct sigcontext __user *sc)
+{
+	int err, sig;
+
+	err = sig = fpcsr_pending(&sc->sc_fpc_csr);
+	if (err > 0)
+		err = 0;
+	err |= restore_fp_context(sc);
+	return err ?: sig;
+}
+
 int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
 {
 	unsigned int used_math;
@@ -162,7 +193,8 @@ int restore_sigcontext(struct pt_regs *r
 	if (used_math()) {
 		/* restore fpu context if we have used it before */
 		own_fpu();
-		err |= restore_fp_context(sc);
+		if (!err)
+			err = check_and_restore_fp_context(sc);
 	} else {
 		/* signal handler may have used FPU.  Give it up. */
 		lose_fpu();
@@ -332,6 +364,7 @@ asmlinkage void sys_sigreturn(nabi_no_re
 {
 	struct sigframe __user *frame;
 	sigset_t blocked;
+	int sig;
 
 	frame = (struct sigframe __user *) regs.regs[29];
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -345,8 +378,11 @@ asmlinkage void sys_sigreturn(nabi_no_re
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	if (restore_sigcontext(&regs, &frame->sf_sc))
+	sig = restore_sigcontext(&regs, &frame->sf_sc);
+	if (sig < 0)
 		goto badframe;
+	else if (sig)
+		force_sig(sig, current);
 
 	/*
 	 * Don't let your children do this ...
@@ -368,6 +404,7 @@ asmlinkage void sys_rt_sigreturn(nabi_no
 	struct rt_sigframe __user *frame;
 	sigset_t set;
 	stack_t st;
+	int sig;
 
 	frame = (struct rt_sigframe __user *) regs.regs[29];
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -381,8 +418,11 @@ asmlinkage void sys_rt_sigreturn(nabi_no
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	if (restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext))
+	sig = restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext);
+	if (sig < 0)
 		goto badframe;
+	else if (sig)
+		force_sig(sig, current);
 
 	if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st)))
 		goto badframe;
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 19bbef0..20013b6 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -220,6 +220,18 @@ static int setup_sigcontext32(struct pt_
 	return err;
 }
 
+static int
+check_and_restore_fp_context32(struct sigcontext32 __user *sc)
+{
+	int err, sig;
+
+	err = sig = fpcsr_pending(&sc->sc_fpc_csr);
+	if (err > 0)
+		err = 0;
+	err |= restore_fp_context32(sc);
+	return err ?: sig;
+}
+
 static int restore_sigcontext32(struct pt_regs *regs,
 				struct sigcontext32 __user *sc)
 {
@@ -255,7 +267,8 @@ static int restore_sigcontext32(struct p
 	if (used_math()) {
 		/* restore fpu context if we have used it before */
 		own_fpu();
-		err |= restore_fp_context32(sc);
+		if (!err)
+			err = check_and_restore_fp_context32(sc);
 	} else {
 		/* signal handler may have used FPU.  Give it up. */
 		lose_fpu();
@@ -508,6 +521,7 @@ asmlinkage void sys32_sigreturn(nabi_no_
 {
 	struct sigframe32 __user *frame;
 	sigset_t blocked;
+	int sig;
 
 	frame = (struct sigframe32 __user *) regs.regs[29];
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -521,8 +535,11 @@ asmlinkage void sys32_sigreturn(nabi_no_
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	if (restore_sigcontext32(&regs, &frame->sf_sc))
+	sig = restore_sigcontext32(&regs, &frame->sf_sc);
+	if (sig < 0)
 		goto badframe;
+	else if (sig)
+		force_sig(sig, current);
 
 	/*
 	 * Don't let your children do this ...
@@ -545,6 +562,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_
 	sigset_t set;
 	stack_t st;
 	s32 sp;
+	int sig;
 
 	frame = (struct rt_sigframe32 __user *) regs.regs[29];
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -558,8 +576,11 @@ asmlinkage void sys32_rt_sigreturn(nabi_
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	if (restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext))
+	sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
+	if (sig < 0)
 		goto badframe;
+	else if (sig)
+		force_sig(sig, current);
 
 	/* The ucontext contains a stack32_t, so we must convert!  */
 	if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index ecf1f7e..a9202fa 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -127,6 +127,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi
 	sigset_t set;
 	stack_t st;
 	s32 sp;
+	int sig;
 
 	frame = (struct rt_sigframe_n32 __user *) regs.regs[29];
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -140,8 +141,11 @@ asmlinkage void sysn32_rt_sigreturn(nabi
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	if (restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext))
+	sig = restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext);
+	if (sig < 0)
 		goto badframe;
+	else if (sig)
+		force_sig(sig, current);
 
 	/* The ucontext contains a stack32_t, so we must convert!  */
 	if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))

From anemo@mba.ocn.ne.jp Fri Mar  9 16:09:05 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 09 Mar 2007 16:09:11 +0000 (GMT)
Received: from mba.ocn.ne.jp ([122.1.175.29]:59841 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20021482AbXCIQJF (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 9 Mar 2007 16:09:05 +0000
Received: from localhost (p4160-ipad211funabasi.chiba.ocn.ne.jp [58.91.160.160])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id E320EBB19; Sat, 10 Mar 2007 01:07:45 +0900 (JST)
Date:	Sat, 10 Mar 2007 01:07:45 +0900 (JST)
Message-Id: <20070310.010745.07456268.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org
Subject: [PATCH] do_fpe() cleanup
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14404
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

If we had already lost FPU before disabling preempt, we do not have to
own it at all.  And we do not prevent preemption when managing saved
FCR31 if we did not have FPU ownership.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
This is an update of:
http://www.linux-mips.org/archives/linux-mips/2007-02/msg00086.html

 arch/mips/kernel/traps.c |   22 ++++++++--------------
 1 files changed, 8 insertions(+), 14 deletions(-)

diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index d5833a4..2aaf76b 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -610,16 +610,6 @@ asmlinkage void do_fpe(struct pt_regs *r
 	if (fcr31 & FPU_CSR_UNI_X) {
 		int sig;
 
-		preempt_disable();
-
-#ifdef CONFIG_PREEMPT
-		if (!is_fpu_owner()) {
-			/* We might lose fpu before disabling preempt... */
-			own_fpu();
-			BUG_ON(!used_math());
-			restore_fp(current);
-		}
-#endif
 		/*
 		 * Unimplemented operation exception.  If we've got the full
 		 * software emulator on-board, let's use it...
@@ -630,7 +620,11 @@ asmlinkage void do_fpe(struct pt_regs *r
 		 * register operands before invoking the emulator, which seems
 		 * a bit extreme for what should be an infrequent event.
 		 */
-		save_fp(current);
+		preempt_disable();
+
+		/* We might have lost fpu before disabling preempt... */
+		if (is_fpu_owner())
+			save_fp(current);
 		/* Ensure 'resume' not overwrite saved fp context again. */
 		lose_fpu();
 
@@ -639,15 +633,15 @@ asmlinkage void do_fpe(struct pt_regs *r
 		/* Run the emulator */
 		sig = fpu_emulator_cop1Handler (regs, &current->thread.fpu, 1);
 
-		preempt_disable();
-
-		own_fpu();	/* Using the FPU again.  */
 		/*
 		 * We can't allow the emulated instruction to leave any of
 		 * the cause bit set in $fcr31.
 		 */
 		current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
 
+		preempt_disable();
+
+		own_fpu();	/* Using the FPU again.  */
 		/* Restore the hardware register state */
 		restore_fp(current);
 

From anemo@mba.ocn.ne.jp Fri Mar  9 16:20:08 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 09 Mar 2007 16:20:13 +0000 (GMT)
Received: from mba.ocn.ne.jp ([122.1.175.29]:27869 "HELO smtp.mba.ocn.ne.jp")
	by ftp.linux-mips.org with SMTP id S20021495AbXCIQUI (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 9 Mar 2007 16:20:08 +0000
Received: from localhost (p4160-ipad211funabasi.chiba.ocn.ne.jp [58.91.160.160])
	by smtp.mba.ocn.ne.jp (Postfix) with ESMTP
	id 1AFE0BB9A; Sat, 10 Mar 2007 01:18:46 +0900 (JST)
Date:	Sat, 10 Mar 2007 01:18:45 +0900 (JST)
Message-Id: <20070310.011845.85420915.anemo@mba.ocn.ne.jp>
To:	linux-mips@linux-mips.org
Cc:	ralf@linux-mips.org
Subject: [PATCH] rewrite restore_fp_context/save_fp_context
From:	Atsushi Nemoto <anemo@mba.ocn.ne.jp>
X-Fingerprint: 6ACA 1623 39BD 9A94 9B1A  B746 CA77 FE94 2874 D52F
X-Pgp-Public-Key: http://wwwkeys.pgp.net/pks/lookup?op=get&search=0x2874D52F
X-Mailer: Mew version 3.3 on Emacs 21.4 / Mule 5.0 (SAKAKI)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Return-Path: <anemo@mba.ocn.ne.jp>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 14405
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: anemo@mba.ocn.ne.jp
Precedence: bulk
X-list: linux-mips

The setup_sigcontect()/restore_sigcontext() might sleep on
put_user()/get_user() with preemption disabled (i.e. atomic context).
Sleeping in atomic context is not allowed.  This patch fixes this
problem by rewriting restore_fp_context()/save_fp_context().

A path to save fp context was:
	(current.thread.fpu -> ) real FPU -> sigcontext on userstack

And with this patch it is:
	(real FPU -> ) current.thread.fpu -> sigcontext on userstack

While transfer between real FPU and current.thread.fpu can be done by
usual context save/restore routines, all arch/mips/kernel/*_fpu.S,
SMP-variant of {save,restore}_fp_context and SC_ symbols in
asm-offset.h can be removed.

There is an another approach: enabling CpU exception in kernel.  But
that is somewhat tricky and fragile (and add an additional instruction
in resume() code).  This patch is simpler and would not add additional
overhead for most cases.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
This is an update of:
http://www.linux-mips.org/archives/linux-mips/2006-08/msg00287.html

This patch depends on:
> Subject: [PATCH] Check FCSR for pending interrupts, alternative version
> Message-Id: <20070310.010348.72708233.anemo@mba.ocn.ne.jp>

This patch conflicts with:
> Subject: [PATCH] Allow CpU exception in kernel partially

 arch/mips/kernel/Makefile           |   36 +++---
 arch/mips/kernel/asm-offsets.c      |   47 --------
 arch/mips/kernel/r2300_fpu.S        |  126 ----------------------
 arch/mips/kernel/r4k_fpu.S          |  188 ----------------------------------
 arch/mips/kernel/r6000_fpu.S        |   87 ---------------
 arch/mips/kernel/signal.c           |   52 +++++++--
 arch/mips/kernel/signal32.c         |   45 +++++---
 arch/mips/kernel/traps.c            |   76 -------------
 arch/mips/math-emu/kernel_linkage.c |   69 ------------
 include/asm-mips/fpu.h              |    9 -
 10 files changed, 90 insertions(+), 645 deletions(-)

diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 4924626..8377760 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -14,24 +14,24 @@ binfmt_irix-objs	:= irixelf.o irixinv.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_MODULES)		+= mips_ksyms.o module.o
 
-obj-$(CONFIG_CPU_R3000)		+= r2300_fpu.o r2300_switch.o
-obj-$(CONFIG_CPU_TX39XX)	+= r2300_fpu.o r2300_switch.o
-obj-$(CONFIG_CPU_TX49XX)	+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_R4000)		+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_VR41XX)	+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_R4300)		+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_R4X00)		+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_R5000)		+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_R5432)		+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_R8000)		+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_RM7000)	+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_RM9000)	+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_NEVADA)	+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_R10000)	+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_SB1)		+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_MIPS32)	+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_MIPS64)	+= r4k_fpu.o r4k_switch.o
-obj-$(CONFIG_CPU_R6000)		+= r6000_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_R3000)		+= r2300_switch.o
+obj-$(CONFIG_CPU_TX39XX)	+= r2300_switch.o
+obj-$(CONFIG_CPU_TX49XX)	+= r4k_switch.o
+obj-$(CONFIG_CPU_R4000)		+= r4k_switch.o
+obj-$(CONFIG_CPU_VR41XX)	+= r4k_switch.o
+obj-$(CONFIG_CPU_R4300)		+= r4k_switch.o
+obj-$(CONFIG_CPU_R4X00)		+= r4k_switch.o
+obj-$(CONFIG_CPU_R5000)		+= r4k_switch.o
+obj-$(CONFIG_CPU_R5432)		+= r4k_switch.o
+obj-$(CONFIG_CPU_R8000)		+= r4k_switch.o
+obj-$(CONFIG_CPU_RM7000)	+= r4k_switch.o
+obj-$(CONFIG_CPU_RM9000)	+= r4k_switch.o
+obj-$(CONFIG_CPU_NEVADA)	+= r4k_switch.o
+obj-$(CONFIG_CPU_R10000)	+= r4k_switch.o
+obj-$(CONFIG_CPU_SB1)		+= r4k_switch.o
+obj-$(CONFIG_CPU_MIPS32)	+= r4k_switch.o
+obj-$(CONFIG_CPU_MIPS64)	+= r4k_switch.o
+obj-$(CONFIG_CPU_R6000)		+= r4k_switch.o
 
 obj-$(CONFIG_SMP)		+= smp.o
 
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 222de46..e312ed8 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -243,53 +243,6 @@ void output_mm_defines(void)
 	linefeed;
 }
 
-#ifdef CONFIG_32BIT
-void output_sc_defines(void)
-{
-	text("/* Linux sigcontext offsets. */");
-	offset("#define SC_REGS       ", struct sigcontext, sc_regs);
-	offset("#define SC_FPREGS     ", struct sigcontext, sc_fpregs);
-	offset("#define SC_ACX        ", struct sigcontext, sc_acx);
-	offset("#define SC_MDHI       ", struct sigcontext, sc_mdhi);
-	offset("#define SC_MDLO       ", struct sigcontext, sc_mdlo);
-	offset("#define SC_PC         ", struct sigcontext, sc_pc);
-	offset("#define SC_FPC_CSR    ", struct sigcontext, sc_fpc_csr);
-	offset("#define SC_FPC_EIR    ", struct sigcontext, sc_fpc_eir);
-	offset("#define SC_HI1        ", struct sigcontext, sc_hi1);
-	offset("#define SC_LO1        ", struct sigcontext, sc_lo1);
-	offset("#define SC_HI2        ", struct sigcontext, sc_hi2);
-	offset("#define SC_LO2        ", struct sigcontext, sc_lo2);
-	offset("#define SC_HI3        ", struct sigcontext, sc_hi3);
-	offset("#define SC_LO3        ", struct sigcontext, sc_lo3);
-	linefeed;
-}
-#endif
-
-#ifdef CONFIG_64BIT
-void output_sc_defines(void)
-{
-	text("/* Linux sigcontext offsets. */");
-	offset("#define SC_REGS       ", struct sigcontext, sc_regs);
-	offset("#define SC_FPREGS     ", struct sigcontext, sc_fpregs);
-	offset("#define SC_MDHI       ", struct sigcontext, sc_mdhi);
-	offset("#define SC_MDLO       ", struct sigcontext, sc_mdlo);
-	offset("#define SC_PC         ", struct sigcontext, sc_pc);
-	offset("#define SC_FPC_CSR    ", struct sigcontext, sc_fpc_csr);
-	linefeed;
-}
-#endif
-
-#ifdef CONFIG_MIPS32_COMPAT
-void output_sc32_defines(void)
-{
-	text("/* Linux 32-bit sigcontext offsets. */");
-	offset("#define SC32_FPREGS     ", struct sigcontext32, sc_fpregs);
-	offset("#define SC32_FPC_CSR    ", struct sigcontext32, sc_fpc_csr);
-	offset("#define SC32_FPC_EIR    ", struct sigcontext32, sc_fpc_eir);
-	linefeed;
-}
-#endif
-
 void output_signal_defined(void)
 {
 	text("/* Linux signal numbers. */");
diff --git a/arch/mips/kernel/r2300_fpu.S b/arch/mips/kernel/r2300_fpu.S
deleted file mode 100644
index ac68e68..0000000
--- a/arch/mips/kernel/r2300_fpu.S
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1996, 1998 by Ralf Baechle
- *
- * Multi-arch abstraction and asm macros for easier reading:
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * Further modifications to make this work:
- * Copyright (c) 1998 Harald Koerfgen
- */
-#include <asm/asm.h>
-#include <asm/errno.h>
-#include <asm/fpregdef.h>
-#include <asm/mipsregs.h>
-#include <asm/asm-offsets.h>
-#include <asm/regdef.h>
-
-#define EX(a,b)							\
-9:	a,##b;							\
-	.section __ex_table,"a";				\
-	PTR	9b,bad_stack;					\
-	.previous
-
-	.set	noreorder
-	.set	mips1
-	/* Save floating point context */
-LEAF(_save_fp_context)
-	li	v0, 0					# assume success
-	cfc1	t1,fcr31
-	EX(swc1	$f0,(SC_FPREGS+0)(a0))
-	EX(swc1	$f1,(SC_FPREGS+8)(a0))
-	EX(swc1	$f2,(SC_FPREGS+16)(a0))
-	EX(swc1	$f3,(SC_FPREGS+24)(a0))
-	EX(swc1	$f4,(SC_FPREGS+32)(a0))
-	EX(swc1	$f5,(SC_FPREGS+40)(a0))
-	EX(swc1	$f6,(SC_FPREGS+48)(a0))
-	EX(swc1	$f7,(SC_FPREGS+56)(a0))
-	EX(swc1	$f8,(SC_FPREGS+64)(a0))
-	EX(swc1	$f9,(SC_FPREGS+72)(a0))
-	EX(swc1	$f10,(SC_FPREGS+80)(a0))
-	EX(swc1	$f11,(SC_FPREGS+88)(a0))
-	EX(swc1	$f12,(SC_FPREGS+96)(a0))
-	EX(swc1	$f13,(SC_FPREGS+104)(a0))
-	EX(swc1	$f14,(SC_FPREGS+112)(a0))
-	EX(swc1	$f15,(SC_FPREGS+120)(a0))
-	EX(swc1	$f16,(SC_FPREGS+128)(a0))
-	EX(swc1	$f17,(SC_FPREGS+136)(a0))
-	EX(swc1	$f18,(SC_FPREGS+144)(a0))
-	EX(swc1	$f19,(SC_FPREGS+152)(a0))
-	EX(swc1	$f20,(SC_FPREGS+160)(a0))
-	EX(swc1	$f21,(SC_FPREGS+168)(a0))
-	EX(swc1	$f22,(SC_FPREGS+176)(a0))
-	EX(swc1	$f23,(SC_FPREGS+184)(a0))
-	EX(swc1	$f24,(SC_FPREGS+192)(a0))
-	EX(swc1	$f25,(SC_FPREGS+200)(a0))
-	EX(swc1	$f26,(SC_FPREGS+208)(a0))
-	EX(swc1	$f27,(SC_FPREGS+216)(a0))
-	EX(swc1	$f28,(SC_FPREGS+224)(a0))
-	EX(swc1	$f29,(SC_FPREGS+232)(a0))
-	EX(swc1	$f30,(SC_FPREGS+240)(a0))
-	EX(swc1	$f31,(SC_FPREGS+248)(a0))
-	EX(sw	t1,(SC_FPC_CSR)(a0))
-	cfc1	t0,$0				# implementation/version
-	jr	ra
-	.set	nomacro
-	 EX(sw	t0,(SC_FPC_EIR)(a0))
-	.set	macro
-	END(_save_fp_context)
-
-/*
- * Restore FPU state:
- *  - fp gp registers
- *  - cp1 status/control register
- *
- * We base the decision which registers to restore from the signal stack
- * frame on the current content of c0_status, not on the content of the
- * stack frame which might have been changed by the user.
- */
-LEAF(_restore_fp_context)
-	li	v0, 0					# assume success
-	EX(lw t0,(SC_FPC_CSR)(a0))
-	EX(lwc1	$f0,(SC_FPREGS+0)(a0))
-	EX(lwc1	$f1,(SC_FPREGS+8)(a0))
-	EX(lwc1	$f2,(SC_FPREGS+16)(a0))
-	EX(lwc1	$f3,(SC_FPREGS+24)(a0))
-	EX(lwc1	$f4,(SC_FPREGS+32)(a0))
-	EX(lwc1	$f5,(SC_FPREGS+40)(a0))
-	EX(lwc1	$f6,(SC_FPREGS+48)(a0))
-	EX(lwc1	$f7,(SC_FPREGS+56)(a0))
-	EX(lwc1	$f8,(SC_FPREGS+64)(a0))
-	EX(lwc1	$f9,(SC_FPREGS+72)(a0))
-	EX(lwc1	$f10,(SC_FPREGS+80)(a0))
-	EX(lwc1	$f11,(SC_FPREGS+88)(a0))
-	EX(lwc1	$f12,(SC_FPREGS+96)(a0))
-	EX(lwc1	$f13,(SC_FPREGS+104)(a0))
-	EX(lwc1	$f14,(SC_FPREGS+112)(a0))
-	EX(lwc1	$f15,(SC_FPREGS+120)(a0))
-	EX(lwc1	$f16,(SC_FPREGS+128)(a0))
-	EX(lwc1	$f17,(SC_FPREGS+136)(a0))
-	EX(lwc1	$f18,(SC_FPREGS+144)(a0))
-	EX(lwc1	$f19,(SC_FPREGS+152)(a0))
-	EX(lwc1	$f20,(SC_FPREGS+160)(a0))
-	EX(lwc1	$f21,(SC_FPREGS+168)(a0))
-	EX(lwc1	$f22,(SC_FPREGS+176)(a0))
-	EX(lwc1	$f23,(SC_FPREGS+184)(a0))
-	EX(lwc1	$f24,(SC_FPREGS+192)(a0))
-	EX(lwc1	$f25,(SC_FPREGS+200)(a0))
-	EX(lwc1	$f26,(SC_FPREGS+208)(a0))
-	EX(lwc1	$f27,(SC_FPREGS+216)(a0))
-	EX(lwc1	$f28,(SC_FPREGS+224)(a0))
-	EX(lwc1	$f29,(SC_FPREGS+232)(a0))
-	EX(lwc1	$f30,(SC_FPREGS+240)(a0))
-	EX(lwc1	$f31,(SC_FPREGS+248)(a0))
-	jr	ra
-	 ctc1	t0,fcr31
-	END(_restore_fp_context)
-	.set	reorder
-
-	.type	fault@function
-	.ent	fault
-fault:	li	v0, -EFAULT
-	jr	ra
-	.end	fault
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
deleted file mode 100644
index dbd42ad..0000000
--- a/arch/mips/kernel/r4k_fpu.S
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1996, 98, 99, 2000, 01 Ralf Baechle
- *
- * Multi-arch abstraction and asm macros for easier reading:
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000 MIPS Technologies, Inc.
- * Copyright (C) 1999, 2001 Silicon Graphics, Inc.
- */
-#include <asm/asm.h>
-#include <asm/errno.h>
-#include <asm/fpregdef.h>
-#include <asm/mipsregs.h>
-#include <asm/asm-offsets.h>
-#include <asm/regdef.h>
-
-	.macro	EX insn, reg, src
-	.set	push
-	.set	nomacro
-.ex\@:	\insn	\reg, \src
-	.set	pop
-	.section __ex_table,"a"
-	PTR	.ex\@, fault
-	.previous
-	.endm
-
-	.set	noreorder
-	.set	mips3
-
-LEAF(_save_fp_context)
-	cfc1	t1, fcr31
-
-#ifdef CONFIG_64BIT
-	/* Store the 16 odd double precision registers */
-	EX	sdc1 $f1, SC_FPREGS+8(a0)
-	EX	sdc1 $f3, SC_FPREGS+24(a0)
-	EX	sdc1 $f5, SC_FPREGS+40(a0)
-	EX	sdc1 $f7, SC_FPREGS+56(a0)
-	EX	sdc1 $f9, SC_FPREGS+72(a0)
-	EX	sdc1 $f11, SC_FPREGS+88(a0)
-	EX	sdc1 $f13, SC_FPREGS+104(a0)
-	EX	sdc1 $f15, SC_FPREGS+120(a0)
-	EX	sdc1 $f17, SC_FPREGS+136(a0)
-	EX	sdc1 $f19, SC_FPREGS+152(a0)
-	EX	sdc1 $f21, SC_FPREGS+168(a0)
-	EX	sdc1 $f23, SC_FPREGS+184(a0)
-	EX	sdc1 $f25, SC_FPREGS+200(a0)
-	EX	sdc1 $f27, SC_FPREGS+216(a0)
-	EX	sdc1 $f29, SC_FPREGS+232(a0)
-	EX	sdc1 $f31, SC_FPREGS+248(a0)
-#endif
-
-	/* Store the 16 even double precision registers */
-	EX	sdc1 $f0, SC_FPREGS+0(a0)
-	EX	sdc1 $f2, SC_FPREGS+16(a0)
-	EX	sdc1 $f4, SC_FPREGS+32(a0)
-	EX	sdc1 $f6, SC_FPREGS+48(a0)
-	EX	sdc1 $f8, SC_FPREGS+64(a0)
-	EX	sdc1 $f10, SC_FPREGS+80(a0)
-	EX	sdc1 $f12, SC_FPREGS+96(a0)
-	EX	sdc1 $f14, SC_FPREGS+112(a0)
-	EX	sdc1 $f16, SC_FPREGS+128(a0)
-	EX	sdc1 $f18, SC_FPREGS+144(a0)
-	EX	sdc1 $f20, SC_FPREGS+160(a0)
-	EX	sdc1 $f22, SC_FPREGS+176(a0)
-	EX	sdc1 $f24, SC_FPREGS+192(a0)
-	EX	sdc1 $f26, SC_FPREGS+208(a0)
-	EX	sdc1 $f28, SC_FPREGS+224(a0)
-	EX	sdc1 $f30, SC_FPREGS+240(a0)
-	EX	sw t1, SC_FPC_CSR(a0)
-	jr	ra
-	 li	v0, 0					# success