LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: When are machine checks suppose to be recoverable?
From: Marcelo Tosatti @ 2005-08-23  2:56 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev list, David Woodhouse
In-Reply-To: <8DC63AB4-C547-4023-BE7F-46176BC71535@freescale.com>

On Wed, Aug 17, 2005 at 10:42:12PM -0500, Kumar Gala wrote:
> 
> On Aug 17, 2005, at 5:30 PM, David Woodhouse wrote:
> 
> >On Thu, 2005-08-18 at 07:44 +1000, Benjamin Herrenschmidt wrote:
> >
> >>On Wed, 2005-08-17 at 09:00 -0500, Kumar Gala wrote:
> >>
> >>>David's 8250 cleanup patch made me wondering when are machine checks
> >>>
> >
> >
> >>>suppose to recoverable?  General class of conditions is what I'm
> >>>looking for here.
> >>>
> >>>Is David's case due to some PCI master abort or something else?
> >>>
> >>
> >>Might be some issue on SMP machines...
> >>
> >
> >Yeah, that'll probably be the reason it turns out _not_ to be
> >recoverable despite our expectations. But that wasn't Kumar's  
> >question.
> 
> David's right, that wasn't my question :)  I was asking more about  
> what cases do we actually recover and that is considered correct  
> behavior.

Quoting David:

"My dual G4 PowerMac crashes sometimes when it probes for the (absent)
serial ports. Theoretically it's supposed to take a machine check and
recover -- but it doesn't always work like that."

Maybe you just need the proper entry in the exception table for IO
inb/outb?

Is there a stacktrace, David?

arch/ppc/kernel/traps.c:

/*
 * I/O accesses can cause machine checks on powermacs.
 * Check if the NIP corresponds to the address of a sync
 * instruction for which there is an entry in the exception
 * table.
 * Note that the 601 only takes a machine check on TEA
 * (transfer error ack) signal assertion, and does not
 * set any of the top 16 bits of SRR1.
 *  -- paulus.
 */
static inline int check_io_access(struct pt_regs *regs)
{
#ifdef CONFIG_PPC_PMAC
        unsigned long msr = regs->msr;
        const struct exception_table_entry *entry;
        unsigned int *nip = (unsigned int *)regs->nip;

        if (((msr & 0xffff0000) == 0 || (msr & (0x80000 | 0x40000)))
            && (entry = search_exception_tables(regs->nip)) != NULL) {

^ permalink raw reply

* RE: How NEC uPD720101 USB chip work well on linux2.6.12
From: JohnsonCheng @ 2005-08-23  2:38 UTC (permalink / raw)
  To: 'JohnsonCheng', 'Stefan Nickl'; +Cc: linuxppc-embedded
In-Reply-To: <20050823022508.C583967F88@ozlabs.org>

Correct it. 
I only turn on OHCI in kernel configuration, not UHCI.

Thanks,
Johnson Cheng

-----Original Message-----
From: linuxppc-embedded-bounces@ozlabs.org
[mailto:linuxppc-embedded-bounces@ozlabs.org] On Behalf Of JohnsonCheng
Sent: Saturday, July 23, 2005 10:24 AM
To: 'Stefan Nickl'
Cc: linuxppc-embedded@ozlabs.org
Subject: RE: How NEC uPD720101 USB chip work well on linux2.6.12

I tried this case before, only turn on UHCI option in kernel. The conclusion
is two USB port have the same result ( Kernel Oops), and another one has no
response. Do you know if I want to set these three USB port sharing the same
IRQ, where to modify it in kernel 2.6.12?

Thanks,
Johnson Cheng

-----Original Message-----
From: linuxppc-embedded-bounces@ozlabs.org
[mailto:linuxppc-embedded-bounces@ozlabs.org] On Behalf Of Stefan Nickl
Sent: Monday, August 22, 2005 9:55 PM
To: JohnsonCheng
Cc: linuxppc-embedded@ozlabs.org
Subject: Re: How NEC uPD720101 USB chip work well on linux2.6.12

On Fri, 2005-07-22 at 20:26 +0800, JohnsonCheng wrote:
> Dear All,
>  
> 
> I use NEC uPD720101 USB chip, 2 OHCI and 1 EHCI, I also have turn on
> the following options in kernel menuconfig:
[...]
> [*] USB Support / EHCI HCD (USB 2.0) support
[...]
>  
> 
> But when I plug-in a USB mouse, then Kernel Oops..
> 
> I use MPC8241 CPU, and there are three USB ports sharing the same IRQ
> on my borad.

I recently came across similar trouble with a chip from this series, the
uPD720113 and another one in a off-the-shelf USB hub which I tried for
reference.
It may have been even the 101, but I'm not sure.

Anyways, I've also seen hard resets with 2.6.12 to 2.6.13-rc-something,
albeit in a x86-environment. The system would reset hard when plugging
something after the hub or the hub itself, in case of the 113 it crashed
100% as soon as the hub was attached or detected during bootup. With the
off-the-shelf hub, it was somewhat more random.

In my case, disabling the EHCI controller in the BIOS helped, so you may
try to disable the USB "2.0" support in the kernel config and see what
happens.
No problems running the system with only UHCI for some weeks now.

I've deferred this problem because Hi-Speed is not an issue to me now,
but I'd be curious to hear and test things if somebody had a take on
this.

Regards,

-- 
Stefan Nickl
Kontron Modular Computers


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


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

^ permalink raw reply

* Enabling 8xx debug mode
From: Marcelo Tosatti @ 2005-08-23  2:20 UTC (permalink / raw)
  To: Dan Malek, linux-ppc-embedded


Hi Dan,

I know now that the BDI automatically enables debug mode by asserting
the DSCK signal (available through the JTAG port). Is there any way 
to enable debugging mode purely via software?

44.3.1.2 Entering Debug Mode

By appropriately programming the development port during reset, debug
mode can be entered immediately out of reset, thus allowing the user to
debug a ROM-less system. If DSCK is asserted throughout SRESET assertion
and then past SRESET negation, the processor takes a breakpoint
exception and goes directly to debug mode instead of fetching the reset
vector. To avoid entering debug mode after reset, DSCK must be negated
no later than seven clock cycles after SRESET negates, allowing the
processor to jump to the reset vector and begin normal execution. If
debug mode is entered immediately after reset, as shown in Figure 44-7,
ICR[DPI] is set. The user can enable events that can initiate debug mode
and determine which events require regular interrupt handling.

^ permalink raw reply

* RE: How NEC uPD720101 USB chip work well on linux2.6.12
From: JohnsonCheng @ 2005-08-23  2:25 UTC (permalink / raw)
  To: 'Stefan Nickl'; +Cc: linuxppc-embedded
In-Reply-To: <1124718877.19750.23.camel@lucy.pep-kaufbeuren.de>

I tried this case before, only turn on UHCI option in kernel. The conclusion
is two USB port have the same result ( Kernel Oops), and another one has no
response. Do you know if I want to set these three USB port sharing the same
IRQ, where to modify it in kernel 2.6.12?

Thanks,
Johnson Cheng

-----Original Message-----
From: linuxppc-embedded-bounces@ozlabs.org
[mailto:linuxppc-embedded-bounces@ozlabs.org] On Behalf Of Stefan Nickl
Sent: Monday, August 22, 2005 9:55 PM
To: JohnsonCheng
Cc: linuxppc-embedded@ozlabs.org
Subject: Re: How NEC uPD720101 USB chip work well on linux2.6.12

On Fri, 2005-07-22 at 20:26 +0800, JohnsonCheng wrote:
> Dear All,
>  
> 
> I use NEC uPD720101 USB chip, 2 OHCI and 1 EHCI, I also have turn on
> the following options in kernel menuconfig:
[...]
> [*] USB Support / EHCI HCD (USB 2.0) support
[...]
>  
> 
> But when I plug-in a USB mouse, then Kernel Oops..
> 
> I use MPC8241 CPU, and there are three USB ports sharing the same IRQ
> on my borad.

I recently came across similar trouble with a chip from this series, the
uPD720113 and another one in a off-the-shelf USB hub which I tried for
reference.
It may have been even the 101, but I'm not sure.

Anyways, I've also seen hard resets with 2.6.12 to 2.6.13-rc-something,
albeit in a x86-environment. The system would reset hard when plugging
something after the hub or the hub itself, in case of the 113 it crashed
100% as soon as the hub was attached or detected during bootup. With the
off-the-shelf hub, it was somewhat more random.

In my case, disabling the EHCI controller in the BIOS helped, so you may
try to disable the USB "2.0" support in the kernel config and see what
happens.
No problems running the system with only UHCI for some weeks now.

I've deferred this problem because Hi-Speed is not an issue to me now,
but I'd be curious to hear and test things if somebody had a take on
this.

Regards,

-- 
Stefan Nickl
Kontron Modular Computers


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

^ permalink raw reply

* [PATCH 3/3] fs_enet: support
From: Pantelis Antoniou @ 2005-08-22 19:21 UTC (permalink / raw)
  To: linuxppc-embedded

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

Hi 

This is a snapshot of the work in progress of the new
fs_enet driver. It's aim is to replace all the various
SCC/FCC/FEC drivers for the Freescale PQs.

Don't expect it to work on your board just yet, just take
a look and comment.

This part contains the support files for it to work 
(platform devices & the rest).

Regards

Pantelis

[-- Attachment #2: fs_enet-support.patch --]
[-- Type: text/plain, Size: 36284 bytes --]

diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
--- a/arch/ppc/platforms/Makefile
+++ b/arch/ppc/platforms/Makefile
@@ -46,6 +46,8 @@ obj-$(CONFIG_SANDPOINT)		+= sandpoint.o
 obj-$(CONFIG_SBC82xx)		+= sbc82xx.o
 obj-$(CONFIG_SPRUCE)		+= spruce.o
 obj-$(CONFIG_LITE5200)		+= lite5200.o
+obj-$(CONFIG_MPC86XADS)		+= mpc866ads_setup.o
+obj-$(CONFIG_MPC885ADS)		+= mpc885ads_setup.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_PMAC)		+= pmac_smp.o
diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/platforms/mpc866ads_setup.c
@@ -0,0 +1,378 @@
+/*
+ * arch/ppc/platforms/mpc866ads.c  Platform setup for the Freescale mpc86Xads board
+ *
+ * Copyright 2005 MontaVista Software Inc.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/mpc8xx.h>
+
+extern unsigned char __res[];
+
+/* access ports */
+#define setbits32(_addr, _v) out_be32(&(_addr), in_be32(&(_addr)) |  (_v))
+#define clrbits32(_addr, _v) out_be32(&(_addr), in_be32(&(_addr)) & ~(_v))
+
+#define setbits16(_addr, _v) out_be16(&(_addr), in_be16(&(_addr)) |  (_v))
+#define clrbits16(_addr, _v) out_be16(&(_addr), in_be16(&(_addr)) & ~(_v))
+
+#define MPC8xx_INT_SCC1		(CPM_IRQ_OFFSET + CPMVEC_SCC1)
+#define MPC8xx_INT_SCC2		(CPM_IRQ_OFFSET + CPMVEC_SCC2)
+#define MPC8xx_INT_SCC3		(CPM_IRQ_OFFSET + CPMVEC_SCC3)
+#define MPC8xx_INT_SCC4		(CPM_IRQ_OFFSET + CPMVEC_SCC4)
+#define MPC8xx_INT_SMC1		(CPM_IRQ_OFFSET + CPMVEC_SMC1)
+#define MPC8xx_INT_SMC2		(CPM_IRQ_OFFSET + CPMVEC_SMC2)
+
+/* Offset from IMMAP base address */
+#define MPC8xx_SCC1_OFFSET	(0xa00)
+#define MPC8xx_SCC1_SIZE	(0x18)
+#define MPC8xx_SCC2_OFFSET	(0xa20)
+#define MPC8xx_SCC2_SIZE	(0x18)
+#define MPC8xx_SCC3_OFFSET	(0xa40)
+#define MPC8xx_SCC3_SIZE	(0x18)
+#define MPC8xx_SCC4_OFFSET	(0xa60)
+#define MPC8xx_SCC4_SIZE	(0x18)
+#define MPC8xx_SMC1_OFFSET	(0xa82)
+#define MPC8xx_SMC1_SIZE	(0x0f)
+#define MPC8xx_SMC2_OFFSET	(0xa92)
+#define MPC8xx_SMC2_SIZE	(0x0d)
+#define MPC8xx_FEC1_OFFSET	(0xe00)
+#define MPC8xx_FEC1_SIZE	(0x88)
+#define MPC8xx_DPARAM_SCC1_OFFSET	(0x3C00)
+#define MPC8xx_DPARAM_SCC1_SIZE	(0x80)
+#define MPC8xx_DPARAM_SCC2_OFFSET	(0x3D00)
+#define MPC8xx_DPARAM_SCC2_SIZE	(0x80)
+#define MPC8xx_DPARAM_SCC3_OFFSET	(0x3E00)
+#define MPC8xx_DPARAM_SCC3_SIZE	(0x80)
+#define MPC8xx_DPARAM_SCC4_OFFSET	(0x3F00)
+#define MPC8xx_DPARAM_SCC4_SIZE	(0x80)
+#define MPC8xx_DPARAM_SMC1_OFFSET	(0x3E80)
+#define MPC8xx_DPARAM_SMC1_SIZE	(0x40)
+#define MPC8xx_DPARAM_SMC2_OFFSET	(0x3F80)
+#define MPC8xx_DPARAM_SMC2_SIZE	(0x40)
+
+#ifdef CONFIG_SCC1_ETHERNET
+
+void __init mpc866ads_scc_phy_init(void);
+
+static struct fs_mii_bus_info scc_mii_bus_info = {
+	.method = fsmii_fixed,
+	.id = 0,
+	.i.fixed.speed = 10,
+	.i.fixed.duplex = 0,
+};
+#endif
+
+#if defined (CONFIG_FS_ENET)
+static struct fs_mii_bus_info fec_mii_bus_info = {
+	.method = fsmii_fec,
+	.id = 0,
+};
+
+static struct fs_platform_info mpc8xx_fec_pdata[] = {
+	{
+	 .rx_ring = 128,
+	 .tx_ring = 16,
+	 .rx_copybreak = 240,
+
+	 .use_napi = 1,
+	 .napi_weight = 17,
+	 .bus_info = &fec_mii_bus_info,
+	 },
+};
+#endif
+
+#ifdef CONFIG_SCC1_ETHERNET
+static struct fs_platform_info mpc8xx_scc_pdata[] = {
+	{
+	 .rx_ring = 64,
+	 .tx_ring = 8,
+	 .rx_copybreak = 240,
+
+	 .use_napi = 1,
+	 .napi_weight = 17,
+	 .bus_info = &scc_mii_bus_info,
+	 }
+
+};
+#endif
+
+#if defined (CONFIG_FS_ENET)
+
+static struct platform_device mpc8xx_fec1_device = {
+	.name = FS_ENET_NAME,
+	.id = fsid_fec1,
+	.dev.platform_data = &mpc8xx_fec_pdata[0],
+	.num_resources = 2,
+	.resource = (struct resource[]){
+					{
+					 .name = "regs",
+					 .start =
+					 MPC8xx_FEC1_OFFSET,
+					 MPC8xx_FEC1_OFFSET + MPC8xx_FEC1_SIZE,
+					 .flags = IORESOURCE_MEM,
+					 },
+					{
+					 .name = "interrupt",
+					 .start = FEC_INTERRUPT,
+					 .end = FEC_INTERRUPT,
+					 .flags = IORESOURCE_IRQ,
+					 },
+					},
+};
+#endif
+
+#ifdef CONFIG_SCC1_ETHERNET
+
+static struct platform_device mpc8xx_scc1_device = {
+	.name = FS_ENET_NAME,
+	.id = fsid_scc1,
+	.dev.platform_data = &mpc8xx_scc_pdata,
+	.num_resources = 3,
+	.resource = (struct resource[]){
+					{
+					 .name = "regs",
+					 .start = MPC8xx_SCC1_OFFSET,
+					 .end = MPC8xx_SCC1_OFFSET + MPC8xx_SCC1_SIZE,
+					 .flags = IORESOURCE_MEM,
+					 },
+					{
+					 .name = "pram",
+					 .start = MPC8xx_DPARAM_SCC1_OFFSET,
+					 .end = MPC8xx_DPARAM_SCC1_OFFSET + MPC8xx_DPARAM_SCC1_SIZE,
+					 .flags = IORESOURCE_MEM,
+					 },
+					{
+					 .name = "interrupt",
+					 .start = MPC8xx_INT_SCC1,
+					 .end = MPC8xx_INT_SCC1,
+					 .flags = IORESOURCE_IRQ,
+					 },
+					},
+};
+#endif
+
+static void __init mach_mpc86x_fixup(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < pdev->num_resources; i++) {
+		struct resource *r = &pdev->resource[i];
+		if ((r->flags & IORESOURCE_MEM) == IORESOURCE_MEM) {
+			r->start += IMAP_ADDR;
+			r->end += IMAP_ADDR;
+		}
+	}
+}
+
+static void __init
+mpc86x_nonplatform_device_init (void)
+{
+	volatile cpm8xx_t *cp = cpmp;
+	unsigned long* bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+#ifdef CONFIG_SERIAL_CPM_SMC1
+	cp->cp_simode &= ~(0xe0000000>>17);	/* brg1 */
+	out_be32((volatile unsigned __iomem *)bcsr_io,
+		in_be32((volatile unsigned __iomem *)bcsr_io) &
+			~(0x80000000>>7));
+#else
+	out_be32((volatile unsigned __iomem *)bcsr_io,
+		in_be32((volatile unsigned __iomem *)bcsr_io) |
+			(0x80000000>>7));
+	cp->cp_pbpar &= ~(0x000000c0);
+	cp->cp_pbdir |= 0x000000c0;
+	cp->cp_smc[0].smc_smcmr = 0;
+	cp->cp_smc[0].smc_smce = 0;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+	cp->cp_simode &= ~(0xe0000000>>1);
+	cp->cp_simode |=  (0x20000000>>1);	/* brg2 */
+	out_be32((volatile unsigned __iomem *)bcsr_io,
+		in_be32((volatile unsigned __iomem *)bcsr_io) &
+			~(0x80000000>>13));
+#else
+	out_be32((volatile unsigned __iomem *)bcsr_io,
+		in_be32((volatile unsigned __iomem *)bcsr_io) | (0x80000000>>13));
+	cp->cp_pbpar &= ~(0x00000c00);
+	cp->cp_pbdir |= 0x00000c00;
+	cp->cp_smc[1].smc_smcmr =0;
+	cp->cp_smc[1].smc_smce =0;
+#endif
+	iounmap (bcsr_io);
+}
+
+static void __init mpc866ads_fixup_enet_pdata(struct platform_device *pdev,
+					      int idx)
+{
+	struct fs_platform_info *fpi = pdev->dev.platform_data;
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+	volatile cpm8xx_t *cp;
+	bd_t *bd = (bd_t *) __res;
+	char *e;
+	int i;
+	unsigned long* bcsr_io;
+
+	cp = cpmp;		/* Get pointer to Communication Processor */
+	/* common settings */
+	fpi->fs_no = pdev->id;
+	fpi->use_rmii = 0;
+
+		e = (unsigned char *)&bd->bi_enetaddr;
+		for (i = 0; i < 6; i++)
+			fpi->macaddr[i] = *e++;
+		if (idx)
+			fpi->macaddr[5]++;
+
+	switch (idx) {
+	case fsid_fec1:
+		mach_mpc86x_fixup(&mpc8xx_fec1_device);
+		/* configure FEC1 pins 
+		 */
+		setbits16(immap->im_ioport.iop_pdpar, 0x1fff);
+		setbits16(immap->im_ioport.iop_pddir, 0x1fff);
+		bcsr_io = ioremap (BCSR5, sizeof(unsigned long));
+		out_be32((volatile void __iomem *)bcsr_io, BCSR5_ETHRST | BCSR5_ETHEN);
+		iounmap (bcsr_io);
+
+		/* setup specific */
+		fpi->phy_addr = -1;
+		fpi->phy_irq = PHY_INTERRUPT;
+
+		break;
+
+	case fsid_scc1:
+		mach_mpc86x_fixup(&mpc8xx_scc1_device);
+		/* Enable the PHY.
+		 */
+		bcsr_io = ioremap (BCSR1, sizeof(unsigned long));
+		out_be32((volatile void __iomem *)bcsr_io, 
+			((in_be32((volatile void __iomem *)bcsr_io) & ~BCSR1_ETHEN)));
+		iounmap (bcsr_io);
+
+		/* Configure port A pins for Txd and Rxd.
+		 */
+	        /* Disable receive and transmit in case EPPC-Bug started it.
+        	*/
+		setbits16(immap->im_ioport.iop_papar,
+			  PA_ENET_RXD | PA_ENET_TXD);
+		clrbits16(immap->im_ioport.iop_padir,
+			  PA_ENET_RXD | PA_ENET_TXD);
+		clrbits16(immap->im_ioport.iop_paodr, PA_ENET_TXD);
+
+		/* Configure port C pins to enable CLSN and RENA.
+		 */
+		clrbits16(immap->im_ioport.iop_pcpar,
+			  PC_ENET_CLSN | PC_ENET_RENA);
+		clrbits16(immap->im_ioport.iop_pcdir,
+			  PC_ENET_CLSN | PC_ENET_RENA);
+		setbits16(immap->im_ioport.iop_pcso,
+			  PC_ENET_CLSN | PC_ENET_RENA);
+		/* Configure port A for TCLK and RCLK.
+		 */
+		setbits16(immap->im_ioport.iop_papar, PA_ENET_TCLK | PA_ENET_RCLK);
+		clrbits16(immap->im_ioport.iop_padir,
+			  PA_ENET_TCLK | PA_ENET_RCLK);
+		clrbits32(immap->im_cpm.cp_pbpar, PB_ENET_TENA);
+		clrbits32(immap->im_cpm.cp_pbdir, PB_ENET_TENA);
+
+		/* Configure Serial Interface clock routing.
+		 * First, clear all SCC bits to zero, then set the ones we want.
+		 */
+		clrbits32(immap->im_cpm.cp_sicr, SICR_ENET_MASK);
+		setbits32(immap->im_cpm.cp_sicr, SICR_ENET_CLKRT);
+
+		fpi->phy_addr = -1;
+		fpi->phy_irq = -1;
+
+		/* In the original SCC enet driver the following code is placed at the end of the initialization */
+		setbits32(immap->im_cpm.cp_pbpar, PB_ENET_TENA);
+		setbits32(immap->im_cpm.cp_pbdir, PB_ENET_TENA);
+		break;
+	}
+}
+
+static int __init mpc866ads_platform_notify(struct device *dev)
+{
+	/* devices in the table below usially have bus_id look like __name__ ".__num" when several devices
+	reside in one bus, this __num will be passed into rtn function as idx. In case of FS_ENET, no need 
+	to duplicate as we already have "id" field in platform_device. This is just a remembrance where
+	the respictive fs_no should be pulled from. */
+	static struct {
+		const char *drv_id;
+		int dev_id;
+		void (*rtn) (struct platform_device * pdev, int idx);
+	} dev_map [] = {
+#ifdef CONFIG_FS_ENET
+		{FS_ENET_NAME, fsid_fec1, mpc866ads_fixup_enet_pdata},
+#endif
+#ifdef CONFIG_SCC1_ETHERNET
+		{FS_ENET_NAME, fsid_scc1, mpc866ads_fixup_enet_pdata},
+#endif
+	};
+
+	struct platform_device *pdev;
+	int i, j, idx;
+	char *s;
+
+	if (dev && dev->bus_id)
+		for (i = 0; i < ARRAY_SIZE(dev_map); i++) {
+			idx = -1;
+
+			if ((s = strrchr(dev->bus_id, '.')) != NULL) {
+				idx = (int)simple_strtol(s + 1, NULL, 10);
+			} else
+				s = dev->bus_id;
+			j = s - dev->bus_id;
+
+			if ((!strncmp(dev->bus_id, dev_map[i].drv_id, j)) &&
+			    (idx == dev_map[i].dev_id)) {
+				pdev =
+				    container_of(dev, struct platform_device,
+						 dev);
+				dev_map[i].rtn(pdev, idx);
+			}
+		}
+	return 0;
+}
+
+int __init mpc866ads_init(void)
+{
+	printk(KERN_NOTICE "mpc866ads: Init\n");
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc866ads_init:enter", 0);
+	mpc86x_nonplatform_device_init();
+	platform_notify = mpc866ads_platform_notify;
+#if defined (CONFIG_FS_ENET)
+	platform_device_register(&mpc8xx_fec1_device);
+#endif
+#ifdef CONFIG_SCC1_ETHERNET
+	platform_device_register(&mpc8xx_scc1_device);
+#endif
+	return 0;
+}
+
+arch_initcall(mpc866ads_init);
diff --git a/arch/ppc/platforms/mpc885ads.h b/arch/ppc/platforms/mpc885ads.h
--- a/arch/ppc/platforms/mpc885ads.h
+++ b/arch/ppc/platforms/mpc885ads.h
@@ -88,5 +88,7 @@
 #define SICR_ENET_MASK	((uint)0x00ff0000)
 #define SICR_ENET_CLKRT	((uint)0x002c0000)
 
+#define BOARD_NAME "MPC885"
+
 #endif /* __ASM_MPC885ADS_H__ */
 #endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/mpc885ads_setup.c b/arch/ppc/platforms/mpc885ads_setup.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/platforms/mpc885ads_setup.c
@@ -0,0 +1,399 @@
+/*arch/ppc/platforms/mpc885ads-setup.c  
+ *
+ * Platform setup for the Freescale mpc885ads board
+ *
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright 2005 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+
+extern unsigned char __res[];
+
+/* access ports */
+#define setbits32(_addr, _v) out_be32(&(_addr), in_be32(&(_addr)) |  (_v))
+#define clrbits32(_addr, _v) out_be32(&(_addr), in_be32(&(_addr)) & ~(_v))
+
+#define setbits16(_addr, _v) out_be16(&(_addr), in_be16(&(_addr)) |  (_v))
+#define clrbits16(_addr, _v) out_be16(&(_addr), in_be16(&(_addr)) & ~(_v))
+
+void __init mpc885ads_scc_phy_init(void);
+
+static struct fs_mii_bus_info fec_mii_bus_info = {
+	.method = fsmii_fec,
+	.id = 0,
+};
+
+static struct fs_mii_bus_info scc_mii_bus_info = {
+#ifdef CONFIG_MPC885ADS_SCC_ENET_FIXED
+	.method = fsmii_fixed,
+#else
+	.method = fsmii_fec,
+#endif
+
+	.id = 0,
+};
+
+static struct fs_platform_info mpc8xx_fec_pdata[] = {
+	{
+	 .rx_ring = 128,
+	 .tx_ring = 16,
+	 .rx_copybreak = 240,
+
+	 .use_napi = 1,
+	 .napi_weight = 17,
+
+	 .bus_info = &fec_mii_bus_info,
+	 }, {
+	     .rx_ring = 128,
+	     .tx_ring = 16,
+	     .rx_copybreak = 240,
+
+	     .use_napi = 1,
+	     .napi_weight = 17,
+
+	     .bus_info = &fec_mii_bus_info,
+	     }
+};
+
+static struct fs_platform_info mpc8xx_scc_pdata = {
+	 .rx_ring = 64,
+	 .tx_ring = 8,
+	 .rx_copybreak = 240,
+
+	 .use_napi = 1,
+	 .napi_weight = 17,
+	 .bus_info = &scc_mii_bus_info,
+};
+
+static void __init mpc885_nonplatform_device_init(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+	volatile cpm8xx_t *cp = cpmp;
+	unsigned long *bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+	BUG_ON(bcsr_io == NULL);	/* check */
+
+#ifdef CONFIG_SERIAL_CPM_SMC1
+	cp->cp_simode &= ~(0xe0000000 >> 17);	/* brg1 */
+	out_be32((volatile unsigned __iomem *)bcsr_io,
+		 in_be32((volatile unsigned __iomem *)bcsr_io) &
+		 ~BCSR1_RS232EN_1);
+#else
+	out_be32((volatile unsigned __iomem *)bcsr_io,
+		 in_be32((volatile unsigned __iomem *)bcsr_io) |
+		 BCSR1_RS232EN_1);
+	cp->cp_smc[0].smc_smcmr = 0;
+	cp->cp_smc[0].smc_smce = 0;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+	cp->cp_simode &= ~(0xe0000000 >> 1);
+	cp->cp_simode |= (0x20000000 >> 1);	/* brg2 */
+	out_be32((volatile unsigned __iomem *)bcsr_io,
+		 in_be32((volatile unsigned __iomem *)bcsr_io) &
+		 ~BCSR1_RS232EN_2);
+#else
+	out_be32((volatile unsigned __iomem *)bcsr_io,
+		 in_be32((volatile unsigned __iomem *)bcsr_io) |
+		 BCSR1_RS232EN_2);
+	cp->cp_smc[1].smc_smcmr = 0;
+	cp->cp_smc[1].smc_smce = 0;
+#endif
+	iounmap(bcsr_io);
+
+#ifdef CONFIG_FS_ENET
+	/* use MDC for MII (common) */
+	setbits16(immap->im_ioport.iop_pdpar, 0x0080);
+	clrbits16(immap->im_ioport.iop_pddir, 0x0080);
+#endif
+}
+
+static void setup_fec1_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+
+	/* configure FEC1 pins  */
+	setbits16(immap->im_ioport.iop_papar, 0xf830);
+	setbits16(immap->im_ioport.iop_padir, 0x0830);
+	clrbits16(immap->im_ioport.iop_padir, 0xf000);
+	setbits32(immap->im_cpm.cp_pbpar, 0x00001001);
+
+	clrbits32(immap->im_cpm.cp_pbdir, 0x00001001);
+	setbits16(immap->im_ioport.iop_pcpar, 0x000c);
+	clrbits16(immap->im_ioport.iop_pcdir, 0x000c);
+	setbits32(immap->im_cpm.cp_pepar, 0x00000003);
+
+	setbits32(immap->im_cpm.cp_pedir, 0x00000003);
+	clrbits32(immap->im_cpm.cp_peso, 0x00000003);
+	clrbits32(immap->im_cpm.cp_cptr, 0x00000100);
+}
+
+static void setup_fec2_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+
+	/* configure FEC2 pins */
+	setbits32(immap->im_cpm.cp_pepar, 0x0003fffc);
+	setbits32(immap->im_cpm.cp_pedir, 0x0003fffc);
+	setbits32(immap->im_cpm.cp_peso, 0x00037800);
+	clrbits32(immap->im_cpm.cp_peso, 0x000087fc);
+	clrbits32(immap->im_cpm.cp_cptr, 0x00000080);
+}
+
+static void setup_scc3_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+	unsigned long *bcsr_io;
+
+	bcsr_io = ioremap(BCSR0, sizeof(unsigned long) * 5);
+
+	/* Enable the PHY.
+	 */
+	out_be32((volatile void __iomem *)(bcsr_io + 4),
+		 (in_be32((volatile void __iomem *)(bcsr_io + 4)) |
+		  BCSR4_ETH10_RST));
+	
+	/* Configure port A pins for Txd and Rxd.
+	 */
+	setbits16(immap->im_ioport.iop_papar, PA_ENET_RXD | PA_ENET_TXD);
+	clrbits16(immap->im_ioport.iop_padir, PA_ENET_RXD | PA_ENET_TXD);
+
+	/* Configure port C pins to enable CLSN and RENA.
+	 */
+	clrbits16(immap->im_ioport.iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
+	clrbits16(immap->im_ioport.iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
+	setbits16(immap->im_ioport.iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
+
+	/* Configure port E for TCLK and RCLK.
+	 */
+	setbits32(immap->im_cpm.cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK);
+	clrbits32(immap->im_cpm.cp_pepar, PE_ENET_TENA);
+	clrbits32(immap->im_cpm.cp_pedir,
+		  PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA);
+	clrbits32(immap->im_cpm.cp_peso, PE_ENET_TCLK | PE_ENET_RCLK);
+	setbits32(immap->im_cpm.cp_peso, PE_ENET_TENA);
+
+	/* Configure Serial Interface clock routing.
+	 * First, clear all SCC bits to zero, then set the ones we want.
+	 */
+	clrbits32(immap->im_cpm.cp_sicr, SICR_ENET_MASK);
+	setbits32(immap->im_cpm.cp_sicr, SICR_ENET_CLKRT);
+
+	/* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used.
+	 */
+	immap->im_cpm.cp_smc[0].smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+	/* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex mode
+	 * by H/W setting after reset. SCC ethernet controller support only half duplex.
+	 * This discrepancy of modes causes a lot of carrier lost errors.
+	 */
+	
+	/* In the original SCC enet driver the following code is placed at the end of the initialization */
+	setbits32(immap->im_cpm.cp_pepar, PE_ENET_TENA);
+	clrbits32(immap->im_cpm.cp_pedir, PE_ENET_TENA);
+	setbits32(immap->im_cpm.cp_peso, PE_ENET_TENA);
+
+	out_be32(((volatile void __iomem *)(bcsr_io + 1)),
+		 (in_be32((volatile void __iomem *)(bcsr_io + 1)) |
+		  BCSR1_ETHEN));
+	iounmap(bcsr_io);
+
+}
+
+static void __init mpc885ads_fixup_enet_pdata(struct platform_device *pdev,
+					      int fs_no)
+{
+	struct fs_platform_info *fpi = pdev->dev.platform_data;
+
+	volatile cpm8xx_t *cp;
+	bd_t *bd = (bd_t *) __res;
+	char *e;
+	int i;
+
+	/* Get pointer to Communication Processor */
+	cp = cpmp;
+	switch (fs_no) {
+	case fsid_fec1:
+		fpi = &mpc8xx_fec_pdata[fs_get_fec_index(fs_no)];
+		fpi->init_ioports = &setup_fec1_ioports;
+
+		fpi->phy_addr = 0;
+		fpi->phy_irq = SIU_IRQ7;
+		break;
+	case fsid_fec2:
+		fpi = &mpc8xx_fec_pdata[fs_get_fec_index(fs_no)];
+		fpi->init_ioports = &setup_fec2_ioports;
+
+		fpi->phy_addr = 1;
+		fpi->phy_irq = SIU_IRQ7;
+		break;
+	case fsid_scc3:
+		fpi = &mpc8xx_scc_pdata;
+		fpi->init_ioports = &setup_scc3_ioports;
+		mpc885ads_scc_phy_init();
+
+		fpi->phy_addr = 2;
+
+#ifdef CONFIG_MPC885ADS_SCC_ENET_FIXED
+		fpi->phy_irq = -1;
+#else
+		fpi->phy_irq = SIU_IRQ7;
+#endif
+
+		break;
+	default:
+		break;
+	}
+
+	pdev->dev.platform_data = fpi;
+	fpi->fs_no = fs_no;
+	fpi->use_rmii = 0;
+	e = (unsigned char *)&bd->bi_enetaddr;
+	for (i = 0; i < 6; i++)
+		fpi->macaddr[i] = *e++;
+
+	fpi->macaddr[5 - pdev->id]++;
+
+}
+
+static void __init mpc885ads_fixup_fec_enet_pdata(struct platform_device* pdev, int idx)
+{
+	int fs_no = fsid_fec1 + pdev->id -1;
+	mpc885ads_fixup_enet_pdata(pdev, fs_no);
+}
+
+static void __init mpc885ads_fixup_scc_enet_pdata(struct platform_device* pdev, int idx)
+{
+	int fs_no = fsid_scc1 + pdev->id -1;
+	mpc885ads_fixup_enet_pdata(pdev, fs_no);
+}
+
+/* SCC ethernet controller does not have MII management channel. FEC1 MII
+ * channel is used to communicate with the 10Mbit PHY.
+ */
+
+#define PHY_ADDR            0x2
+
+#define MII_ECNTRL_PINMUX        0x4
+#define FEC_ECNTRL_PINMUX        0x00000004
+#define FEC_RCNTRL_MII_MODE        0x00000004
+
+/* Make MII read/write commands.
+ */
+#define mk_mii_write(REG, VAL)    (0x50020000 | (((REG) & 0x1f) << 18) | \
+                ((VAL) & 0xffff) | (PHY_ADDR << 23))
+
+void __init mpc885ads_scc_phy_init(void)
+{
+	volatile immap_t *immap;
+	volatile fec_t *fecp;
+	bd_t *bd;
+
+	bd = (bd_t *) __res;
+	immap = (immap_t *) IMAP_ADDR;	/* pointer to internal registers */
+	fecp = &(immap->im_cpm.cp_fec);
+
+	/* Enable MII pins of the FEC1
+	 */
+	immap->im_ioport.iop_pdpar |= 0x0080;
+	immap->im_ioport.iop_pddir &= ~0x0080;
+	/* Set MII speed to 2.5 MHz
+	 */
+	fecp->fec_mii_speed =
+	    ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1;
+
+	/* Enable FEC pin MUX
+	 */
+	fecp->fec_ecntrl |= MII_ECNTRL_PINMUX;
+	fecp->fec_r_cntrl |= FEC_RCNTRL_MII_MODE;
+
+	fecp->fec_mii_data = mk_mii_write(MII_BMCR, BMCR_ISOLATE);
+	udelay(100);
+	fecp->fec_mii_data =
+	    mk_mii_write(MII_ADVERTISE, ADVERTISE_10HALF | ADVERTISE_CSMA);
+	udelay(100);
+
+	/* Disable FEC MII settings
+	 */
+	fecp->fec_ecntrl &= ~MII_ECNTRL_PINMUX;
+	fecp->fec_r_cntrl &= ~FEC_RCNTRL_MII_MODE;
+	fecp->fec_mii_speed = 0;
+}
+
+static int __init mpc885ads_platform_notify(struct device *dev)
+{
+	static struct {
+		const char *bus_id;
+		void (*rtn) (struct platform_device * pdev, int idx);
+	} dev_map[] = {
+		{"fsl-cpm-fec", mpc885ads_fixup_fec_enet_pdata}, 
+		{"fsl-cpm-scc", mpc885ads_fixup_scc_enet_pdata},
+	};
+	struct platform_device *pdev;
+	int i, j, idx;
+	const char *s;
+	if (dev && dev->bus_id)
+		for (i = 0; i < ARRAY_SIZE(dev_map); i++) {
+			idx = -1;
+
+			if ((s = strrchr(dev->bus_id, '.')) != NULL)
+				idx = (int)simple_strtol(s + 1, NULL, 10);
+			else
+				s = dev->bus_id;
+			j = s - dev->bus_id;
+			if (!strncmp(dev->bus_id, dev_map[i].bus_id, j)) {
+				pdev =
+				    container_of(dev, struct platform_device,
+						 dev);
+				dev_map[i].rtn(pdev, idx);
+			}
+		}
+	return 0;
+}
+
+int __init mpc885ads_init(void)
+{
+	printk(KERN_NOTICE "mpc885ads: Init\n");
+
+	mpc885_nonplatform_device_init();
+	platform_notify = mpc885ads_platform_notify;
+
+	identify_ppc_sys_by_name(BOARD_NAME);
+
+#ifdef CONFIG_MPC885ADS_SECOND_ETH_SCC
+	ppc_sys_device_remove(MPC8xx_CPM_FEC2);	
+#endif
+#ifdef CONFIG_MPC885ADS_SECOND_ETH_FEC2
+	ppc_sys_device_remove(MPC8xx_CPM_SCC3);
+#endif
+	
+	return 0;
+}
+
+arch_initcall(mpc885ads_init);
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -34,7 +34,8 @@ ifeq ($(CONFIG_40x),y)
 obj-$(CONFIG_PCI)		+= indirect_pci.o pci_auto.o ppc405_pci.o
 endif
 endif
-obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y)
+obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) \
+				   ppc_sys.o mpc8xx_devices.o mpc8xx_sys.o
 ifeq ($(CONFIG_8xx),y)
 obj-$(CONFIG_PCI)		+= qspan_pci.o i8259.o
 endif
diff --git a/arch/ppc/syslib/mpc8xx_devices.c b/arch/ppc/syslib/mpc8xx_devices.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/mpc8xx_devices.c
@@ -0,0 +1,274 @@
+/*
+ * arch/ppc/syslib/mpc8xx_devices.c
+ *
+ * MPC8xx Device descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 MontaVista Software, Inc. by Vitaly Bordug<vbordug@ru.mvista.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/module.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <linux/fsl_devices.h>
+#include <linux/fs_enet_pd.h>
+#include <linux/mii.h>
+#include <asm/commproc.h>
+#include <asm/mpc8xx.h>
+#include <asm/irq.h>
+#include <asm/ppc_sys.h>
+
+/* access ports */
+#define setbits32(_addr, _v) out_be32(&(_addr), in_be32(&(_addr)) |  (_v))
+#define clrbits32(_addr, _v) out_be32(&(_addr), in_be32(&(_addr)) & ~(_v))
+
+#define setbits16(_addr, _v) out_be16(&(_addr), in_be16(&(_addr)) |  (_v))
+#define clrbits16(_addr, _v) out_be16(&(_addr), in_be16(&(_addr)) & ~(_v))
+
+#define MPC8xx_INT_FEC1		SIU_LEVEL1
+#define MPC8xx_INT_FEC2		SIU_LEVEL3
+
+#define MPC8xx_INT_SCC1		(CPM_IRQ_OFFSET + CPMVEC_SCC1)
+#define MPC8xx_INT_SCC2		(CPM_IRQ_OFFSET + CPMVEC_SCC2)
+#define MPC8xx_INT_SCC3		(CPM_IRQ_OFFSET + CPMVEC_SCC3)
+#define MPC8xx_INT_SCC4		(CPM_IRQ_OFFSET + CPMVEC_SCC4)
+#define MPC8xx_INT_SMC1		(CPM_IRQ_OFFSET + CPMVEC_SMC1)
+#define MPC8xx_INT_SMC2		(CPM_IRQ_OFFSET + CPMVEC_SMC2)
+
+/* Offset from IMMAP base address */
+#define MPC8xx_SCC1_OFFSET	(0xa00)
+#define MPC8xx_SCC1_SIZE	(0x18)
+#define MPC8xx_SCC2_OFFSET	(0xa20)
+#define MPC8xx_SCC2_SIZE	(0x18)
+#define MPC8xx_SCC3_OFFSET	(0xa40)
+#define MPC8xx_SCC3_SIZE	(0x18)
+#define MPC8xx_SCC4_OFFSET	(0xa60)
+#define MPC8xx_SCC4_SIZE	(0x18)
+#define MPC8xx_SMC1_OFFSET	(0xa82)
+#define MPC8xx_SMC1_SIZE	(0x0f)
+#define MPC8xx_SMC2_OFFSET	(0xa92)
+#define MPC8xx_SMC2_SIZE	(0x0d)
+#define MPC8xx_FEC1_OFFSET	(0xe00)
+#define MPC8xx_FEC1_SIZE	(0x88)
+#define MPC8xx_FEC2_OFFSET	(0x1e00)
+#define MPC8xx_FEC2_SIZE	(0x88)
+
+#define MPC8xx_DPARAM_SCC1_OFFSET	(0x3C00)
+#define MPC8xx_DPARAM_SCC1_SIZE	(0x80)
+#define MPC8xx_DPARAM_SCC2_OFFSET	(0x3D00)
+#define MPC8xx_DPARAM_SCC2_SIZE	(0x80)
+#define MPC8xx_DPARAM_SCC3_OFFSET	(0x3E00)
+#define MPC8xx_DPARAM_SCC3_SIZE	(0x80)
+#define MPC8xx_DPARAM_SCC4_OFFSET	(0x3F00)
+#define MPC8xx_DPARAM_SCC4_SIZE	(0x80)
+#define MPC8xx_DPARAM_SMC1_OFFSET	(0x3E80)
+#define MPC8xx_DPARAM_SMC1_SIZE	(0x40)
+#define MPC8xx_DPARAM_SMC2_OFFSET	(0x3F80)
+#define MPC8xx_DPARAM_SMC2_SIZE	(0x40)
+
+/* We use offsets for IORESOURCE_MEM to do not set dependences at compile time.
+ * They will get fixed up by mach_mpc8xx_fixup
+ */
+
+struct platform_device ppc_sys_platform_devices[] = {
+	[MPC8xx_CPM_FEC1] =	{
+		.name = "fsl-cpm-fec",
+		.id	= 1,
+		.num_resources = 2,
+		.resource = (struct resource[])	{
+			{
+				.name 	= "regs",
+				.start	= MPC8xx_FEC1_OFFSET,
+				.end	= MPC8xx_FEC1_OFFSET + MPC8xx_FEC1_SIZE,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name	= "interrupt",
+				.start	= MPC8xx_INT_FEC1,
+				.end	= MPC8xx_INT_FEC1,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC8xx_CPM_FEC2] =	{
+		.name = "fsl-cpm-fec",
+		.id	= 2,
+		.num_resources = 2,
+		.resource = (struct resource[])	{
+			{
+				.name	= "regs",
+				.start	= MPC8xx_FEC2_OFFSET,
+				.end	= MPC8xx_FEC2_OFFSET + MPC8xx_FEC2_SIZE,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name	= "interrupt",
+				.start	= MPC8xx_INT_FEC2,
+				.end	= MPC8xx_INT_FEC2,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC8xx_CPM_SCC1] = {
+		.name = "fsl-cpm-scc",
+		.id	= 1,
+		.num_resources = 3,
+		.resource = (struct resource[]) {
+			{
+				.name	= "regs",
+				.start	= MPC8xx_SCC1_OFFSET,
+				.end	= MPC8xx_SCC1_OFFSET + MPC8xx_SCC1_SIZE,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name 	= "pram",
+				.start 	= MPC8xx_DPARAM_SCC1_OFFSET,
+				.end 	= MPC8xx_DPARAM_SCC1_OFFSET + MPC8xx_DPARAM_SCC1_SIZE,
+				.flags 	= IORESOURCE_MEM,
+			},
+			{
+				.name	= "interrupt",
+				.start	= MPC8xx_INT_SCC1,
+				.end	= MPC8xx_INT_SCC1,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC8xx_CPM_SCC2] = {
+		.name = "fsl-cpm-scc",
+		.id	= 2,
+		.num_resources	= 3,
+		.resource = (struct resource[]) {
+			{
+				.name	= "regs",
+				.start	= MPC8xx_SCC2_OFFSET,
+				.end	= MPC8xx_SCC2_OFFSET + MPC8xx_SCC2_SIZE,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name 	= "pram",
+				.start 	= MPC8xx_DPARAM_SCC2_OFFSET,
+				.end 	= MPC8xx_DPARAM_SCC2_OFFSET + MPC8xx_DPARAM_SCC2_SIZE,
+				.flags 	= IORESOURCE_MEM,
+			},
+
+			{
+				.name	= "interrupt",
+				.start	= MPC8xx_INT_SCC2,
+				.end	= MPC8xx_INT_SCC2,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC8xx_CPM_SCC3] = {
+		.name = "fsl-cpm-scc",
+		.id	= 3,
+		.num_resources	= 3,
+		.resource = (struct resource[]) {
+			{
+				.name	= "regs",
+				.start	= MPC8xx_SCC3_OFFSET,
+				.end	= MPC8xx_SCC3_OFFSET + MPC8xx_SCC3_SIZE,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name 	= "pram",
+				.start 	= MPC8xx_DPARAM_SCC3_OFFSET,
+				.end 	= MPC8xx_DPARAM_SCC3_OFFSET + MPC8xx_DPARAM_SCC3_SIZE,
+				.flags 	= IORESOURCE_MEM,
+			},
+
+			{
+				.name	= "interrupt",
+				.start	= MPC8xx_INT_SCC3,
+				.end	= MPC8xx_INT_SCC3,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC8xx_CPM_SCC4] = {
+		.name = "fsl-cpm-scc",
+		.id	= 4,
+		.num_resources	= 3,
+		.resource = (struct resource[]) {
+			{
+				.name	= "regs",
+				.start	= MPC8xx_SCC4_OFFSET,
+				.end	= MPC8xx_SCC3_OFFSET + MPC8xx_SCC1_SIZE,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name 	= "pram",
+				.start 	= MPC8xx_DPARAM_SCC4_OFFSET,
+				.end 	= MPC8xx_DPARAM_SCC4_OFFSET + MPC8xx_DPARAM_SCC4_SIZE,
+				.flags 	= IORESOURCE_MEM,
+			},
+
+			{
+				.name	= "interrupt",
+				.start	= MPC8xx_INT_SCC4,
+				.end	= MPC8xx_INT_SCC4,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC8xx_CPM_SMC1] = {
+		.name = "fsl-cpm-smc",
+		.id	= 1,
+		.num_resources	= 2,
+		.resource = (struct resource[]) {
+			{
+				.name	= "regs",
+				.start	= MPC8xx_SMC1_OFFSET,
+				.end	= MPC8xx_SCC3_OFFSET + MPC8xx_SMC1_SIZE,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name	= "interrupt",
+				.start	= MPC8xx_INT_SMC1,
+				.end	= MPC8xx_INT_SMC1,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+	[MPC8xx_CPM_SMC2] = {
+		.name = "fsl-cpm-smc",
+		.id	= 2,
+		.num_resources	= 2,
+		.resource = (struct resource[]) {
+			{
+				.name	= "regs",
+				.start	= MPC8xx_SMC2_OFFSET,
+				.end	= MPC8xx_SMC2_OFFSET + MPC8xx_SMC2_SIZE,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name	= "interrupt",
+				.start	= MPC8xx_INT_SMC2,
+				.end	= MPC8xx_INT_SMC2,
+				.flags	= IORESOURCE_IRQ,
+			},
+		},
+	},
+};
+
+static int __init mach_mpc8xx_fixup(struct platform_device *pdev)
+{
+	ppc_sys_fixup_mem_resource (pdev, IMAP_ADDR);
+	return 0;
+}
+
+static int __init mach_mpc8xx_init(void)
+{
+	ppc_sys_device_fixup = mach_mpc8xx_fixup;
+	return 0;
+}
+
+postcore_initcall(mach_mpc8xx_init);
diff --git a/arch/ppc/syslib/mpc8xx_sys.c b/arch/ppc/syslib/mpc8xx_sys.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/mpc8xx_sys.c
@@ -0,0 +1,51 @@
+/*
+ * arch/ppc/platforms/mpc8xx_sys.c
+ *
+ * MPC8xx System descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 MontaVista Software, Inc. by Vitaly Bordug <vbordug@ru.mvista.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/module.h>
+#include <linux/device.h>
+#include <asm/ppc_sys.h>
+
+struct ppc_sys_spec *cur_ppc_sys_spec; 
+struct ppc_sys_spec ppc_sys_specs[] = {
+	{
+		.ppc_sys_name	= "MPC86X",
+		.mask 		= 0xFFFFFFFF,
+		.value 		= 0x00000000,
+		.num_devices	= 2,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC8xx_CPM_FEC1,
+			MPC8xx_CPM_SCC1,
+		},
+	},
+	{
+		.ppc_sys_name	= "MPC885",
+		.mask 		= 0xFFFFFFFF,
+		.value 		= 0x00000000,
+		.num_devices	= 3,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC8xx_CPM_FEC1,
+			MPC8xx_CPM_FEC2,
+			MPC8xx_CPM_SCC3,
+		},
+	},
+	{	/* default match */
+		.ppc_sys_name	= "",
+		.mask 		= 0x00000000,
+		.value 		= 0x00000000,
+	},
+};
diff --git a/arch/ppc/syslib/ppc_sys.c b/arch/ppc/syslib/ppc_sys.c
--- a/arch/ppc/syslib/ppc_sys.c
+++ b/arch/ppc/syslib/ppc_sys.c
@@ -6,6 +6,7 @@
  * Maintainer: Kumar Gala <kumar.gala@freescale.com>
  *
  * Copyright 2005 Freescale Semiconductor Inc.
+ * Copyright 2005 MontaVista, Inc. by Vitaly Bordug <vbordug@ru.mvista.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
@@ -35,10 +36,58 @@ void __init identify_ppc_sys_by_id(u32 i
 
 void __init identify_ppc_sys_by_name(char *name)
 {
-	/* TODO */
+	unsigned int i = 0;
+	while (strcmp(ppc_sys_specs[i].ppc_sys_name, "")) {
+		if (!strcmp(ppc_sys_specs[i].ppc_sys_name, name))
+			break;
+		i++;
+	}
+	cur_ppc_sys_spec = &ppc_sys_specs[i];
 	return;
 }
 
+static int __init count_sys_specs(void)
+{
+	int i = 0;
+	while (ppc_sys_specs[i].ppc_sys_name[0])
+		i++;
+	return i;
+}
+
+static int __init find_chip_by_name_and_id(char *name, u32 id)
+{
+	int ret = -1;
+	unsigned int i = 0;
+	unsigned int j = 0;
+	unsigned int dups = 0;
+
+	unsigned char matched[count_sys_specs()];
+
+	while (ppc_sys_specs[i].ppc_sys_name[0]) {
+		if (!strcmp(ppc_sys_specs[i].ppc_sys_name, name))
+			matched[j++] = i;
+		i++;
+	}
+	if (j != 0) {
+		for (i = 0; i < j; i++) {
+			if ((ppc_sys_specs[matched[i]].mask & id) ==
+			    ppc_sys_specs[matched[i]].value) {
+				ret = matched[i];
+				dups++;
+			}
+		}
+		ret = (dups == 1) ? ret : (-1 * dups);
+	}
+	return ret;
+}
+
+void __init identify_ppc_sys_by_name_and_id(char *name, u32 id)
+{
+	int i = find_chip_by_name_and_id(name, id);
+	BUG_ON(i < 0);
+	cur_ppc_sys_spec = &ppc_sys_specs[i];
+}
+
 /* Update all memory resources by paddr, call before platform_device_register */
 void __init
 ppc_sys_fixup_mem_resource(struct platform_device *pdev, phys_addr_t paddr)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
new file mode 100644
diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile
new file mode 100644
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
new file mode 100644
diff --git a/drivers/net/fs_enet/fs_enet-mii.c b/drivers/net/fs_enet/fs_enet-mii.c
new file mode 100644
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
new file mode 100644
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
new file mode 100644
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
new file mode 100644
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
new file mode 100644
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
new file mode 100644
diff --git a/drivers/net/fs_enet/mii-fixed.c b/drivers/net/fs_enet/mii-fixed.c
new file mode 100644
diff --git a/include/asm-ppc/mpc8xx.h b/include/asm-ppc/mpc8xx.h
--- a/include/asm-ppc/mpc8xx.h
+++ b/include/asm-ppc/mpc8xx.h
@@ -20,6 +20,10 @@
 #include <platforms/fads.h>
 #endif
 
+#ifdef CONFIG_MPC86XADS	
+#include <platforms/8xx/mpc86xads.h>
+#endif
+
 #ifdef CONFIG_RPXLITE
 #include <platforms/rpxlite.h>
 #endif
@@ -101,6 +105,22 @@ extern unsigned char __res[];
 
 struct pt_regs;
 
+enum ppc_sys_devices {
+	MPC8xx_CPM_FEC1,
+	MPC8xx_CPM_FEC2,
+	MPC8xx_CPM_I2C,
+	MPC8xx_CPM_SCC1,
+	MPC8xx_CPM_SCC2,
+	MPC8xx_CPM_SCC3,
+	MPC8xx_CPM_SCC4,
+	MPC8xx_CPM_SPI,
+	MPC8xx_CPM_MCC1,
+	MPC8xx_CPM_MCC2,
+	MPC8xx_CPM_SMC1,
+	MPC8xx_CPM_SMC2,
+	MPC8xx_CPM_USB,
+};
+
 #endif /* !__ASSEMBLY__ */
 #endif /* CONFIG_8xx */
 #endif /* __CONFIG_8xx_DEFS */
diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h
--- a/include/asm-ppc/ppc_sys.h
+++ b/include/asm-ppc/ppc_sys.h
@@ -25,6 +25,8 @@
 #include <asm/mpc83xx.h>
 #elif defined(CONFIG_85xx)
 #include <asm/mpc85xx.h>
+#elif defined(CONFIG_8xx)
+#include <asm/mpc8xx.h>
 #elif defined(CONFIG_PPC_MPC52xx)
 #include <asm/mpc52xx.h>
 #elif defined(CONFIG_MPC10X_BRIDGE)
@@ -49,7 +51,8 @@ extern struct ppc_sys_spec *cur_ppc_sys_
 
 /* determine which specific SOC we are */
 extern void identify_ppc_sys_by_id(u32 id) __init;
-extern void identify_ppc_sys_by_name(char *name) __init;
+extern void identify_ppc_sys_by_name(char* name) __init;
+extern void identify_ppc_sys_by_name_and_id(char *name, u32 id) __init;
 
 /* describes all devices that may exist in a given family of processors */
 extern struct platform_device ppc_sys_platform_devices[];
diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h
new file mode 100644

^ permalink raw reply

* [PATCH 2/3] fs_enet: hardware
From: Pantelis Antoniou @ 2005-08-22 19:21 UTC (permalink / raw)
  To: linuxppc-embedded

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

Hi 

This is a snapshot of the work in progress of the new
fs_enet driver. It's aim is to replace all the various
SCC/FCC/FEC drivers for the Freescale PQs.

Don't expect it to work on your board just yet, just take
a look and comment.

This part contains the hardware specific files (MACs & MIIs)

Regards

Pantelis

[-- Attachment #2: fs_enet-hw.patch --]
[-- Type: text/plain, Size: 56495 bytes --]

--- /dev/null
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -0,0 +1,572 @@
+/*
+ * FCC driver for Motorola MPC82xx (PQ2).
+ *
+ * Copyright (c) 2003 Intracom S.A. 
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc. 
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+
+#include <asm/immap_cpm2.h>
+#include <asm/mpc8260.h>
+#include <asm/cpm2.h>
+
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "fs_enet.h"
+
+/*************************************************/
+
+/* FCC access macros */
+
+#define __fcc_out32(addr, x)	out_be32((unsigned *)addr, x)
+#define __fcc_out16(addr, x)	out_be16((unsigned short *)addr, x)
+#define __fcc_out8(addr, x)	out_8((unsigned char *)addr, x)
+#define __fcc_in32(addr)	in_be32((unsigned *)addr)
+#define __fcc_in16(addr)	in_be16((unsigned short *)addr)
+#define __fcc_in8(addr)		in_8((unsigned char *)addr)
+
+/* parameter space */
+
+/* write, read, set bits, clear bits */
+#define W32(_p, _m, _v)	__fcc_out32(&(_p)->_m, (_v))
+#define R32(_p, _m)	__fcc_in32(&(_p)->_m)
+#define S32(_p, _m, _v)	W32(_p, _m, R32(_p, _m) | (_v))
+#define C32(_p, _m, _v)	W32(_p, _m, R32(_p, _m) & ~(_v))
+
+#define W16(_p, _m, _v)	__fcc_out16(&(_p)->_m, (_v))
+#define R16(_p, _m)	__fcc_in16(&(_p)->_m)
+#define S16(_p, _m, _v)	W16(_p, _m, R16(_p, _m) | (_v))
+#define C16(_p, _m, _v)	W16(_p, _m, R16(_p, _m) & ~(_v))
+
+#define W8(_p, _m, _v)	__fcc_out8(&(_p)->_m, (_v))
+#define R8(_p, _m)	__fcc_in8(&(_p)->_m)
+#define S8(_p, _m, _v)	W8(_p, _m, R8(_p, _m) | (_v))
+#define C8(_p, _m, _v)	W8(_p, _m, R8(_p, _m) & ~(_v))
+
+/*************************************************/
+
+#define FCC_MAX_MULTICAST_ADDRS	64
+
+#define mk_mii_read(REG)	(0x60020000 | ((REG & 0x1f) << 18))
+#define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))
+#define mk_mii_end		0
+
+#define MAX_CR_CMD_LOOPS	10000
+
+static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op)
+{
+	const struct fs_platform_info *fpi = fep->fpi;
+		
+	cpm2_map_t *immap = fs_enet_immap;
+	cpm_cpm2_t *cpmp = &immap->im_cpm;
+	u32 v;
+	
+	/* Currently I don't know what feature call will look like. But 
+	I guess there'd be something like do_cpm_cmd() which will require page & sblock*/
+	v = mk_cr_cmd(fpi->cp_page,fpi->cp_block , mcn, op);
+	W32(cpmp, cp_cpcr, v | CPM_CR_FLG);
+	while ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) != 0)
+		;
+
+	return 0;
+}
+
+static int do_pd_setup(struct fs_enet_private *fep)
+{
+	struct platform_device *pdev = to_platform_device(fep->dev); 
+	struct resource	*r; 
+	
+
+	/* Fill out IRQ field */
+	fep->interrupt = platform_get_irq(pdev, 0);
+	
+	/* Attach the memory for the FCC Parameter RAM */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
+	fep->fcc.ep = (void*)r->start;
+	
+	if(fep->fcc.ep == NULL)
+		return -EINVAL;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs");
+	fep->fcc.fccp =(void*)r->start;
+
+	if(fep->fcc.fccp == NULL)
+		return -EINVAL;
+
+	fep->fcc.fcccp = (void*)fep->fpi->fcc_regs_c;
+
+	if(fep->fcc.fcccp == NULL)
+		return -EINVAL;
+
+	return 0;
+}
+
+#define FCC_NAPI_RX_EVENT_MSK	(FCC_ENET_RXF | FCC_ENET_RXB)
+#define FCC_RX_EVENT		(FCC_ENET_RXF)
+#define FCC_TX_EVENT		(FCC_ENET_TXB)
+#define FCC_ERR_EVENT_MSK	(FCC_ENET_TXE | FCC_ENET_BSY)
+
+static int setup_data(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+
+	fep->fcc.idx = fs_get_fcc_index(fpi->fs_no);
+	if ((unsigned int)fep->fcc.idx >= 3)	/* max 3 FCCs */
+		return -EINVAL;
+	
+	fep->fcc.mem = (void*)fpi->mem_offset;
+	
+	if(do_pd_setup(fep) != 0)
+		return -EINVAL;
+
+	fep->ev_napi_rx = FCC_NAPI_RX_EVENT_MSK;
+	fep->ev_rx = FCC_RX_EVENT;
+	fep->ev_tx = FCC_TX_EVENT;
+	fep->ev_err = FCC_ERR_EVENT_MSK;
+
+	return 0;
+}
+
+static int allocate_bd(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+
+	fep->ring_base = dma_alloc_coherent(fep->dev,
+					    (fpi->tx_ring + fpi->rx_ring) *
+					    sizeof(cbd_t), &fep->ring_mem_addr,
+					    GFP_KERNEL);
+	if (fep->ring_base == NULL) {
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void free_bd(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+
+	if(fep->ring_base)
+		dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring)
+					* sizeof(cbd_t),
+					fep->ring_base,
+					fep->ring_mem_addr);
+}
+
+static void cleanup_data(struct net_device *dev)
+{
+	/* nothing */
+}
+
+static void set_promiscuous_mode(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	S32(fccp, fcc_fpsmr, FCC_PSMR_PRO);
+}
+
+static void set_multicast_start(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_enet_t *ep = fep->fcc.ep;
+
+	W32(ep, fen_gaddrh, 0);
+	W32(ep, fen_gaddrl, 0);
+}
+
+static void set_multicast_one(struct net_device *dev, const u8 *mac)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_enet_t *ep = fep->fcc.ep;
+	u16 taddrh, taddrm, taddrl;
+
+	taddrh = ((u16)mac[5] << 8) | mac[4];
+	taddrm = ((u16)mac[3] << 8) | mac[2];
+	taddrl = ((u16)mac[1] << 8) | mac[0];
+
+	W16(ep, fen_taddrh, taddrh);
+	W16(ep, fen_taddrm, taddrm);
+	W16(ep, fen_taddrl, taddrl);
+	fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR);
+}
+
+static void set_multicast_finish(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+	fcc_enet_t *ep = fep->fcc.ep;
+
+	/* clear promiscuous always */
+	C32(fccp, fcc_fpsmr, FCC_PSMR_PRO);
+
+	/* if all multi or too many multicasts; just enable all */
+	if ((dev->flags & IFF_ALLMULTI) != 0 ||
+	    dev->mc_count > FCC_MAX_MULTICAST_ADDRS) {
+
+		W32(ep, fen_gaddrh, 0xffffffff);
+		W32(ep, fen_gaddrl, 0xffffffff);
+	}
+
+	/* read back */
+	fep->fcc.gaddrh = R32(ep, fen_gaddrh);
+	fep->fcc.gaddrl = R32(ep, fen_gaddrl);
+}
+
+static void set_multicast_list(struct net_device *dev)
+{
+	struct dev_mc_list *pmc;
+
+	if ((dev->flags & IFF_PROMISC) == 0) {
+		set_multicast_start(dev);
+		for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next)
+			set_multicast_one(dev, pmc->dmi_addr);
+		set_multicast_finish(dev);
+	} else
+		set_promiscuous_mode(dev);
+}
+
+static void restart(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+	fcc_t *fccp = fep->fcc.fccp;
+	fcc_c_t *fcccp = fep->fcc.fcccp;
+	fcc_enet_t *ep = fep->fcc.ep;
+	dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
+	u16 paddrh, paddrm, paddrl;
+	u16 mem_addr;
+	const unsigned char *mac;
+	int i;
+
+	C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
+
+	/* clear everything (slow & steady does it) */
+	for (i = 0; i < sizeof(*ep); i++)
+		__fcc_out8((char *)ep + i, 0);
+
+	/* get physical address */
+	rx_bd_base_phys = fep->ring_mem_addr;
+	tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring;
+
+	/* point to bds */
+	W32(ep, fen_genfcc.fcc_rbase, rx_bd_base_phys);
+	W32(ep, fen_genfcc.fcc_tbase, tx_bd_base_phys);
+
+	/* Set maximum bytes per receive buffer.
+	 * It must be a multiple of 32.
+	 */
+	W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE);
+
+	W32(ep, fen_genfcc.fcc_rstate, (CPMFCR_GBL | CPMFCR_EB) << 24);
+	W32(ep, fen_genfcc.fcc_tstate, (CPMFCR_GBL | CPMFCR_EB) << 24);
+
+	/* Allocate space in the reserved FCC area of DPRAM for the
+	 * internal buffers.  No one uses this space (yet), so we
+	 * can do this.  Later, we will add resource management for
+	 * this area.
+	 */
+	
+	mem_addr = (u32)fep->fcc.mem; /* de-fixup dpram offset*/
+
+	W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff));
+	W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff));
+	W16(ep, fen_padptr, mem_addr + 64);
+	
+	/* fill with special symbol...  */
+	memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32);
+
+	W32(ep, fen_genfcc.fcc_rbptr, 0);
+	W32(ep, fen_genfcc.fcc_tbptr, 0);
+	W32(ep, fen_genfcc.fcc_rcrc, 0);
+	W32(ep, fen_genfcc.fcc_tcrc, 0);
+	W16(ep, fen_genfcc.fcc_res1, 0);
+	W32(ep, fen_genfcc.fcc_res2, 0);
+
+	/* no CAM */
+	W32(ep, fen_camptr, 0);
+
+	/* Set CRC preset and mask */
+	W32(ep, fen_cmask, 0xdebb20e3);
+	W32(ep, fen_cpres, 0xffffffff);
+
+	W32(ep, fen_crcec, 0);		/* CRC Error counter       */
+	W32(ep, fen_alec, 0);		/* alignment error counter */
+	W32(ep, fen_disfc, 0);		/* discard frame counter   */
+	W16(ep, fen_retlim, 15);	/* Retry limit threshold   */
+	W16(ep, fen_pper, 0);		/* Normal persistence      */
+
+	/* set group address */
+	W32(ep, fen_gaddrh, fep->fcc.gaddrh);
+	W32(ep, fen_gaddrl, fep->fcc.gaddrh);
+
+	/* Clear hash filter tables */
+	W32(ep, fen_iaddrh, 0);
+	W32(ep, fen_iaddrl, 0);
+
+	/* Clear the Out-of-sequence TxBD  */
+	W16(ep, fen_tfcstat, 0);
+	W16(ep ,fen_tfclen, 0);
+	W32(ep, fen_tfcptr, 0);
+
+	W16(ep, fen_mflr, PKT_MAXBUF_SIZE);   /* maximum frame length register */
+	W16(ep, fen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */
+
+	/* set address */
+	mac = dev->dev_addr;
+	paddrh = ((u16)mac[5] << 8) | mac[4];
+	paddrm = ((u16)mac[3] << 8) | mac[2];
+	paddrl = ((u16)mac[1] << 8) | mac[0];
+
+	W16(ep, fen_paddrh, paddrh);
+	W16(ep, fen_paddrm, paddrm);
+	W16(ep, fen_paddrl, paddrl);
+
+	W16(ep, fen_taddrh, 0);
+	W16(ep, fen_taddrm, 0);
+	W16(ep, fen_taddrl, 0);
+
+	W16(ep, fen_maxd1, 1520);	/* maximum DMA1 length */
+	W16(ep, fen_maxd2, 1520);	/* maximum DMA2 length */
+
+	/* Clear stat counters, in case we ever enable RMON */
+	W32(ep, fen_octc, 0);
+	W32(ep, fen_colc, 0);
+	W32(ep, fen_broc, 0);
+	W32(ep, fen_mulc, 0);
+	W32(ep, fen_uspc, 0);
+	W32(ep, fen_frgc, 0);
+	W32(ep, fen_ospc, 0);
+	W32(ep, fen_jbrc, 0);
+	W32(ep, fen_p64c, 0);
+	W32(ep, fen_p65c, 0);
+	W32(ep, fen_p128c, 0);
+	W32(ep, fen_p256c, 0);
+	W32(ep, fen_p512c, 0);
+	W32(ep, fen_p1024c, 0);
+
+	W16(ep, fen_rfthr, 0);	/* Suggested by manual */
+	W16(ep, fen_rfcnt, 0);
+	W16(ep, fen_cftype, 0);
+
+	fs_init_bds(dev);
+
+	/* adjust to speed (for RMII mode) */
+	if (fpi->use_rmii) {
+		if (fep->speed == 100)
+			C8(fcccp, fcc_gfemr, 0x20);
+		else
+			S8(fcccp, fcc_gfemr, 0x20);
+	}
+
+	fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX);
+
+	/* clear events */
+	W16(fccp, fcc_fcce, 0xffff);
+
+	/* Enable interrupts we wish to service */
+	W16(fccp, fcc_fccm, FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB);
+
+	/* Set GFMR to enable Ethernet operating mode */
+	W32(fccp, fcc_gfmr, FCC_GFMR_TCI | FCC_GFMR_MODE_ENET);
+
+	/* set sync/delimiters */
+	W16(fccp, fcc_fdsr, 0xd555);
+
+	W32(fccp, fcc_fpsmr, FCC_PSMR_ENCRC);
+
+	if (fpi->use_rmii)
+		S32(fccp, fcc_fpsmr, FCC_PSMR_RMII);
+
+	/* adjust to duplex mode */
+	if (fep->duplex)
+		S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
+	else
+		C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
+
+	S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
+}
+
+static void stop(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	/* stop ethernet */
+	C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
+
+	/* clear events */
+	W16(fccp, fcc_fcce, 0xffff);
+
+	/* clear interrupt mask */
+	W16(fccp, fcc_fccm, 0);
+
+	fs_cleanup_bds(dev);
+}
+
+static void pre_request_irq(struct net_device *dev, int irq)
+{
+	/* nothing */
+}
+
+static void post_free_irq(struct net_device *dev, int irq)
+{
+	/* nothing */
+}
+
+static void napi_clear_rx_event(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK);
+}
+
+static void napi_enable_rx(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);
+}
+
+static void napi_disable_rx(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);
+}
+
+static void rx_bd_done(struct net_device *dev)
+{
+	/* nothing */
+}
+
+static void tx_kickstart(struct net_device *dev)
+{
+	/* nothing */
+}
+
+static u32 get_int_events(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	return (u32)R16(fccp, fcc_fcce);
+}
+
+static void clear_int_events(struct net_device *dev, u32 int_events)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	W16(fccp, fcc_fcce, int_events & 0xffff);
+}
+
+static void ev_error(struct net_device *dev, u32 int_events)
+{
+	printk(KERN_WARNING DRV_MODULE_NAME
+	       ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events);
+}
+
+int get_regs(struct net_device *dev, void *p, int *sizep)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t))
+		return -EINVAL;
+
+	memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t));
+	p = (char *)p + sizeof(fcc_t);
+
+	memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t));
+	p = (char *)p + sizeof(fcc_c_t);
+
+	memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t));
+
+	return 0;
+}
+
+int get_regs_len(struct net_device *dev)
+{
+	return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t);
+}
+
+/* Some transmit errors cause the transmitter to shut
+ * down.  We now issue a restart transmit.  Since the
+ * errors close the BD and update the pointers, the restart
+ * _should_ pick up without having to reset any of our
+ * pointers either.  Also, To workaround 8260 device erratum 
+ * CPM37, we must disable and then re-enable the transmitter
+ * following a Late Collision, Underrun, or Retry Limit error.
+ */
+void tx_restart(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	C32(fccp, fcc_gfmr, FCC_GFMR_ENT);
+	udelay(10);
+	S32(fccp, fcc_gfmr, FCC_GFMR_ENT);
+
+	fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX);
+}
+
+/*************************************************************************/
+
+const struct fs_ops fs_fcc_ops = {
+	.setup_data		= setup_data,
+	.cleanup_data		= cleanup_data,
+	.set_multicast_list	= set_multicast_list,
+	.restart		= restart,
+	.stop			= stop,
+	.pre_request_irq	= pre_request_irq,
+	.post_free_irq		= post_free_irq,
+	.napi_clear_rx_event	= napi_clear_rx_event,
+	.napi_enable_rx		= napi_enable_rx,
+	.napi_disable_rx	= napi_disable_rx,
+	.rx_bd_done		= rx_bd_done,
+	.tx_kickstart		= tx_kickstart,
+	.get_int_events		= get_int_events,
+	.clear_int_events	= clear_int_events,
+	.ev_error		= ev_error,
+	.get_regs		= get_regs,
+	.get_regs_len		= get_regs_len,
+	.tx_restart		= tx_restart,
+	.allocate_bd		= allocate_bd,
+	.free_bd		= free_bd,
+};
--- /dev/null
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -0,0 +1,653 @@
+/*
+ * Freescale Ethernet controllers
+ *
+ * Copyright (c) 2005 Intracom S.A. 
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc. 
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_8xx
+#include <asm/8xx_immap.h>
+#include <asm/pgtable.h>
+#include <asm/mpc8xx.h>
+#include <asm/commproc.h>
+#endif
+
+#include "fs_enet.h"
+
+/*************************************************/
+
+#if defined(CONFIG_CPM1)
+/* for a CPM1 __raw_xxx's are sufficient */
+#define __fs_out32(addr, x)	__raw_writel(x, addr)
+#define __fs_out16(addr, x)	__raw_writew(x, addr)
+#define __fs_in32(addr)	__raw_readl(addr)
+#define __fs_in16(addr)	__raw_readw(addr)
+#else
+/* for others play it safe */
+#define __fs_out32(addr, x)	out_be32(addr, x)
+#define __fs_out16(addr, x)	out_be16(addr, x)
+#define __fs_in32(addr)	in_be32(addr)
+#define __fs_in16(addr)	in_be16(addr)
+#endif
+
+/* write */
+#define FW(_fecp, _reg, _v) __fs_out32(&(_fecp)->fec_ ## _reg, (_v))
+
+/* read */
+#define FR(_fecp, _reg)	__fs_in32(&(_fecp)->fec_ ## _reg)
+
+/* set bits */
+#define FS(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) | (_v))
+
+/* clear bits */
+#define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v))
+
+
+/* CRC polynomium used by the FEC for the multicast group filtering */
+#define FEC_CRC_POLY   0x04C11DB7
+
+#define FEC_MAX_MULTICAST_ADDRS	64
+
+/* Interrupt events/masks.
+*/
+#define FEC_ENET_HBERR	0x80000000U	/* Heartbeat error          */
+#define FEC_ENET_BABR	0x40000000U	/* Babbling receiver        */
+#define FEC_ENET_BABT	0x20000000U	/* Babbling transmitter     */
+#define FEC_ENET_GRA	0x10000000U	/* Graceful stop complete   */
+#define FEC_ENET_TXF	0x08000000U	/* Full frame transmitted   */
+#define FEC_ENET_TXB	0x04000000U	/* A buffer was transmitted */
+#define FEC_ENET_RXF	0x02000000U	/* Full frame received      */
+#define FEC_ENET_RXB	0x01000000U	/* A buffer was received    */
+#define FEC_ENET_MII	0x00800000U	/* MII interrupt            */
+#define FEC_ENET_EBERR	0x00400000U	/* SDMA bus error           */
+
+#define FEC_ECNTRL_PINMUX	0x00000004
+#define FEC_ECNTRL_ETHER_EN	0x00000002
+#define FEC_ECNTRL_RESET	0x00000001
+
+#define FEC_RCNTRL_BC_REJ	0x00000010
+#define FEC_RCNTRL_PROM		0x00000008
+#define FEC_RCNTRL_MII_MODE	0x00000004
+#define FEC_RCNTRL_DRT		0x00000002
+#define FEC_RCNTRL_LOOP		0x00000001
+
+#define FEC_TCNTRL_FDEN		0x00000004
+#define FEC_TCNTRL_HBC		0x00000002
+#define FEC_TCNTRL_GTS		0x00000001
+
+
+/* Make MII read/write commands for the FEC.
+*/
+#define mk_mii_read(REG)	(0x60020000 | ((REG & 0x1f) << 18))
+#define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))
+#define mk_mii_end		0
+
+#define FEC_MII_LOOPS	10000
+
+/*
+ * Delay to wait for FEC reset command to complete (in us) 
+ */
+#define FEC_RESET_DELAY		50
+
+static int whack_reset(fec_t * fecp)
+{
+	int i;
+
+	FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET);
+	for (i = 0; i < FEC_RESET_DELAY; i++) {
+		if ((FR(fecp, ecntrl) & FEC_ECNTRL_RESET) == 0)
+			return 0;	/* OK */
+		udelay(1);
+	}
+
+	return -1;
+}
+
+static int do_pd_setup(struct fs_enet_private *fep)
+{
+	struct platform_device *pdev = to_platform_device(fep->dev); 
+	struct resource	*r;
+	
+	/* Fill out IRQ field */
+	fep->interrupt = platform_get_irq_byname(pdev,"interrupt");
+	
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	fep->fec.fecp =(void*)r->start;
+
+	if(fep->fec.fecp == NULL)
+		return -EINVAL;
+
+	return 0;
+	
+}
+
+#define FEC_NAPI_RX_EVENT_MSK	(FEC_ENET_RXF | FEC_ENET_RXB)
+#define FEC_RX_EVENT		(FEC_ENET_RXF)
+#define FEC_TX_EVENT		(FEC_ENET_TXF)
+#define FEC_ERR_EVENT_MSK	(FEC_ENET_HBERR | FEC_ENET_BABR | \
+				 FEC_ENET_BABT | FEC_ENET_EBERR)
+
+static int setup_data(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	if (do_pd_setup(fep) != 0)
+		return -EINVAL;
+
+	fep->fec.hthi = 0;
+	fep->fec.htlo = 0;
+
+	fep->ev_napi_rx = FEC_NAPI_RX_EVENT_MSK;
+	fep->ev_rx = FEC_RX_EVENT;
+	fep->ev_tx = FEC_TX_EVENT;
+	fep->ev_err = FEC_ERR_EVENT_MSK;
+
+	return 0;
+}
+
+static int allocate_bd(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+	
+	fep->ring_base = dma_alloc_coherent(fep->dev,
+					    (fpi->tx_ring + fpi->rx_ring) *
+					    sizeof(cbd_t), &fep->ring_mem_addr,
+					    GFP_KERNEL);
+	if (fep->ring_base == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void free_bd(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+
+	if(fep->ring_base)
+		dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring)
+					* sizeof(cbd_t),
+					fep->ring_base,
+					fep->ring_mem_addr);
+}
+
+static void cleanup_data(struct net_device *dev)
+{
+	/* nothing */
+}
+
+static void set_promiscuous_mode(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fec_t *fecp = fep->fec.fecp;
+
+	FS(fecp, r_cntrl, FEC_RCNTRL_PROM);
+}
+
+static void set_multicast_start(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	fep->fec.hthi = 0;
+	fep->fec.htlo = 0;
+}
+
+static void set_multicast_one(struct net_device *dev, const u8 *mac)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	int temp, hash_index, i, j;
+	u32 crc, csrVal;
+	u8 byte, msb;
+
+	crc = 0xffffffff;
+	for (i = 0; i < 6; i++) {
+		byte = mac[i];
+		for (j = 0; j < 8; j++) {
+			msb = crc >> 31;
+			crc <<= 1;
+			if (msb ^ (byte & 0x1))
+				crc ^= FEC_CRC_POLY;
+			byte >>= 1;
+		}
+	}
+
+	temp = (crc & 0x3f) >> 1;
+	hash_index = ((temp & 0x01) << 4) |
+		     ((temp & 0x02) << 2) |
+		     ((temp & 0x04)) |
+		     ((temp & 0x08) >> 2) |
+		     ((temp & 0x10) >> 4);
+	csrVal = 1 << hash_index;
+	if (crc & 1)
+		fep->fec.hthi |= csrVal;
+	else
+		fep->fec.htlo |= csrVal;
+}
+
+static void set_multicast_finish(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fec_t *fecp = fep->fec.fecp;
+
+	/* if all multi or too many multicasts; just enable all */
+	if ((dev->flags & IFF_ALLMULTI) != 0 ||
+	    dev->mc_count > FEC_MAX_MULTICAST_ADDRS) {
+		fep->fec.hthi = 0xffffffffU;
+		fep->fec.htlo = 0xffffffffU;
+	}
+
+	FC(fecp, r_cntrl, FEC_RCNTRL_PROM);
+	FW(fecp, hash_table_high, fep->fec.hthi);
+	FW(fecp, hash_table_low, fep->fec.htlo);
+}
+
+static void set_multicast_list(struct net_device *dev)
+{
+	struct dev_mc_list *pmc;
+
+	if ((dev->flags & IFF_PROMISC) == 0) {
+		set_multicast_start(dev);
+		for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next)
+			set_multicast_one(dev, pmc->dmi_addr);
+		set_multicast_finish(dev);
+	} else
+		set_promiscuous_mode(dev);
+}
+
+static void restart(struct net_device *dev)
+{
+#ifdef CONFIG_DUET
+	immap_t *immap = fs_enet_immap;
+	u32 cptr;
+#endif
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fec_t *fecp = fep->fec.fecp;
+	const struct fs_platform_info *fpi = fep->fpi;
+	dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
+	int r;
+	u32 addrhi, addrlo;
+
+	r = whack_reset(fep->fec.fecp);
+	if (r != 0)
+		printk(KERN_ERR DRV_MODULE_NAME
+				": %s FEC Reset FAILED!\n", dev->name);
+
+	/*
+	 * Set station address. 
+	 */
+	addrhi = ((u32) dev->dev_addr[0] << 24) |
+		 ((u32) dev->dev_addr[1] << 16) |
+		 ((u32) dev->dev_addr[2] <<  8) |
+		  (u32) dev->dev_addr[3];
+	addrlo = ((u32) dev->dev_addr[4] << 24) |
+		 ((u32) dev->dev_addr[5] << 16);
+	FW(fecp, addr_low, addrhi);
+	FW(fecp, addr_high, addrlo);
+
+	/*
+	 * Reset all multicast. 
+	 */
+	FW(fecp, hash_table_high, fep->fec.hthi);
+	FW(fecp, hash_table_low, fep->fec.htlo);
+
+	/*
+	 * Set maximum receive buffer size. 
+	 */
+	FW(fecp, r_buff_size, PKT_MAXBLR_SIZE);
+	FW(fecp, r_hash, PKT_MAXBUF_SIZE);
+
+	/* get physical address */
+	rx_bd_base_phys = fep->ring_mem_addr;
+	tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring;
+
+	/*
+	 * Set receive and transmit descriptor base. 
+	 */
+	FW(fecp, r_des_start, rx_bd_base_phys);
+	FW(fecp, x_des_start, tx_bd_base_phys);
+
+	fs_init_bds(dev);
+
+	/*
+	 * Enable big endian and don't care about SDMA FC. 
+	 */
+	FW(fecp, fun_code, 0x78000000);
+
+	/*
+	 * Set MII speed. 
+	 */
+	FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed);
+
+	/*
+	 * Clear any outstanding interrupt. 
+	 */
+	FW(fecp, ievent, 0xffc0);
+	FW(fecp, ivec, (fep->interrupt / 2) << 29);
+	
+
+	/*
+	 * adjust to speed (only for DUET & RMII) 
+	 */
+#ifdef CONFIG_DUET
+	if (fpi->use_rmii) {
+		cptr = in_be32(&immap->im_cpm.cp_cptr);
+		switch (fs_get_fec_index(fpi->fs_no)) {
+		case 0:
+			cptr |= 0x100;
+			if (fep->speed == 10)
+				cptr |= 0x0000010;
+			else if (fep->speed == 100)
+				cptr &= ~0x0000010;
+			break;
+		case 1:
+			cptr |= 0x80;
+			if (fep->speed == 10)
+				cptr |= 0x0000008;
+			else if (fep->speed == 100)
+				cptr &= ~0x0000008;
+			break;
+		default:
+			BUG();	/* should never happen */
+			break;
+		}
+		out_be32(&immap->im_cpm.cp_cptr, cptr);
+	}
+#endif
+
+	FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */
+	/*
+	 * adjust to duplex mode 
+	 */
+	if (fep->duplex) {
+		FC(fecp, r_cntrl, FEC_RCNTRL_DRT);
+		FS(fecp, x_cntrl, FEC_TCNTRL_FDEN);	/* FD enable */
+	} else {
+		FS(fecp, r_cntrl, FEC_RCNTRL_DRT);
+		FC(fecp, x_cntrl, FEC_TCNTRL_FDEN);	/* FD disable */
+	}
+
+	/*
+	 * Enable interrupts we wish to service. 
+	 */
+	FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB |
+	   FEC_ENET_RXF | FEC_ENET_RXB);
+
+	/*
+	 * And last, enable the transmit and receive processing. 
+	 */
+	FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
+	FW(fecp, r_des_active, 0x01000000);
+}
+
+static void stop(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fec_t *fecp = fep->fec.fecp;
+	struct fs_enet_mii_bus *bus = fep->mii_bus;
+	const struct fs_mii_bus_info *bi = bus->bus_info;
+	int i;
+
+	if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0)
+		return;		/* already down */
+
+	FW(fecp, x_cntrl, 0x01);	/* Graceful transmit stop */
+	for (i = 0; ((FR(fecp, ievent) & 0x10000000) == 0) &&
+	     i < FEC_RESET_DELAY; i++)
+		udelay(1);
+
+	if (i == FEC_RESET_DELAY)
+		printk(KERN_WARNING DRV_MODULE_NAME
+		       ": %s FEC timeout on graceful transmit stop\n",
+		       dev->name);
+	/*
+	 * Disable FEC. Let only MII interrupts. 
+	 */
+	FW(fecp, imask, 0);
+	FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN);
+
+	fs_cleanup_bds(dev);
+
+	/* shut down FEC1? that's where the mii bus is */
+	if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) {
+		FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */
+		FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
+		FW(fecp, ievent, FEC_ENET_MII);
+		FW(fecp, mii_speed, bus->fec.mii_speed);
+	}
+}
+
+static void pre_request_irq(struct net_device *dev, int irq)
+{
+	immap_t *immap = fs_enet_immap;
+	u32 siel;
+
+	/* SIU interrupt */
+	if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) {
+
+		siel = in_be32(&immap->im_siu_conf.sc_siel);
+		if ((irq & 1) == 0)
+			siel |= (0x80000000 >> irq);
+		else
+			siel &= ~(0x80000000 >> (irq & ~1));
+		out_be32(&immap->im_siu_conf.sc_siel, siel);
+	}
+}
+
+static void post_free_irq(struct net_device *dev, int irq)
+{
+	/* nothing */
+}
+
+static void napi_clear_rx_event(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fec_t *fecp = fep->fec.fecp;
+
+	FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK);
+}
+
+static void napi_enable_rx(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fec_t *fecp = fep->fec.fecp;
+
+	FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
+}
+
+static void napi_disable_rx(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fec_t *fecp = fep->fec.fecp;
+
+	FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
+}
+
+static void rx_bd_done(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fec_t *fecp = fep->fec.fecp;
+
+	FW(fecp, r_des_active, 0x01000000);
+}
+
+static void tx_kickstart(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fec_t *fecp = fep->fec.fecp;
+
+	FW(fecp, x_des_active, 0x01000000);
+}
+
+static u32 get_int_events(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fec_t *fecp = fep->fec.fecp;
+
+	return FR(fecp, ievent) & FR(fecp, imask);
+}
+
+static void clear_int_events(struct net_device *dev, u32 int_events)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fec_t *fecp = fep->fec.fecp;
+
+	FW(fecp, ievent, int_events);
+}
+
+static void ev_error(struct net_device *dev, u32 int_events)
+{
+	printk(KERN_WARNING DRV_MODULE_NAME
+	       ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events);
+}
+
+int get_regs(struct net_device *dev, void *p, int *sizep)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	if (*sizep < sizeof(fec_t))
+		return -EINVAL;
+
+	memcpy_fromio(p, fep->fec.fecp, sizeof(fec_t));
+
+	return 0;
+}
+
+int get_regs_len(struct net_device *dev)
+{
+	return sizeof(fec_t);
+}
+
+void tx_restart(struct net_device *dev)
+{
+	/* nothing */
+}
+
+/*************************************************************************/
+
+const struct fs_ops fs_fec_ops = {
+	.setup_data		= setup_data,
+	.cleanup_data		= cleanup_data,
+	.set_multicast_list	= set_multicast_list,
+	.restart		= restart,
+	.stop			= stop,
+	.pre_request_irq	= pre_request_irq,
+	.post_free_irq		= post_free_irq,
+	.napi_clear_rx_event	= napi_clear_rx_event,
+	.napi_enable_rx		= napi_enable_rx,
+	.napi_disable_rx	= napi_disable_rx,
+	.rx_bd_done		= rx_bd_done,
+	.tx_kickstart		= tx_kickstart,
+	.get_int_events		= get_int_events,
+	.clear_int_events	= clear_int_events,
+	.ev_error		= ev_error,
+	.get_regs		= get_regs,
+	.get_regs_len		= get_regs_len,
+	.tx_restart		= tx_restart,
+	.allocate_bd		= allocate_bd,
+	.free_bd		= free_bd,
+};
+
+/***********************************************************************/
+
+static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)
+{
+	fec_t *fecp = bus->fec.fecp;
+	int i, ret = -1;
+
+	if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
+		BUG();
+
+	/* Add PHY address to register command.  */
+	FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location));
+
+	for (i = 0; i < FEC_MII_LOOPS; i++)
+		if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
+			break;
+
+	if (i < FEC_MII_LOOPS) {
+		FW(fecp, ievent, FEC_ENET_MII);
+		ret = FR(fecp, mii_data) & 0xffff;
+	}
+
+	return ret;
+}
+
+static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value)
+{
+	fec_t *fecp = bus->fec.fecp;
+	int i;
+
+	/* this must never happen */
+	if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
+		BUG();
+
+	/* Add PHY address to register command.  */
+	FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value));
+
+	for (i = 0; i < FEC_MII_LOOPS; i++)
+		if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
+			break;
+
+	if (i < FEC_MII_LOOPS)
+		FW(fecp, ievent, FEC_ENET_MII);
+}
+
+int fs_mii_fec_init(struct fs_enet_mii_bus *bus)
+{
+	bd_t *bd = (bd_t *)__res;
+	const struct fs_mii_bus_info *bi = bus->bus_info;
+	fec_t *fecp;
+
+	if (bi->id != 0)
+		return -1;
+
+	bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec;
+	bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2)
+				& 0x3F) << 1;
+
+	fecp = bus->fec.fecp;
+
+	FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */
+	FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
+	FW(fecp, ievent, FEC_ENET_MII);
+	FW(fecp, mii_speed, bus->fec.mii_speed);
+
+	bus->mii_read = mii_read;
+	bus->mii_write = mii_write;
+
+	return 0;
+}
--- /dev/null
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -0,0 +1,517 @@
+/*
+ * Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx.
+ *
+ * Copyright (c) 2003 Intracom S.A. 
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ * 
+ * 2005 (c) MontaVista Software, Inc. 
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_8xx
+#include <asm/8xx_immap.h>
+#include <asm/pgtable.h>
+#include <asm/mpc8xx.h>
+#include <asm/commproc.h>
+#endif
+
+#include "fs_enet.h"
+
+/*************************************************/
+
+#if defined(CONFIG_CPM1)
+/* for a 8xx __raw_xxx's are sufficient */
+#define __fs_out32(addr, x)	__raw_writel(x, addr)
+#define __fs_out16(addr, x)	__raw_writew(x, addr)
+#define __fs_out8(addr, x)	__raw_writeb(x, addr)
+#define __fs_in32(addr)	__raw_readl(addr)
+#define __fs_in16(addr)	__raw_readw(addr)
+#define __fs_in8(addr)	__raw_readb(addr)
+#else
+/* for others play it safe */
+#define __fs_out32(addr, x)	out_be32(addr, x)
+#define __fs_out16(addr, x)	out_be16(addr, x)
+#define __fs_in32(addr)	in_be32(addr)
+#define __fs_in16(addr)	in_be16(addr)
+#endif
+
+/* write, read, set bits, clear bits */
+#define W32(_p, _m, _v) __fs_out32(&(_p)->_m, (_v))
+#define R32(_p, _m)     __fs_in32(&(_p)->_m)
+#define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v))
+#define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v))
+
+#define W16(_p, _m, _v) __fs_out16(&(_p)->_m, (_v))
+#define R16(_p, _m)     __fs_in16(&(_p)->_m)
+#define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v))
+#define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v))
+
+#define W8(_p, _m, _v)  __fs_out8(&(_p)->_m, (_v))
+#define R8(_p, _m)      __fs_in8(&(_p)->_m)
+#define S8(_p, _m, _v)  W8(_p, _m, R8(_p, _m) | (_v))
+#define C8(_p, _m, _v)  W8(_p, _m, R8(_p, _m) & ~(_v))
+
+#define SCC_MAX_MULTICAST_ADDRS	64
+
+/*
+ * Delay to wait for SCC reset command to complete (in us) 
+ */
+#define SCC_RESET_DELAY		50
+
+static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op)
+{
+	cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm;
+	u32 v, ch;
+
+	ch = fep->scc.idx << 2;
+	v = mk_cr_cmd(ch, op);
+	W16(cpmp, cp_cpcr, v | CPM_CR_FLG);
+	while ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) != 0)
+		udelay(10);
+
+	return 0;
+}
+
+static int do_pd_setup(struct fs_enet_private *fep)
+{
+	struct platform_device *pdev = to_platform_device(fep->dev);
+	struct resource *r;
+
+	/* Fill out IRQ field */
+	fep->interrupt = platform_get_irq_byname(pdev, "interrupt");
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	fep->scc.sccp = (void *)r->start;
+
+	if (fep->scc.sccp == NULL)
+		return -EINVAL;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram");
+	fep->scc.ep = (void *)r->start;
+
+	if (fep->scc.ep == NULL)
+		return -EINVAL;
+
+	return 0;
+}
+
+#define SCC_NAPI_RX_EVENT_MSK	(SCCE_ENET_RXF | SCCE_ENET_RXB)
+#define SCC_RX_EVENT		(SCCE_ENET_RXF)
+#define SCC_TX_EVENT		(SCCE_ENET_TXB)
+#define SCC_ERR_EVENT_MSK	(SCCE_ENET_TXE | SCCE_ENET_BSY)
+
+static int setup_data(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+
+	fep->scc.idx = fs_get_scc_index(fpi->fs_no);
+	if ((unsigned int)fep->fcc.idx > 4)	/* max 4 SCCs */
+		return -EINVAL;
+
+	do_pd_setup(fep);
+
+	fep->scc.hthi = 0;
+	fep->scc.htlo = 0;
+
+	fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK;
+	fep->ev_rx = SCC_RX_EVENT;
+	fep->ev_tx = SCC_TX_EVENT;
+	fep->ev_err = SCC_ERR_EVENT_MSK;
+
+	return 0;
+}
+
+static int allocate_bd(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+
+	fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) *
+					 sizeof(cbd_t), 8);
+	if (IS_DPERR(fep->ring_mem_addr)) {
+		return -ENOMEM;
+	}
+
+	fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr);
+
+	return 0;
+}
+
+static void free_bd(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	if (fep->ring_base)
+		cpm_dpfree(fep->ring_mem_addr);
+}
+
+static void cleanup_data(struct net_device *dev)
+{
+	/* nothing */
+}
+
+static void set_promiscuous_mode(struct net_device *dev)
+{				
+	struct fs_enet_private *fep = netdev_priv(dev);
+	scc_t *sccp = fep->scc.sccp;
+
+	S16(sccp, scc_psmr, SCC_PSMR_PRO);
+}
+
+static void set_multicast_start(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	scc_enet_t *ep = fep->scc.ep;
+
+	W16(ep, sen_gaddr1, 0);
+	W16(ep, sen_gaddr2, 0);
+	W16(ep, sen_gaddr3, 0);
+	W16(ep, sen_gaddr4, 0);
+}
+
+static void set_multicast_one(struct net_device *dev, const u8 * mac)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	scc_enet_t *ep = fep->scc.ep;
+	u16 taddrh, taddrm, taddrl;
+
+	taddrh = ((u16) mac[5] << 8) | mac[4];
+	taddrm = ((u16) mac[3] << 8) | mac[2];
+	taddrl = ((u16) mac[1] << 8) | mac[0];
+
+	W16(ep, sen_taddrh, taddrh);
+	W16(ep, sen_taddrm, taddrm);
+	W16(ep, sen_taddrl, taddrl);
+	scc_cr_cmd(fep, CPM_CR_SET_GADDR);
+}
+
+static void set_multicast_finish(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	scc_t *sccp = fep->scc.sccp;
+	scc_enet_t *ep = fep->scc.ep;
+
+	/* clear promiscuous always */
+	C16(sccp, scc_psmr, SCC_PSMR_PRO);
+
+	/* if all multi or too many multicasts; just enable all */
+	if ((dev->flags & IFF_ALLMULTI) != 0 ||
+	    dev->mc_count > SCC_MAX_MULTICAST_ADDRS) {
+
+		W16(ep, sen_gaddr1, 0xffff);
+		W16(ep, sen_gaddr2, 0xffff);
+		W16(ep, sen_gaddr3, 0xffff);
+		W16(ep, sen_gaddr4, 0xffff);
+	}
+}
+
+static void set_multicast_list(struct net_device *dev)
+{
+	struct dev_mc_list *pmc;
+
+	if ((dev->flags & IFF_PROMISC) == 0) {
+		set_multicast_start(dev);
+		for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next)
+			set_multicast_one(dev, pmc->dmi_addr);
+		set_multicast_finish(dev);
+	} else
+		set_promiscuous_mode(dev);
+}
+
+/*
+ * This function is called to start or restart the FEC during a link
+ * change.  This only happens when switching between half and full
+ * duplex.
+ */
+static void restart(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	scc_t *sccp = fep->scc.sccp;
+	scc_enet_t *ep = fep->scc.ep;
+	const struct fs_platform_info *fpi = fep->fpi;
+	u16 paddrh, paddrm, paddrl;
+	const unsigned char *mac;
+	int i;
+
+	C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	/* clear everything (slow & steady does it) */
+	for (i = 0; i < sizeof(*ep); i++)
+		__fs_out8((char *)ep + i, 0);
+
+	/* point to bds */
+	W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr);
+	W16(ep, sen_genscc.scc_tbase,
+	    fep->ring_mem_addr + sizeof(cbd_t) * fpi->rx_ring);
+
+	/* Initialize function code registers for big-endian.
+	 */
+	W8(ep, sen_genscc.scc_rfcr, SCC_EB);
+	W8(ep, sen_genscc.scc_tfcr, SCC_EB);
+
+	/* Set maximum bytes per receive buffer.
+	 * This appears to be an Ethernet frame size, not the buffer
+	 * fragment size.  It must be a multiple of four.
+	 */
+	W16(ep, sen_genscc.scc_mrblr, 0x5f0);
+
+	/* Set CRC preset and mask.
+	 */
+	W32(ep, sen_cpres, 0xffffffff);
+	W32(ep, sen_cmask, 0xdebb20e3);
+
+	W32(ep, sen_crcec, 0);	/* CRC Error counter */
+	W32(ep, sen_alec, 0);	/* alignment error counter */
+	W32(ep, sen_disfc, 0);	/* discard frame counter */
+
+	W16(ep, sen_pads, 0x8888);	/* Tx short frame pad character */
+	W16(ep, sen_retlim, 15);	/* Retry limit threshold */
+
+	W16(ep, sen_maxflr, 0x5ee);	/* maximum frame length register */
+
+	W16(ep, sen_minflr, PKT_MINBUF_SIZE);	/* minimum frame length register */
+
+	W16(ep, sen_maxd1, 0x000005f0);	/* maximum DMA1 length */
+	W16(ep, sen_maxd2, 0x000005f0);	/* maximum DMA2 length */
+
+	/* Clear hash tables.
+	 */
+	W16(ep, sen_gaddr1, 0);
+	W16(ep, sen_gaddr2, 0);
+	W16(ep, sen_gaddr3, 0);
+	W16(ep, sen_gaddr4, 0);
+	W16(ep, sen_iaddr1, 0);
+	W16(ep, sen_iaddr2, 0);
+	W16(ep, sen_iaddr3, 0);
+	W16(ep, sen_iaddr4, 0);
+
+	/* set address 
+	 */
+	mac = dev->dev_addr;
+	paddrh = ((u16) mac[5] << 8) | mac[4];
+	paddrm = ((u16) mac[3] << 8) | mac[2];
+	paddrl = ((u16) mac[1] << 8) | mac[0];
+
+	W16(ep, sen_paddrh, paddrh);
+	W16(ep, sen_paddrm, paddrm);
+	W16(ep, sen_paddrl, paddrl);
+
+	W16(ep, sen_pper, 0);
+	W16(ep, sen_taddrl, 0);
+	W16(ep, sen_taddrm, 0);
+	W16(ep, sen_taddrh, 0);
+
+	fs_init_bds(dev);
+
+	scc_cr_cmd(fep, CPM_CR_INIT_TRX);
+
+	W16(sccp, scc_scce, 0xffff);
+
+	/* Enable interrupts we wish to service. 
+	 */
+	W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB);
+
+	/* Set GSMR_H to enable all normal operating modes.
+	 * Set GSMR_L to enable Ethernet to MC68160.
+	 */
+	W32(sccp, scc_gsmrh, 0);
+	W32(sccp, scc_gsmrl,
+	    SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 |
+	    SCC_GSMRL_MODE_ENET);
+
+	/* Set sync/delimiters.
+	 */
+	W16(sccp, scc_dsr, 0xd555);
+
+	/* Set processing mode.  Use Ethernet CRC, catch broadcast, and
+	 * start frame search 22 bit times after RENA.
+	 */
+	W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22);
+
+	/* Set full duplex mode if needed */
+	if (fep->duplex)
+		S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE);
+
+	S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+}
+
+static void stop(struct net_device *dev)	
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	scc_t *sccp = fep->scc.sccp;
+	int i;
+
+	for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++)
+		udelay(1);
+
+	if (i == SCC_RESET_DELAY)
+		printk(KERN_WARNING DRV_MODULE_NAME
+		       ": %s SCC timeout on graceful transmit stop\n",
+		       dev->name);
+
+	W16(sccp, scc_sccm, 0);
+	C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	fs_cleanup_bds(dev);
+}
+
+static void pre_request_irq(struct net_device *dev, int irq)
+{
+	immap_t *immap = fs_enet_immap;
+	u32 siel;
+
+	/* SIU interrupt */
+	if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) {
+
+		siel = in_be32(&immap->im_siu_conf.sc_siel);
+		if ((irq & 1) == 0)
+			siel |= (0x80000000 >> irq);
+		else
+			siel &= ~(0x80000000 >> (irq & ~1));
+		out_be32(&immap->im_siu_conf.sc_siel, siel);
+	}
+}
+
+static void post_free_irq(struct net_device *dev, int irq)
+{
+	/* nothing */
+}
+
+static void napi_clear_rx_event(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	scc_t *sccp = fep->scc.sccp;
+
+	W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK);
+}
+
+static void napi_enable_rx(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	scc_t *sccp = fep->scc.sccp;
+
+	S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK);
+}
+
+static void napi_disable_rx(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	scc_t *sccp = fep->scc.sccp;
+
+	C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK);
+}
+
+static void rx_bd_done(struct net_device *dev)
+{
+	/* nothing */
+}
+
+static void tx_kickstart(struct net_device *dev)
+{
+	/* nothing */
+}
+
+static u32 get_int_events(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	scc_t *sccp = fep->scc.sccp;
+
+	return (u32) R16(sccp, scc_scce);
+}
+
+static void clear_int_events(struct net_device *dev, u32 int_events)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	scc_t *sccp = fep->scc.sccp;
+
+	W16(sccp, scc_scce, int_events & 0xffff);
+}
+
+static void ev_error(struct net_device *dev, u32 int_events)
+{
+	printk(KERN_WARNING DRV_MODULE_NAME
+	       ": %s SCC ERROR(s) 0x%x\n", dev->name, int_events);
+}
+
+static int get_regs(struct net_device *dev, void *p, int *sizep)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t))
+		return -EINVAL;
+
+	memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t));
+	p = (char *)p + sizeof(scc_t);
+
+	memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t));
+
+	return 0;
+}
+
+static int get_regs_len(struct net_device *dev)
+{
+	return sizeof(scc_t) + sizeof(scc_enet_t);
+}
+
+static void tx_restart(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	scc_cr_cmd(fep, CPM_CR_RESTART_TX);
+}
+
+/*************************************************************************/
+
+const struct fs_ops fs_scc_ops = {
+	.setup_data		= setup_data,
+	.cleanup_data		= cleanup_data,
+	.set_multicast_list	= set_multicast_list,
+	.restart		= restart,
+	.stop			= stop,
+	.pre_request_irq	= pre_request_irq,
+	.post_free_irq		= post_free_irq,
+	.napi_clear_rx_event	= napi_clear_rx_event,
+	.napi_enable_rx		= napi_enable_rx,
+	.napi_disable_rx	= napi_disable_rx,
+	.rx_bd_done		= rx_bd_done,
+	.tx_kickstart		= tx_kickstart,
+	.get_int_events		= get_int_events,
+	.clear_int_events	= clear_int_events,
+	.ev_error		= ev_error,
+	.get_regs		= get_regs,
+	.get_regs_len		= get_regs_len,
+	.tx_restart		= tx_restart,
+	.allocate_bd		= allocate_bd,
+	.free_bd		= free_bd,
+};
--- /dev/null
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -0,0 +1,405 @@
+/*
+ * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
+ *
+ * Copyright (c) 2003 Intracom S.A. 
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ * 
+ * 2005 (c) MontaVista Software, Inc. 
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "fs_enet.h"
+
+#ifdef CONFIG_8xx
+static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit)
+{
+	immap_t *im = (immap_t *)fs_enet_immap;
+	void *dir, *dat, *ppar;
+	int adv;
+	u8 msk;
+
+	switch (port) {
+		case fsiop_porta:
+			dir = &im->im_ioport.iop_padir;
+			dat = &im->im_ioport.iop_padat;
+			ppar = &im->im_ioport.iop_papar;
+			break;
+
+		case fsiop_portb:
+			dir = &im->im_cpm.cp_pbdir;
+			dat = &im->im_cpm.cp_pbdat;
+			ppar = &im->im_cpm.cp_pbpar;
+			break;
+
+		case fsiop_portc:
+			dir = &im->im_ioport.iop_pcdir;
+			dat = &im->im_ioport.iop_pcdat;
+			ppar = &im->im_ioport.iop_pcpar;
+			break;
+
+		case fsiop_portd:
+			dir = &im->im_ioport.iop_pddir;
+			dat = &im->im_ioport.iop_pddat;
+			ppar = &im->im_ioport.iop_pdpar;
+			break;
+
+		case fsiop_porte:
+			dir = &im->im_cpm.cp_pedir;
+			dat = &im->im_cpm.cp_pedat;
+			ppar = &im->im_cpm.cp_pepar;
+			break;
+
+		default:
+			printk(KERN_ERR DRV_MODULE_NAME
+			       "Illegal port value %d!\n", port);
+			return -EINVAL;
+	}
+
+	adv = bit >> 3;
+	dir = (char *)dir + adv;
+	dat = (char *)dat + adv;
+	ppar = (char *)ppar + adv;
+
+	msk = 1 << (7 - (bit & 7));
+	if ((in_8(ppar) & msk) != 0) {
+		printk(KERN_ERR DRV_MODULE_NAME
+		       "pin %d on port %d is not general purpose!\n", bit, port);
+		return -EINVAL;
+	}
+
+	*dirp = dir;
+	*datp = dat;
+	*mskp = msk;
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_8260
+static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit)
+{
+	iop_cpm2_t *io = &((cpm2_map_t *)fs_enet_immap)->im_ioport;
+	void *dir, *dat, *ppar;
+	int adv;
+	u8 msk;
+
+	switch (port) {
+		case fsiop_porta:
+			dir = &io->iop_pdira;
+			dat = &io->iop_pdata;
+			ppar = &io->iop_ppara;
+			break;
+
+		case fsiop_portb:
+			dir = &io->iop_pdirb;
+			dat = &io->iop_pdatb;
+			ppar = &io->iop_pparb;
+			break;
+
+		case fsiop_portc:
+			dir = &io->iop_pdirc;
+			dat = &io->iop_pdatc;
+			ppar = &io->iop_pparc;
+			break;
+
+		case fsiop_portd:
+			dir = &io->iop_pdird;
+			dat = &io->iop_pdatd;
+			ppar = &io->iop_ppard;
+			break;
+
+		default:
+			printk(KERN_ERR DRV_MODULE_NAME
+			       "Illegal port value %d!\n", port);
+			return -EINVAL;
+	}
+
+	adv = bit >> 3;
+	dir = (char *)dir + adv;
+	dat = (char *)dat + adv;
+	ppar = (char *)ppar + adv;
+
+	msk = 1 << (7 - (bit & 7));
+	if ((in_8(ppar) & msk) != 0) {
+		printk(KERN_ERR DRV_MODULE_NAME
+		       "pin %d on port %d is not general purpose!\n", bit, port);
+		return -EINVAL;
+	}
+
+	*dirp = dir;
+	*datp = dat;
+	*mskp = msk;
+
+	return 0;
+}
+#endif
+
+static inline void bb_set(u8 *p, u8 m)
+{
+	out_8(p, in_8(p) | m);
+}
+
+static inline void bb_clr(u8 *p, u8 m)
+{
+	out_8(p, in_8(p) & ~m);
+}
+
+static inline int bb_read(u8 *p, u8 m)
+{
+	return (in_8(p) & m) != 0;
+}
+
+static inline void mdio_active(struct fs_enet_mii_bus *bus)
+{
+	bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk);
+}
+
+static inline void mdio_tristate(struct fs_enet_mii_bus *bus)
+{
+	bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk);
+}
+
+static inline int mdio_read(struct fs_enet_mii_bus *bus)
+{
+	return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);
+}
+
+static inline void mdio(struct fs_enet_mii_bus *bus, int what)
+{
+	if (what)
+		bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);
+	else
+		bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);
+}
+
+static inline void mdc(struct fs_enet_mii_bus *bus, int what)
+{
+	if (what)
+		bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk);
+	else
+		bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk);
+}
+
+static inline void mii_delay(struct fs_enet_mii_bus *bus)
+{
+	udelay(bus->bus_info->i.bitbang.delay);
+}
+
+/* Utility to send the preamble, address, and register (common to read and write). */
+static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg)
+{
+	int j;
+
+	/*
+	 * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
+	 * The IEEE spec says this is a PHY optional requirement.  The AMD
+	 * 79C874 requires one after power up and one after a MII communications
+	 * error.  This means that we are doing more preambles than we need,
+	 * but it is safer and will be much more robust.
+	 */
+
+	mdio_active(bus);
+	mdio(bus, 1);
+	for (j = 0; j < 32; j++) {
+		mdc(bus, 0);
+		mii_delay(bus);
+		mdc(bus, 1);
+		mii_delay(bus);
+	}
+
+	/* send the start bit (01) and the read opcode (10) or write (10) */
+	mdc(bus, 0);
+	mdio(bus, 0);
+	mii_delay(bus);
+	mdc(bus, 1);
+	mii_delay(bus);
+	mdc(bus, 0);
+	mdio(bus, 1);
+	mii_delay(bus);
+	mdc(bus, 1);
+	mii_delay(bus);
+	mdc(bus, 0);
+	mdio(bus, read);
+	mii_delay(bus);
+	mdc(bus, 1);
+	mii_delay(bus);
+	mdc(bus, 0);
+	mdio(bus, !read);
+	mii_delay(bus);
+	mdc(bus, 1);
+	mii_delay(bus);
+
+	/* send the PHY address */
+	for (j = 0; j < 5; j++) {
+		mdc(bus, 0);
+		mdio(bus, (addr & 0x10) != 0);
+		mii_delay(bus);
+		mdc(bus, 1);
+		mii_delay(bus);
+		addr <<= 1;
+	}
+
+	/* send the register address */
+	for (j = 0; j < 5; j++) {
+		mdc(bus, 0);
+		mdio(bus, (reg & 0x10) != 0);
+		mii_delay(bus);
+		mdc(bus, 1);
+		mii_delay(bus);
+		reg <<= 1;
+	}
+}
+
+static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)
+{
+	u16 rdreg;
+	int ret, j;
+	u8 addr = phy_id & 0xff;
+	u8 reg = location & 0xff;
+
+	bitbang_pre(bus, 1, addr, reg);
+
+	/* tri-state our MDIO I/O pin so we can read */
+	mdc(bus, 0);
+	mdio_tristate(bus);
+	mii_delay(bus);
+	mdc(bus, 1);
+	mii_delay(bus);
+
+	/* check the turnaround bit: the PHY should be driving it to zero */
+	if (mdio_read(bus) != 0) {
+		/* PHY didn't drive TA low */
+		for (j = 0; j < 32; j++) {
+			mdc(bus, 0);
+			mii_delay(bus);
+			mdc(bus, 1);
+			mii_delay(bus);
+		}
+		ret = -1;
+		goto out;
+	}
+
+	mdc(bus, 0);
+	mii_delay(bus);
+
+	/* read 16 bits of register data, MSB first */
+	rdreg = 0;
+	for (j = 0; j < 16; j++) {
+		mdc(bus, 1);
+		mii_delay(bus);
+		rdreg <<= 1;
+		rdreg |= mdio_read(bus);
+		mdc(bus, 0);
+		mii_delay(bus);
+	}
+
+	mdc(bus, 1);
+	mii_delay(bus);
+	mdc(bus, 0);
+	mii_delay(bus);
+	mdc(bus, 1);
+	mii_delay(bus);
+
+	ret = rdreg;
+out:
+	return ret;
+}
+
+static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val)
+{
+	int j;
+	u8 addr = phy_id & 0xff;
+	u8 reg = location & 0xff;
+	u16 value = val & 0xffff;
+
+	bitbang_pre(bus, 0, addr, reg);
+
+	/* send the turnaround (10) */
+	mdc(bus, 0);
+	mdio(bus, 1);
+	mii_delay(bus);
+	mdc(bus, 1);
+	mii_delay(bus);
+	mdc(bus, 0);
+	mdio(bus, 0);
+	mii_delay(bus);
+	mdc(bus, 1);
+	mii_delay(bus);
+
+	/* write 16 bits of register data, MSB first */
+	for (j = 0; j < 16; j++) {
+		mdc(bus, 0);
+		mdio(bus, (value & 0x8000) != 0);
+		mii_delay(bus);
+		mdc(bus, 1);
+		mii_delay(bus);
+		value <<= 1;
+	}
+
+	/*
+	 * Tri-state the MDIO line.
+	 */
+	mdio_tristate(bus);
+	mdc(bus, 0);
+	mii_delay(bus);
+	mdc(bus, 1);
+	mii_delay(bus);
+}
+
+int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus)
+{
+	const struct fs_mii_bus_info *bi = bus->bus_info;
+	int r;
+
+	r = bitbang_prep_bit(&bus->bitbang.mdio_dir,
+			 &bus->bitbang.mdio_dat,
+			 &bus->bitbang.mdio_msk,
+			 bi->i.bitbang.mdio_port,
+			 bi->i.bitbang.mdio_bit);
+	if (r != 0)
+		return r;
+
+	r = bitbang_prep_bit(&bus->bitbang.mdc_dir,
+			 &bus->bitbang.mdc_dat,
+			 &bus->bitbang.mdc_msk,
+			 bi->i.bitbang.mdc_port,
+			 bi->i.bitbang.mdc_bit);
+	if (r != 0)
+		return r;
+
+	bus->mii_read = mii_read;
+	bus->mii_write = mii_write;
+
+	return 0;
+}
--- /dev/null
+++ b/drivers/net/fs_enet/mii-fixed.c
@@ -0,0 +1,92 @@
+/*
+ * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
+ *
+ * Copyright (c) 2003 Intracom S.A. 
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ * 
+ * 2005 (c) MontaVista Software, Inc. 
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "fs_enet.h"
+
+static const u16 mii_regs[7] = {
+	0x3100,
+	0x786d,
+	0x0fff,
+	0x0fff,
+	0x01e1,
+	0x45e1,
+	0x0003,
+};
+
+static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)
+{
+	int ret = 0;
+
+	if ((unsigned int)location >= ARRAY_SIZE(mii_regs))
+		return -1;
+
+	if (location != 5)
+		ret = mii_regs[location];
+	else
+		ret = bus->fixed.lpa;
+
+	return ret;
+}
+
+static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val)
+{
+	/* do nothing */
+}
+
+int fs_mii_fixed_init(struct fs_enet_mii_bus *bus)
+{
+	const struct fs_mii_bus_info *bi = bus->bus_info;
+
+	bus->fixed.lpa = 0x45e1;	/* default 100Mb, full duplex */
+
+	/* if speed is fixed at 10Mb, remove 100Mb modes */
+	if (bi->i.fixed.speed == 10)
+		bus->fixed.lpa &= ~LPA_100;
+
+	/* if duplex is half, remove full duplex modes */
+	if (bi->i.fixed.duplex == 0)
+		bus->fixed.lpa &= ~LPA_DUPLEX;
+
+	bus->mii_read = mii_read;
+	bus->mii_write = mii_write;
+
+	return 0;
+}

^ permalink raw reply

* [PATCH 1/3] fs_enet: core
From: Pantelis Antoniou @ 2005-08-22 19:21 UTC (permalink / raw)
  To: linuxppc-embedded

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

Hi 

This is a snapshot of the work in progress of the new
fs_enet driver. It's aim is to replace all the various
SCC/FCC/FEC drivers for the Freescale PQs.

Don't expect it to work on your board just yet, just take
a look and comment.

This part contains the core driver files.

Regards

Pantelis

[-- Attachment #2: fs_enet-core.patch --]
[-- Type: text/plain, Size: 54727 bytes --]

diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -527,6 +527,42 @@ config WINCEPT
 
 endchoice
 
+menu "Freescale Ethernet driver platform-specific options"
+	depends on FS_ENET
+	
+	config MPC8xx_SECOND_ETH
+	bool "Second Ethernet channel"
+	depends on (MPC885ADS || MPC86xADS)
+	default y
+	help
+	  This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
+	  The latter will use SCC1, for 885ADS you can select it below.
+	
+	choice 
+		prompt "Second Ethernet channel"
+		depends on MPC8xx_SECOND_ETH
+		default MPC885ADS_SECOND_ETH_FEC2
+				
+		config MPC885ADS_SECOND_ETH_FEC2
+		bool "FEC2"
+		help
+		  Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2 
+		  (often 2-nd UART) will not work if this is enabled.
+	  
+		config MPC885ADS_SECOND_ETH_SCC
+		bool "SCC3"
+    		help
+		  Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC2 
+		  (often 1-nd UART) will not work if this is enabled.
+	
+	endchoice
+	
+		config MPC885ADS_SCC_ENET_FIXED
+		depends on MPC885ADS_SECOND_ETH_SCC
+		default n
+		bool "Use fixed MII-less mode for SCC Ethernet"
+endmenu
+
 choice
 	prompt "Machine Type"
 	depends on 6xx || POWER3 || POWER4
@@ -759,6 +795,16 @@ config MPC834x
 	bool
 	default y if MPC834x_SYS
 
+config CPM1
+	bool
+	depends on 8xx
+	default y
+	help
+	  The CPM1 (Communications Processor Module) is a coprocessor on
+	  embedded CPUs made by Motorola.  Selecting this option means that
+	  you wish to build a kernel for a machine with a CPM1 coprocessor
+	  on it (8xx, 827x, 8560).
+
 config CPM2
 	bool
 	depends on 8260 || MPC8560 || MPC8555
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1750,6 +1750,7 @@ config NE_H8300
 	  controller on the Renesas H8/300 processor.
 
 source "drivers/net/fec_8xx/Kconfig"
+source "drivers/net/fs_enet/Kconfig"
 
 endmenu
 
--- /dev/null
+++ b/include/linux/fs_enet_pd.h
@@ -0,0 +1,136 @@
+/*
+ * Platform information definitions for the
+ * universal Freescale Ethernet driver.
+ *
+ * Copyright (c) 2003 Intracom S.A. 
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc. 
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+#ifndef FS_ENET_PD_H
+#define FS_ENET_PD_H
+
+#include <linux/version.h>
+#include <asm/types.h>
+
+#define FS_ENET_NAME	"fs_enet"
+
+enum fs_id {
+	fsid_fec1,
+	fsid_fec2,
+	fsid_fcc1,
+	fsid_fcc2,
+	fsid_fcc3,
+	fsid_scc1,
+	fsid_scc2,
+	fsid_scc3,
+	fsid_scc4,
+};
+
+#define FS_MAX_INDEX	9
+
+static inline int fs_get_fec_index(enum fs_id id)
+{
+	if (id >= fsid_fec1 && id <= fsid_fec2)
+		return id - fsid_fec1;
+	return -1;
+}
+
+static inline int fs_get_fcc_index(enum fs_id id)
+{
+	if (id >= fsid_fcc1 && id <= fsid_fcc3)
+		return id - fsid_fcc1;
+	return -1;
+}
+
+static inline int fs_get_scc_index(enum fs_id id)
+{
+	if (id >= fsid_scc1 && id <= fsid_scc4)
+		return id - fsid_scc1;
+	return -1;
+}
+
+enum fs_mii_method {
+	fsmii_fixed,
+	fsmii_fec,
+	fsmii_bitbang,
+};
+
+enum fs_ioport {
+	fsiop_porta,
+	fsiop_portb,
+	fsiop_portc,
+	fsiop_portd,
+	fsiop_porte,
+};
+
+struct fs_mii_bus_info {
+	int method;		/* mii method                  */
+	int id;			/* the id of the mii_bus       */
+	int disable_aneg;	/* if the controller needs to negothiate speed & duplex */
+	int lpa; 		/* the default board-specific vallues will be applied otherwise */
+
+	union {
+		struct {
+			int duplex;
+			int speed;
+		} fixed;
+
+		struct {
+			/* nothing */
+		} fec;
+		
+		struct {
+			/* nothing */
+		} scc;
+
+		struct {
+			int mdio_port;	/* port & bit for MDIO */
+			int mdio_bit;
+			int mdc_port;	/* port & bit for MDC  */
+			int mdc_bit;
+			int delay;	/* delay in us         */
+		} bitbang;
+	} i;
+};
+
+struct fs_platform_info {
+	
+	void(*init_ioports)(void);
+	/* device specific information */
+	int fs_no;		/* controller index            */
+
+	u32 cp_page;		/* CPM page */
+	u32 cp_block;		/* CPM sblock */
+	
+	u32 clk_trx;		/* some stuff for pins & mux configuration*/
+	u32 clk_route;
+	u32 clk_mask;
+	
+	u32 mem_offset;
+	u32 dpram_offset;
+	u32 fcc_regs_c;
+	
+	u32 device_flags;
+
+	int phy_addr;		/* the phy address (-1 no phy) */
+	int phy_irq;		/* the phy irq (if it exists)  */
+
+	const struct fs_mii_bus_info *bus_info;
+
+	int rx_ring, tx_ring;	/* number of buffers on rx     */
+	__u8 macaddr[6];	/* mac address                 */
+	int rx_copybreak;	/* limit we copy small frames  */
+	int use_napi;		/* use NAPI                    */
+	int napi_weight;	/* NAPI weight                 */
+
+	int use_rmii;		/* use RMII mode 	       */
+};
+
+#endif
diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
--- a/include/asm-ppc/cpm2.h
+++ b/include/asm-ppc/cpm2.h
@@ -1088,5 +1088,7 @@ typedef struct im_idma {
 #define SCCR_PCIDF_SHIFT 3
 
 
+
+#define FCC_PSMR_RMII   ((uint)0x00020000)      /* Use RMII interface */ 
 #endif /* __CPM2__ */
 #endif /* __KERNEL__ */
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -195,3 +195,6 @@ obj-$(CONFIG_IRDA) += irda/
 obj-$(CONFIG_ETRAX_ETHERNET) += cris/
 
 obj-$(CONFIG_NETCONSOLE) += netconsole.o
+
+obj-$(CONFIG_FS_ENET) += fs_enet/
+
--- /dev/null
+++ b/drivers/net/fs_enet/Kconfig
@@ -0,0 +1,41 @@
+config FS_ENET
+       tristate "Freescale Ethernet Driver"
+       depends on NET_ETHERNET && (CPM1 || CPM2)
+       select MII
+
+config FS_ENET_HAS_SCC
+	bool "Chip has an SCC usable for ethernet"
+	depends on FS_ENET && (CPM1 || CPM2)
+	default y
+
+config FS_ENET_HAS_FCC
+	bool "Chip has an FCC usable for ethernet"
+	depends on FS_ENET && CPM2
+	default y
+
+config FS_ENET_HAS_FEC
+	bool "Chip has an FEC usable for ethernet"
+	depends on FS_ENET && CPM1
+	default y
+
+config SCC_ENET_8XX_FIXED
+        bool "Fixed method for SCC Ethernet PHY access "
+        depends on FS_ENET && (MPC885ADS ||  MPC866ADS)
+        default y
+
+choice
+        prompt "Second Ethernet channel"
+        depends on FS_ENET && MPC885ADS
+        default FEC2
+
+config FEC2
+        bool "FEC2"
+        help
+          Use MPC885 Fast rthernet controller 2 to drive Ethernet.
+
+config SCC_ETHERNET
+        bool "SCC3"
+        help
+          Use MPC8xx serial communications controller 3 to drive Ethernet.
+
+endchoice
--- /dev/null
+++ b/drivers/net/fs_enet/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+
+obj-$(CONFIG_FS_ENET) += fs_enet.o
+
+obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o
+obj-$(CONFIG_8260) += mac-fcc.o
+
+fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o
--- /dev/null
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -0,0 +1,1100 @@
+/*
+ * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
+ *
+ * Copyright (c) 2003 Intracom S.A. 
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ * 
+ * 2005 (c) MontaVista Software, Inc. 
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
+ * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+
+#include <linux/vmalloc.h>
+#include <asm/pgtable.h>
+
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "fs_enet.h"
+
+/*************************************************/
+
+static char version[] __devinitdata =
+    DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n";
+
+MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");
+MODULE_DESCRIPTION("Freescale Ethernet Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+MODULE_PARM(fs_enet_debug, "i");
+MODULE_PARM_DESC(fs_enet_debug,
+		 "Freescale bitmapped debugging message enable value");
+
+int fs_enet_debug = -1;		/* -1 == use FS_ENET_DEF_MSG_ENABLE as value */
+
+static void fs_set_multicast_list(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	(*fep->ops->set_multicast_list)(dev);
+}
+
+/* common receive function */
+static int fs_enet_rx_common(struct net_device *dev, int *budget)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+	cbd_t *bdp;
+	struct sk_buff *skb, *skbn, *skbt;
+	int received = 0;
+	u16 pkt_len, sc;
+	int curidx;
+	int rx_work_limit = 0;	/* pacify gcc */
+
+	if (fpi->use_napi) {
+		rx_work_limit = min(dev->quota, *budget);
+
+		if (!netif_running(dev))
+			return 0;
+	}
+
+	/*
+	 * First, grab all of the stats for the incoming packet.
+	 * These get messed up if we get called due to a busy condition.
+	 */
+	bdp = fep->cur_rx;
+
+	/* clear RX status bits for napi*/
+	if (fpi->use_napi)
+		(*fep->ops->napi_clear_rx_event)(dev);
+
+	while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) {
+
+		curidx = bdp - fep->rx_bd_base;
+
+		/*
+		 * Since we have allocated space to hold a complete frame,
+		 * the last indicator should be set.
+		 */
+		if ((sc & BD_ENET_RX_LAST) == 0)
+			printk(KERN_WARNING DRV_MODULE_NAME
+			       ": %s rcv is not +last\n",
+			       dev->name);
+
+		/*
+		 * Check for errors. 
+		 */
+		if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL |
+			  BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) {
+			fep->stats.rx_errors++;
+			/* Frame too long or too short. */
+			if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH))
+				fep->stats.rx_length_errors++;
+			/* Frame alignment */
+			if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL))
+				fep->stats.rx_frame_errors++;
+			/* CRC Error */
+			if (sc & BD_ENET_RX_CR)
+				fep->stats.rx_crc_errors++;
+			/* FIFO overrun */
+			if (sc & BD_ENET_RX_OV)
+				fep->stats.rx_crc_errors++;
+
+			skb = fep->rx_skbuff[curidx];
+
+			dma_unmap_single(fep->dev, skb->data,
+				L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),
+				DMA_FROM_DEVICE);
+
+			skbn = skb;
+
+		} else {
+
+			/* napi, got packet but no quota */
+			if (fpi->use_napi && --rx_work_limit < 0)
+				break;
+
+			skb = fep->rx_skbuff[curidx];
+
+			dma_unmap_single(fep->dev, skb->data,
+				L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),
+				DMA_FROM_DEVICE);
+
+			/*
+			 * Process the incoming frame.
+			 */
+			fep->stats.rx_packets++;
+			pkt_len = CBDR_DATLEN(bdp) - 4;	/* remove CRC */
+			fep->stats.rx_bytes += pkt_len + 4;
+
+			if (pkt_len <= fpi->rx_copybreak) {
+				/* +2 to make IP header L1 cache aligned */
+				skbn = dev_alloc_skb(pkt_len + 2);
+				if (skbn != NULL) {
+					skb_reserve(skbn, 2);	/* align IP header */
+					memcpy(skbn->data, skb->data, pkt_len);
+					/* swap */
+					skbt = skb;
+					skb = skbn;
+					skbn = skbt;
+				}
+			} else
+				skbn = dev_alloc_skb(ENET_RX_FRSIZE);
+
+			if (skbn != NULL) {
+				skb->dev = dev;
+				skb_put(skb, pkt_len);	/* Make room */
+				skb->protocol = eth_type_trans(skb, dev);
+				received++;
+				if (!fpi->use_napi)
+					netif_rx(skb);
+				else
+					netif_receive_skb(skb);
+			} else {
+				printk(KERN_WARNING DRV_MODULE_NAME
+				       ": %s Memory squeeze, dropping packet.\n",
+				       dev->name);
+				fep->stats.rx_dropped++;
+				skbn = skb;
+			}
+		}
+
+		fep->rx_skbuff[curidx] = skbn;
+		CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data,
+			     L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),
+			     DMA_FROM_DEVICE));
+		CBDW_DATLEN(bdp, 0);
+		CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY);
+
+		/*
+		 * Update BD pointer to next entry. 
+		 */
+		if ((sc & BD_ENET_RX_WRAP) == 0)
+			bdp++;
+		else
+			bdp = fep->rx_bd_base;
+
+		(*fep->ops->rx_bd_done)(dev);
+	}
+
+	fep->cur_rx = bdp;
+
+	if (fpi->use_napi) {
+		dev->quota -= received;
+		*budget -= received;
+
+		if (rx_work_limit < 0)
+			return 1;	/* not done */
+
+		/* done */
+		netif_rx_complete(dev);
+
+		(*fep->ops->napi_enable_rx)(dev);
+	}
+
+	return 0;
+}
+
+static void fs_enet_tx(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	cbd_t *bdp;
+	struct sk_buff *skb;
+	int dirtyidx, do_wake, do_restart;
+	u16 sc;
+
+	spin_lock(&fep->lock);
+	bdp = fep->dirty_tx;
+
+	do_wake = do_restart = 0;
+	while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) {
+
+		dirtyidx = bdp - fep->tx_bd_base;
+
+		if (fep->tx_free == fep->tx_ring)
+			break;
+
+		skb = fep->tx_skbuff[dirtyidx];
+
+		/*
+		 * Check for errors. 
+		 */
+		if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC |
+			  BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) {
+
+			if (sc & BD_ENET_TX_HB)	/* No heartbeat */
+				fep->stats.tx_heartbeat_errors++;
+			if (sc & BD_ENET_TX_LC)	/* Late collision */
+				fep->stats.tx_window_errors++;
+			if (sc & BD_ENET_TX_RL)	/* Retrans limit */
+				fep->stats.tx_aborted_errors++;
+			if (sc & BD_ENET_TX_UN)	/* Underrun */
+				fep->stats.tx_fifo_errors++;
+			if (sc & BD_ENET_TX_CSL)	/* Carrier lost */
+				fep->stats.tx_carrier_errors++;
+
+			if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) {
+				fep->stats.tx_errors++;
+				do_restart = 1;
+			}
+		} else
+			fep->stats.tx_packets++;
+
+		if (sc & BD_ENET_TX_READY)
+			printk(KERN_WARNING DRV_MODULE_NAME
+			       ": %s HEY! Enet xmit interrupt and TX_READY.\n",
+			       dev->name);
+
+		/*
+		 * Deferred means some collisions occurred during transmit,
+		 * but we eventually sent the packet OK.
+		 */
+		if (sc & BD_ENET_TX_DEF)
+			fep->stats.collisions++;
+
+		/* unmap */
+		dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE);
+
+		/*
+		 * Free the sk buffer associated with this last transmit. 
+		 */
+		dev_kfree_skb_irq(skb);
+		fep->tx_skbuff[dirtyidx] = NULL;
+
+		/*
+		 * Update pointer to next buffer descriptor to be transmitted. 
+		 */
+		if ((sc & BD_ENET_TX_WRAP) == 0)
+			bdp++;
+		else
+			bdp = fep->tx_bd_base;
+
+		/*
+		 * Since we have freed up a buffer, the ring is no longer
+		 * full.
+		 */
+		if (!fep->tx_free++)
+			do_wake = 1;
+	}
+
+	fep->dirty_tx = bdp;
+
+	if (do_restart)
+		(*fep->ops->tx_restart)(dev);
+
+	spin_unlock(&fep->lock);
+
+	if (do_wake)
+		netif_wake_queue(dev);
+}
+
+/*
+ * The interrupt handler.
+ * This is called from the MPC core interrupt.
+ */
+static irqreturn_t
+fs_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct fs_enet_private *fep;
+	const struct fs_platform_info *fpi;
+	u32 int_events;
+	u32 int_clr_events;
+	int nr, napi_ok;
+
+	fep = netdev_priv(dev);
+	fpi = fep->fpi;
+
+	nr = 0;
+	while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) {
+
+		nr++;
+
+		int_clr_events = int_events;
+		if (fpi->use_napi)
+			int_clr_events &= ~fep->ev_napi_rx;
+
+		(*fep->ops->clear_int_events)(dev, int_clr_events);
+
+		if (int_events & fep->ev_err)
+			(*fep->ops->ev_error)(dev, int_events);
+
+		if (int_events & fep->ev_rx) {
+			if (!fpi->use_napi)
+				fs_enet_rx_common(dev, NULL);
+			else {
+				napi_ok = netif_rx_schedule_prep(dev);
+
+				(*fep->ops->napi_disable_rx)(dev);
+				(*fep->ops->clear_int_events)(dev, fep->ev_napi_rx);
+
+				/* NOTE: it is possible for FCCs in NAPI mode    */
+				/* to submit an spurious interrupt while in poll */
+				if (napi_ok)
+					__netif_rx_schedule(dev);
+			}
+		}
+
+		if (int_events & fep->ev_tx)
+			fs_enet_tx(dev);
+	}
+
+	if (nr == 0)
+		return IRQ_NONE;
+
+	return IRQ_HANDLED;
+}
+
+void fs_init_bds(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	cbd_t *bdp;
+	struct sk_buff *skb;
+	int i;
+
+	fs_cleanup_bds(dev);
+
+	fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
+	fep->tx_free = fep->tx_ring;
+	fep->cur_rx = fep->rx_bd_base;
+
+	/*
+	 * Initialize the receive buffer descriptors. 
+	 */
+	for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) {
+		skb = dev_alloc_skb(ENET_RX_FRSIZE);
+		if (skb == NULL) {
+			printk(KERN_WARNING DRV_MODULE_NAME
+			       ": %s Memory squeeze, unable to allocate skb\n",
+			       dev->name);
+			break;
+		}
+		fep->rx_skbuff[i] = skb;
+		skb->dev = dev;
+		CBDW_BUFADDR(bdp,
+			dma_map_single(fep->dev, skb->data,
+				L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),
+				DMA_FROM_DEVICE));
+		CBDW_DATLEN(bdp, 0);	/* zero */
+		CBDW_SC(bdp, BD_ENET_RX_EMPTY |
+			((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP));
+	}
+	/*
+	 * if we failed, fillup remainder 
+	 */
+	for (; i < fep->rx_ring; i++, bdp++) {
+		fep->rx_skbuff[i] = NULL;
+		CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP);
+	}
+
+	/*
+	 * ...and the same for transmit.  
+	 */
+	for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) {
+		fep->tx_skbuff[i] = NULL;
+		CBDW_BUFADDR(bdp, 0);
+		CBDW_DATLEN(bdp, 0);
+		CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP);
+	}
+}
+
+void fs_cleanup_bds(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	struct sk_buff *skb;
+	int i;
+
+	/*
+	 * Reset SKB transmit buffers.  
+	 */
+	for (i = 0; i < fep->tx_ring; i++) {
+		if ((skb = fep->tx_skbuff[i]) == NULL)
+			continue;
+
+		/* unmap */
+		dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE);
+
+		fep->tx_skbuff[i] = NULL;
+		dev_kfree_skb(skb);
+	}
+
+	/*
+	 * Reset SKB receive buffers 
+	 */
+	for (i = 0; i < fep->rx_ring; i++) {
+		if ((skb = fep->rx_skbuff[i]) == NULL)
+			continue;
+		fep->rx_skbuff[i] = NULL;
+		dev_kfree_skb(skb);
+	}
+}
+
+/**********************************************************************************/
+
+static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	cbd_t *bdp;
+	int curidx;
+	u16 sc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fep->tx_lock, flags);
+
+	/*
+	 * Fill in a Tx ring entry 
+	 */
+	bdp = fep->cur_tx;
+
+	if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) {
+		netif_stop_queue(dev);
+		spin_unlock_irqrestore(&fep->tx_lock, flags);
+
+		/*
+		 * Ooops.  All transmit buffers are full.  Bail out.
+		 * This should not happen, since the tx queue should be stopped.
+		 */
+		printk(KERN_WARNING DRV_MODULE_NAME
+		       ": %s tx queue full!.\n", dev->name);
+		return NETDEV_TX_BUSY;
+	}
+
+	curidx = bdp - fep->tx_bd_base;
+	/*
+	 * Clear all of the status flags. 
+	 */
+	CBDC_SC(bdp, BD_ENET_TX_STATS);
+
+	/*
+	 * Save skb pointer. 
+	 */
+	fep->tx_skbuff[curidx] = skb;
+
+	fep->stats.tx_bytes += skb->len;
+
+	/*
+	 * Push the data cache so the CPM does not get stale memory data. 
+	 */
+	CBDW_BUFADDR(bdp, dma_map_single(fep->dev,
+				skb->data, skb->len, DMA_TO_DEVICE));
+	CBDW_DATLEN(bdp, skb->len);
+
+	dev->trans_start = jiffies;
+
+	/*
+	 * If this was the last BD in the ring, start at the beginning again. 
+	 */
+	if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0)
+		fep->cur_tx++;
+	else
+		fep->cur_tx = fep->tx_bd_base;
+
+	if (!--fep->tx_free)
+		netif_stop_queue(dev);
+
+	/* Trigger transmission start */
+	sc = BD_ENET_TX_READY | BD_ENET_TX_INTR |
+	     BD_ENET_TX_LAST | BD_ENET_TX_TC;
+
+	/* note that while FEC does not have this bit
+	 * it marks it as available for software use
+	 * yay for hw reuse :) */
+	if (skb->len <= 60)
+		sc |= BD_ENET_TX_PAD;
+	CBDS_SC(bdp, sc);
+
+	(*fep->ops->tx_kickstart)(dev);
+
+	spin_unlock_irqrestore(&fep->tx_lock, flags);
+
+	return NETDEV_TX_OK;
+}
+
+static int fs_request_irq(struct net_device *dev, int irq, const char *name,
+		irqreturn_t (*irqf)(int irq, void *dev_id, struct pt_regs *regs))
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	(*fep->ops->pre_request_irq)(dev, irq);
+	return request_irq(irq, irqf, SA_SHIRQ, name, dev);
+}
+
+static void fs_free_irq(struct net_device *dev, int irq)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	free_irq(irq, dev);
+	(*fep->ops->post_free_irq)(dev, irq);
+}
+
+/**********************************************************************************/
+
+/* This interrupt occurs when the PHY detects a link change. */
+static irqreturn_t
+fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct fs_enet_private *fep;
+	const struct fs_platform_info *fpi;
+
+	fep = netdev_priv(dev);
+	fpi = fep->fpi;
+
+	/*
+	 * Acknowledge the interrupt if possible. If we have not
+	 * found the PHY yet we can't process or acknowledge the
+	 * interrupt now. Instead we ignore this interrupt for now,
+	 * which we can do since it is edge triggered. It will be
+	 * acknowledged later by fs_enet_open().
+	 */
+	if (!fep->phy)
+		return IRQ_NONE;
+
+	fs_mii_ack_int(dev);
+	fs_mii_link_status_change_check(dev, 0);
+
+	return IRQ_HANDLED;
+}
+
+static void fs_timeout(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	unsigned long flags;
+
+	fep->stats.tx_errors++;
+
+	if (dev->flags & IFF_UP) {
+		spin_lock_irqsave(&fep->lock, flags);
+		(*fep->ops->stop)(dev);
+		(*fep->ops->restart)(dev);
+		spin_unlock_irqrestore(&fep->lock, flags);
+	}
+
+	netif_schedule(dev);
+}
+
+static int fs_enet_open(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+	int r;
+
+	/* Install our interrupt handler. */
+	r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt);
+	if (r != 0) {
+		printk(KERN_ERR DRV_MODULE_NAME
+		       ": %s Could not allocate FEC IRQ!", dev->name);
+		return -EINVAL;
+	}
+
+	/* Install our phy interrupt handler */
+	if (fpi->phy_irq != -1) {
+
+		r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt);
+		if (r != 0) {
+			printk(KERN_ERR DRV_MODULE_NAME
+			       ": %s Could not allocate PHY IRQ!", dev->name);
+			fs_free_irq(dev, fep->interrupt);
+			return -EINVAL;
+		}
+	}
+
+	fs_mii_startup(dev);
+	netif_carrier_off(dev);
+	fs_mii_link_status_change_check(dev, 1);
+
+	return 0;
+}
+
+static int fs_enet_close(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+	unsigned long flags;
+
+	netif_stop_queue(dev);
+	netif_carrier_off(dev);
+	fs_mii_shutdown(dev);
+
+	spin_lock_irqsave(&fep->lock, flags);
+	(*fep->ops->stop)(dev);
+	spin_unlock_irqrestore(&fep->lock, flags);
+
+	/* release any irqs */
+	if (fpi->phy_irq != -1)
+		fs_free_irq(dev, fpi->phy_irq);
+	fs_free_irq(dev, fep->interrupt);
+
+	return 0;
+}
+
+static struct net_device_stats *fs_enet_get_stats(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	return &fep->stats;
+}
+
+/*************************************************************************/
+
+static void fs_get_drvinfo(struct net_device *dev,
+			    struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, DRV_MODULE_NAME);
+	strcpy(info->version, DRV_MODULE_VERSION);
+}
+
+static int fs_get_regs_len(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	return (*fep->ops->get_regs_len)(dev);
+}
+
+static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+			 void *p)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	unsigned long flags;
+	int r, len;
+
+	len = regs->len;
+
+	spin_lock_irqsave(&fep->lock, flags);
+	r = (*fep->ops->get_regs)(dev, p, &len);
+	spin_unlock_irqrestore(&fep->lock, flags);
+
+	if (r == 0)
+		regs->version = 0;
+}
+
+static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&fep->lock, flags);
+	rc = mii_ethtool_gset(&fep->mii_if, cmd);
+	spin_unlock_irqrestore(&fep->lock, flags);
+
+	return rc;
+}
+
+static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&fep->lock, flags);
+	rc = mii_ethtool_sset(&fep->mii_if, cmd);
+	spin_unlock_irqrestore(&fep->lock, flags);
+
+	return rc;
+}
+
+static int fs_nway_reset(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	return mii_nway_restart(&fep->mii_if);
+}
+
+static u32 fs_get_msglevel(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	return fep->msg_enable;
+}
+
+static void fs_set_msglevel(struct net_device *dev, u32 value)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fep->msg_enable = value;
+}
+
+static struct ethtool_ops fs_ethtool_ops = {
+	.get_drvinfo = fs_get_drvinfo,
+	.get_regs_len = fs_get_regs_len,
+	.get_settings = fs_get_settings,
+	.set_settings = fs_set_settings,
+	.nway_reset = fs_nway_reset,
+	.get_link = ethtool_op_get_link,
+	.get_msglevel = fs_get_msglevel,
+	.set_msglevel = fs_set_msglevel,
+	.get_tx_csum = ethtool_op_get_tx_csum,
+	.set_tx_csum = ethtool_op_set_tx_csum,	/* local! */
+	.get_sg = ethtool_op_get_sg,
+	.set_sg = ethtool_op_set_sg,
+	.get_regs = fs_get_regs,
+};
+
+static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data;
+	unsigned long flags;
+	int rc;
+
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	spin_lock_irqsave(&fep->lock, flags);
+	rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL);
+	spin_unlock_irqrestore(&fep->lock, flags);
+	return rc;
+}
+
+extern int fs_mii_connect(struct net_device *dev);
+extern void fs_mii_disconnect(struct net_device *dev);
+
+static struct net_device *fs_init_instance(struct device *dev,
+		const struct fs_platform_info *fpi)
+{
+	struct net_device *ndev = NULL;
+	struct fs_enet_private *fep = NULL;
+	int privsize, i, r, err = 0, registered = 0;
+
+	/* guard */
+	if ((unsigned int)fpi->fs_no >= FS_MAX_INDEX)
+		return ERR_PTR(-EINVAL);
+
+	privsize = sizeof(*fep) + (sizeof(struct sk_buff **) *
+			    (fpi->rx_ring + fpi->tx_ring));
+
+	ndev = alloc_etherdev(privsize);
+	if (!ndev) {
+		err = -ENOMEM;
+		goto err;
+	}
+	SET_MODULE_OWNER(ndev);
+
+	fep = netdev_priv(ndev);
+	memset(fep, 0, privsize);	/* clear everything */
+
+	fep->dev = dev;
+	dev_set_drvdata(dev, ndev);
+	fep->fpi = fpi;
+	if (fpi->init_ioports)
+		fpi->init_ioports();
+
+#ifdef CONFIG_FS_ENET_HAS_FEC
+	if (fs_get_fec_index(fpi->fs_no) >= 0)
+		fep->ops = &fs_fec_ops;
+#endif
+
+#ifdef CONFIG_FS_ENET_HAS_SCC
+	if (fs_get_scc_index(fpi->fs_no) >=0 )
+		fep->ops = &fs_scc_ops;
+#endif
+
+#ifdef CONFIG_FS_ENET_HAS_FCC
+	if (fs_get_fcc_index(fpi->fs_no) >= 0)
+		fep->ops = &fs_fcc_ops;
+#endif
+
+	if (fep->ops == NULL) {
+		printk(KERN_ERR DRV_MODULE_NAME
+		       ": %s No matching ops found (%d).\n",
+		       ndev->name, fpi->fs_no);
+		err = -EINVAL;
+		goto err;
+	}
+
+	r = (*fep->ops->setup_data)(ndev);
+	if (r != 0) {
+		printk(KERN_ERR DRV_MODULE_NAME
+		       ": %s setup_data failed\n",
+			ndev->name);
+		err = r;
+		goto err;
+	}
+
+	/* point rx_skbuff, tx_skbuff */
+	fep->rx_skbuff = (struct sk_buff **)&fep[1];
+	fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring;
+
+	/* init locks */
+	spin_lock_init(&fep->lock);
+	spin_lock_init(&fep->tx_lock);
+
+	/*
+	 * Set the Ethernet address. 
+	 */
+	for (i = 0; i < 6; i++)
+		ndev->dev_addr[i] = fpi->macaddr[i];
+	
+	r = (*fep->ops->allocate_bd)(ndev);
+	
+	if (fep->ring_base == NULL) {
+		printk(KERN_ERR DRV_MODULE_NAME
+		       ": %s buffer descriptor alloc failed (%d).\n", ndev->name, r);
+		err = r;
+		goto err;
+	}
+
+	/*
+	 * Set receive and transmit descriptor base.
+	 */
+	fep->rx_bd_base = fep->ring_base;
+	fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring;
+
+	/* initialize ring size variables */
+	fep->tx_ring = fpi->tx_ring;
+	fep->rx_ring = fpi->rx_ring;
+
+	/*
+	 * The FEC Ethernet specific entries in the device structure. 
+	 */
+	ndev->open = fs_enet_open;
+	ndev->hard_start_xmit = fs_enet_start_xmit;
+	ndev->tx_timeout = fs_timeout;
+	ndev->watchdog_timeo = 2 * HZ;
+	ndev->stop = fs_enet_close;
+	ndev->get_stats = fs_enet_get_stats;
+	ndev->set_multicast_list = fs_set_multicast_list;
+	if (fpi->use_napi) {
+		ndev->poll = fs_enet_rx_common;
+		ndev->weight = fpi->napi_weight;
+	}
+	ndev->ethtool_ops = &fs_ethtool_ops;
+	ndev->do_ioctl = fs_ioctl;
+
+	init_timer(&fep->phy_timer_list);
+
+	netif_carrier_off(ndev);
+
+	err = register_netdev(ndev);
+	if (err != 0) {
+		printk(KERN_ERR DRV_MODULE_NAME
+		       ": %s register_netdev failed.\n", ndev->name);
+		goto err;
+	}
+	registered = 1;
+
+	err = fs_mii_connect(ndev);
+	if (err != 0) {
+		printk(KERN_ERR DRV_MODULE_NAME
+		       ": %s fs_mii_connect failed.\n", ndev->name);
+		goto err;
+	}
+
+	return ndev;
+
+      err:
+	if (ndev != NULL) {
+
+		if (registered)
+			unregister_netdev(ndev);
+
+		if (fep != NULL) {
+			(*fep->ops->free_bd)(ndev);
+			(*fep->ops->cleanup_data)(ndev);
+		}
+
+		free_netdev(ndev);
+	}
+
+	dev_set_drvdata(dev, NULL);
+
+	return ERR_PTR(err);
+}
+
+static int fs_cleanup_instance(struct net_device *ndev)
+{
+	struct fs_enet_private *fep;
+	const struct fs_platform_info *fpi;
+	struct device *dev;
+
+	if (ndev == NULL)
+		return -EINVAL;
+
+	fep = netdev_priv(ndev);
+	if (fep == NULL)
+		return -EINVAL;
+
+	fpi = fep->fpi;
+
+	fs_mii_disconnect(ndev);
+
+	unregister_netdev(ndev);
+
+	dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),
+			  fep->ring_base, fep->ring_mem_addr);
+
+	/* reset it */
+	(*fep->ops->cleanup_data)(ndev);
+
+	dev = fep->dev;
+	if (dev != NULL) {
+		dev_set_drvdata(dev, NULL);
+		fep->dev = NULL;
+	}
+
+	free_netdev(ndev);
+
+	return 0;
+}
+
+/**************************************************************************************/
+
+/* handy pointer to the immap */
+void *fs_enet_immap = NULL;
+
+static int setup_immap(void)
+{
+	phys_addr_t paddr = 0;
+	unsigned long size = 0;
+
+#ifdef CONFIG_CPM1
+	paddr = IMAP_ADDR;
+	size = 0x10000;	/* map 64K */
+#endif
+
+#ifdef CONFIG_CPM2
+	paddr = CPM_MAP_ADDR;
+	size = 0x40000;	/* map 256 K */
+#endif
+	fs_enet_immap = ioremap(paddr, size);
+	if (fs_enet_immap == NULL)
+		return -EBADF;	/* XXX ahem; maybe just BUG_ON? */
+
+	return 0;
+}
+
+static void cleanup_immap(void)
+{
+	if (fs_enet_immap != NULL) {
+		iounmap(fs_enet_immap);
+		fs_enet_immap = NULL;
+	}
+}
+
+/**************************************************************************************/
+
+static int __devinit fs_enet_probe(struct device *dev)
+{
+	struct net_device *ndev;
+
+	/* no fixup - no device */
+	if (dev->platform_data == NULL) {
+		printk(KERN_INFO "fs_enet: "
+				"probe called with no platform data; "
+				"remove unused devices");
+		return -ENODEV;
+	}
+
+	ndev = fs_init_instance(dev, dev->platform_data);
+	if (IS_ERR(ndev))
+		return PTR_ERR(ndev);
+	return 0;
+}
+
+static int fs_enet_remove(struct device *dev)
+{
+	return fs_cleanup_instance(dev_get_drvdata(dev));
+}
+
+static struct device_driver fs_enet_fec_driver = {
+	.name	  	= "fsl-cpm-fec",
+	.bus		= &platform_bus_type,
+	.probe		= fs_enet_probe,
+	.remove		= fs_enet_remove,
+#ifdef CONFIG_PM
+/*	.suspend	= fs_enet_suspend,	TODO */
+/*	.resume		= fs_enet_resume,	TODO */
+#endif
+};
+
+static struct device_driver fs_enet_scc_driver = {
+	.name	  	= "fsl-cpm-scc",
+	.bus		= &platform_bus_type,
+	.probe		= fs_enet_probe,
+	.remove		= fs_enet_remove,
+#ifdef CONFIG_PM
+/*	.suspend	= fs_enet_suspend,	TODO */
+/*	.resume		= fs_enet_resume,	TODO */
+#endif
+};
+
+static struct device_driver fs_enet_fcc_driver = {
+	.name	  	= "fsl-cpm-fcc",
+	.bus		= &platform_bus_type,
+	.probe		= fs_enet_probe,
+	.remove		= fs_enet_remove,
+#ifdef CONFIG_PM
+/*	.suspend	= fs_enet_suspend,	TODO */
+/*	.resume		= fs_enet_resume,	TODO */
+#endif
+};
+
+static int __init fs_init(void)
+{
+	int r;
+
+	printk(KERN_INFO
+			"%s", version);
+
+	r = setup_immap();
+	if (r != 0)
+		return r;
+	r = driver_register(&fs_enet_fec_driver);
+	if (r != 0)
+		goto err;
+
+	r = driver_register(&fs_enet_fcc_driver);
+	if (r != 0)
+		goto err;
+
+	r = driver_register(&fs_enet_scc_driver);
+	if (r != 0)
+		goto err;
+
+	return 0;
+err:
+	cleanup_immap();
+	return r;
+	
+}
+
+static void __exit fs_cleanup(void)
+{
+	driver_unregister(&fs_enet_fec_driver);
+	driver_unregister(&fs_enet_fcc_driver);
+	driver_unregister(&fs_enet_scc_driver);
+	cleanup_immap();
+}
+
+/**************************************************************************************/
+
+module_init(fs_init);
+module_exit(fs_cleanup);
--- /dev/null
+++ b/drivers/net/fs_enet/fs_enet-mii.c
@@ -0,0 +1,522 @@
+/*
+ * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
+ *
+ * Copyright (c) 2003 Intracom S.A. 
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ * 
+ * 2005 (c) MontaVista Software, Inc. 
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
+ * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "fs_enet.h"
+
+/*************************************************/
+
+/*
+ * Generic PHY support.
+ * Should work for all PHYs, but link change is detected by polling
+ */
+
+static void generic_timer_callback(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	fep->phy_timer_list.expires = jiffies + HZ / 2;
+
+	add_timer(&fep->phy_timer_list);
+
+	fs_mii_link_status_change_check(dev, 0);
+}
+
+static void generic_startup(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	fep->phy_timer_list.expires = jiffies + HZ / 2;	/* every 500ms */
+	fep->phy_timer_list.data = (unsigned long)dev;
+	fep->phy_timer_list.function = generic_timer_callback;
+	add_timer(&fep->phy_timer_list);
+}
+
+static void generic_shutdown(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	del_timer_sync(&fep->phy_timer_list);
+}
+
+/* ------------------------------------------------------------------------- */
+/* The Davicom DM9161 is used on the NETTA board			     */
+
+/* register definitions */
+
+#define MII_DM9161_ANAR		4	/* Aux. Config Register         */
+#define MII_DM9161_ACR		16	/* Aux. Config Register         */
+#define MII_DM9161_ACSR		17	/* Aux. Config/Status Register  */
+#define MII_DM9161_10TCSR	18	/* 10BaseT Config/Status Reg.   */
+#define MII_DM9161_INTR		21	/* Interrupt Register           */
+#define MII_DM9161_RECR		22	/* Receive Error Counter Reg.   */
+#define MII_DM9161_DISCR	23	/* Disconnect Counter Register  */
+
+static void dm9161_startup(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000);
+	/* Start autonegotiation */
+	fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ*8);
+}
+
+static void dm9161_ack_int(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR);
+}
+
+static void dm9161_shutdown(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00);
+}
+
+/**********************************************************************************/
+
+static const struct phy_info phy_info[] = {
+	{
+		.id = 0x00181b88,
+		.name = "DM9161",
+		.startup = dm9161_startup,
+		.ack_int = dm9161_ack_int,
+		.shutdown = dm9161_shutdown,
+	}, {
+		.id = 0,
+		.name = "GENERIC",
+		.startup = generic_startup,
+		.shutdown = generic_shutdown,
+	},
+};
+
+/**********************************************************************************/
+
+static int phy_id_detect(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+	struct fs_enet_mii_bus *bus = fep->mii_bus;
+	int i, r, start, end, phytype, physubtype;
+	const struct phy_info *phy;
+	int phy_hwid, phy_id;
+
+	phy_hwid = -1;
+	fep->phy = NULL;
+
+	/* auto-detect? */
+	if (fpi->phy_addr == -1) {
+		start = 1;
+		end = 32;
+	} else {		/* direct */
+		start = fpi->phy_addr;
+		end = start + 1;
+	}
+
+	for (phy_id = start; phy_id < end; phy_id++) {
+		/* skip already used phy addresses on this bus */ 
+		if (bus->usage_map & (1 << phy_id))
+			continue;
+		r = fs_mii_read(dev, phy_id, MII_PHYSID1);
+		if (r == -1 || (phytype = (r & 0xffff)) == 0xffff)
+			continue;
+		r = fs_mii_read(dev, phy_id, MII_PHYSID2);
+		if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff)
+			continue;
+		phy_hwid = (phytype << 16) | physubtype;
+		if (phy_hwid != -1)
+			break;
+	}
+
+	if (phy_hwid == -1) {
+		printk(KERN_ERR DRV_MODULE_NAME
+		       ": %s No PHY detected! range=0x%02x-0x%02x\n",
+			dev->name, start, end);
+		return -1;
+	}
+
+	for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++)
+		if (phy->id == (phy_hwid >> 4) || phy->id == 0)
+			break;
+
+	if (i >= ARRAY_SIZE(phy_info)) {
+		printk(KERN_ERR DRV_MODULE_NAME
+		       ": %s PHY id 0x%08x is not supported!\n",
+		       dev->name, phy_hwid);
+		return -1;
+	}
+
+	fep->phy = phy;
+
+	/* mark this address as used */
+	bus->usage_map |= (1 << phy_id);
+
+	printk(KERN_INFO DRV_MODULE_NAME
+	       ": %s Phy @ 0x%x, type %s (0x%08x)%s\n",
+	       dev->name, phy_id, fep->phy->name, phy_hwid,
+	       fpi->phy_addr == -1 ? " (auto-detected)" : "");
+
+	return phy_id;
+}
+
+void fs_mii_startup(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	if (fep->phy == NULL)
+		return;
+
+	if (fep->phy->startup == NULL)
+		return;
+
+	(*fep->phy->startup) (dev);
+}
+
+void fs_mii_shutdown(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	if (fep->phy == NULL)
+		return;
+
+	if (fep->phy->shutdown == NULL)
+		return;
+
+	(*fep->phy->shutdown) (dev);
+}
+
+void fs_mii_ack_int(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	if (fep->phy == NULL)
+		return;
+
+	if (fep->phy->ack_int == NULL)
+		return;
+
+	(*fep->phy->ack_int) (dev);
+}
+
+#define MII_LINK	0x0001
+#define MII_HALF	0x0002
+#define MII_FULL	0x0004
+#define MII_BASE4	0x0008
+#define MII_10M		0x0010
+#define MII_100M	0x0020
+#define MII_1G		0x0040
+#define MII_10G		0x0080
+
+/* return full mii info at one gulp, with a usable form */
+static unsigned int mii_full_status(struct mii_if_info *mii)
+{
+	unsigned int status;
+	int bmsr, adv, lpa, neg;
+	struct fs_enet_private* fep = netdev_priv(mii->dev);
+	
+	/* first, a dummy read, needed to latch some MII phys */
+	(void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
+	bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
+
+	/* no link */
+	if ((bmsr & BMSR_LSTATUS) == 0)
+		return 0;
+
+	status = MII_LINK;
+	
+	/* Lets look what ANEG says if it's supported - otherwize we shall
+	   take the right values from the platform info*/
+	if(!mii->force_media) {
+		/* autoneg not completed; don't bother */
+		if ((bmsr & BMSR_ANEGCOMPLETE) == 0)
+			return 0;
+
+		adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE);
+		lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA);
+
+		neg = lpa & adv;
+	} else {
+		neg = fep->fpi->bus_info->lpa;
+	}
+
+	if (neg & LPA_100FULL)
+		status |= MII_FULL | MII_100M;
+	else if (neg & LPA_100BASE4)
+		status |= MII_FULL | MII_BASE4 | MII_100M;
+	else if (neg & LPA_100HALF)
+		status |= MII_HALF | MII_100M;
+	else if (neg & LPA_10FULL)
+		status |= MII_FULL | MII_10M;
+	else
+		status |= MII_HALF | MII_10M;
+	
+	return status;
+}
+
+void fs_mii_link_status_change_check(struct net_device *dev, int init_media)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	struct mii_if_info *mii = &fep->mii_if;
+	unsigned int mii_status;
+	int ok_to_print, link, duplex, speed;
+	unsigned long flags;
+
+	ok_to_print = netif_msg_link(fep);
+
+	mii_status = mii_full_status(mii);
+
+	if (!init_media && mii_status == fep->last_mii_status)
+		return;
+
+	fep->last_mii_status = mii_status;
+
+	link = !!(mii_status & MII_LINK);
+	duplex = !!(mii_status & MII_FULL);
+	speed = (mii_status & MII_100M) ? 100 : 10;
+
+	if (link == 0) {
+		netif_carrier_off(mii->dev);
+		netif_stop_queue(dev);
+		if (!init_media) {
+			spin_lock_irqsave(&fep->lock, flags);
+			(*fep->ops->stop)(dev);
+			spin_unlock_irqrestore(&fep->lock, flags);
+		}
+
+		if (ok_to_print)
+			printk(KERN_INFO "%s: link down\n", mii->dev->name);
+
+	} else {
+
+		mii->full_duplex = duplex;
+
+		netif_carrier_on(mii->dev);
+
+		spin_lock_irqsave(&fep->lock, flags);
+		fep->duplex = duplex;
+		fep->speed = speed;
+		(*fep->ops->restart)(dev);
+		spin_unlock_irqrestore(&fep->lock, flags);
+
+		netif_start_queue(dev);
+
+		if (ok_to_print)
+			printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n",
+			       dev->name, speed, duplex ? "full" : "half");
+	}
+}
+
+/**********************************************************************************/
+
+int fs_mii_read(struct net_device *dev, int phy_id, int location)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	struct fs_enet_mii_bus *bus = fep->mii_bus;
+
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&bus->mii_lock, flags);
+	ret = (*bus->mii_read)(bus, phy_id, location);
+	spin_unlock_irqrestore(&bus->mii_lock, flags);
+
+	return ret;
+}
+
+void fs_mii_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	struct fs_enet_mii_bus *bus = fep->mii_bus;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bus->mii_lock, flags);
+	(*bus->mii_write)(bus, phy_id, location, value);
+	spin_unlock_irqrestore(&bus->mii_lock, flags);
+}
+
+/*****************************************************************************/
+
+/* list of all registered mii buses */
+static LIST_HEAD(fs_mii_bus_list);
+
+static struct fs_enet_mii_bus *lookup_bus(int method, int id)
+{
+	struct list_head *ptr;
+	struct fs_enet_mii_bus *bus;
+
+	list_for_each(ptr, &fs_mii_bus_list) {
+		bus = list_entry(ptr, struct fs_enet_mii_bus, list);
+		if (bus->bus_info->method == method &&
+			bus->bus_info->id == id)
+			return bus;
+	}
+	return NULL;
+}
+
+static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi)
+{
+	struct fs_enet_mii_bus *bus;
+	int ret = 0;
+
+	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+	if (bus == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+	memset(bus, 0, sizeof(*bus));
+	spin_lock_init(&bus->mii_lock);
+	bus->bus_info = bi;
+	bus->refs = 0;
+	bus->usage_map = 0;
+
+	/* perform initialization */
+	switch (bi->method) {
+
+		case fsmii_fixed:
+			ret = fs_mii_fixed_init(bus);
+			if (ret != 0)
+				goto err;
+			break;
+
+		case fsmii_bitbang:
+			ret = fs_mii_bitbang_init(bus);
+			if (ret != 0)
+				goto err;
+			break;
+#ifdef CONFIG_FS_ENET_HAS_FEC
+		case fsmii_fec:
+			ret = fs_mii_fec_init(bus);
+			if (ret != 0)
+				goto err;
+			break;
+#endif
+		default:
+			ret = -EINVAL;
+			goto err;
+	}
+
+	list_add(&bus->list, &fs_mii_bus_list);
+
+	return bus;
+
+err:
+	if (bus)
+		kfree(bus);
+	return ERR_PTR(ret);
+}
+
+static void destroy_bus(struct fs_enet_mii_bus *bus)
+{
+	/* remove from bus list */
+	list_del(&bus->list);
+
+	/* nothing more needed */
+	kfree(bus);
+}
+
+int fs_mii_connect(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+	struct fs_enet_mii_bus *bus = NULL;
+
+	/* check method validity */
+	switch (fpi->bus_info->method) {
+		case fsmii_fixed:
+		case fsmii_bitbang:
+			break;
+#ifdef CONFIG_FS_ENET_HAS_FEC
+		case fsmii_fec:
+			break;
+#endif
+		default:
+			printk(KERN_ERR DRV_MODULE_NAME
+			       ": %s Unknown MII bus method (%d)!\n",
+			       dev->name, fpi->bus_info->method);
+			return -EINVAL; 
+	}
+
+	bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id);
+
+	/* if not found create new bus */
+	if (bus == NULL) {
+		bus = create_bus(fpi->bus_info);
+		if (IS_ERR(bus)) {
+			printk(KERN_ERR DRV_MODULE_NAME
+			       ": %s MII bus creation failure!\n", dev->name);
+			return PTR_ERR(bus);
+		}
+	}
+
+	bus->refs++;
+
+	fep->mii_bus = bus;
+
+	fep->mii_if.dev = dev;
+	fep->mii_if.phy_id_mask = 0x1f;
+	fep->mii_if.reg_num_mask = 0x1f;
+	fep->mii_if.mdio_read = fs_mii_read;
+	fep->mii_if.mdio_write = fs_mii_write;
+	fep->mii_if.force_media = fpi->bus_info->disable_aneg;
+	fep->mii_if.phy_id = phy_id_detect(dev);
+
+	return 0;
+}
+
+void fs_mii_disconnect(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	struct fs_enet_mii_bus *bus = NULL;
+
+	bus = fep->mii_bus;
+	fep->mii_bus = NULL;
+
+	if (--bus->refs <= 0)
+		destroy_bus(bus);
+}
--- /dev/null
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -0,0 +1,269 @@
+#ifndef FS_ENET_H
+#define FS_ENET_H
+
+#include <linux/mii.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/list.h>
+
+#include <linux/fs_enet_pd.h>
+
+#include <asm/dma-mapping.h>
+
+#ifdef CONFIG_CPM1
+#include <asm/commproc.h>
+#endif
+
+#ifdef CONFIG_CPM2
+#include <asm/cpm2.h>
+#endif
+
+/* hw driver ops */
+struct fs_ops {
+	int (*setup_data)(struct net_device *dev);
+	int (*allocate_bd)(struct net_device *dev);
+	void (*free_bd)(struct net_device *dev);
+	void (*cleanup_data)(struct net_device *dev);
+	void (*set_multicast_list)(struct net_device *dev);
+	void (*restart)(struct net_device *dev);
+	void (*stop)(struct net_device *dev);
+	void (*pre_request_irq)(struct net_device *dev, int irq);
+	void (*post_free_irq)(struct net_device *dev, int irq);
+	void (*napi_clear_rx_event)(struct net_device *dev);
+	void (*napi_enable_rx)(struct net_device *dev);
+	void (*napi_disable_rx)(struct net_device *dev);
+	void (*rx_bd_done)(struct net_device *dev);
+	void (*tx_kickstart)(struct net_device *dev);
+	u32 (*get_int_events)(struct net_device *dev);
+	void (*clear_int_events)(struct net_device *dev, u32 int_events);
+	void (*ev_error)(struct net_device *dev, u32 int_events);
+	int (*get_regs)(struct net_device *dev, void *p, int *sizep);
+	int (*get_regs_len)(struct net_device *dev);
+	void (*tx_restart)(struct net_device *dev);
+};
+
+#define MII_ADVERTISE_HALF	(ADVERTISE_100HALF | \
+				 ADVERTISE_10HALF | ADVERTISE_CSMA)
+#define MII_ADVERTISE_ALL	(ADVERTISE_100FULL | \
+				 ADVERTISE_10FULL | MII_ADVERTISE_HALF)
+
+/* values for MII phy_status */
+
+#define PHY_CONF_ANE	0x0001	/* 1 auto-negotiation enabled     */
+#define PHY_CONF_LOOP	0x0002	/* 1 loopback mode enabled        */
+#define PHY_CONF_SPMASK	0x00f0	/* mask for speed                 */
+#define PHY_CONF_10HDX	0x0010	/* 10 Mbit half duplex supported  */
+#define PHY_CONF_10FDX	0x0020	/* 10 Mbit full duplex supported  */
+#define PHY_CONF_100HDX	0x0040	/* 100 Mbit half duplex supported */
+#define PHY_CONF_100FDX	0x0080	/* 100 Mbit full duplex supported */
+
+#define PHY_STAT_LINK	0x0100	/* 1 up - 0 down                  */
+#define PHY_STAT_FAULT	0x0200	/* 1 remote fault                 */
+#define PHY_STAT_ANC	0x0400	/* 1 auto-negotiation complete    */
+#define PHY_STAT_SPMASK	0xf000	/* mask for speed                 */
+#define PHY_STAT_10HDX	0x1000	/* 10 Mbit half duplex selected   */
+#define PHY_STAT_10FDX	0x2000	/* 10 Mbit full duplex selected   */
+#define PHY_STAT_100HDX	0x4000	/* 100 Mbit half duplex selected  */
+#define PHY_STAT_100FDX	0x8000	/* 100 Mbit full duplex selected  */
+
+struct phy_info {
+	unsigned int id;
+	const char *name;
+	void (*startup) (struct net_device * dev);
+	void (*shutdown) (struct net_device * dev);
+	void (*ack_int) (struct net_device * dev);
+};
+
+/* The FEC stores dest/src/type, data, and checksum for receive packets.
+ */
+#define MAX_MTU 1508		/* Allow fullsized pppoe packets over VLAN */
+#define MIN_MTU 46		/* this is data size */
+#define CRC_LEN 4
+
+#define PKT_MAXBUF_SIZE		(MAX_MTU+ETH_HLEN+CRC_LEN)
+#define PKT_MINBUF_SIZE		(MIN_MTU+ETH_HLEN+CRC_LEN)
+
+/* Must be a multiple of 32 (to cover both FEC & FCC) */
+#define PKT_MAXBLR_SIZE		((PKT_MAXBUF_SIZE + 31) & ~31)
+/* This is needed so that invalidate_xxx wont invalidate too much */
+#define ENET_RX_FRSIZE		L1_CACHE_ALIGN(PKT_MAXBUF_SIZE)
+
+struct fs_enet_mii_bus {
+	struct list_head list;
+	spinlock_t mii_lock;
+	const struct fs_mii_bus_info *bus_info;
+	int refs;
+	u32 usage_map;
+
+	int (*mii_read)(struct fs_enet_mii_bus *bus,
+			int phy_id, int location);
+
+	void (*mii_write)(struct fs_enet_mii_bus *bus,
+			int phy_id, int location, int value);
+
+	union {
+		struct {
+			unsigned int mii_speed;
+			void *fecp;
+		} fec;
+
+		struct {
+			/* note that the actual port size may */
+			/* be different; cpm(s) handle it OK  */
+			u8 mdio_msk;
+			u8 *mdio_dir;
+			u8 *mdio_dat;
+			u8 mdc_msk;
+			u8 *mdc_dir;
+			u8 *mdc_dat;
+		} bitbang;
+
+		struct {
+			u16 lpa;
+		} fixed;
+	};
+};
+
+int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus);
+int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
+int fs_mii_fec_init(struct fs_enet_mii_bus *bus);
+
+struct fs_enet_private {
+	struct device *dev;	/* pointer back to the device (must be initialized first) */
+	spinlock_t lock;	/* during all ops except TX pckt processing */
+	spinlock_t tx_lock;	/* during fs_start_xmit and fs_tx         */
+	const struct fs_platform_info *fpi;
+	const struct fs_ops *ops;
+	int rx_ring, tx_ring;
+	dma_addr_t ring_mem_addr;
+	void *ring_base;
+	struct sk_buff **rx_skbuff;
+	struct sk_buff **tx_skbuff;
+	cbd_t *rx_bd_base;	/* Address of Rx and Tx buffers.    */
+	cbd_t *tx_bd_base;
+	cbd_t *dirty_tx;	/* ring entries to be free()ed.     */
+	cbd_t *cur_rx;
+	cbd_t *cur_tx;
+	int tx_free;
+	struct net_device_stats stats;
+	struct timer_list phy_timer_list;
+	const struct phy_info *phy;
+	u32 msg_enable;
+	struct mii_if_info mii_if;
+	unsigned int last_mii_status;
+	struct fs_enet_mii_bus *mii_bus;
+	int interrupt;
+
+	int duplex, speed;	/* current settings */
+
+	/* event masks */
+	u32 ev_napi_rx;		/* mask of NAPI rx events */
+	u32 ev_rx;		/* rx event mask          */
+	u32 ev_tx;		/* tx event mask          */
+	u32 ev_err;		/* error event mask       */
+
+	u16 bd_rx_empty;	/* mask of BD rx empty	  */
+	u16 bd_rx_err;		/* mask of BD rx errors   */
+
+	union {
+		struct {
+			int idx;		/* FEC1 = 0, FEC2 = 1  */
+			void *fecp;		/* hw registers        */
+			u32 hthi, htlo;		/* state for multicast */
+		} fec;
+
+		struct {
+			int idx;		/* FCC1-3 = 0-2	       */
+			void *fccp;		/* hw registers	       */
+			void *ep;		/* parameter ram       */
+			void *fcccp;		/* hw registers cont.  */
+			void *mem;		/* FCC DPRAM */
+			u32 gaddrh, gaddrl;	/* group address       */
+		} fcc;
+
+		struct {
+			int idx;		/* FEC1 = 0, FEC2 = 1  */
+			void *sccp;		/* hw registers        */
+			void *ep;		/* parameter ram       */
+			u32 hthi, htlo;		/* state for multicast */
+		} scc;
+
+	};
+};
+
+/***************************************************************************/
+
+int fs_mii_read(struct net_device *dev, int phy_id, int location);
+void fs_mii_write(struct net_device *dev, int phy_id, int location, int value);
+
+void fs_mii_startup(struct net_device *dev);
+void fs_mii_shutdown(struct net_device *dev);
+void fs_mii_ack_int(struct net_device *dev);
+
+void fs_mii_link_status_change_check(struct net_device *dev, int init_media);
+
+void fs_init_bds(struct net_device *dev);
+void fs_cleanup_bds(struct net_device *dev);
+
+/***************************************************************************/
+
+#define DRV_MODULE_NAME		"fs_enet"
+#define PFX DRV_MODULE_NAME	": "
+#define DRV_MODULE_VERSION	"1.0"
+#define DRV_MODULE_RELDATE	"Aug 8, 2005"
+
+/***************************************************************************/
+
+int fs_enet_platform_init(void);
+void fs_enet_platform_cleanup(void);
+
+/***************************************************************************/
+
+/* buffer descriptor access macros */
+
+/* access macros */
+#if defined(CONFIG_CPM1)
+/* for a a CPM1 __raw_xxx's are sufficient */
+#define __cbd_out32(addr, x)	__raw_writel(x, addr)
+#define __cbd_out16(addr, x)	__raw_writew(x, addr)
+#define __cbd_in32(addr)	__raw_readl(addr)
+#define __cbd_in16(addr)	__raw_readw(addr)
+#else
+/* for others play it safe */
+#define __cbd_out32(addr, x)	out_be32(addr, x)
+#define __cbd_out16(addr, x)	out_be16(addr, x)
+#define __cbd_in32(addr)	in_be32(addr)
+#define __cbd_in16(addr)	in_be16(addr)
+#endif
+
+/* write */
+#define CBDW_SC(_cbd, _sc) 		__cbd_out16(&(_cbd)->cbd_sc, (_sc))
+#define CBDW_DATLEN(_cbd, _datlen)	__cbd_out16(&(_cbd)->cbd_datlen, (_datlen))
+#define CBDW_BUFADDR(_cbd, _bufaddr)	__cbd_out32(&(_cbd)->cbd_bufaddr, (_bufaddr))
+
+/* read */
+#define CBDR_SC(_cbd) 			__cbd_in16(&(_cbd)->cbd_sc)
+#define CBDR_DATLEN(_cbd)		__cbd_in16(&(_cbd)->cbd_datlen)
+#define CBDR_BUFADDR(_cbd)		__cbd_in32(&(_cbd)->cbd_bufaddr)
+
+/* set bits */
+#define CBDS_SC(_cbd, _sc) 		CBDW_SC(_cbd, CBDR_SC(_cbd) | (_sc))
+
+/* clear bits */
+#define CBDC_SC(_cbd, _sc) 		CBDW_SC(_cbd, CBDR_SC(_cbd) & ~(_sc))
+
+/*******************************************************************/
+
+extern const struct fs_ops fs_fec_ops;
+extern const struct fs_ops fs_fcc_ops;
+extern const struct fs_ops fs_scc_ops;
+
+/*******************************************************************/
+
+/* handy pointer to the immap */
+extern void *fs_enet_immap;
+
+/*******************************************************************/
+
+#endif

^ permalink raw reply

* Re: mmap nocache on PPC, 2.4
From: Stephen Williams @ 2005-08-22 17:47 UTC (permalink / raw)
  To: Stephen Williams; +Cc: linuxppc-embedded
In-Reply-To: <430A0AB9.20000@icarus.com>

Stephen Williams wrote:
> Dan Malek wrote:

> | Even if this did what you thought it should, I'm not sure you
> | would be happy with the results.  The challenge is ensuring
> | anyone that touches these physical pages also does so
> | uncached.  Depending upon the processor, this isn't something
> | that is trivial to change in the kernel, since we always map
> | all of memory as efficiently as possible with a cached mapping.
> | The caching of memory has many desirable performance
> | side effects, making the trade off the manage coherency in
> | software if needed an overall system gain.
> 
> The processor is touching this memory only very briefly to put
> image headers around the data, and even at that it would need
> to be immediately flushed again so that it can be DMAed off the
> system.
> 
> My problem is that I need a lot of memory that is mostly accessed
> by high performance devices that make lots of data, and only
> very occasionally accessed by the processor for minor fixups.
> Caching is very much getting in my way here in this specialized
> case, I think.

I would like to add that it is not exactly the cache that is
getting in my way, but *cache invalidation*. For the tests I'm
running the destination buffer is 16Meg. The PPC405GPr 266MHz
is taking 10ms to invalidate the cache for all that memory and
another 6ms to "map" it and get physical addresses for DMA, but
I need it to be turned around in more like 1ms.

Of the 16ms to turn the buffer around, I've eliminated 10ms
simply by treating the memory of the buffer as uncached. I'm
hoping to work on the remaining 6ms by premapping where I can.


-- 
Steve Williams                "The woods are lovely, dark and deep.
steve at icarus.com           But I have promises to keep,
http://www.icarus.com         and lines to code before I sleep,
http://www.picturel.com       And lines to code before I sleep."

^ permalink raw reply

* Re: mmap nocache on PPC, 2.4
From: Stephen Williams @ 2005-08-22 17:26 UTC (permalink / raw)
  To: Dan Malek; +Cc: linuxppc-embedded
In-Reply-To: <20d4aca8d8032c5762deb047185d2c6e@embeddededge.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Dan Malek wrote:
|
| On Aug 22, 2005, at 10:35 AM, Stephen Williams wrote:
|
|> In an embedded system, I want a big chunk of virtual memory in the
|> user process to be uncached.
|
|
| Why?  What processor it this?  Who else touches this memory?

PPC405GPr. The only things touching the memory are a PCI compressor
chip that is writing the buffer, a user mode thread that is putting
some image headers around it, and another device that reads it out.
I believe that if the memory is mapped uncached in the user mode
process then I'm safe.


|> .... I've created a virtual device driver that
|> has this mmap method:
|
|
| Even if this did what you thought it should, I'm not sure you
| would be happy with the results.  The challenge is ensuring
| anyone that touches these physical pages also does so
| uncached.  Depending upon the processor, this isn't something
| that is trivial to change in the kernel, since we always map
| all of memory as efficiently as possible with a cached mapping.
| The caching of memory has many desirable performance
| side effects, making the trade off the manage coherency in
| software if needed an overall system gain.

The processor is touching this memory only very briefly to put
image headers around the data, and even at that it would need
to be immediately flushed again so that it can be DMAed off the
system.

My problem is that I need a lot of memory that is mostly accessed
by high performance devices that make lots of data, and only
very occasionally accessed by the processor for minor fixups.
Caching is very much getting in my way here in this specialized
case, I think.

- --
Steve Williams                "The woods are lovely, dark and deep.
steve at icarus.com           But I have promises to keep,
http://www.icarus.com         and lines to code before I sleep,
http://www.picturel.com       And lines to code before I sleep."
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFDCgq4rPt1Sc2b3ikRApqMAJ9IuHhK6mi92ysju18xyQJsKNG4qQCff9aV
4sTZ0uRyuPmNW+FQYJYfS10=
=z2iH
-----END PGP SIGNATURE-----

^ permalink raw reply

* Re: mmap nocache on PPC, 2.4
From: Dan Malek @ 2005-08-22 17:09 UTC (permalink / raw)
  To: Stephen Williams; +Cc: linuxppc-embedded
In-Reply-To: <4309E2AC.9080404@icarus.com>


On Aug 22, 2005, at 10:35 AM, Stephen Williams wrote:

> In an embedded system, I want a big chunk of virtual memory in the
> user process to be uncached.

Why?  What processor it this?  Who else touches this memory?

> .... I've created a virtual device driver that
> has this mmap method:

Even if this did what you thought it should, I'm not sure you
would be happy with the results.  The challenge is ensuring
anyone that touches these physical pages also does so
uncached.  Depending upon the processor, this isn't something
that is trivial to change in the kernel, since we always map
all of memory as efficiently as possible with a cached mapping.
The caching of memory has many desirable performance
side effects, making the trade off the manage coherency in
software if needed an overall system gain.

Thanks.

	-- Dan

^ permalink raw reply

* Re: [PATCH 3/3] Move all the very similar files
From: Olof Johansson @ 2005-08-22 15:01 UTC (permalink / raw)
  To: Kumar Gala; +Cc: Olof Johansson, Stephen Rothwell, linuxppc-dev list, ppc64-dev
In-Reply-To: <0F51EC83-8969-4083-B0D7-9343D075B635@freescale.com>

On Mon, Aug 22, 2005 at 09:20:10AM -0500, Kumar Gala wrote:

> >Since the need is considered big enough to create  a hierarchy for
> >the code under arch/powerpc/, wouldn't something corresponding be a
> >good idea for the include files? Or do we want to clutter them with
> >all platform-specific files in one directory?
> 
> I'm in agreement, but am wondering how many of the pmac specific  
> headers could end up in arch/powerpc/platforms/pmac in the future.

Yeah, not sure -- I was thinking the same while I wrote that reply. There
are some pSeries and iSeries files that could maybe be moved there too.


-Olof

^ permalink raw reply

* mmap nocache on PPC, 2.4
From: Stephen Williams @ 2005-08-22 14:35 UTC (permalink / raw)
  To: linuxppc-embedded

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


In an embedded system, I want a big chunk of virtual memory in the
user process to be uncached. I've created a virtual device driver that
has this mmap method:

static int heap_mmap(struct file*filp, struct vm_area_struct*vma)
{
	/* Mark this whole region uncached. The setup of this
	   additional flag, and the VM_RESERVED, are the whole point
	   of this module. This hopefully will cause all pages mapped
	   into this vma to be uncached. */
~      pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
~      vma->vm_flags |= VM_RESERVED;

~      vma->vm_ops = &heap_vm_ops;
~      heap_vm_open(vma);
~      return 0;
}

I then allocate in the nopage from get_free_page as usual. My
question is, "Is this doing what I think it is doing?"

- --
Steve Williams                "The woods are lovely, dark and deep.
steve at icarus.com           But I have promises to keep,
http://www.icarus.com         and lines to code before I sleep,
http://www.picturel.com       And lines to code before I sleep."
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFDCeKrrPt1Sc2b3ikRAlsVAKDD6+O4ihBYkHreyqkNcQuuvKIK8wCg4b6v
jRBU8FJrOyczJJdPkicf22s=
=zMkX
-----END PGP SIGNATURE-----

^ permalink raw reply

* Re: [PATCH 3/3] Move all the very similar files
From: Kumar Gala @ 2005-08-22 14:20 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev list, Stephen Rothwell, ppc64-dev
In-Reply-To: <20050822141235.GA7110@austin.ibm.com>


On Aug 22, 2005, at 9:12 AM, Olof Johansson wrote:

> On Mon, Aug 22, 2005 at 04:10:30PM +1000, Stephen Rothwell wrote:
>
>> This moves all the very similar files - either the ppc64 file  
>> included
>> the ppc file or they differed in simple comments.
>>
>
> [...]
>
>>  include/asm-powerpc/pmac_feature.h |  379
>>
> ++++++++++++++++++++++++++++++++++++
>
>>  include/asm-powerpc/pmac_low_i2c.h |   43 ++++
>>
>
> Since the need is considered big enough to create  a hierarchy for
> the code under arch/powerpc/, wouldn't something corresponding be a
> good idea for the include files? Or do we want to clutter them with
> all platform-specific files in one directory?

I'm in agreement, but am wondering how many of the pmac specific  
headers could end up in arch/powerpc/platforms/pmac in the future.

- kumar

^ permalink raw reply

* AW: MPC5200 mmap, ioremap
From: Achim Machura @ 2005-08-22 14:12 UTC (permalink / raw)
  To: 'Kunkel, Ulrich'; +Cc: Linuxppc-Embedded (E-Mail)
In-Reply-To: <D3524C0FFDC6A54F9D7B6BBEECD341D505618A78@hbmntx0.da.hbm.com>

Hello Ulrich,

> mem =12 M
i think it means the kernel knows about 12 MB

This code below works fine at our board, but we use only a few kb in the
protected ram.
I don't Know whats happen if size is bigger as one page.

int asi_common_mmap(struct file *filp, struct vm_area_struct *vma)
{
//	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
	unsigned long physical = ASI_IOMEM_BASE;
	unsigned long vsize = vma->vm_end - vma->vm_start;
//	unsigned long psize = ASI_IOMEM_SIZE - off;

//	rt_printk("start : 0x%08lX\n", vma->vm_start);
//	rt_printk("end   : 0x%08lX\n", vma->vm_end);
//	rt_printk("offset: 0x%08lX\n", off);
//	rt_printk("phys  : 0x%08lX\n", physical);
//	rt_printk("vsize : 0x%08lX\n", vsize);
//	rt_printk("psize : 0x%08lX\n", psize);

	if (filp->f_flags & O_SYNC)
	{
//		rt_printk("I/O-Mem");
		vma->vm_flags |= VM_IO;
	}
	vma->vm_flags |= VM_RESERVED;
	//if (vsize > psize) return -EINVAL; /* spans too high */
	if(remap_page_range(vma->vm_start, physical, vsize, vma->vm_page_prot))
	{
		return -EAGAIN;
	}
	return(0);
}

Achim

^ permalink raw reply

* Re: How NEC uPD720101 USB chip work well on linux2.6.12
From: Stefan Nickl @ 2005-08-22 13:54 UTC (permalink / raw)
  To: JohnsonCheng; +Cc: linuxppc-embedded
In-Reply-To: <20050822122645.7AE6867FBD@ozlabs.org>

On Fri, 2005-07-22 at 20:26 +0800, JohnsonCheng wrote:
> Dear All,
> =20
>=20
> I use NEC uPD720101 USB chip, 2 OHCI and 1 EHCI, I also have turn on
> the following options in kernel menuconfig:
[...]
> [*] USB Support / EHCI HCD (USB 2.0) support
[...]
> =20
>=20
> But when I plug-in a USB mouse, then Kernel Oops=85.
>=20
> I use MPC8241 CPU, and there are three USB ports sharing the same IRQ
> on my borad.

I recently came across similar trouble with a chip from this series, the
uPD720113 and another one in a off-the-shelf USB hub which I tried for
reference.
It may have been even the 101, but I'm not sure.

Anyways, I've also seen hard resets with 2.6.12 to 2.6.13-rc-something,
albeit in a x86-environment. The system would reset hard when plugging
something after the hub or the hub itself, in case of the 113 it crashed
100% as soon as the hub was attached or detected during bootup. With the
off-the-shelf hub, it was somewhat more random.

In my case, disabling the EHCI controller in the BIOS helped, so you may
try to disable the USB "2.0" support in the kernel config and see what
happens.
No problems running the system with only UHCI for some weeks now.

I've deferred this problem because Hi-Speed is not an issue to me now,
but I'd be curious to hear and test things if somebody had a take on
this.

Regards,

--=20
Stefan Nickl
Kontron Modular Computers

^ permalink raw reply

* Re: [RFC] MPC5200 BestComm microcode [en]/[de]coding draft
From: Wolfgang Denk @ 2005-08-22 13:48 UTC (permalink / raw)
  To: Sylvain Munaut; +Cc: linuxppc-embedded
In-Reply-To: <4309D3CF.4030201@246tNt.com>

In message <4309D3CF.4030201@246tNt.com> you wrote:
> 
> But I'm not sure including that into the Documentation/ directory is
> such a good idea. Changing documentation that's there requires sending
> patch to Linus and get it processed etc ... And since It's mostly
> reverse engineering, it's probably going to change often as we get a
> better understanding.

Documentation/  is  the  first  place  to  look  for   Linux   kernel
documentation, so it seems the best place for such stuff to me.

> We could publish it as a Wiki (that's a tendency these days ;) so that
> everyone can contribute easily and post code examples etc ... What do
> you think ?

This is a good idea for collecting  the  information,  but  IMHO  the
document itself should go (too) to Documentation/

Just my $ 0.02

Best regards,

Wolfgang Denk

-- 
Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Programmer's Lament: (Shakespeare, Macbeth, Act I, Scene vii)
        "That we but teach bloody instructions,
        which, being taught, return to plague the inventor..."

^ permalink raw reply

* Re: [00/02] MPC5200 Bestcomm platform driver
From: Sylvain Munaut @ 2005-08-22 13:41 UTC (permalink / raw)
  To: Andrey Volkov; +Cc: linuxppc-embedded
In-Reply-To: <4300AF41.9000807@varma-el.com>

Andrey Volkov wrote:

>> - I never really liked to have multiple "type" of buffer descriptors
>>depending of the number of pointers in them. "standard" task have
>>either 1 or 2 pointers true but I have custom tasks with 3 so I need a
>>subtmitbuffer3 ... Not very extensible imho. I think there is no problem
>>as defining the descriptor structure with an array of pointer and then
>>just allocate the good size at init. Whoever use them must anyway know
>>the number of pointer to fill.
> 
> Accepted. But I think it will be better to start from another end:
> allow everyone to create him/here self task (variable buffers number
> will consequence of that).

Sure, see my comments about your bestcomm microcode doc in my preceing mail.


>> - When I started to clean up bescomm a while ago, the only thing I
>>really got done was a rewrite of the SRAM allocator that supports the
>>freeing of block at little overcost. I'll try to find it and send it to you.
> 
> I agree with you, sram_free is required function, especially if
> sdma-depended drivers will loaded/unloaded as modules. But I also agree
> with Dale's comments: What to do with fragmentations? I could lightly
> imagine situation, when after some load/unload iterations we receive
> ENOMEM :(.

Sure, fragmentation is a problem but there is no 'easy' way to prevent
that ... It's not perfet but better than nothing IMHO.


>> - I like the separation of phys/virt ;)
> 
> I'd like it too :), but I had a pa/va headache when setting up
> task/var/inc tables, so everyone, who will write sdma related code must
> be very careful.

Anyway, they must be careful ;)
Bestcomm is like a very fragile balance between numerous task competing
for some dma transfers. Without caution, one will starve the others ...




	Sylvain

^ permalink raw reply

* Re: [RFC] MPC5200 BestComm microcode [en]/[de]coding draft
From: Sylvain Munaut @ 2005-08-22 13:31 UTC (permalink / raw)
  To: Andrey Volkov; +Cc: linuxppc-embedded
In-Reply-To: <4304CE06.6080202@varma-el.com>

Hi Andrey,


Andrey Volkov wrote:
> Hello Sylvain,
> 
> This a draft of Documentation/powerpc/bestcomm.txt,
> it was born since I couldn't find DRD/LCD description and
> "... graphical task builder are currently in development"
> (quotation from AN2604) :(, so I try write doco by myself.
> Here result of my reverse engineering.
> 
> If you or somebody have more information or found some
> bugs, please, fix/expand my text, especially places marked by "?".

First, yes, it's definitly a good idea to work on some documentation on
how to write microcode.

But I'm not sure including that into the Documentation/ directory is
such a good idea. Changing documentation that's there requires sending
patch to Linus and get it processed etc ... And since It's mostly
reverse engineering, it's probably going to change often as we get a
better understanding.

We could publish it as a Wiki (that's a tendency these days ;) so that
everyone can contribute easily and post code examples etc ... What do
you think ?


See comments below for the "real" comments ;)


> +All instructions of Bestcomm microcode are divided on 
> +two main types: LCD (Loop Control Descriptor) and 
> +DRD (Data Routing Descriptor). Any Task must started from 
> +LCD[EX] instruction and finished by DRD instruction (usually NOP).
> +Each of instruction types, in one's turn, are divided on two 
> +and three subtypes accordingly, which are described below:
> +
> +1) DRD1A - load/store data, and, optionally, made some operation 
> +on it (depend on what loaded to FDT). Here is fields description
> +of this DRD:
> +
> +Bits num.  Name          Desc.
> +[31:29]    		Reserved, must be 0 

Well yes, the 3 first bits indicate what type of descriptor it is ;-

> +[28:28]    MORE		?????, if set then idx/var
> +			dst/src fields are changed. I.e. 
> +			[16:10] contain SOURCE, 
> +			and [09:03] contain DESTINATION.

What I got for this bit is that if it's set that means the next DRD is
in the same LCD context, if not, it goes one LCD context before (like a
closing brace for a for loop } ).

> +[27:27]	   TFD		Transfer Frame Done. Assert frame 
> +			done Transfer Frame Done line of 
> +			selected (in INIT field) periphery.
> +[26:26]	   INT 		Interrupt. If set to 1, 
> +			then generate core interrupt

Generate the core interrupt when the bestcomm engine exits the current
LCD. Don't know why it's part of the DRD descriptors and from what a
Freescale engineer told me, he doesn't know either ;)


> +[25:21]	   INIT		Initiator (aka requestor) number.
> +[20:19]	   RS		Read Size (0 - 32bit word, 1 - byte,
> +			2 - 16 bit word, 3 - dynamic/reserved??
> +			(masked in real	time?))

IIRC, there is a field in the SDMA registers to specify what 3 means.
However, the bestcomm api replace all the 3 with the correct size in the
ucode itself. That functionnality may not work or just isn't practical.
Best to have the correct size specified when running the task anyway.

> +[18:17]	   WS		Write Size (see above)
> +[16:16]			??????????????
> +[15:15]	   		Destination index prefix, 
> +			if set (i.e. =1), then bitfield [13:10]
> +			contain index number, and [14:14] have 
> +			meaning of indirect addressing flag.
> +			If this field cleared then field 
> +			[14:10] contain	index of VARIABLE.
> +[14:14]			Indirect addressing by idx, 
> +			(and only by idx) flag, or high bit of
> +			variable index.
> +[13:10]			index of DESTINATION/SOURCE idx/var.
> +
> +[09:09]			???? For some cases 1, for another 0.????
> +
> +[08:08]			Same as in [14:10], but for source.
> +[07:03]			Same as in [14:10], but for source.
> +[02:00]	   EU3		Number of function, which will execute
> +			on EU#3.

[2:0] is FN but what do you exactly mean it is. The only thing I notice
is that if it =1 then the source is "EU3()" ... whatever that means.

Also, I'm not sure it has something to do with the FDT since there is
only 3 bits.


> +Note: For DRD1A exist special case, aka NOP, which act as 
> +task terminator. Fields, in this case, have next meanings:
> +
> +[31:28]			Reserved must be 0.
> +[27:27]	  TFD		Transfer Frame Done. 
> +[26:26]	  INT 		Interrupt.
> +[25:21]	  INIT		Initiator (aka requestor) number. Usually 0,
> +			or ALWAYS INITIATOR.
> +[16:00]	  NOP code	Must be 0x1f8 

Where did you see that that you could use theses bit in NOP ?


> +Ex. Please, pay attention to first two lines: since MORE is set,
> +codes for idx2 and var13 are in different fields, then for case
> +where MORE is not set (var4 = var2).:
> + 0x10601010 -- DRD1A: var4 = var2; FN=0 MORE init=3 WS=0 RS=0
> + 0x00008868 -- DRD1A: idx2 = var13; FN=0 init=0 WS=0 RS=0
> + 0x0404c999 -- DRD1A: *idx2 = EU3(); FN=1 INT init=0 WS=2 RS=0
> + 0x000001f8 -- DRD1A: NOP
> + 0x040001f8 -- DRD1A: INT init=0
> +
> +Next two DRDs are ALWAYS coupled, i.e it is impossible to using 
> +DRD2B1 without preceded DRD2A, but any (?fixme?) number DRD2B1 
> +may followed by DRD2A.

? AFAIU it's either
DRD2A, DRD2B1
or
DRD2A, DRDF2B2

> +2) DRD2A - setup bestcomm Execution Unit (EU)
> +Bitfields encodings:
> +
> +Bits num.  Name          Desc
> +[31:31]    MORE		?????????
> +[30:29]    EXT		must be always initialized 
> +			by 3 (binary 11)

What I have is that
[31:29] Always 011 - Indicates a DRD2A.
[28:28] MORE -  Same meaning as before. Just tells if the following
(here that's the one that is after the corresponding DRD2B{1,2}) DRD is
in the same loop or if it's in the previous loop level ?


> +[27:27]	   TFD		Transfer Frame Done.
> +[26:21]	   INIT		Initiator number.
> +[20:19]	   RS		Read Size 
> +[18:17]	   WS		Write Size
> +[16:04]			reserved, must be 0

They are the function number to use in EU#{0,1,2} but in MPC5200, only
EU3 is implemented.

> +[03:00]	   EU3		Number of function, which will execute
> +			on EU#3 at DRD2B1 time.
> +Ex:
> + 0x60140002 -- DRD2A: EU3=2 EXT init=0 WS=2 RS=2
> +
> +3) DRD2B1 - execute function and store result of it. 

Can't find the piece if paper where I wrote about DRD2B1 ...
For DRD2B2 there is only 1 example I know of, so quite hard to deduce
anything.

> +4) LCD - run followed loop microcode, or may be used for checking
> +some conditions. LCD may be nested (only two levels are supported).

Two levels ? Didn't know that but sure there is no example with 3 levels.

> +
> +Bits num.  Name          Desc
> +[31:31]	   LOOP		Loop prefix, always 1
> +[30:30]			???????????????????
> +[29:23]	   INIT1	???Initializition part of first init expression.???
> +[22:11]			???????????????????
> +[10:06]	   CMP_VAR	Variable to which idx compared. Part of
> +			Termination control.
> +[05:03]	   INC1		increment1 
> +[02:00]	   INC2		increment2, if unsused may be any value 

What I got :

bits[31:30] : 10 - identify a LCD
bit [29   ] : d  - Whether to dereferentiate init_a or not. idx_a =
deref ? *(init_a) : init_a
bits[28:27] : ta - Type of init_a : 00 -> var
                                    11 -> idx
bits[26:23] : ia - init_a : Where to find initial value for idx_a
bits[22:21] : ?? - Unknow
bits[20:19] : tb - Type of init_b
bits[18:15] : ib - init_b
bits[14:13] : cc - condition_choice : 00 - use idx_a
                                      01 - use idx_b
                                      11 - no condition
bits[12:11] : ?? - Unknow always 00
bits[10: 6] : ca - condition_arg : What to do the comparaison against
bits[ 5: 3] : sa - step_a : What inc[] to use to increment idx_a (and
also where to look for the condition code)
bits[ 2: 0] : sb - step_b


Condition codes (first 4 bits of the increments)
>=   c
>    4
once 0
!=   6
<=   a
<    2



> +5) LCDEXT - If in yours loop used more then 2 indexes, then 
> +this record MUST PRECEDED LCD. Also loop end condition MAY pointed HERE,
> +then it not pointed in LCD. 
> +
> +Bits num.  Name          Desc
> +[31:31]	   LOOP		Loop prefix, always 1
> +[30:30]			???????????????????
> +[29:23]	   INIT1	???Initializition part of first init expression.???
> +[22:11]			???????????????????
> +[10:06]	   CMP_VAR	Variable to which idx compared. Part of
> +			Termination control.
> +[05:03]	   INC1		increment1 
> +[02:00]	   INC2		increment2, if unsused may be any value 

similar to LCD


	Sylvain

^ permalink raw reply

* Re: Linux Kernel MTD question
From: Wolfgang Denk @ 2005-08-22 13:07 UTC (permalink / raw)
  To: JohnsonCheng; +Cc: linuxppc-embedded
In-Reply-To: <20050822104924.214ED429CB@denx.de>

In message <20050822104924.214ED429CB@denx.de> you wrote:
> 
> How can I put the Environment variables or configurations in
> 0x00060000-0x00080000, or put User Data in 0x005C0000-0x1000000?
> Use U-boot command? Or....

It is up to you to define a memory map for your flash  device(s)  and
create  appropriate partitions for this map in Linux (and probably in
U-Boot, too, using the new "mtdparts" command).

Then you can use standard commands in U-Boot (erase, cp) and in Linux
(erase_all, cp) to store any data you likein your flash.

It is *your* design. *You* must create it.

Best regards,

Wolfgang Denk

-- 
Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
The IQ of the group is the lowest IQ of a member of the group divided
by the number of people in the group.

^ permalink raw reply

* Re: [PATCH] ppc32: Big-endian I/O memory accessors.
From: Arthur Othieno @ 2005-08-22 12:51 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1124659361.5197.121.camel@gaston>

On Mon, Aug 22, 2005 at 07:22:41AM +1000, Benjamin Herrenschmidt wrote:
> On Sat, 2005-08-20 at 21:16 -0400, Arthur Othieno wrote:
> > I/O memory accessors. Big-endian version. For those busses/devices
> > that do export big-endian I/O memory.
> 
> No, that's not correct. You need to use the in_be/out_be variants which
> provide proper memory barriers.
> 
> Ben.

Oops. Silly me. Updated patch inline.

Signed-Off-By: Arthur Othieno <a.othieno@bluewin.ch>


 io.h |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+)
 
diff -uprN a/include/asm-ppc/io.h b/include/asm-ppc/io.h
--- a/include/asm-ppc/io.h	2005-08-21 17:49:44.000000000 -0400
+++ b/include/asm-ppc/io.h	2005-08-21 20:29:55.000000000 -0400
@@ -487,11 +487,21 @@ static inline unsigned int ioread16(void
 	return readw(addr);
 }
 
+static inline unsigned int ioread16be(void __iomem *addr)
+{
+	return in_be16(addr);
+}
+
 static inline unsigned int ioread32(void __iomem *addr)
 {
 	return readl(addr);
 }
 
+static inline unsigned int ioread32be(void __iomem *addr)
+{
+	return in_be32(addr);
+}
+
 static inline void iowrite8(u8 val, void __iomem *addr)
 {
 	writeb(val, addr);
@@ -502,11 +512,21 @@ static inline void iowrite16(u16 val, vo
 	writew(val, addr);
 }
 
+static inline void iowrite16be(u16 val, void __iomem *addr)
+{
+	out_be16(addr, val);
+}
+
 static inline void iowrite32(u32 val, void __iomem *addr)
 {
 	writel(val, addr);
 }
 
+static inline void iowrite32be(u32 val, void __iomem *addr)
+{
+	out_be32(addr, val);
+}
+
 static inline void ioread8_rep(void __iomem *addr, void *dst, unsigned long count)
 {
 	_insb(addr, dst, count);

^ permalink raw reply

* How NEC uPD720101 USB chip work well on linux2.6.12
From: JohnsonCheng @ 2005-08-22 12:27 UTC (permalink / raw)
  To: linuxppc-embedded

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

Dear All,

 

I use NEC uPD720101 USB chip, 2 OHCI and 1 EHCI, I also have turn on the
following options in kernel menuconfig:

[*] USB Support / support for Host-side USB

[*] USB Support / USB device filesystem

[*] USB Support / EHCI HCD (USB 2.0) support

[*] USB Support / OHCI HCD support

[*] USB Support / USB HID Boot Protocol drivers / USB HIDBP Mouse (simple
Boot) support

 

But when I plug-in a USB mouse, then Kernel Oops..

I use MPC8241 CPU, and there are three USB ports sharing the same IRQ on my
borad.

 

Thanks,

Johnson Cheng


[-- Attachment #2: Type: text/html, Size: 3937 bytes --]

^ permalink raw reply

* RE: Linux Kernel MTD question
From: JohnsonCheng @ 2005-08-22 10:46 UTC (permalink / raw)
  To: 'Wolfgang Denk'; +Cc: linuxppc-embedded
In-Reply-To: <20050822081708.74890352B0C@atlas.denx.de>

I have browsed the website, http://www.denx.de/twiki/bin/view/DULG/Manual.
For this example:
0x00000000-0x00060000 : "U-Boot"
0x00060000-0x00080000 : "Environment 1"
0x00080000-0x000A0000 : "Environment 2"
0x000A0000-0x000C0000 : "ASIC Images"
0x000C0000-0x001C0000 : "Linux Kernel"
0x001C0000-0x005C0000 : "Ramdisk Image"
0x005C0000-0x01000000 : "User Data"

How can I put the Environment variables or configurations in
0x00060000-0x00080000, or put User Data in 0x005C0000-0x1000000?
Use U-boot command? Or....

Best Regards,
Johnson Cheng


-----Original Message-----
From: linuxppc-embedded-bounces@ozlabs.org
[mailto:linuxppc-embedded-bounces@ozlabs.org] On Behalf Of Wolfgang Denk
Sent: Monday, August 22, 2005 4:17 PM
To: JohnsonCheng
Cc: linuxppc-embedded@ozlabs.org
Subject: Re: Linux Kernel MTD question 

In message <20050822030032.4917442C7E@denx.de> you wrote:
>
> Actually, the range of my flash is from 0xFF000000 to 0xFFFFFFFF. My
> starting address of Kernel is 0xFF000000, and the starting address of
> ramdisk image is FF200000, so the partitions is as following:
> 0xFF000000 - 0xFF1FFFFF		Kernel
> 0xFF200000 - 0xFF9FFFFF		RamDisk Image ( also my Root File
System )
> 
> And I found my RootFS image is so big that waste many time while write it
to
> flash.

Then avoid writing it that often. Use  a  more  efficient  setup  for
developoment and test, like root file system mounted over NFS.

> I hope I can use MTD to distribute it into two parts, Simple RootFS and
> libraries, but I don't know how to implement it?

You can use MTD to provide an additional file system which  can  then
be mounted by one of your startup scripts. MTD configuration and file
system building is documented in the DULG, please see
http://www.denx.de/twiki/bin/view/DULG/Manual

It is not possible to  give  good  advice  how  to  split  data  into
separate  file  systems,  or  how  exactly  you  can mount it without
precise knowledge of your system and it's requirements. For  example,
do you use a SysV init with several run levels, or a simple setup for
example based on busybox? In the end this is something which you have
to design yourself.

Best regards,

Wolfgang Denk

-- 
Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Let the programmers be many and the managers few -- then all will  be
productive.               -- Geoffrey James, "The Tao of Programming"
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

^ permalink raw reply

* mpc8247 restart
From: Mike Rapoport @ 2005-08-22 10:54 UTC (permalink / raw)
  To: 'linuxppc-embedded@ozlabs.org'

Hi all,

I have a custom board based on mpc8247. I use u-boot-1.1.3 and linux 
2.6.12.3. Each time there is some critical exception and the kernel 
tries to reset the machine, I get machine check exception instead of 
jumping to the u-boot code. What can be a reason of this?

The u-boot is in flash at offset 0x300000 from the flash start, the 
flash is mapped to 0xff800000 and I set the BOOTROM_RESTART_ADDR to 
0xffb00110.

-- 
Sincerely yours,
Mike Rapoport

^ permalink raw reply

* Víagrra Really Works Wonder
From: wfctwcw_98_bp5ucz @ 2005-08-22  9:05 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/html, Size: 2086 bytes --]

^ permalink raw reply

* MPC5200 mmap, ioremap
From: Kunkel, Ulrich @ 2005-08-22  8:47 UTC (permalink / raw)
  To: 'linuxppc-embedded@ozlabs.org'

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

Hello,

  

I am using a Motorola PPC Hardware (MPC5200) with linux kernel 2.4.25 and 32
MB RAM.

 

I  would like to map a large contiguous kernel memory buffer (6 MB) into
user space with mmap and remap_page_range. For this action I reserved memory
at the end of the phyiscal memory at boot time. (Kernel boot option mem =12
M) Now, the kernel only knows about 20 MB of memory. The high_memory border
is at 0x1400000 (physical address).

I have to do a ioremap() on the high_memory (0x1400000) to map the high
physical memory into a virtual kernel memory.

 

ioremap_ptr = ioremap_nocache (__pa(high_memory), 6*1024*1024);  //6 MB

 

ioremap_ptr is a virtual kernel address.

 

Now I do a mem_map_reserve () on every page in this memory block.

 

On the ioremap ptr I do a memset to check the data in user space later.

 

memset(ioremap_ptr, 0xAB, 6*1024*1024);

 

With bdi2000 I looked to the memory values at 0x1400000 and everything is
ok, I see 0xABABABAB.

 

If I do a virt_to_phys() on ioremap_ptr, I get a really strange address. I
expected to get the physical address 0x1400000.

 

Example:

 

__pa(high_memory): 0x1400000

ioremap_ptr: 0xc22a4000

virt_to_phys(ioremap_ptr): 0x22a4000

virt_to_bus(ioremap_ptr): 0x22a4000

 

 

Now I want to map the buffer into to user space with mmap and
remap_page_range.

 

 

static int mmmap (struct file *file, struct vm_area_struct *vma)

{

      unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;

      int error;

      unsigned long start = (unsigned long)vma->vm_start;

      unsigned long size = (unsigned long)(vma->vm_end - vma->vm_start);

 

 

 

      if (offset != 0)

      {

        printk ("rt_iso1394_mmap: invalid offset: must be 0\n");

        return -ENXIO;

      }

      

 

if(size == PAGE_ALIGN(6*1024*1024)

{

  start,virt_to_phys(shared_buffer_ptr), size, protect);

  error = remap_page_range (vma->vm_start, 0x1400000 , size, PAGE_SHARED);

          

  if (error)

   {

     printk ("rt_iso1394_mmap: remap_page_range failed\n");

     return -EAGAIN;

   }

 }

 

 else

 {

 

  printk ("rt_iso1394_mmap: invalid mmap size, size is: %d\n", (int) size);

  return -EAGAIN;

  }

 

 

      return 0;

}

 

 

The function returned with no errors. 

 

If I call mmap () in user space, the function returnes a virtual user
address. But if do a read on this memory, I don't see the data I have
written in the kernel data block in kernel space. I only get zeros. It seems
that remap_page_range maps a completely different data block.

 

Are the any ideas to solve the problem? What I am doing wrong? What is
missing? Where ist the problem with the addresses???

 

Thanks for your help 

 

 

 

Ulrich Kunkel

Hottinger Baldwin Messtechnik GmbH



[-- Attachment #2: Type: text/html, Size: 13418 bytes --]

^ permalink raw reply


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