LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PPC,SOUND] Fix audio gpio state detection
From: Benjamin Herrenschmidt @ 2006-02-12 23:27 UTC (permalink / raw)
  To: Ben Collins; +Cc: alsa-devel, Ben Collins, linuxppc-dev
In-Reply-To: <1139784411.25288.11.camel@grayson>

On Sun, 2006-02-12 at 17:46 -0500, Ben Collins wrote:
> On Mon, 2006-02-13 at 09:35 +1100, Benjamin Herrenschmidt wrote:
> > Can you sync with the patches Ben Collins is doing on this as well ?
> > 
> > Ben, what is your status ? Are you feeding those through upstream the
> > alsa folks ? Or waiting for me to do something ? :)
> > 
> > The above, if it appear to works well enough might be worth merging
> > now ...
> 
> I haven't synced because I've been waiting for some kind of go ahead
> from you. I can rediff against 2.6.16-git and send them to alsa, CC ppc
> list.

Please, do so !

Thanks,
Ben.

^ permalink raw reply

* All children killed in /sbin/init
From: Tore Martin Hagen @ 2006-02-13  7:33 UTC (permalink / raw)
  To: linuxppc-embedded

Hi,

I have a custom board with MPC8275 and NFS root file system. I use 
u-boot to load the kernel and it boots up, mounts the file system and 
starts /sbin/init. Then all the children of init dies, I get the 
following errors (with Debugging enabled in /sbin/init)

Sending DHCP requests ., 
OK                                                                              

IP-Config: Got DHCP answer from 10.0.0.1, my address is 
10.0.0.111                                      
IP-Config: 
Complete:                                                                                     

      device=eth0, addr=10.0.0.111, mask=255.255.255.0, 
gw=10.0.0.1,                                    
     host=10.0.0.111, domain=, 
nis-domain=(none),                                                       
     bootserver=10.0.0.1, rootserver=10.0.0.1, 
rootpath=/local/Mpc8266ads/Box2/root                     
NET4: Unix domain sockets 1.0/SMP for Linux 
NET4.0.                                                     
Looking up port of RPC 100003/2 on 
10.0.0.1                                                             
Looking up port of RPC 100005/1 on 
10.0.0.1                                                             
VFS: Mounted root (nfs 
filesystem).                                                                      

Mounted devfs on 
/dev                                                                                    

Freeing unused kernel memory: 96k 
init                                                                   
                                                               
INIT: version 2.78 booting
INIT: Reading 
inittab                                                                                    

INIT: Checking for children to 
kill                                                                     
INIT: Checking for children to 
start                                                                    
INIT: Started id si (pid 
11)                                                                             

INIT: init_main: 
waiting..                                                                               

INIT: chld_handler: marked 11 as 
zombie                                                                 
INIT: got 
SIGCHLD                                                                                        

INIT: Child died, PID= 
11                                                                                

INIT: Checking for children to 
start                                                                    
INIT: SYSINIT -> 
BOOT                                                                                    

INIT: init_main: 
waiting..                                                                               

INIT: Checking for children to 
start                                                                    
INIT: BOOT -> 
NORMAL                                                                                     

INIT: Entering runlevel: 
3                                                                               

INIT: init_main: 
waiting..                                                                               

INIT: Checking for children to 
start                                                                    
INIT: Started id tmh (pid 
14)                                                                            

INIT: init_main: 
waiting..                                                                               

INIT: chld_handler: marked 14 as 
zombie                                                                 
INIT: got 
SIGCHLD                                                                                        

INIT: Child died, PID= 14
.....

The file system works fine on my MPC8266ADS board.

Do I have a problem with the mounting of the file system, or is there 
something wrong with my MMU?

The kernel is compiled with     CONFIG_PPC_STD_MMU=y

Any suggestions about where i should start digging would be appreciated.

/Tore Martin Hagen
                                                                     

^ permalink raw reply

* Re: Stability of MPC5200 FEC
From: Asier Llano Palacios @ 2006-02-13  8:08 UTC (permalink / raw)
  To: Sylvain Munaut; +Cc: John Rigby, linuxppc-embedded
In-Reply-To: <43EE029A.5040504@246tNt.com>

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

El sáb, 11-02-2006 a las 16:28 +0100, Sylvain Munaut escribió:
> Asier Llano Palacios wrote:
> Did you ever observe that behavior on a lite5200 ?
> What is 'long uptime' and do you have sustained transfer during that
> period ? (To try reproduice the problem).

Weeks uptime. We don't work with the lite5200 for so long time, but our
board is based on a lite5200, and the FEC configuration is exactly
equal.

> Also, what are the 'symptoms' ? (anything in dmesg ?)

FEC doesn't work at all, everything else works. If using a console I
execute 'ifconfig eth0 down && ifconfig eth0 up <IP>' the fec starts
working again.
I haven't reproduced it directly, but a partner and a customer. I'll try
to reproduce this behaviour myself and bring back more information.

> I haven't touched the FEC code much except to remove the
> aligment code (newer bestcomm microcode doesn't require alignement of
> the skb). 
> 
> You can send me the driver/net/fec_mpc52xx and arch/ppc/syslib/bestcomm
> you're using, I'll tell you if there was major changes.

I've sent to you the patches that I extracted from your kernel source
tree some time ago.
I have all the patches until the 1.2161 one. But I've only sent to you
the ones related to the FEC and the bestcomm.


-- 
Asier Llano Palacios
ZIV I+D Smart Energy Networks
Dpto. Ingeniería de Desarrollo.

ZIV, Aplicaciones y Tecnología.
Parque Tecnológico, 210
48170 ZAMUDIO (Bizkaia)

E-mail: a.llano@ziv.es
Tlfno: 944037400 
 
----------------------------------------- PLEASE NOTE -------------------------------------------
This message, along with any attachments, may be confidential or legally privileged. 
It is intended only for the named person(s), who is/are the only authorized recipients.
If this message has reached you in error, kindly destroy it without review and notify the sender immediately.
Thank you for your help.
µSysCom uses virus scanning software but excludes any liability for viruses contained in any attachment.
 
------------------------------------ ROGAMOS LEA ESTE TEXTO -------------------------------
Este mensaje y sus anexos pueden contener información confidencial y/o con derecho legal. 
Está dirigido únicamente a la/s persona/s o entidad/es reseñadas como único destinatario autorizado.
Si este mensaje le hubiera llegado por error, por favor elimínelo sin revisarlo ni reenviarlo y notifíquelo inmediatamente al remitente. Gracias por su colaboración.  
µSysCom utiliza software antivirus, pero no se hace responsable de los virus contenidos en los ficheros anexos.

[-- Attachment #2: 1.2156-bestcomm-api-mpc52xx.patch --]
[-- Type: text/x-patch, Size: 30882 bytes --]

diff -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig
--- a/arch/ppc/Kconfig	2004-11-19 12:41:34 +01:00
+++ b/arch/ppc/Kconfig	2004-11-20 23:21:00 +01:00
@@ -623,6 +623,10 @@
 config PPC_MPC52xx
 	bool
 
+config PPC_BESTCOMM
+	bool
+	depends on PPC_MPC52xx
+
 config 8260
 	bool "CPM2 Support" if WILLOW
 	depends on 6xx
diff -Nru a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
--- a/arch/ppc/syslib/Makefile	2004-11-19 12:41:34 +01:00
+++ b/arch/ppc/syslib/Makefile	2004-11-20 23:21:00 +01:00
@@ -88,3 +88,4 @@
 ifeq ($(CONFIG_PPC_MPC52xx),y)
 obj-$(CONFIG_PCI)		+= mpc52xx_pci.o
 endif
+obj-$(CONFIG_PPC_BESTCOMM)	+= bestcomm/
diff -Nru a/arch/ppc/syslib/bestcomm/Makefile b/arch/ppc/syslib/bestcomm/Makefile
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/arch/ppc/syslib/bestcomm/Makefile	2004-11-20 23:21:00 +01:00
@@ -0,0 +1,2 @@
+obj-$(CONFIG_PPC_BESTCOMM) 	+= bestcomm.o
+obj-$(CONFIG_FEC_MPC52xx)	+= sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o
diff -Nru a/arch/ppc/syslib/bestcomm/bestcomm.c b/arch/ppc/syslib/bestcomm/bestcomm.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/arch/ppc/syslib/bestcomm/bestcomm.c	2004-11-20 23:21:01 +01:00
@@ -0,0 +1,248 @@
+/*
+ * arch/ppc/syslib/bestcomm/bestcomm.c
+ *
+ * Driver for MPC52xx processor BestComm peripheral controller
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) 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/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <asm/bug.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#include <asm/mpc52xx.h>
+
+#include "bestcomm.h"
+
+static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Use a very simple SRAM allocator.
+ * There is no mechanism for freeing space.
+ * In an attempt to minimize internal fragmentation, the SRAM is
+ * divided into two areas.
+ *
+ * Area 1 is at the beginning of SRAM
+ * and is used for allocations requiring alignments of 16 bytes or less.
+ * Successive allocations return higher addresses.
+ *
+ * Area 2 is at the end of SRAM and is used for the remaining allocations.
+ * Successive allocations return lower addresses.
+ *
+ * I've considered adding routines to support the freeing of SRAM allocations,
+ * but the SRAM is so small (16K) that fragmentation can quickly cause the
+ * SRAM to be unusable.  If you can come up with a slick way to free SRAM
+ * memory without the fragmentation problem, please do so.
+ */
+
+struct sdma_tdt *sdma_tdt;
+
+static u8 *area1_end;
+static u8 *area2_begin;
+
+static void sdma_init(void);
+
+void *sdma_sram_alloc(int size, int alignment)
+{
+	u8 *a;
+
+	spin_lock(&sdma_lock);
+	if (!area1_end)
+		sdma_init();
+
+	/* alignment must be a power of 2 */
+	BUG_ON(alignment & (alignment - 1));
+
+	if (alignment < 16) {
+		a = (u8 *)(((u32)area1_end + (alignment-1)) & ~(alignment-1));
+		if (a + size <= area2_begin)
+			area1_end = a + size;
+		else
+			a = 0;				/* out of memory */
+	} else {
+		a = (u8 *)(((u32)area2_begin - size) & ~(alignment - 1));
+		if (a >= area1_end)
+			area2_begin = a;
+		else
+			a = 0;				/* out of memory */
+	}
+	spin_unlock(&sdma_lock);
+	return (void *)a;
+}
+
+/* this will need to be updated if Freescale changes their task code FDT */
+static u32 fdt_ops[] = {
+	0xa0045670,	/* FDT[48] */
+	0x80045670,	/* FDT[49] */
+	0x21800000,	/* FDT[50] */
+	0x21e00000,	/* FDT[51] */
+	0x21500000,	/* FDT[52] */
+	0x21400000,	/* FDT[53] */
+	0x21500000,	/* FDT[54] */
+	0x20400000,	/* FDT[55] */
+	0x20500000,	/* FDT[56] */
+	0x20800000,	/* FDT[57] */
+	0x20a00000,	/* FDT[58] */
+	0xc0170000,	/* FDT[59] */
+	0xc0145670,	/* FDT[60] */
+	0xc0345670,	/* FDT[61] */
+	0xa0076540,	/* FDT[62] */
+	0xa0000760,	/* FDT[63] */
+};
+
+static void sdma_init(void)
+{
+	struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA;
+	int task;
+	u32 *context;
+	u32 *var;
+	u32 *fdt;
+	struct sdma_tdt *tdt;
+
+	area1_end = (u8 *)MPC52xx_SRAM;
+	area2_begin = (u8 *)(MPC52xx_SRAM + MPC52xx_SRAM_SIZE);
+
+	memset((void *)MPC52xx_SRAM, 0, MPC52xx_SRAM_SIZE);
+
+	/* allocate space for task descriptors, contexts, and var tables */
+	sdma_tdt = sdma_sram_alloc(sizeof(*sdma_tdt) * SDMA_MAX_TASKS, 4);
+	context = sdma_sram_alloc(SDMA_CONTEXT_SIZE * SDMA_MAX_TASKS,
+							SDMA_CONTEXT_ALIGN);
+	var = sdma_sram_alloc(SDMA_VAR_SIZE * SDMA_MAX_TASKS, SDMA_VAR_ALIGN);
+	fdt = sdma_sram_alloc(SDMA_FDT_SIZE, SDMA_FDT_ALIGN);
+	memcpy(&fdt[48], fdt_ops, sizeof(fdt_ops));
+
+	out_be32(&sdma->taskBar, (u32)sdma_tdt);
+
+	tdt = sdma_tdt;
+	for (task=0; task < SDMA_MAX_TASKS; task++) {
+		out_be16(&sdma->tcr[task], 0);
+		out_8(&sdma->ipr[task], 0);
+
+		tdt->context = context;
+		tdt->var = var;
+		tdt->fdt = fdt;
+		var += SDMA_MAX_VAR + SDMA_MAX_INC;
+		context += SDMA_MAX_CONTEXT;
+		tdt++;
+	}
+
+	out_8(&sdma->ipr[SDMA_INITIATOR_ALWAYS], SDMA_IPR_ALWAYS);
+
+	/* Disable COMM Bus Prefetch, apparently it's not reliable yet */
+	out_be16(&sdma->PtdCntrl, in_be16(&sdma->PtdCntrl) | 1);
+}
+
+static int new_task_number(void)
+{
+	struct sdma_tdt *tdt;
+	int i;
+
+	spin_lock(&sdma_lock);
+
+	if (!sdma_tdt)
+		sdma_init();
+	tdt = sdma_tdt;
+
+	for (i=0; i<SDMA_MAX_TASKS; i++, tdt++)
+		if (tdt->start == 0)
+			break;
+	if (i == SDMA_MAX_TASKS)
+		i = -1;
+
+	spin_unlock(&sdma_lock);
+
+	return i;
+}
+
+int sdma_load_task(u32 *task_image)
+{
+	struct sdma_task_header *head = (struct sdma_task_header *)task_image;
+	struct sdma_tdt *tdt;
+	int tasknum;
+	u32 *desc;
+	u32 *var;
+	u32 *inc;
+
+	BUG_ON(head->magic != SDMA_TASK_MAGIC);
+
+	tasknum = new_task_number();
+	if (tasknum < 0)
+		return -ENOMEM;
+
+	desc = (u32 *)(head + 1);
+	var = desc + head->desc_size;
+	inc = var + head->var_size;
+
+	tdt = &sdma_tdt[tasknum];
+	tdt->start = sdma_sram_alloc(head->desc_size * 4, 4);
+	if (!tdt->start)
+		return -ENOMEM;
+	tdt->stop = tdt->start + head->desc_size - 1;
+
+	memcpy(tdt->start, desc, head->desc_size * sizeof(u32));
+	memcpy(tdt->var + head->first_var, var, head->var_size * sizeof(u32));
+	memcpy(tdt->var + SDMA_MAX_VAR, inc, head->inc_size * sizeof(u32));
+	return tasknum;
+}
+
+void sdma_set_initiator(int task, int initiator)
+{
+	int i;
+	int num_descs;
+	u32 *desc;
+	int next_drd_has_initiator;
+
+	sdma_set_tcr_initiator(task, initiator);
+
+	desc = sdma_task_desc(task);
+	next_drd_has_initiator = 1;
+	num_descs = sdma_task_num_descs(task);
+
+	for (i=0; i<num_descs; i++, desc++) {
+		if (!sdma_desc_is_drd(*desc))
+			continue;
+		if (next_drd_has_initiator)
+			if (sdma_desc_initiator(*desc) != SDMA_INITIATOR_ALWAYS)
+				sdma_set_desc_initiator(desc, initiator);
+		next_drd_has_initiator = !sdma_drd_is_extended(*desc);
+	}
+}
+
+struct sdma *sdma_alloc(int queue_size)
+{
+	struct sdma *s = kmalloc(sizeof(*s), GFP_KERNEL);
+	void **cookie;
+
+	if (!s)
+		return NULL;
+
+	memset(s, 0, sizeof(*s));
+
+	if (queue_size) {
+		cookie = kmalloc(sizeof(*cookie) * queue_size, GFP_KERNEL);
+		if (!cookie) {
+			kfree(s);
+			return NULL;
+		}
+		s->cookie = cookie;
+	}
+
+	s->num_bd = queue_size;
+	return s;
+}
+
+void sdma_free(struct sdma *s)
+{
+	if (s->cookie)
+		kfree(s->cookie);
+	kfree(s);
+}
diff -Nru a/arch/ppc/syslib/bestcomm/bestcomm.h b/arch/ppc/syslib/bestcomm/bestcomm.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/arch/ppc/syslib/bestcomm/bestcomm.h	2004-11-20 23:21:02 +01:00
@@ -0,0 +1,441 @@
+/*
+ * arch/ppc/syslib/bestcomm/bestcomm.h
+ *
+ * Driver for MPC52xx processor BestComm peripheral controller
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) 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.
+ */
+
+#ifndef __BESTCOMM_BESTCOMM_H__
+#define __BESTCOMM_BESTCOMM_H__
+
+
+#undef SDMA_DEBUG
+
+/* Buffer Descriptor definitions */
+struct sdma_bd {
+	u32 status;
+	void *data;
+};
+
+struct sdma_bd2 {
+	u32 status;
+	void *data1;
+	void *data2;
+};
+
+#define SDMA_LEN_BITS		26
+#define SDMA_LEN_MASK		((1 << SDMA_LEN_BITS) - 1)
+
+#define SDMA_BD_READY		0x40000000UL
+
+#define SDMA_FEC_TX_BD_TFD	0x08000000UL	/* transmit frame done */
+#define SDMA_FEC_TX_BD_INT	0x04000000UL	/* Interrupt */
+#define SDMA_FEC_TX_BD_TFD_INIT	(SDMA_BD_READY | SDMA_FEC_TX_BD_TFD | \
+							SDMA_FEC_TX_BD_INT)
+
+struct sdma {
+	union {
+		struct sdma_bd *bd;
+		struct sdma_bd2 *bd2;
+	};
+	void **cookie;
+	u16 index;
+	u16 outdex;
+	u16 num_bd;
+	s16 tasknum;
+	u32 flags;
+};
+
+#define SDMA_FLAGS_NONE		0x0000
+#define SDMA_FLAGS_ENABLE_TASK	0x0001
+#define SDMA_FLAGS_BD2		0x0002
+
+/* Task Descriptor Table Entry */
+struct sdma_tdt {
+	u32 *start;
+	u32 *stop;
+	u32 *var;
+	u32 *fdt;
+	u32 status;
+	u32 mvtp;
+	u32 *context;
+	u32 litbase;
+};
+
+extern struct sdma_tdt *sdma_tdt;
+
+#define SDMA_MAX_TASKS		16
+#define SDMA_MAX_VAR		24
+#define SDMA_MAX_INC		8
+#define SDMA_MAX_FDT		64
+#define SDMA_MAX_CONTEXT	20
+#define SDMA_CONTEXT_SIZE	SDMA_MAX_CONTEXT * sizeof(u32)
+#define SDMA_CONTEXT_ALIGN	0x100
+#define SDMA_VAR_SIZE		SDMA_MAX_VAR * sizeof(u32)
+#define SDMA_VAR_ALIGN		0x80
+#define SDMA_FDT_SIZE		SDMA_MAX_FDT * sizeof(u32)
+#define SDMA_FDT_ALIGN		0x100
+#define SDMA_BD_ALIGN		0x10
+
+#define TASK_ENABLE		0x8000
+
+static inline void sdma_enable_task(int task)
+{
+	struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA;
+
+	out_be16(&sdma->tcr[task], in_be16(&sdma->tcr[task]) | TASK_ENABLE);
+}
+
+static inline void sdma_disable_task(int task)
+{
+	struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA;
+
+	out_be16(&sdma->tcr[task], in_be16(&sdma->tcr[task]) & ~TASK_ENABLE);
+}
+
+static inline int sdma_irq(struct sdma *s)
+{
+	return MPC52xx_SDMA_IRQ_BASE + s->tasknum;
+}
+
+static inline void sdma_enable(struct sdma *s)
+{
+	sdma_enable_task(s->tasknum);
+}
+
+static inline void sdma_disable(struct sdma *s)
+{
+	sdma_disable_task(s->tasknum);
+}
+
+static inline int sdma_queue_empty(struct sdma *s)
+{
+	return s->index == s->outdex;
+}
+
+static inline void sdma_clear_irq(struct sdma *s)
+{
+	struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA;
+
+	out_be32(&sdma->IntPend, 1 << s->tasknum);
+}
+
+static inline int sdma_next_index(struct sdma *s)
+{
+	return ((s->index + 1) == s->num_bd) ? 0 : s->index + 1;
+}
+
+static inline int sdma_next_outdex(struct sdma *s)
+{
+	return ((s->outdex + 1) == s->num_bd) ? 0 : s->outdex + 1;
+}
+
+static inline int sdma_queue_full(struct sdma *s)
+{
+	return s->outdex == sdma_next_index(s);
+}
+
+static inline int sdma_buffer_done(struct sdma *s)
+{
+#ifdef SDMA_DEBUG
+	BUG_ON(s->flags & SDMA_FLAGS_BD2);
+#endif
+	if (sdma_queue_empty(s))
+		return 0;
+
+	return (s->bd[s->outdex].status & SDMA_BD_READY) == 0;
+}
+
+static inline int sdma_buffer2_done(struct sdma *s)
+{
+#ifdef SDMA_DEBUG
+	BUG_ON(!(s->flags & SDMA_FLAGS_BD2));
+#endif
+	if (sdma_queue_empty(s))
+		return 0;
+	return (s->bd2[s->outdex].status & SDMA_BD_READY) == 0;
+}
+
+static inline u32 *sdma_task_desc(int task)
+{
+	return sdma_tdt[task].start;
+}
+
+static inline int sdma_task_num_descs(int task)
+{
+	return sdma_tdt[task].stop - sdma_tdt[task].start + 1;
+}
+
+static inline u32 *sdma_task_var(int task)
+{
+	return sdma_tdt[task].var;
+}
+
+static inline u32 *sdma_task_inc(int task)
+{
+	return sdma_task_var(task) + SDMA_MAX_VAR;
+}
+
+static inline void sdma_set_tcr_initiator(int task, int initiator) {
+	struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA;
+
+	u16 *tcr = &sdma->tcr[task];
+
+	out_be16(tcr, (in_be16(tcr) & ~0x1f00) | (initiator << 8));
+}
+
+#define SDMA_DRD_INITIATOR_SHIFT	21
+
+static inline int sdma_desc_initiator(u32 desc)
+{
+	return (desc >> SDMA_DRD_INITIATOR_SHIFT) & 0x1f;
+}
+
+static inline void sdma_set_desc_initiator(u32 *desc, int initiator)
+{
+	*desc = (*desc & ~(0x1f << SDMA_DRD_INITIATOR_SHIFT)) |
+			((initiator << SDMA_DRD_INITIATOR_SHIFT) & 0x1f);
+}
+
+static inline void sdma_submit_buffer(struct sdma *s, void *cookie, void *data,
+								int length)
+{
+#ifdef SDMA_DEBUG
+	BUG_ON(s->flags & SDMA_FLAGS_BD2);
+#endif
+	s->cookie[s->index] = cookie;
+	s->bd[s->index].data = data;
+	s->bd[s->index].status = SDMA_BD_READY | length;
+	s->index = sdma_next_index(s);
+	if (s->flags & SDMA_FLAGS_ENABLE_TASK)
+		sdma_enable_task(s->tasknum);
+}
+
+/*
+ * Special submit_buffer function to submit last buffer of a frame to
+ * the FEC tx task.  tfd means "transmit frame done".
+ */
+static inline void sdma_fec_tfd_submit_buffer(struct sdma *s, void *cookie,
+							void *data, int length)
+{
+#ifdef SDMA_DEBUG
+	BUG_ON(s->flags & SDMA_FLAGS_BD2);
+#endif
+	s->cookie[s->index] = cookie;
+	s->bd[s->index].data = data;
+	s->bd[s->index].status = SDMA_FEC_TX_BD_TFD_INIT | length;
+	s->index = sdma_next_index(s);
+	sdma_enable_task(s->tasknum);
+}
+
+static inline void *sdma_retrieve_buffer(struct sdma *s, int *length)
+{
+	void *cookie = s->cookie[s->outdex];
+
+#ifdef SDMA_DEBUG
+	BUG_ON(s->flags & SDMA_FLAGS_BD2);
+#endif
+	if (length)
+		*length = s->bd[s->outdex].status & SDMA_LEN_MASK;
+	s->outdex = sdma_next_outdex(s);
+	return cookie;
+}
+
+static inline void sdma_submit_buffer2(struct sdma *s, void *cookie,
+					void *data1, void *data2, int length)
+{
+#ifdef SDMA_DEBUG
+	BUG_ON(!(s->flags & SDMA_FLAGS_BD2));
+#endif
+	s->cookie[s->index] = cookie;
+	s->bd2[s->index].data1 = data1;
+	s->bd2[s->index].data2 = data2;
+	s->bd2[s->index].status = SDMA_BD_READY | length;
+	s->index = sdma_next_index(s);
+	if (s->flags & SDMA_FLAGS_ENABLE_TASK)
+		sdma_enable_task(s->tasknum);
+}
+
+static inline void *sdma_retrieve_buffer2(struct sdma *s, int *length)
+{
+	void *cookie = s->cookie[s->outdex];
+
+#ifdef SDMA_DEBUG
+	BUG_ON(!(s->flags & SDMA_FLAGS_BD2));
+#endif
+	if (length)
+		*length = s->bd2[s->outdex].status & SDMA_LEN_MASK;
+	s->outdex = sdma_next_outdex(s);
+	return cookie;
+}
+
+#define SDMA_TASK_MAGIC		0x4243544B	/* 'BCTK' */
+
+/* the size fields are given in number of 32-bit words */
+struct sdma_task_header {
+	u32	magic;
+	u8	desc_size;
+	u8	var_size;
+	u8	inc_size;
+	u8	first_var;
+	u8	reserved[8];
+};
+
+#define SDMA_DESC_NOP		0x000001f8
+#define SDMA_LCD_MASK		0x80000000
+#define SDMA_DRD_EXTENDED	0x40000000
+
+#define sdma_drd_is_extended(desc) ((desc) & SDMA_DRD_EXTENDED)
+
+static inline int sdma_desc_is_drd(u32 desc) {
+	return !(desc & SDMA_LCD_MASK) && desc != SDMA_DESC_NOP;
+};
+
+#define SDMA_PRAGMA_BIT_RSV		7	/* reserved pragma bit */
+#define SDMA_PRAGMA_BIT_PRECISE_INC	6	/* increment 0=when possible, */
+						/*	1=iter end */
+#define SDMA_PRAGMA_BIT_RST_ERROR_NO	5	/* don't reset errors on */
+						/* task enable */
+#define SDMA_PRAGMA_BIT_PACK		4	/* pack data enable */
+#define SDMA_PRAGMA_BIT_INTEGER		3	/* data alignment */
+						/* 0=frac(msb), 1=int(lsb) */
+#define SDMA_PRAGMA_BIT_SPECREAD	2	/* XLB speculative read */
+#define SDMA_PRAGMA_BIT_CW		1	/* write line buffer enable */
+#define SDMA_PRAGMA_BIT_RL		0	/* read line buffer enable */
+
+#define SDMA_STD_PRAGMA		((0 << SDMA_PRAGMA_BIT_RSV)		| \
+				 (0 << SDMA_PRAGMA_BIT_PRECISE_INC)	| \
+				 (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO)	| \
+				 (0 << SDMA_PRAGMA_BIT_PACK)		| \
+				 (0 << SDMA_PRAGMA_BIT_INTEGER)		| \
+				 (1 << SDMA_PRAGMA_BIT_SPECREAD)	| \
+				 (1 << SDMA_PRAGMA_BIT_CW)		| \
+				 (1 << SDMA_PRAGMA_BIT_RL))
+
+#define SDMA_PCI_PRAGMA		((0 << SDMA_PRAGMA_BIT_RSV)		| \
+				 (0 << SDMA_PRAGMA_BIT_PRECISE_INC)	| \
+				 (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO)	| \
+				 (0 << SDMA_PRAGMA_BIT_PACK)		| \
+				 (1 << SDMA_PRAGMA_BIT_INTEGER)		| \
+				 (1 << SDMA_PRAGMA_BIT_SPECREAD)	| \
+				 (1 << SDMA_PRAGMA_BIT_CW)		| \
+				 (1 << SDMA_PRAGMA_BIT_RL))
+
+#define SDMA_ATA_PRAGMA		SDMA_STD_PRAGMA
+#define SDMA_CRC16_DP_0_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_CRC16_DP_1_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_FEC_RX_BD_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_FEC_TX_BD_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_GEN_DP_0_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_GEN_DP_1_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_GEN_DP_2_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_GEN_DP_3_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_GEN_DP_BD_0_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_GEN_DP_BD_1_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_GEN_RX_BD_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_GEN_TX_BD_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_GEN_LPC_PRAGMA	SDMA_STD_PRAGMA
+#define SDMA_PCI_RX_PRAGMA	SDMA_PCI_PRAGMA
+#define SDMA_PCI_TX_PRAGMA	SDMA_PCI_PRAGMA
+
+static inline void sdma_set_task_pragma(int task, int pragma)
+{
+	u32 *fdt = (u32 *)&sdma_tdt[task].fdt;
+
+	*fdt = (*fdt & ~0xff) | pragma;
+}
+
+static inline void sdma_set_task_auto_start(int task, int next_task)
+{
+	struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA;
+	u16 *tcr = &sdma->tcr[task];
+
+	out_be16(tcr, (in_be16(tcr) & ~0xff) | 0x00c0 | next_task);
+}
+
+#define SDMA_INITIATOR_ALWAYS	 0
+#define SDMA_INITIATOR_SCTMR_0	 1
+#define SDMA_INITIATOR_SCTMR_1	 2
+#define SDMA_INITIATOR_FEC_RX	 3
+#define SDMA_INITIATOR_FEC_TX	 4
+#define SDMA_INITIATOR_ATA_RX	 5
+#define SDMA_INITIATOR_ATA_TX	 6
+#define SDMA_INITIATOR_SCPCI_RX	 7
+#define SDMA_INITIATOR_SCPCI_TX	 8
+#define SDMA_INITIATOR_PSC3_RX	 9
+#define SDMA_INITIATOR_PSC3_TX	10
+#define SDMA_INITIATOR_PSC2_RX	11
+#define SDMA_INITIATOR_PSC2_TX	12
+#define SDMA_INITIATOR_PSC1_RX	13
+#define SDMA_INITIATOR_PSC1_TX	14
+#define SDMA_INITIATOR_SCTMR_2	15
+#define SDMA_INITIATOR_SCLPC	16
+#define SDMA_INITIATOR_PSC5_RX	17
+#define SDMA_INITIATOR_PSC5_TX	18
+#define SDMA_INITIATOR_PSC4_RX	19
+#define SDMA_INITIATOR_PSC4_TX	20
+#define SDMA_INITIATOR_I2C2_RX	21
+#define SDMA_INITIATOR_I2C2_TX	22
+#define SDMA_INITIATOR_I2C1_RX	23
+#define SDMA_INITIATOR_I2C1_TX	24
+#define SDMA_INITIATOR_PSC6_RX	25
+#define SDMA_INITIATOR_PSC6_TX	26
+#define SDMA_INITIATOR_IRDA_RX	25
+#define SDMA_INITIATOR_IRDA_TX	26
+#define SDMA_INITIATOR_SCTMR_3	27
+#define SDMA_INITIATOR_SCTMR_4	28
+#define SDMA_INITIATOR_SCTMR_5	29
+#define SDMA_INITIATOR_SCTMR_6	30
+#define SDMA_INITIATOR_SCTMR_7	31
+
+#define SDMA_IPR_ALWAYS	7
+#define SDMA_IPR_SCTMR_0 	2
+#define SDMA_IPR_SCTMR_1 	2
+#define SDMA_IPR_FEC_RX 	6
+#define SDMA_IPR_FEC_TX 	5
+#define SDMA_IPR_ATA_RX 	4
+#define SDMA_IPR_ATA_TX 	3
+#define SDMA_IPR_SCPCI_RX	2
+#define SDMA_IPR_SCPCI_TX	2
+#define SDMA_IPR_PSC3_RX	2
+#define SDMA_IPR_PSC3_TX	2
+#define SDMA_IPR_PSC2_RX	2
+#define SDMA_IPR_PSC2_TX	2
+#define SDMA_IPR_PSC1_RX	2
+#define SDMA_IPR_PSC1_TX	2
+#define SDMA_IPR_SCTMR_2	2
+#define SDMA_IPR_SCLPC		2
+#define SDMA_IPR_PSC5_RX	2
+#define SDMA_IPR_PSC5_TX	2
+#define SDMA_IPR_PSC4_RX	2
+#define SDMA_IPR_PSC4_TX	2
+#define SDMA_IPR_I2C2_RX	2
+#define SDMA_IPR_I2C2_TX	2
+#define SDMA_IPR_I2C1_RX	2
+#define SDMA_IPR_I2C1_TX	2
+#define SDMA_IPR_PSC6_RX	2
+#define SDMA_IPR_PSC6_TX	2
+#define SDMA_IPR_IRDA_RX	2
+#define SDMA_IPR_IRDA_TX	2
+#define SDMA_IPR_SCTMR_3	2
+#define SDMA_IPR_SCTMR_4	2
+#define SDMA_IPR_SCTMR_5	2
+#define SDMA_IPR_SCTMR_6	2
+#define SDMA_IPR_SCTMR_7	2
+
+extern struct sdma *sdma_alloc(int request_queue_size);
+extern void sdma_free(struct sdma *sdma_struct);
+extern int sdma_load_task(u32 *task_image);
+extern void *sdma_sram_alloc(int size, int alignment);
+extern void sdma_init_bd(struct sdma *s);
+extern void sdma_init_bd2(struct sdma *s);
+
+#define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f)))
+
+#endif  /* __BESTCOMM_BESTCOMM_H__ */
diff -Nru a/arch/ppc/syslib/bestcomm/fec.c b/arch/ppc/syslib/bestcomm/fec.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/arch/ppc/syslib/bestcomm/fec.c	2004-11-20 23:21:03 +01:00
@@ -0,0 +1,161 @@
+/*
+ * arch/ppc/syslib/bestcomm/fec.c
+ *
+ * Driver for MPC52xx processor BestComm FEC controller
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) 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/string.h>
+#include <linux/types.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#include <asm/mpc52xx.h>
+
+#include "bestcomm.h"
+#include "fec.h"
+
+/*
+ * Initialize FEC receive task.
+ * Returns task number of FEC receive task.
+ * Returns -1 on failure
+ */
+int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize)
+{
+	struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA;
+	struct sdma_fec_rx_var *var;
+	struct sdma_fec_rx_inc *inc;
+	static int tasknum = -1;
+	static struct sdma_bd *bd = 0;
+
+	if (tasknum < 0) {
+		tasknum = sdma_load_task(sdma_fec_rx_task);
+		if (tasknum < 0)
+			return tasknum;
+	}
+
+	if (!bd)
+		bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * s->num_bd,
+								SDMA_BD_ALIGN);
+	if (!bd)
+		return -ENOMEM;
+
+	sdma_disable_task(tasknum);
+
+	s->tasknum = tasknum;
+	s->bd = bd;
+	s->flags = SDMA_FLAGS_NONE;
+	s->index = 0;
+	s->outdex = 0;
+	memset(bd, 0, sizeof(*bd) * s->num_bd);
+
+	var = (struct sdma_fec_rx_var *)sdma_task_var(tasknum);
+	var->enable		= MPC52xx_SDMA +
+				  FIELD_OFFSET(mpc52xx_sdma,tcr[tasknum]);
+	var->fifo		= fifo;
+	var->bd_base		= bd;
+	var->bd_last		= &bd[s->num_bd - 1];
+	var->bd_start		= bd;
+	var->buffer_size	= maxbufsize;
+
+	/* These are constants, they should have been in the image file */
+	inc = (struct sdma_fec_rx_inc *)sdma_task_inc(tasknum);
+	inc->incr_bytes		= -(s16)sizeof(u32);
+	inc->incr_dst		= sizeof(u32);
+
+	sdma_set_task_pragma(tasknum, SDMA_FEC_RX_BD_PRAGMA);
+	sdma_set_task_auto_start(tasknum, tasknum);
+
+	/* clear pending interrupt bits */
+	out_be32(&sdma->IntPend, 1<<tasknum);
+
+	out_8(&sdma->ipr[SDMA_INITIATOR_FEC_RX], SDMA_IPR_FEC_RX);
+
+	return tasknum;
+}
+
+/*
+ * Return 2nd to last DRD
+ * This is an ugly hack, but at least it's only done once at initialization
+ */
+static u32 *self_modified_drd(int tasknum)
+{
+	u32 *desc;
+	int num_descs;
+	int drd_count;
+	int i;
+
+	num_descs = sdma_task_num_descs(tasknum);
+	desc = sdma_task_desc(tasknum) + num_descs - 1;
+	drd_count = 0;
+	for (i=0; i<num_descs; i++, desc--)
+		if (sdma_desc_is_drd(*desc) && ++drd_count == 3)
+			break;
+	return desc;
+}
+
+/*
+ * Initialize FEC transmit task.
+ * Returns task number of FEC transmit task.
+ * Returns -1 on failure
+ */
+int sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo)
+{
+	struct mpc52xx_sdma *sdma = (struct mpc52xx_sdma *)MPC52xx_SDMA;
+	struct sdma_fec_tx_var *var;
+	struct sdma_fec_tx_inc *inc;
+	static int tasknum = -1;
+	static struct sdma_bd *bd = 0;
+
+	if (tasknum < 0) {
+		tasknum = sdma_load_task(sdma_fec_tx_task);
+		if (tasknum < 0)
+			return tasknum;
+	}
+
+	if (!bd)
+		bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * s->num_bd,
+								SDMA_BD_ALIGN);
+	if (!bd)
+		return -ENOMEM;
+
+	sdma_disable_task(tasknum);
+
+	s->tasknum = tasknum;
+	s->bd = bd;
+	s->flags = SDMA_FLAGS_ENABLE_TASK;
+	s->index = 0;
+	s->outdex = 0;
+	memset(bd, 0, sizeof(*bd) * s->num_bd);
+
+	var = (struct sdma_fec_tx_var *)sdma_task_var(tasknum);
+	var->DRD		= self_modified_drd(tasknum);
+	var->fifo		= fifo;
+	var->enable		= MPC52xx_SDMA +
+				  FIELD_OFFSET(mpc52xx_sdma,tcr[tasknum]);
+	var->bd_base		= bd;
+	var->bd_last		= &bd[s->num_bd - 1];
+	var->bd_start		= bd;
+
+	/* These are constants, they should have been in the image file */
+	inc = (struct sdma_fec_tx_inc *)sdma_task_inc(tasknum);
+	inc->incr_bytes		= -(s16)sizeof(u32);
+	inc->incr_src		= sizeof(u32);
+	inc->incr_src_ma	= sizeof(u8);
+
+	sdma_set_task_pragma(tasknum, SDMA_FEC_TX_BD_PRAGMA);
+	sdma_set_task_auto_start(tasknum, tasknum);
+
+	/* clear pending interrupt bits */
+	out_be32(&sdma->IntPend, 1<<tasknum);
+
+	out_8(&sdma->ipr[SDMA_INITIATOR_FEC_TX], SDMA_IPR_FEC_RX);
+
+	return tasknum;
+}
diff -Nru a/arch/ppc/syslib/bestcomm/fec.h b/arch/ppc/syslib/bestcomm/fec.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/arch/ppc/syslib/bestcomm/fec.h	2004-11-20 23:21:04 +01:00
@@ -0,0 +1,64 @@
+/*
+ * arch/ppc/syslib/bestcomm/fec.h
+ *
+ * Driver for MPC52xx processor BestComm FEC controller
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) 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.
+ */
+
+#ifndef __BESTCOMM_FEC_H__
+#define __BESTCOMM_FEC_H__
+
+
+/* rx task vars that need to be set before enabling the task */
+struct sdma_fec_rx_var {
+	u32 enable;		/* (u16*) address of task's control register */
+	u32 fifo;		/* (u32*) address of fec's fifo */
+	u32 bd_base;		/* (struct sdma_bd*) beginning of ring buffer */
+	u32 bd_last;		/* (struct sdma_bd*) end of ring buffer */
+	u32 bd_start;		/* (struct sdma_bd*) current bd */
+	u32 buffer_size;	/* size of receive buffer */
+};
+
+/* rx task incs that need to be set before enabling the task */
+struct sdma_fec_rx_inc {
+	u16 pad0;
+	s16 incr_bytes;
+	u16 pad1;
+	s16 incr_dst;
+};
+
+/* tx task vars that need to be set before enabling the task */
+struct sdma_fec_tx_var {
+	u32 DRD;		/* (u32*) address of self-modified DRD */
+	u32 fifo;		/* (u32*) address of fec's fifo */
+	u32 enable;		/* (u16*) address of task's control register */
+	u32 bd_base;		/* (struct sdma_bd*) beginning of ring buffer */
+	u32 bd_last;		/* (struct sdma_bd*) end of ring buffer */
+	u32 bd_start;		/* (struct sdma_bd*) current bd */
+	u32 buffer_size;	/* set by uCode for each packet */
+};
+
+/* tx task incs that need to be set before enabling the task */
+struct sdma_fec_tx_inc {
+	u16 pad0;
+	s16 incr_bytes;
+	u16 pad1;
+	s16 incr_src;
+	u16 pad2;
+	s16 incr_src_ma;
+};
+
+extern int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize);
+extern int sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo);
+
+extern u32 sdma_fec_rx_task[];
+extern u32 sdma_fec_tx_task[];
+
+
+#endif  /* __BESTCOMM_FEC_H__ */
diff -Nru a/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c	2004-11-20 23:21:05 +01:00
@@ -0,0 +1,52 @@
+/*
+ * sdma_fec_rx_task.c
+ *
+ * Automatically created by split_dma_image based on dma_image.hex
+ * on Wed Sep  8 00:37:22 2004 GMT
+ */
+
+#include <linux/types.h>
+
+/*
+ * The header consists of the following fields:
+ *	uint32_t	magic;
+ *	uint8_t		desc_size;
+ *	uint8_t		var_size;
+ *	uint8_t		inc_size;
+ *	uint8_t		first_var;
+ *	uint8_t		reserved[8];
+ *
+ * The size fields contain the number of 32-bit words.
+*/
+
+uint32_t sdma_fec_rx_task[] = {
+	/* header */
+	0x4243544b,
+	0x0c020409,
+	0x00000000,
+	0x00000000,
+
+	/* Task descriptors */
+	0x808220da, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc3, idx1 += inc2 */
+	0x10601010, /*   DRD1A: var4 = var2; FN=0 MORE init=3 WS=0 RS=0 */
+	0xb880025b, /*   LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc3, idx3 += inc3 */
+	0x10001308, /*     DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+	0x60140002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
+	0x0cccfcca, /*     DRD2B1: *idx3 = EU3(); EU3(*idx3,var10)  */
+	0xd9190240, /*   LCDEXT: idx2 = idx2; idx2 > var9; idx2 += inc0 */
+	0xb8c5e009, /*   LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */
+	0x047ecf80, /*     DRD1A: *idx3 = *idx0; FN=0 INT init=3 WS=3 RS=3 */
+	0x98190024, /*   LCD: idx2 = idx0; idx2 once var0; idx2 += inc4 */
+	0x0060c790, /*     DRD1A: *idx1 = *idx2; FN=0 init=3 WS=0 RS=0 */
+	0x000001f8, /*   NOP */
+
+	/* VAR[9]-VAR[10] */
+	0x40000000,
+	0x7fff7fff,
+
+	/* INC[0]-INC[3] */
+	0x40000000,
+	0xe0000000,
+	0xa0000008,
+	0x20000000,
+};
diff -Nru a/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c	2004-11-20 23:21:06 +01:00
@@ -0,0 +1,74 @@
+/*
+ * sdma_fec_tx_task.c
+ *
+ * Automatically created by split_dma_image based on dma_image.hex
+ * on Wed Sep  8 00:37:22 2004 GMT
+ */
+
+#include <linux/types.h>
+
+/*
+ * The header consists of the following fields:
+ *	uint32_t	magic;
+ *	uint8_t		desc_size;
+ *	uint8_t		var_size;
+ *	uint8_t		inc_size;
+ *	uint8_t		first_var;
+ *	uint8_t		reserved[8];
+ *
+ * The size fields contain the number of 32-bit words.
+*/
+
+uint32_t sdma_fec_tx_task[] = {
+	/* header */
+	0x4243544b,
+	0x1b06070c,
+	0x00000000,
+	0x00000000,
+
+	/* Task descriptors */
+	0x8018001b, /* LCD: idx0 = var0; idx0 <= var0; idx0 += inc3 */
+	0x60000005, /*   DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
+	0x01ccfc0c, /*   DRD2B1: var7 = EU3(); EU3(*idx0,var12)  */
+	0x8082a123, /* LCD: idx0 = var1, idx1 = var5; idx1 <= var4; idx0 += inc4, idx1 += inc3 */
+	0x10801418, /*   DRD1A: var5 = var3; FN=0 MORE init=4 WS=0 RS=0 */
+	0xf8810364, /*   LCDEXT: idx2 = *idx1, idx3 = var2; idx2 < var13; idx2 += inc4, idx3 += inc4 */
+	0x801a6024, /*   LCD: idx4 = var0; ; idx4 += inc4 */
+	0x10001708, /*     DRD1A: var5 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+	0x60140002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
+	0x0cccfcce, /*     DRD2B1: *idx3 = EU3(); EU3(*idx3,var14)  */
+	0x991a002c, /*   LCD: idx2 = idx2, idx3 = idx4; idx2 once var0; idx2 += inc5, idx3 += inc4 */
+	0x60000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */
+	0x088cfc4f, /*     DRD2B1: idx2 = EU3(); EU3(*idx1,var15)  */
+	0x9919802c, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 once var0; idx2 += inc5, idx3 += inc4 */
+	0x70000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+	0x024cfc4c, /*     DRD2B1: var9 = EU3(); EU3(*idx1,var12)  */
+	0x60000003, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */
+	0x0cccf247, /*     DRD2B1: *idx3 = EU3(); EU3(var9,var7)  */
+	0xd9190440, /*   LCDEXT: idx2 = idx2; idx2 > var17; idx2 += inc0 */
+	0xb8c86009, /*   LCD: idx3 = *(idx1 + var0000001a); ; idx3 += inc1 */
+	0x009ec398, /*     DRD1A: *idx0 = *idx3; FN=0 init=4 WS=3 RS=3 */
+	0x99198372, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var13; idx2 += inc6, idx3 += inc2 */
+	0x088ac398, /*     DRD1A: *idx0 = *idx3; FN=0 TFD init=4 WS=1 RS=1 */
+	0x9919002d, /*   LCD: idx2 = idx2; idx2 once var0; idx2 += inc5 */
+	0x60000005, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
+	0x0c4cf88d, /*     DRD2B1: *idx1 = EU3(); EU3(idx2,var13)  */
+	0x000001f8, /*   NOP */
+
+	/* VAR[12]-VAR[17] */
+	0x0c000000,
+	0x40000000,
+	0x7fff7fff,
+	0x43ffffff,
+	0x00000000,
+	0x40000004,
+
+	/* INC[0]-INC[6] */
+	0x40000000,
+	0xe0000000,
+	0xe0000000,
+	0xa0000008,
+	0x20000000,
+	0x00000000,
+	0x4000ffff,
+};

[-- Attachment #3: 1.2157-fec-support-mpc52xx.patch --]
[-- Type: text/x-patch, Size: 51475 bytes --]

diff -Nru a/arch/ppc/platforms/lite5200.c b/arch/ppc/platforms/lite5200.c
--- a/arch/ppc/platforms/lite5200.c	2004-11-19 17:20:08 +01:00
+++ b/arch/ppc/platforms/lite5200.c	2004-11-20 23:26:31 +01:00
@@ -132,6 +132,10 @@
 	port_config &= ~0x00007000;     /* Differential mode - USB1 only */
 	port_config |=  0x00001000;
 
+	/* Ethernet port */
+	port_config &= ~0x000f0000;	/* 100 Mbits with MDIO lines */
+	port_config |=  0x00050000;
+
 	/* Commit port config */
 	out_be32(&gpio->port_config, port_config);
 
diff -Nru a/arch/ppc/platforms/mpc5200.c b/arch/ppc/platforms/mpc5200.c
--- a/arch/ppc/platforms/mpc5200.c	2004-11-19 17:20:08 +01:00
+++ b/arch/ppc/platforms/mpc5200.c	2004-11-20 23:26:31 +01:00
@@ -54,6 +54,13 @@
 		.irq		= MPC52xx_USB_IRQ,
 		.pm		= OCP_CPM_NA,
 	}, 
+	{       
+		.vendor		= OCP_VENDOR_FREESCALE,
+		.function	= OCP_FUNC_FEC_MPC52xx,
+		.paddr		= MPC52xx_FEC,
+		.irq		= MPC52xx_FEC_IRQ,
+		.pm		= OCP_CPM_NA,
+	},   
 	{	/* Terminating entry */
 		.vendor		= OCP_VENDOR_INVALID
 	}
diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig
--- a/drivers/net/Kconfig	2004-11-05 11:37:26 +01:00
+++ b/drivers/net/Kconfig	2004-11-20 23:26:31 +01:00
@@ -1817,6 +1817,7 @@
 	  controller on the Renesas H8/300 processor.
 
 source "drivers/net/fec_8xx/Kconfig"
+source "drivers/net/fec_mpc52xx/Kconfig"
 
 endmenu
 
diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	2004-11-11 09:34:32 +01:00
+++ b/drivers/net/Makefile	2004-11-20 23:26:31 +01:00
@@ -182,6 +182,7 @@
 obj-$(CONFIG_S2IO) += s2io.o
 obj-$(CONFIG_SMC91X) += smc91x.o
 obj-$(CONFIG_FEC_8XX) += fec_8xx/
+obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx/
 
 obj-$(CONFIG_ARM) += arm/
 obj-$(CONFIG_NET_FC) += fc/
diff -Nru a/drivers/net/fec_mpc52xx/Kconfig b/drivers/net/fec_mpc52xx/Kconfig
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/net/fec_mpc52xx/Kconfig	2004-11-20 23:26:31 +01:00
@@ -0,0 +1,23 @@
+menu "MPC5200 Networking Options"
+	depends PPC_MPC52xx && NET_ETHERNET
+
+config FEC_MPC52xx
+	bool "FEC Ethernet"
+	depends on NET_ETHERNET
+	select PPC_BESTCOMM
+	select CRC32
+	---help---
+	  This option enables support for the MPC5200's on-chip
+	  Fast Ethernet Controller
+
+config USE_MDIO
+	bool "  Use external Ethernet MII PHY"
+	select MII
+	depends FEC_MPC52xx
+	---help---
+	  The MPC5200's FEC can connect to the Ethernet either with
+	  an external MII PHY chip or 10 Mbps 7-wire interface 
+	  (Motorola? industry standard).
+	  If your board uses an external PHY, say y, else n.
+
+endmenu
diff -Nru a/drivers/net/fec_mpc52xx/Makefile b/drivers/net/fec_mpc52xx/Makefile
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/net/fec_mpc52xx/Makefile	2004-11-20 23:26:32 +01:00
@@ -0,0 +1,2 @@
+obj-$(CONFIG_FEC_MPC52xx) 	+= fec.o
+obj-$(CONFIG_USE_MDIO)		+= fec_phy.o
diff -Nru a/drivers/net/fec_mpc52xx/fec.c b/drivers/net/fec_mpc52xx/fec.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/net/fec_mpc52xx/fec.c	2004-11-20 23:26:33 +01:00
@@ -0,0 +1,791 @@
+/*
+ * drivers/net/fec_mpc52xx/fec.c
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) 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/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/ppcboot.h>
+#include <asm/mpc52xx.h>
+#include <asm/ocp.h>
+
+#include <syslib/bestcomm/bestcomm.h>
+#include <syslib/bestcomm/fec.h>
+
+#include "fec_phy.h"
+#include "fec.h"
+
+static irqreturn_t fec_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t fec_rx_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t fec_tx_interrupt(int, void *, struct pt_regs *);
+static struct net_device_stats *fec_get_stats(struct net_device *);
+static void fec_set_multicast_list(struct net_device *dev);
+static void fec_reinit(struct net_device *dev);
+
+static u8 mpc52xx_fec_mac_addr[6];
+static u8 null_mac[6];
+
+static void fec_tx_timeout(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+
+	priv->stats.tx_errors++;
+
+	if (!priv->tx_full)
+		netif_wake_queue(dev);
+}
+
+static void fec_set_paddr(struct net_device *dev, u8 *mac)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+
+	out_be32(&fec->paddr1, *(u32*)(&mac[0]));
+	out_be32(&fec->paddr2, (*(u16*)(&mac[4]) << 16) | 0x8808);
+}
+
+static void fec_get_paddr(struct net_device *dev, u8 *mac)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+
+	*(u32*)(&mac[0]) = in_be32(&fec->paddr1);
+	*(u16*)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
+}
+
+static int fec_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct sockaddr *sock = (struct sockaddr *)addr;
+
+	memcpy(dev->dev_addr, sock->sa_data, dev->addr_len);
+
+	fec_set_paddr(dev, sock->sa_data);
+	return 0;
+}
+
+/* This function is called to start or restart the FEC during a link
+ * change.  This happens on fifo errors or when switching between half
+ * and full duplex.
+ */
+static void fec_restart(struct net_device *dev, int duplex)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	u32 rcntrl;
+	u32 tcntrl;
+	int i;
+
+	out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & 0x700000);
+	out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & 0x700000);
+	out_be32(&fec->reset_cntrl, 0x1000000);
+
+	/* Whack a reset.  We should wait for this. */
+	out_be32(&fec->ecntrl, FEC_ECNTRL_RESET);
+	for (i = 0; i < FEC_RESET_DELAY; ++i) {
+		if ((in_be32(&fec->ecntrl) & FEC_ECNTRL_RESET) == 0)
+			break;
+		udelay(1);
+	}
+	if (i == FEC_RESET_DELAY)
+		printk (KERN_ERR "FEC Reset timeout!\n");
+
+	/* Set station address. */
+	fec_set_paddr(dev, dev->dev_addr);
+
+	fec_set_multicast_list(dev);
+
+	rcntrl = FEC_RX_BUFFER_SIZE << 16;	/* max frame length */
+	rcntrl |= FEC_RCNTRL_FCE;
+	rcntrl |= MII_RCNTL_MODE;
+	if (duplex)
+		tcntrl = FEC_TCNTRL_FDEN;		/* FD enable */
+	else {
+		rcntrl |= FEC_RCNTRL_DRT;
+		tcntrl = 0;
+	}
+	out_be32(&fec->r_cntrl, rcntrl);
+	out_be32(&fec->x_cntrl, tcntrl);
+
+	set_phy_speed(fec, priv->phy_speed);
+
+	priv->full_duplex = duplex;
+
+	/* Clear any outstanding interrupt. */
+	out_be32(&fec->ievent, 0xffffffff);	/* clear intr events */
+
+	/* Enable interrupts we wish to service.
+	*/
+	out_be32(&fec->imask, FEC_IMASK_ENABLE);
+
+	/* And last, enable the transmit and receive processing.
+	*/
+	out_be32(&fec->ecntrl, FEC_ECNTRL_ETHER_EN);
+	out_be32(&fec->r_des_active, 0x01000000);
+
+	/* The tx ring is no longer full. */
+	if (priv->tx_full)
+	{
+		priv->tx_full = 0;
+		netif_wake_queue(dev);
+	}
+}
+
+static void fec_free_rx_buffers(struct sdma *s)
+{
+	struct sk_buff *skb;
+
+	while (!sdma_queue_empty(s)) {
+		skb = sdma_retrieve_buffer(s, NULL);
+		kfree_skb(skb);
+	}
+}
+
+static int fec_open(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct sk_buff *skb;
+	void *data;
+
+	sdma_fec_rx_init(priv->rx_sdma, priv->rx_fifo, FEC_RX_BUFFER_SIZE);
+	sdma_fec_tx_init(priv->tx_sdma, priv->tx_fifo);
+
+	while (!sdma_queue_full(priv->rx_sdma)) {
+		skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+		if (skb == 0)
+			goto eagain;
+		skb->dev = dev;
+		skb_put(skb, FEC_RX_BUFFER_SIZE);
+
+		/* zero out the initial receive buffers to aid debugging */
+		memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
+		data = (void *)virt_to_phys(skb->data);
+		sdma_submit_buffer(priv->rx_sdma, skb, data, skb->len);
+	}
+
+	fec_set_paddr(dev, dev->dev_addr);
+
+	if (fec_mii_wait(dev) != 0)
+		return -ENODEV;
+
+	sdma_enable(priv->rx_sdma);
+	sdma_enable(priv->tx_sdma);
+
+	netif_start_queue(dev);
+
+	return 0;
+
+eagain:
+	printk(KERN_ERR "fec_open: failed\n");
+
+	fec_free_rx_buffers(priv->rx_sdma);
+
+	return -EAGAIN;
+}
+
+/* The BestComm hardware requires data to be 32-bit aligned.
+ * We also pad to minimum ethernet packet length, ETH_ZLEN.
+ */
+static inline struct sk_buff *fec_skb_align_and_pad(struct sk_buff *skb)
+{
+	void *data = skb->data;
+	int len = skb->len;
+	int pad = (int)data & 0x3;
+	struct sk_buff *nskb;
+	int nlen;
+
+	if (pad == 0)
+		return skb;
+
+	if (!skb_cloned(skb)) {
+		skb_push(skb, pad);
+		memmove(skb->data, data, len);
+		skb_trim(skb, len);
+		skb = skb_padto(skb, ETH_ZLEN);
+		return skb;
+	}
+
+	/* ensure skb_padto doesn't have to reallocate */
+	nlen = (len >= ETH_ZLEN) ? len : ETH_ZLEN;
+
+	nskb = alloc_skb(nlen, GFP_ATOMIC);
+	if (nskb) {
+		skb_put(nskb, len);
+		memcpy(nskb->data, data, len);
+		nskb = skb_padto(nskb, ETH_ZLEN);
+	}
+	kfree_skb(skb);
+	return nskb;
+}
+
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+static int fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	void *data;
+
+	if (sdma_queue_full(priv->tx_sdma))
+		panic("MPC52xx transmit queue overrun\n");
+
+	skb = fec_skb_align_and_pad(skb);
+	if (!skb) {
+		priv->stats.tx_dropped++;
+		return 0;
+	}
+
+	spin_lock_irq(&priv->lock);
+	dev->trans_start = jiffies;
+
+	data = (void *)virt_to_phys(skb->data);
+	sdma_fec_tfd_submit_buffer(priv->tx_sdma, skb, data, skb->len);
+
+	if (sdma_queue_full(priv->tx_sdma)) {
+		priv->tx_full = 1;
+		netif_stop_queue(dev);
+	}
+	spin_unlock_irq(&priv->lock);
+
+	return 0;
+}
+
+/* This handles BestComm transmit task interrupts
+ */
+static irqreturn_t fec_tx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct sk_buff *skb;
+
+	for (;;) {
+		sdma_clear_irq(priv->tx_sdma);
+		spin_lock(&priv->lock);
+		if (!sdma_buffer_done(priv->tx_sdma)) {
+			spin_unlock(&priv->lock);
+			break;
+		}
+		skb = sdma_retrieve_buffer(priv->tx_sdma, NULL);
+
+		if (priv->tx_full) {
+			priv->tx_full = 0;
+			netif_wake_queue(dev);
+		}
+		spin_unlock(&priv->lock);
+		dev_kfree_skb_irq(skb);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t fec_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct sk_buff *skb;
+	struct sk_buff *rskb;
+	void *data;
+	int length;
+
+	for (;;) {
+		sdma_clear_irq(priv->rx_sdma);
+
+		if (!sdma_buffer_done(priv->rx_sdma))
+			break;
+
+		rskb = sdma_retrieve_buffer(priv->rx_sdma, &length);
+		/* length included sizeof CRC32 */
+		skb_trim(rskb, length - sizeof(u32));
+
+		/* allocate replacement skb */
+		skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+		if (skb) {
+			rskb->protocol = eth_type_trans(rskb, dev);
+			netif_rx(rskb);
+			dev->last_rx = jiffies;
+		} else {
+			printk(KERN_NOTICE
+				"%s: Memory squeeze, dropping packet.\n",
+				dev->name);
+			priv->stats.rx_dropped++;
+
+			skb_trim(rskb, 0);
+			skb = rskb;
+		}
+
+		skb->dev = dev;
+		skb_put(skb, FEC_RX_BUFFER_SIZE);
+		data = (void *)virt_to_phys(skb->data);
+		sdma_submit_buffer(priv->rx_sdma, skb, data, skb->len);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t fec_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	int ievent;
+
+	ievent = in_be32(&fec->ievent);
+	out_be32(&fec->ievent, ievent);		/* clear pending events */
+
+	if (ievent & (FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
+		if (ievent & FEC_IEVENT_RFIFO_ERROR)
+			printk(KERN_WARNING "FEC_IEVENT_RFIFO_ERROR\n");
+		if (ievent & FEC_IEVENT_XFIFO_ERROR)
+			printk(KERN_WARNING "FEC_IEVENT_XFIFO_ERROR\n");
+		fec_reinit(dev);
+	}
+	else if (ievent & FEC_IEVENT_MII)
+		fec_mii(dev);
+	return IRQ_HANDLED;
+}
+
+static int fec_close(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	unsigned long timeout;
+
+	priv->open_time = 0;
+	priv->sequence_done = 0;
+
+	netif_stop_queue(dev);
+
+	sdma_disable(priv->rx_sdma);		/* disable receive task */
+
+	/* Wait for queues to drain */
+	timeout = jiffies + 2*HZ;
+	while (time_before(jiffies, timeout) &&
+					(!sdma_queue_empty(priv->tx_sdma) ||
+					!sdma_queue_empty(priv->rx_sdma))) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ/10);
+	}
+	if (time_after_eq(jiffies, timeout))
+		printk(KERN_ERR "fec_close: queues didn't drain\n");
+
+	sdma_disable(priv->tx_sdma);
+
+	fec_free_rx_buffers(priv->rx_sdma);
+
+	fec_get_stats(dev);
+
+	return 0;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *fec_get_stats(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct net_device_stats *stats = &priv->stats;
+	struct mpc52xx_fec *fec = priv->fec;
+
+	stats->rx_bytes = in_be32(&fec->rmon_r_octets);
+	stats->rx_packets = in_be32(&fec->rmon_r_packets);
+	stats->rx_errors = stats->rx_packets - in_be32(&fec->ieee_r_frame_ok);
+	stats->tx_bytes = in_be32(&fec->rmon_t_octets);
+	stats->tx_packets = in_be32(&fec->rmon_t_packets);
+	stats->tx_errors = stats->tx_packets - (
+					in_be32(&fec->ieee_t_frame_ok) +
+					in_be32(&fec->rmon_t_col) +
+					in_be32(&fec->ieee_t_1col) +
+					in_be32(&fec->ieee_t_mcol) +
+					in_be32(&fec->ieee_t_def));
+	stats->multicast = in_be32(&fec->rmon_r_mc_pkt);
+	stats->collisions = in_be32(&fec->rmon_t_col);
+
+	/* detailed rx_errors: */
+	stats->rx_length_errors = in_be32(&fec->rmon_r_undersize)
+					+ in_be32(&fec->rmon_r_oversize)
+					+ in_be32(&fec->rmon_r_frag)
+					+ in_be32(&fec->rmon_r_jab);
+	stats->rx_over_errors = in_be32(&fec->r_macerr);
+	stats->rx_crc_errors = in_be32(&fec->ieee_r_crc);
+	stats->rx_frame_errors = in_be32(&fec->ieee_r_align);
+	stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop);
+	stats->rx_missed_errors = in_be32(&fec->rmon_r_drop);
+
+	/* detailed tx_errors: */
+	stats->tx_aborted_errors = 0;
+	stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr);
+	stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop);
+	stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe);
+	stats->tx_window_errors = in_be32(&fec->ieee_t_lcol);
+
+	return stats;
+}
+
+static void fec_update_stat(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct net_device_stats *stats = &priv->stats;
+	struct mpc52xx_fec *fec = priv->fec;
+
+	out_be32(&fec->mib_control, FEC_MIB_DISABLE);
+	memset_io(&fec->rmon_t_drop, 0,
+			(u32)&fec->reserved10 - (u32)&fec->rmon_t_drop);
+	out_be32(&fec->mib_control, 0);
+	memset(stats, 0, sizeof *stats);
+	fec_get_stats(dev);
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+static void fec_set_multicast_list(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	u32 rx_control;
+
+	rx_control = in_be32(&fec->r_cntrl);
+
+	if (dev->flags & IFF_PROMISC) {
+		rx_control |= FEC_RCNTRL_PROM;
+		out_be32(&fec->r_cntrl, rx_control);
+	} else {
+		rx_control &= ~FEC_RCNTRL_PROM;
+		out_be32(&fec->r_cntrl, rx_control);
+
+		if (dev->flags & IFF_ALLMULTI) {
+			out_be32(&fec->gaddr1, 0xffffffff);
+			out_be32(&fec->gaddr2, 0xffffffff);
+		} else {
+			u32 crc;
+			int i;
+			struct dev_mc_list *dmi;
+			u32 gaddr1 = 0x00000000;
+			u32 gaddr2 = 0x00000000;
+
+			dmi = dev->mc_list;
+			for (i=0; i<dev->mc_count; i++) {
+				crc = ether_crc_le(6, dmi->dmi_addr) >> 26;
+				if (crc >= 32)
+					gaddr1 |= 1 << (crc-32);
+				else
+					gaddr2 |= 1 << crc;
+				dmi = dmi->next;
+			}
+			out_be32(&fec->gaddr1, gaddr1);
+			out_be32(&fec->gaddr2, gaddr2);
+		}
+	}
+}
+
+static void __init fec_str2mac(char *str, unsigned char *mac)
+{
+	int i;
+	u64 val64;
+
+	val64 = simple_strtoull(str, NULL, 16);
+
+	for (i = 0; i < 6; i++)
+		mac[5-i] = val64 >> (i*8);
+}
+
+int __init mpc52xx_fec_mac_setup(char *mac_address)
+{
+	fec_str2mac(mac_address, mpc52xx_fec_mac_addr);
+	return 0;
+}
+
+__setup("mpc52xx_mac=", mpc52xx_fec_mac_setup);
+
+static void fec_hw_init(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	bd_t *bd = (bd_t *) &__res;
+
+	out_be32(&fec->op_pause, 0x00010020);
+	out_be32(&fec->rfifo_cntrl, 0x0f000000);
+	out_be32(&fec->rfifo_alarm, 0x0000030c);
+	out_be32(&fec->tfifo_cntrl, 0x0f000000);
+	out_be32(&fec->tfifo_alarm, 0x00000100);
+	out_be32(&fec->x_wmrk, 0x3);		/* xmit fifo watermark = 256 */
+	out_be32(&fec->xmit_fsm, 0x03000000);	/* enable crc generation */
+	out_be32(&fec->iaddr1, 0x00000000);	/* No individual filter */
+	out_be32(&fec->iaddr2, 0x00000000);	/* No individual filter */
+
+	priv->phy_speed = ((bd->bi_ipbfreq >> 20) / 5) << 1;
+
+	fec_restart(dev, 0);	/* always use half duplex mode only */
+	/*
+	 * Read MIB counters in order to reset them,
+	 * then zero all the stats fields in memory
+	 */
+	fec_update_stat(dev);
+}
+
+
+static void fec_reinit(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	static void fec_update_stat(struct net_device *);
+
+	netif_stop_queue(dev);
+	out_be32(&fec->imask, 0x0);
+
+	/* Disable the rx and tx tasks. */
+	sdma_disable(priv->rx_sdma);
+	sdma_disable(priv->tx_sdma);
+
+	/* Stop FEC */
+	out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~0x2);
+
+	/* Restart the DMA tasks */
+	sdma_fec_rx_init(priv->rx_sdma, priv->rx_fifo, FEC_RX_BUFFER_SIZE);
+	sdma_fec_tx_init(priv->tx_sdma, priv->tx_fifo);
+	fec_hw_init(dev);
+
+	if (priv->sequence_done) {		 /* redo the fec_open() */
+		fec_free_rx_buffers(priv->rx_sdma);
+		fec_open(dev);
+	}
+	return;
+}
+
+
+/* ======================================================================== */
+/* OCP Driver                                                               */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_fec_probe(struct ocp_device *ocp)
+{
+	int ret;
+	struct net_device *dev;
+	struct fec_priv *priv = NULL;
+
+	/* Reserve FEC control zone */
+	if (!request_mem_region(ocp->def->paddr, sizeof(struct mpc52xx_fec),
+	                        "mpc52xx_fec"))
+		return -EBUSY;
+
+	/* Get the ether dev & it's private zone */
+	dev = alloc_etherdev(sizeof(struct fec_priv));
+	if (!dev) {
+		ret = -ENOMEM;
+		goto probe_error;
+	}
+	
+	priv = (struct fec_priv *)dev->priv;
+	
+	/* Init ether dev with what we have */
+	dev->open		= fec_open;
+	dev->stop		= fec_close;
+	dev->hard_start_xmit	= fec_hard_start_xmit;
+	dev->do_ioctl		= fec_ioctl;
+	dev->get_stats		= fec_get_stats;
+	dev->set_mac_address	= fec_set_mac_address;
+	dev->set_multicast_list = fec_set_multicast_list;
+	dev->tx_timeout		= fec_tx_timeout;
+	dev->watchdog_timeo	= FEC_WATCHDOG_TIMEOUT;
+	dev->flags &= ~IFF_RUNNING;
+	dev->base_addr		= ocp->def->paddr;
+
+	priv->rx_fifo = dev->base_addr + FIELD_OFFSET(mpc52xx_fec,rfifo_data);
+	priv->tx_fifo = dev->base_addr + FIELD_OFFSET(mpc52xx_fec,tfifo_data);
+	priv->t_irq = priv->r_irq = dev->irq = -1; /* IRQ are free for now */
+	
+	spin_lock_init(&priv->lock);
+
+	/* ioremap the zones */
+	priv->fec = (struct mpc52xx_fec *)
+		ioremap(ocp->def->paddr, sizeof(struct mpc52xx_fec));
+	
+	if (!priv->fec) {
+		ret = -ENOMEM;
+		goto probe_error;
+	}
+	
+	/* SDMA init */
+	priv->rx_sdma = sdma_alloc(FEC_RX_NUM_BD);
+	priv->tx_sdma = sdma_alloc(FEC_TX_NUM_BD);
+	
+	if (!priv->rx_sdma || !priv->tx_sdma) {
+		ret = -ENOMEM;
+		goto probe_error;
+	}
+
+	ret = sdma_fec_rx_init(priv->rx_sdma, priv->rx_fifo,FEC_RX_BUFFER_SIZE);
+	if (ret < 0)
+		goto probe_error;
+
+	ret = sdma_fec_tx_init(priv->tx_sdma, priv->tx_fifo);
+	if (ret < 0)
+		goto probe_error;
+
+	/* Get the IRQ we need one by one */
+		/* Control */
+	dev->irq = ocp->def->irq;
+	if (request_irq(dev->irq, &fec_interrupt, SA_INTERRUPT,
+	                "mpc52xx_fec_ctrl", dev)) {
+		printk(KERN_ERR "mpc52xx_fec: ctrl interrupt request failed\n");
+		ret = -EBUSY;
+		dev->irq = -1;	/* Don't try to free it */
+		goto probe_error;
+	}
+
+		/* RX */
+	priv->r_irq = sdma_irq(priv->rx_sdma);
+	if (request_irq(priv->r_irq, &fec_rx_interrupt, SA_INTERRUPT,
+	                "mpc52xx_fec_rx", dev)) {
+		printk(KERN_ERR "mpc52xx_fec: rx interrupt request failed\n");
+		ret = -EBUSY;
+		priv->r_irq = -1;	/* Don't try to free it */
+		goto probe_error;
+	}
+
+		/* TX */
+	priv->t_irq = sdma_irq(priv->tx_sdma);
+	if (request_irq(priv->t_irq, &fec_tx_interrupt, SA_INTERRUPT,
+	                "mpc52xx_fec_tx", dev)) {
+		printk(KERN_ERR "mpc52xx_fec: tx interrupt request failed\n");
+		ret = -EBUSY;
+		priv->t_irq = -1;	/* Don't try to free it */
+		goto probe_error;
+	}
+
+	/* MAC address init */
+	if (memcmp(mpc52xx_fec_mac_addr, null_mac, 6) != 0)
+		memcpy(dev->dev_addr, mpc52xx_fec_mac_addr, 6);
+	else
+		fec_get_paddr(dev, dev->dev_addr);
+
+	/* Hardware init */
+	fec_hw_init(dev);
+
+	/* Register the new network device */
+	ret = register_netdev(dev);
+	if(ret < 0)
+		goto probe_error;
+
+	/* MII init : After register ???? */
+	fec_mii_init(dev);
+	
+	/* We're done ! */
+	ocp_set_drvdata(ocp, dev);
+
+	return 0;
+
+
+	/* Error handling - free everything that might be allocated */
+probe_error:
+
+	if (dev) {
+		if (priv->rx_sdma)	sdma_free(priv->rx_sdma);
+		if (priv->tx_sdma)	sdma_free(priv->tx_sdma);
+		
+		if (dev->irq >= 0)	free_irq(dev->irq, dev);
+		if (priv->r_irq >= 0)	free_irq(priv->r_irq, dev);
+		if (priv->t_irq >= 0)	free_irq(priv->t_irq, dev);
+
+		if (priv->fec)		iounmap(priv->fec);
+	
+		free_netdev(dev);
+	}
+	
+	release_mem_region(ocp->def->paddr, sizeof(struct mpc52xx_fec));
+
+	return ret;
+}
+
+static void
+mpc52xx_fec_remove(struct ocp_device *ocp)
+{
+	struct net_device *dev;
+	struct fec_priv *priv;
+	
+	dev = (struct net_device *) ocp_get_drvdata(ocp);
+	if (!dev)
+		return;
+	priv = (struct fec_priv *) dev->priv;
+
+	unregister_netdev(dev);
+	
+	free_irq(dev->irq, dev);
+	free_irq(priv->r_irq, dev);
+	free_irq(priv->t_irq, dev);
+
+	iounmap(priv->fec);
+	
+	release_mem_region(dev->base_addr, sizeof(struct mpc52xx_fec));
+
+	free_netdev(dev);
+	
+	ocp_set_drvdata(ocp, NULL);
+}
+
+static struct ocp_device_id mpc52xx_fec_ids[] __devinitdata = {
+	{ .vendor = OCP_VENDOR_FREESCALE, .function = OCP_FUNC_FEC_MPC52xx },
+	{ .vendor = OCP_VENDOR_INVALID /* Terminating entry */ }
+};
+
+MODULE_DEVICE_TABLE(ocp, mpc52xx_fec_ids);
+
+static struct ocp_driver mpc52xx_fec_ocp_driver = {
+	.name		= "mpc52xx_fec",
+	.id_table	= mpc52xx_fec_ids,
+	.probe		= mpc52xx_fec_probe,
+	.remove		= mpc52xx_fec_remove,
+#ifdef CONFIG_PM
+/*	.suspend	= mpc52xx_fec_suspend,	TODO */
+/*	.resume		= mpc52xx_fec_resume,	TODO */
+#endif
+};
+
+
+/* ======================================================================== */
+/* Module                                                                   */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_fec_init(void)
+{
+	return ocp_register_driver(&mpc52xx_fec_ocp_driver);
+}
+
+static void __exit
+mpc52xx_fec_exit(void)
+{
+	ocp_unregister_driver(&mpc52xx_fec_ocp_driver);
+}
+
+
+module_init(mpc52xx_fec_init);
+module_exit(mpc52xx_fec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dale Farnsworth");
+MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC");
diff -Nru a/drivers/net/fec_mpc52xx/fec.h b/drivers/net/fec_mpc52xx/fec.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/net/fec_mpc52xx/fec.h	2004-11-20 23:26:34 +01:00
@@ -0,0 +1,308 @@
+/*
+ * drivers/net/fec_mpc52xx/fec.h
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) 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.
+ */
+
+#ifndef __DRIVERS_NET_MPC52XX_FEC_H__
+#define __DRIVERS_NET_MPC52XX_FEC_H__
+
+/* Tunable constant */
+/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */
+#define FEC_RX_BUFFER_SIZE	1522	/* max receive packet size */
+#define FEC_RX_NUM_BD		64
+#define FEC_TX_NUM_BD		64
+
+#define FEC_RESET_DELAY		50 	/* uS */
+
+#define FEC_WATCHDOG_TIMEOUT	((400*HZ)/1000)
+
+struct fec_priv {
+	int full_duplex;
+	int tx_full;
+	int r_irq;
+	int t_irq;
+	u32 last_transmit_time;
+	struct mpc52xx_fec *fec;
+	struct sdma *rx_sdma;
+	struct sdma *tx_sdma;
+	spinlock_t lock;
+	unsigned long open_time;
+	struct net_device_stats stats;
+#ifdef CONFIG_USE_MDIO
+	uint phy_id;
+	uint phy_id_done;
+	uint phy_status;
+	uint phy_speed;
+	phy_info_t *phy;
+	struct tasklet_struct phy_task;
+	uint sequence_done;
+	uint phy_addr;
+	struct timer_list phy_timer_list;
+	u16 old_status;
+	phys_addr_t rx_fifo;
+	phys_addr_t tx_fifo;
+#endif	/* CONFIG_USE_MDIO */
+};
+
+
+/* ======================================================================== */
+/* Hardware register sets & bits                                            */
+/* ======================================================================== */
+
+struct mpc52xx_fec {
+	u32 fec_id;			/* FEC + 0x000 */
+	u32 ievent;			/* FEC + 0x004 */
+	u32 imask;			/* FEC + 0x008 */
+
+	u32 reserved0[1];		/* FEC + 0x00C */
+	u32 r_des_active;		/* FEC + 0x010 */
+	u32 x_des_active;		/* FEC + 0x014 */
+	u32 r_des_active_cl;		/* FEC + 0x018 */
+	u32 x_des_active_cl;		/* FEC + 0x01C */
+	u32 ivent_set;			/* FEC + 0x020 */
+	u32 ecntrl;			/* FEC + 0x024 */
+
+	u32 reserved1[6];		/* FEC + 0x028-03C */
+	u32 mii_data;			/* FEC + 0x040 */
+	u32 mii_speed;			/* FEC + 0x044 */
+	u32 mii_status;			/* FEC + 0x048 */
+
+	u32 reserved2[5];		/* FEC + 0x04C-05C */
+	u32 mib_data;			/* FEC + 0x060 */
+	u32 mib_control;		/* FEC + 0x064 */
+
+	u32 reserved3[6];		/* FEC + 0x068-7C */
+	u32 r_activate;			/* FEC + 0x080 */
+	u32 r_cntrl;			/* FEC + 0x084 */
+	u32 r_hash;			/* FEC + 0x088 */
+	u32 r_data;			/* FEC + 0x08C */
+	u32 ar_done;			/* FEC + 0x090 */
+	u32 r_test;			/* FEC + 0x094 */
+	u32 r_mib;			/* FEC + 0x098 */
+	u32 r_da_low;			/* FEC + 0x09C */
+	u32 r_da_high;			/* FEC + 0x0A0 */
+
+	u32 reserved4[7];		/* FEC + 0x0A4-0BC */
+	u32 x_activate;			/* FEC + 0x0C0 */
+	u32 x_cntrl;			/* FEC + 0x0C4 */
+	u32 backoff;			/* FEC + 0x0C8 */
+	u32 x_data;			/* FEC + 0x0CC */
+	u32 x_status;			/* FEC + 0x0D0 */
+	u32 x_mib;			/* FEC + 0x0D4 */
+	u32 x_test;			/* FEC + 0x0D8 */
+	u32 fdxfc_da1;			/* FEC + 0x0DC */
+	u32 fdxfc_da2;			/* FEC + 0x0E0 */
+	u32 paddr1;			/* FEC + 0x0E4 */
+	u32 paddr2;			/* FEC + 0x0E8 */
+	u32 op_pause;			/* FEC + 0x0EC */
+
+	u32 reserved5[4];		/* FEC + 0x0F0-0FC */
+	u32 instr_reg;			/* FEC + 0x100 */
+	u32 context_reg;		/* FEC + 0x104 */
+	u32 test_cntrl;			/* FEC + 0x108 */
+	u32 acc_reg;			/* FEC + 0x10C */
+	u32 ones;			/* FEC + 0x110 */
+	u32 zeros;			/* FEC + 0x114 */
+	u32 iaddr1;			/* FEC + 0x118 */
+	u32 iaddr2;			/* FEC + 0x11C */
+	u32 gaddr1;			/* FEC + 0x120 */
+	u32 gaddr2;			/* FEC + 0x124 */
+	u32 random;			/* FEC + 0x128 */
+	u32 rand1;			/* FEC + 0x12C */
+	u32 tmp;			/* FEC + 0x130 */
+
+	u32 reserved6[3];		/* FEC + 0x134-13C */
+	u32 fifo_id;			/* FEC + 0x140 */
+	u32 x_wmrk;			/* FEC + 0x144 */
+	u32 fcntrl;			/* FEC + 0x148 */
+	u32 r_bound;			/* FEC + 0x14C */
+	u32 r_fstart;			/* FEC + 0x150 */
+	u32 r_count;			/* FEC + 0x154 */
+	u32 r_lag;			/* FEC + 0x158 */
+	u32 r_read;			/* FEC + 0x15C */
+	u32 r_write;			/* FEC + 0x160 */
+	u32 x_count;			/* FEC + 0x164 */
+	u32 x_lag;			/* FEC + 0x168 */
+	u32 x_retry;			/* FEC + 0x16C */
+	u32 x_write;			/* FEC + 0x170 */
+	u32 x_read;			/* FEC + 0x174 */
+
+	u32 reserved7[2];		/* FEC + 0x178-17C */
+	u32 fm_cntrl;			/* FEC + 0x180 */
+	u32 rfifo_data;			/* FEC + 0x184 */
+	u32 rfifo_status;		/* FEC + 0x188 */
+	u32 rfifo_cntrl;		/* FEC + 0x18C */
+	u32 rfifo_lrf_ptr;		/* FEC + 0x190 */
+	u32 rfifo_lwf_ptr;		/* FEC + 0x194 */
+	u32 rfifo_alarm;		/* FEC + 0x198 */
+	u32 rfifo_rdptr;		/* FEC + 0x19C */
+	u32 rfifo_wrptr;		/* FEC + 0x1A0 */
+	u32 tfifo_data;			/* FEC + 0x1A4 */
+	u32 tfifo_status;		/* FEC + 0x1A8 */
+	u32 tfifo_cntrl;		/* FEC + 0x1AC */
+	u32 tfifo_lrf_ptr;		/* FEC + 0x1B0 */
+	u32 tfifo_lwf_ptr;		/* FEC + 0x1B4 */
+	u32 tfifo_alarm;		/* FEC + 0x1B8 */
+	u32 tfifo_rdptr;		/* FEC + 0x1BC */
+	u32 tfifo_wrptr;		/* FEC + 0x1C0 */
+
+	u32 reset_cntrl;		/* FEC + 0x1C4 */
+	u32 xmit_fsm;			/* FEC + 0x1C8 */
+
+	u32 reserved8[3];		/* FEC + 0x1CC-1D4 */
+	u32 rdes_data0;			/* FEC + 0x1D8 */
+	u32 rdes_data1;			/* FEC + 0x1DC */
+	u32 r_length;			/* FEC + 0x1E0 */
+	u32 x_length;			/* FEC + 0x1E4 */
+	u32 x_addr;			/* FEC + 0x1E8 */
+	u32 cdes_data;			/* FEC + 0x1EC */
+	u32 status;			/* FEC + 0x1F0 */
+	u32 dma_control;		/* FEC + 0x1F4 */
+	u32 des_cmnd;			/* FEC + 0x1F8 */
+	u32 data;			/* FEC + 0x1FC */
+
+	u32 rmon_t_drop;		/* FEC + 0x200 */
+	u32 rmon_t_packets;		/* FEC + 0x204 */
+	u32 rmon_t_bc_pkt;		/* FEC + 0x208 */
+	u32 rmon_t_mc_pkt;		/* FEC + 0x20C */
+	u32 rmon_t_crc_align;		/* FEC + 0x210 */
+	u32 rmon_t_undersize;		/* FEC + 0x214 */
+	u32 rmon_t_oversize;		/* FEC + 0x218 */
+	u32 rmon_t_frag;		/* FEC + 0x21C */
+	u32 rmon_t_jab;			/* FEC + 0x220 */
+	u32 rmon_t_col;			/* FEC + 0x224 */
+	u32 rmon_t_p64;			/* FEC + 0x228 */
+	u32 rmon_t_p65to127;		/* FEC + 0x22C */
+	u32 rmon_t_p128to255;		/* FEC + 0x230 */
+	u32 rmon_t_p256to511;		/* FEC + 0x234 */
+	u32 rmon_t_p512to1023;		/* FEC + 0x238 */
+	u32 rmon_t_p1024to2047;		/* FEC + 0x23C */
+	u32 rmon_t_p_gte2048;		/* FEC + 0x240 */
+	u32 rmon_t_octets;		/* FEC + 0x244 */
+	u32 ieee_t_drop;		/* FEC + 0x248 */
+	u32 ieee_t_frame_ok;		/* FEC + 0x24C */
+	u32 ieee_t_1col;		/* FEC + 0x250 */
+	u32 ieee_t_mcol;		/* FEC + 0x254 */
+	u32 ieee_t_def;			/* FEC + 0x258 */
+	u32 ieee_t_lcol;		/* FEC + 0x25C */
+	u32 ieee_t_excol;		/* FEC + 0x260 */
+	u32 ieee_t_macerr;		/* FEC + 0x264 */
+	u32 ieee_t_cserr;		/* FEC + 0x268 */
+	u32 ieee_t_sqe;			/* FEC + 0x26C */
+	u32 t_fdxfc;			/* FEC + 0x270 */
+	u32 ieee_t_octets_ok;		/* FEC + 0x274 */
+
+	u32 reserved9[2];		/* FEC + 0x278-27C */
+	u32 rmon_r_drop;		/* FEC + 0x280 */
+	u32 rmon_r_packets;		/* FEC + 0x284 */
+	u32 rmon_r_bc_pkt;		/* FEC + 0x288 */
+	u32 rmon_r_mc_pkt;		/* FEC + 0x28C */
+	u32 rmon_r_crc_align;		/* FEC + 0x290 */
+	u32 rmon_r_undersize;		/* FEC + 0x294 */
+	u32 rmon_r_oversize;		/* FEC + 0x298 */
+	u32 rmon_r_frag;		/* FEC + 0x29C */
+	u32 rmon_r_jab;			/* FEC + 0x2A0 */
+
+	u32 rmon_r_resvd_0;		/* FEC + 0x2A4 */
+
+	u32 rmon_r_p64;			/* FEC + 0x2A8 */
+	u32 rmon_r_p65to127;		/* FEC + 0x2AC */
+	u32 rmon_r_p128to255;		/* FEC + 0x2B0 */
+	u32 rmon_r_p256to511;		/* FEC + 0x2B4 */
+	u32 rmon_r_p512to1023;		/* FEC + 0x2B8 */
+	u32 rmon_r_p1024to2047;		/* FEC + 0x2BC */
+	u32 rmon_r_p_gte2048;		/* FEC + 0x2C0 */
+	u32 rmon_r_octets;		/* FEC + 0x2C4 */
+	u32 ieee_r_drop;		/* FEC + 0x2C8 */
+	u32 ieee_r_frame_ok;		/* FEC + 0x2CC */
+	u32 ieee_r_crc;			/* FEC + 0x2D0 */
+	u32 ieee_r_align;		/* FEC + 0x2D4 */
+	u32 r_macerr;			/* FEC + 0x2D8 */
+	u32 r_fdxfc;			/* FEC + 0x2DC */
+	u32 ieee_r_octets_ok;		/* FEC + 0x2E0 */
+
+	u32 reserved10[6];		/* FEC + 0x2E4-2FC */
+
+	u32 reserved11[64];		/* FEC + 0x300-3FF */
+};
+
+#define	FEC_MIB_DISABLE			0x80000000
+
+#define	FEC_IEVENT_HBERR		0x80000000
+#define	FEC_IEVENT_BABR			0x40000000
+#define	FEC_IEVENT_BABT			0x20000000
+#define	FEC_IEVENT_GRA			0x10000000
+#define	FEC_IEVENT_TFINT		0x08000000
+#define	FEC_IEVENT_MII			0x00800000
+#define	FEC_IEVENT_LATE_COL		0x00200000
+#define	FEC_IEVENT_COL_RETRY_LIM	0x00100000
+#define	FEC_IEVENT_XFIFO_UN		0x00080000
+#define	FEC_IEVENT_XFIFO_ERROR		0x00040000
+#define	FEC_IEVENT_RFIFO_ERROR		0x00020000
+
+#define	FEC_IMASK_HBERR			0x80000000
+#define	FEC_IMASK_BABR			0x40000000
+#define	FEC_IMASK_BABT			0x20000000
+#define	FEC_IMASK_GRA			0x10000000
+#define	FEC_IMASK_MII			0x00800000
+#define	FEC_IMASK_LATE_COL		0x00200000
+#define	FEC_IMASK_COL_RETRY_LIM		0x00100000
+#define	FEC_IMASK_XFIFO_UN		0x00080000
+#define	FEC_IMASK_XFIFO_ERROR		0x00040000
+#define	FEC_IMASK_RFIFO_ERROR		0x00020000
+
+#define	FEC_RCNTRL_MAX_FL_SHIFT		16
+#define	FEC_RCNTRL_LOOP			0x01
+#define	FEC_RCNTRL_DRT			0x02
+#define	FEC_RCNTRL_MII_MODE		0x04
+#define	FEC_RCNTRL_PROM			0x08
+#define	FEC_RCNTRL_BC_REJ		0x10
+#define	FEC_RCNTRL_FCE			0x20
+
+#define	FEC_TCNTRL_GTS			0x00000001
+#define	FEC_TCNTRL_HBC			0x00000002
+#define	FEC_TCNTRL_FDEN			0x00000004
+#define	FEC_TCNTRL_TFC_PAUSE		0x00000008
+#define	FEC_TCNTRL_RFC_PAUSE		0x00000010
+
+#define	FEC_ECNTRL_RESET		0x00000001
+#define	FEC_ECNTRL_ETHER_EN		0x00000002
+
+struct mibCounters {
+	unsigned int byteReceived;
+	unsigned int byteSent;
+	unsigned int framesReceived;
+	unsigned int framesSent;
+	unsigned int totalByteReceived;
+	unsigned int totalFramesReceived;
+	unsigned int broadcastFramesReceived;
+	unsigned int multicastFramesReceived;
+	unsigned int cRCError;
+	unsigned int oversizeFrames;
+	unsigned int fragments;
+	unsigned int jabber;
+	unsigned int collision;
+	unsigned int lateCollision;
+	unsigned int frames64;
+	unsigned int frames65_127;
+	unsigned int frames128_255;
+	unsigned int frames256_511;
+	unsigned int frames512_1023;
+	unsigned int frames1024_MaxSize;
+	unsigned int macRxError;
+	unsigned int droppedFrames;
+	unsigned int outMulticastFrames;
+	unsigned int outBroadcastFrames;
+	unsigned int undersizeFrames;
+};
+
+
+#endif	/* __DRIVERS_NET_MPC52XX_FEC_H__ */
diff -Nru a/drivers/net/fec_mpc52xx/fec_phy.c b/drivers/net/fec_mpc52xx/fec_phy.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/net/fec_mpc52xx/fec_phy.c	2004-11-20 23:26:34 +01:00
@@ -0,0 +1,526 @@
+/*
+ * arch/ppc/52xx_io/fec_phy.c
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ * Based heavily on the MII support for the MPC8xx by Dan Malek
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) 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/kernel.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+#include <syslib/bestcomm/bestcomm.h>
+#include <syslib/bestcomm/fec.h>
+#include "fec_phy.h"
+#include "fec.h"
+
+static int mpc52xx_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr);
+
+/* MII processing.  We keep this as simple as possible.  Requests are
+ * placed on the list (if there is room).  When the request is finished
+ * by the MII, an optional function may be called.
+ */
+typedef struct mii_list {
+	uint	mii_regval;
+	void	(*mii_func)(uint val, struct net_device *dev, uint data);
+	struct	mii_list *mii_next;
+	uint	mii_data;
+} mii_list_t;
+
+#define		NMII	20
+mii_list_t	mii_cmds[NMII];
+mii_list_t	*mii_free;
+mii_list_t	*mii_head;
+mii_list_t	*mii_tail;
+
+typedef struct mdio_read_data {
+	__u16 regval;
+	struct task_struct *sleeping_task;
+} mdio_read_data_t;
+
+static int mii_queue(struct net_device *dev, int request,
+		void (*func)(uint, struct net_device *, uint), uint data);
+
+/* 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
+
+/* Register definitions for the PHY.
+*/
+
+#define MII_REG_CR	 0	/* Control Register */
+#define MII_REG_SR	 1	/* Status Register */
+#define MII_REG_PHYIR1	 2	/* PHY Identification Register 1 */
+#define MII_REG_PHYIR2	 3	/* PHY Identification Register 2 */
+#define MII_REG_ANAR	 4	/* A-N Advertisement Register */
+#define MII_REG_ANLPAR	 5	/* A-N Link Partner Ability Register */
+#define MII_REG_ANER	 6	/* A-N Expansion Register */
+#define MII_REG_ANNPTR	 7	/* A-N Next Page Transmit Register */
+#define MII_REG_ANLPRNPR 8	/* A-N Link Partner Received Next Page Reg. */
+
+/* values for 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 */
+
+void fec_mii(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	mii_list_t	*mip;
+	uint		mii_reg;
+
+	mii_reg = in_be32(&fec->mii_data);
+
+	if ((mip = mii_head) == NULL) {
+		printk(KERN_ERR "MII and no head!\n");
+		return;
+	}
+
+	if (mip->mii_func != NULL)
+		(*(mip->mii_func))(mii_reg, dev, mip->mii_data);
+
+	mii_head = mip->mii_next;
+	mip->mii_next = mii_free;
+	mii_free = mip;
+
+	if ((mip = mii_head) != NULL)
+		out_be32(&fec->mii_data, mip->mii_regval);
+}
+
+static int mii_queue(struct net_device *dev, int regval,
+				void (*func)(uint, struct net_device *, uint),
+				uint data)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	mii_list_t	*mip;
+	int		retval;
+
+	/* Add PHY address to register command.
+	*/
+	regval |= priv->phy_addr << 23;
+
+	retval = 0;
+
+	if ((mip = mii_free) != NULL) {
+		mii_free = mip->mii_next;
+		mip->mii_regval = regval;
+		mip->mii_func = func;
+		mip->mii_next = NULL;
+		mip->mii_data = data;
+		if (mii_head) {
+			mii_tail->mii_next = mip;
+			mii_tail = mip;
+		} else {
+			mii_head = mii_tail = mip;
+			out_be32(&fec->mii_data, regval);
+		}
+	} else
+		retval = 1;
+
+	return retval;
+}
+
+static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
+{
+	int k;
+
+	if (!c)
+		return;
+
+	for (k = 0; (c+k)->mii_data != mk_mii_end; k++)
+		mii_queue(dev, (c+k)->mii_data, (c+k)->funct, 0);
+}
+
+static void mii_parse_sr(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	uint s = priv->phy_status;
+
+	s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
+
+	if (mii_reg & 0x0004)
+		s |= PHY_STAT_LINK;
+	if (mii_reg & 0x0010)
+		s |= PHY_STAT_FAULT;
+	if (mii_reg & 0x0020)
+		s |= PHY_STAT_ANC;
+
+	priv->phy_status = s;
+}
+
+static void mii_parse_cr(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	uint s = priv->phy_status;
+
+	s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP);
+
+	if (mii_reg & 0x1000)
+		s |= PHY_CONF_ANE;
+	if (mii_reg & 0x4000)
+		s |= PHY_CONF_LOOP;
+
+	priv->phy_status = s;
+}
+
+static void mii_parse_anar(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	uint s = priv->phy_status;
+
+	s &= ~(PHY_CONF_SPMASK);
+
+	if (mii_reg & 0x0020)
+		s |= PHY_CONF_10HDX;
+	if (mii_reg & 0x0040)
+		s |= PHY_CONF_10FDX;
+	if (mii_reg & 0x0080)
+		s |= PHY_CONF_100HDX;
+	if (mii_reg & 0x0100)
+		s |= PHY_CONF_100FDX;
+
+	priv->phy_status = s;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Generic PHY support.  Should work for all PHYs, but does not support link
+ * change interrupts.
+ */
+static phy_info_t phy_info_generic = {
+	0x00000000, /* 0-->match any PHY */
+	"GENERIC",
+
+	(const phy_cmd_t []) {	/* config */
+		/* advertise only half-duplex capabilities */
+		{ mk_mii_write(MII_ADVERTISE, MII_ADVERTISE_HALF),
+			mii_parse_anar },
+
+		/* enable auto-negotiation */
+		{ mk_mii_write(MII_BMCR, BMCR_ANENABLE), mii_parse_cr },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {	/* startup */
+		/* restart auto-negotiation */
+		{ mk_mii_write(MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)),
+			NULL },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) { /* ack_int */
+		/* We don't actually use the ack_int table with a generic
+		 * PHY, but putting a reference to mii_parse_sr here keeps
+		 * us from getting a compiler warning about unused static
+		 * functions in the case where we only compile in generic
+		 * PHY support.
+		 */
+		{ mk_mii_read(MII_BMSR), mii_parse_sr },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {	/* shutdown */
+		{ mk_mii_end, }
+	},
+};
+/* -------------------------------------------------------------------- */
+
+/* register definitions for the 971 */
+
+#define MII_LXT971_PCR	16	/* Port Control Register	*/
+#define MII_LXT971_SR2	17	/* Status Register 2		*/
+#define MII_LXT971_IER	18	/* Interrupt Enable Register	*/
+#define MII_LXT971_ISR	19	/* Interrupt Status Register	*/
+#define MII_LXT971_LCR	20	/* LED Control Register		*/
+#define MII_LXT971_TCR	30	/* Transmit Control Register	*/
+
+static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	uint s = priv->phy_status;
+
+	s &= ~(PHY_STAT_SPMASK);
+
+	if (mii_reg & 0x4000) {
+		if (mii_reg & 0x0200)
+			s |= PHY_STAT_100FDX;
+		else
+			s |= PHY_STAT_100HDX;
+	} else {
+		if (mii_reg & 0x0200)
+			s |= PHY_STAT_10FDX;
+		else
+			s |= PHY_STAT_10HDX;
+	}
+	if (mii_reg & 0x0008)
+		s |= PHY_STAT_FAULT;
+
+	priv->phy_status = s;
+}
+
+static phy_info_t phy_info_lxt971 = {
+	0x0001378e,
+	"LXT971",
+
+	(const phy_cmd_t []) {	/* config */
+		{ mk_mii_write(MII_REG_ANAR, 0x0A1), NULL }, /* 10/100, HD */
+		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
+		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {	/* startup - enable interrupts */
+		{ mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },
+		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
+
+		/* Somehow does the 971 tell me that the link is down
+		 * the first read after power-up.
+		 * read here to get a valid value in ack_int */
+
+		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) { /* ack_int */
+		/* find out the current status */
+
+		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
+		{ mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
+
+		/* we only need to read ISR to acknowledge */
+
+		{ mk_mii_read(MII_LXT971_ISR), NULL },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {	/* shutdown - disable interrupts */
+		{ mk_mii_write(MII_LXT971_IER, 0x0000), NULL },
+		{ mk_mii_end, }
+	},
+};
+
+static phy_info_t *phy_info[] = {
+	&phy_info_lxt971,
+	/* Generic PHY support.  This must be the last PHY in the table.
+	 * It will be used to support any PHY that doesn't match a previous
+	 * entry in the table.
+	 */
+	&phy_info_generic,
+	NULL
+};
+
+static void mii_display_config(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	uint s = priv->phy_status;
+
+	printk(KERN_INFO "%s: config: auto-negotiation ", dev->name);
+
+	if (s & PHY_CONF_ANE)
+		printk("on");
+	else
+		printk("off");
+
+	if (s & PHY_CONF_100FDX)
+		printk(", 100FDX");
+	if (s & PHY_CONF_100HDX)
+		printk(", 100HDX");
+	if (s & PHY_CONF_10FDX)
+		printk(", 10FDX");
+	if (s & PHY_CONF_10HDX)
+		printk(", 10HDX");
+	if (!(s & PHY_CONF_SPMASK))
+		printk(", No speed/duplex selected?");
+
+	if (s & PHY_CONF_LOOP)
+		printk(", loopback enabled");
+
+	printk(".\n");
+
+	priv->sequence_done = 1;
+}
+
+static void mii_queue_config(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+
+	priv->phy_task.func = (void *)mii_display_config;
+	priv->phy_task.data = (unsigned long)dev;
+	tasklet_schedule(&priv->phy_task);
+}
+
+
+phy_cmd_t phy_cmd_config[] =  { { mk_mii_read(MII_REG_CR), mii_queue_config },
+				{ mk_mii_end, } };
+
+
+/* Read remainder of PHY ID.
+*/
+static void mii_discover_phy3(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	int	i;
+
+	priv->phy_id |= (mii_reg & 0xffff);
+
+	for (i = 0; phy_info[i]; i++) {
+		if (phy_info[i]->id == (priv->phy_id >> 4) || !phy_info[i]->id)
+			break;
+		if (phy_info[i]->id == 0)	/* check generic entry */
+			break;
+	}
+
+	if (!phy_info[i])
+		panic("%s: PHY id 0x%08x is not supported!\n",
+			dev->name, priv->phy_id);
+
+	priv->phy = phy_info[i];
+	priv->phy_id_done = 1;
+
+	printk(KERN_INFO "%s: Phy @ 0x%x, type %s (0x%08x)\n",
+		dev->name, priv->phy_addr, priv->phy->name, priv->phy_id);
+}
+
+/* Scan all of the MII PHY addresses looking for someone to respond
+ * with a valid ID.  This usually happens quickly.
+ */
+static void mii_discover_phy(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	uint	phytype;
+
+	if ((phytype = (mii_reg & 0xffff)) != 0xffff) {
+		/* Got first part of ID, now get remainder.
+		*/
+		priv->phy_id = phytype << 16;
+		mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3,
+									0);
+	} else {
+		priv->phy_addr++;
+		if (priv->phy_addr < 32)
+			mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
+							mii_discover_phy, 0);
+		else
+			printk(KERN_ERR "fec: No PHY device found.\n");
+	}
+}
+
+static int mpc52xx_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	__u32 ethcmd;
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof ethcmd))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+		/* Get driver info */
+	case ETHTOOL_GDRVINFO:{
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strncpy(info.driver, "MPC5200 FEC",
+				sizeof info.driver - 1);
+			if (copy_to_user(useraddr, &info, sizeof info))
+				return -EFAULT;
+			return 0;
+		}
+		/* get message-level */
+	case ETHTOOL_GMSGLVL:{
+			struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+			edata.data = 0;	/* XXX */
+			if (copy_to_user(useraddr, &edata, sizeof edata))
+				return -EFAULT;
+			return 0;
+		}
+		/* set message-level */
+	case ETHTOOL_SMSGLVL:{
+			struct ethtool_value edata;
+			if (copy_from_user(&edata, useraddr, sizeof edata))
+				return -EFAULT;
+			return 0;
+		}
+	}
+	return -EOPNOTSUPP;
+}
+
+int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int retval;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		retval = mpc52xx_netdev_ethtool_ioctl(
+					dev, (void *) rq->ifr_data);
+		break;
+
+	default:
+		retval = -EOPNOTSUPP;
+		break;
+	}
+	return retval;
+}
+
+void fec_mii_init(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+	int i;
+
+	for (i=0; i<NMII-1; i++)
+		mii_cmds[i].mii_next = &mii_cmds[i+1];
+	mii_free = mii_cmds;
+
+	/* Queue up command to detect the PHY and initialize the
+	 * remainder of the interface.
+	 */
+	priv->phy_id_done = 0;
+	priv->phy_addr = 0;
+	mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy, 0);
+
+	priv->old_status = 0;
+}
+
+int fec_mii_wait(struct net_device *dev)
+{
+	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+
+	if (!priv->sequence_done) {
+		if (!priv->phy) {
+			printk("KERN_ERR fec_open: PHY not configured\n");
+			return -ENODEV;		/* No PHY we understand */
+		}
+
+		mii_do_cmd(dev, priv->phy->config);
+		mii_do_cmd(dev, phy_cmd_config); /* display configuration */
+		while(!priv->sequence_done)
+			schedule();
+
+		mii_do_cmd(dev, priv->phy->startup);
+	}
+	return 0;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dale Farnsworth");
+MODULE_DESCRIPTION("PHY driver for Motorola MPC52xx FEC");
diff -Nru a/drivers/net/fec_mpc52xx/fec_phy.h b/drivers/net/fec_mpc52xx/fec_phy.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/net/fec_mpc52xx/fec_phy.h	2004-11-20 23:26:35 +01:00
@@ -0,0 +1,73 @@
+/*
+ * arch/ppc/52xx_io/fec_phy.h
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ * Based heavily on the MII support for the MPC8xx by Dan Malek
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) 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.
+ */
+
+#ifdef CONFIG_USE_MDIO
+#define MII_ADVERTISE_HALF	(ADVERTISE_100HALF | ADVERTISE_10HALF | \
+				 ADVERTISE_CSMA)
+
+#define MII_ADVERTISE_ALL	(ADVERTISE_100FULL | ADVERTISE_10FULL | \
+				 MII_ADVERTISE_HALF)
+#ifdef PHY_INTERRUPT
+#define MII_ADVERTISE_DEFAULT	MII_ADVERTISE_ALL
+#else
+#define MII_ADVERTISE_DEFAULT	MII_ADVERTISE_HALF
+#endif
+
+#define MII_RCNTL_MODE		FEC_RCNTRL_MII_MODE
+#define set_phy_speed(fec, s)	out_be32(&fec->mii_speed, s)
+#define FEC_IMASK_ENABLE	0xf0fe0000
+
+typedef struct {
+	uint mii_data;
+	void (*funct)(uint mii_reg, struct net_device *dev, uint data);
+} phy_cmd_t;
+
+typedef struct {
+	uint id;
+	char *name;
+
+	const phy_cmd_t *config;
+	const phy_cmd_t *startup;
+	const phy_cmd_t *ack_int;
+	const phy_cmd_t *shutdown;
+} phy_info_t;
+
+#else
+#define MII_RCNTL_MODE		0
+#define set_phy_speed(fec, s)
+#define FEC_IMASK_ENABLE	0xf07e0000
+#define fec_mii_wait(dev)	0
+#define fec_mii(dev)	printk(KERN_WARNING "unexpected FEC_IEVENT_MII\n")
+#define fec_mii_init(dev)
+#endif	/* CONFIG_USE_MDIO */
+
+/* MII-related definitions */
+#define FEC_MII_DATA_ST		0x40000000	/* Start frame */
+#define FEC_MII_DATA_OP_RD	0x20000000	/* Perform read */
+#define FEC_MII_DATA_OP_WR	0x10000000	/* Perform write */
+#define FEC_MII_DATA_PA_MSK	0x0f800000	/* PHY Address mask */
+#define FEC_MII_DATA_RA_MSK	0x007c0000	/* PHY Register mask */
+#define FEC_MII_DATA_TA		0x00020000	/* Turnaround */
+#define FEC_MII_DATA_DATAMSK	0x00000fff	/* PHY data mask */
+
+#define FEC_MII_DATA_RA_SHIFT	0x12		/* MII reg addr bits */
+#define FEC_MII_DATA_PA_SHIFT	0x17		/* MII PHY addr bits */
+
+#define FEC_MII_SPEED		(5 * 2)
+
+extern void fec_mii_init(struct net_device *dev);
+extern int fec_mii_wait(struct net_device *dev);
+extern void fec_mii(struct net_device *dev);
+
+extern int fec_ioctl(struct net_device *, struct ifreq *rq, int cmd);
diff -Nru a/include/asm-ppc/ocp_ids.h b/include/asm-ppc/ocp_ids.h
--- a/include/asm-ppc/ocp_ids.h	2004-11-11 09:25:52 +01:00
+++ b/include/asm-ppc/ocp_ids.h	2004-11-20 23:26:31 +01:00
@@ -66,6 +66,7 @@
 /* Network 0x0200 - 0x02FF */
 #define OCP_FUNC_EMAC		0x0200
 #define OCP_FUNC_GFAR		0x0201	/* TSEC & FEC */
+#define OCP_FUNC_FEC_MPC52xx	0x0202
 
 /* Bridge devices 0xE00 - 0xEFF */
 #define OCP_FUNC_OPB		0x0E00

[-- Attachment #4: 1.2159-fec-fix-frame-reception.patch --]
[-- Type: text/x-patch, Size: 2263 bytes --]

--- 1.1/drivers/net/fec_mpc52xx/fec.c	2004-11-20 23:26:33 +01:00
+++ 1.2/drivers/net/fec_mpc52xx/fec.c	2005-03-03 16:06:51 +01:00
@@ -175,13 +175,11 @@
 		skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
 		if (skb == 0)
 			goto eagain;
-		skb->dev = dev;
-		skb_put(skb, FEC_RX_BUFFER_SIZE);
 
 		/* zero out the initial receive buffers to aid debugging */
 		memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
 		data = (void *)virt_to_phys(skb->data);
-		sdma_submit_buffer(priv->rx_sdma, skb, data, skb->len);
+		sdma_submit_buffer(priv->rx_sdma, skb, data, FEC_RX_BUFFER_SIZE);
 	}
 
 	fec_set_paddr(dev, dev->dev_addr);
@@ -307,8 +305,7 @@
 	struct fec_priv *priv = (struct fec_priv *)dev->priv;
 	struct sk_buff *skb;
 	struct sk_buff *rskb;
-	void *data;
-	int length;
+	int status;
 
 	for (;;) {
 		sdma_clear_irq(priv->rx_sdma);
@@ -316,30 +313,44 @@
 		if (!sdma_buffer_done(priv->rx_sdma))
 			break;
 
-		rskb = sdma_retrieve_buffer(priv->rx_sdma, &length);
-		/* length included sizeof CRC32 */
-		skb_trim(rskb, length - sizeof(u32));
+		rskb = sdma_retrieve_buffer(priv->rx_sdma, &status);
+
+		/* Test for errors in received frame */
+		if (status & 0x370000) { 
+			/* Drop packet and reuse the buffer */
+			sdma_submit_buffer(
+				priv->rx_sdma, rskb,
+				(void *)virt_to_phys(rskb->data),
+				FEC_RX_BUFFER_SIZE );
+			
+			priv->stats.rx_dropped++;
+
+			continue;
+		}
 
 		/* allocate replacement skb */
 		skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
 		if (skb) {
+			/* Process the received skb */
+			int length = (status & ((1<<11) - 1)) - sizeof(u32);
+			skb_put(rskb, length);	/* length included CRC32 */
+
+			rskb->dev = dev;
 			rskb->protocol = eth_type_trans(rskb, dev);
 			netif_rx(rskb);
 			dev->last_rx = jiffies;
 		} else {
+			/* Can't get a new one : reuse the same & drop pkt */
 			printk(KERN_NOTICE
 				"%s: Memory squeeze, dropping packet.\n",
 				dev->name);
 			priv->stats.rx_dropped++;
 
-			skb_trim(rskb, 0);
 			skb = rskb;
 		}
 
-		skb->dev = dev;
-		skb_put(skb, FEC_RX_BUFFER_SIZE);
-		data = (void *)virt_to_phys(skb->data);
-		sdma_submit_buffer(priv->rx_sdma, skb, data, skb->len);
+		sdma_submit_buffer( priv->rx_sdma, skb,
+			(void *)virt_to_phys(skb->data), FEC_RX_BUFFER_SIZE );
 	}
 
 	return IRQ_HANDLED;

[-- Attachment #5: 1.2160-fix-typo-bestcomm-fec.patch --]
[-- Type: text/x-patch, Size: 372 bytes --]

--- a/arch/ppc/syslib/bestcomm/fec.c	2004-11-20 23:21:03 +01:00
+++ b/arch/ppc/syslib/bestcomm/fec.c	2005-03-22 11:21:01 +01:00
@@ -155,7 +155,7 @@
 	/* clear pending interrupt bits */
 	out_be32(&sdma->IntPend, 1<<tasknum);
 
-	out_8(&sdma->ipr[SDMA_INITIATOR_FEC_TX], SDMA_IPR_FEC_RX);
+	out_8(&sdma->ipr[SDMA_INITIATOR_FEC_TX], SDMA_IPR_FEC_TX);
 
 	return tasknum;
 }

[-- Attachment #6: 1.2161-update-fec-microcode.patch --]
[-- Type: text/x-patch, Size: 10089 bytes --]

diff -Nru a/arch/ppc/syslib/bestcomm/fec.c b/arch/ppc/syslib/bestcomm/fec.c
--- a/arch/ppc/syslib/bestcomm/fec.c	2005-03-22 11:21:01 +01:00
+++ b/arch/ppc/syslib/bestcomm/fec.c	2005-03-22 12:59:04 +01:00
@@ -68,6 +68,7 @@
 	inc = (struct sdma_fec_rx_inc *)sdma_task_inc(tasknum);
 	inc->incr_bytes		= -(s16)sizeof(u32);
 	inc->incr_dst		= sizeof(u32);
+	inc->incr_dst_ma	= sizeof(u8);
 
 	sdma_set_task_pragma(tasknum, SDMA_FEC_RX_BD_PRAGMA);
 	sdma_set_task_auto_start(tasknum, tasknum);
diff -Nru a/arch/ppc/syslib/bestcomm/fec.h b/arch/ppc/syslib/bestcomm/fec.h
--- a/arch/ppc/syslib/bestcomm/fec.h	2004-11-20 23:21:04 +01:00
+++ b/arch/ppc/syslib/bestcomm/fec.h	2005-03-22 12:59:04 +01:00
@@ -31,6 +31,8 @@
 	s16 incr_bytes;
 	u16 pad1;
 	s16 incr_dst;
+	u16 pad2;
+	s16 incr_dst_ma;
 };
 
 /* tx task vars that need to be set before enabling the task */
diff -Nru a/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c
--- a/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c	2004-11-20 23:21:05 +01:00
+++ b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c	2005-03-22 12:59:04 +01:00
@@ -1,8 +1,8 @@
 /*
  * sdma_fec_rx_task.c
  *
- * Automatically created by split_dma_image based on dma_image.hex
- * on Wed Sep  8 00:37:22 2004 GMT
+ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
+ * on Tue Mar 22 11:19:38 2005 GMT
  */
 
 #include <linux/types.h>
@@ -22,31 +22,50 @@
 uint32_t sdma_fec_rx_task[] = {
 	/* header */
 	0x4243544b,
-	0x0c020409,
+	0x18060709,
 	0x00000000,
 	0x00000000,
 
 	/* Task descriptors */
-	0x808220da, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc3, idx1 += inc2 */
+	0x808220e3, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */
 	0x10601010, /*   DRD1A: var4 = var2; FN=0 MORE init=3 WS=0 RS=0 */
-	0xb880025b, /*   LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc3, idx3 += inc3 */
+	0xb8800264, /*   LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc4, idx3 += inc4 */
 	0x10001308, /*     DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
 	0x60140002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
 	0x0cccfcca, /*     DRD2B1: *idx3 = EU3(); EU3(*idx3,var10)  */
-	0xd9190240, /*   LCDEXT: idx2 = idx2; idx2 > var9; idx2 += inc0 */
-	0xb8c5e009, /*   LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */
-	0x047ecf80, /*     DRD1A: *idx3 = *idx0; FN=0 INT init=3 WS=3 RS=3 */
-	0x98190024, /*   LCD: idx2 = idx0; idx2 once var0; idx2 += inc4 */
+	0x80004000, /*   LCDEXT: idx2 = 0x00000000; ; */
+	0xb8c58029, /*   LCD: idx3 = *(idx1 + var00000015); idx3 once var0; idx3 += inc5 */
+	0x60000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */
+	0x088cf8cc, /*     DRD2B1: idx2 = EU3(); EU3(idx3,var12)  */
+	0x991982f2, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var11; idx2 += inc6, idx3 += inc2 */
+	0x006acf80, /*     DRD1A: *idx3 = *idx0; FN=0 init=3 WS=1 RS=1 */
+	0x80004000, /*   LCDEXT: idx2 = 0x00000000; ; */
+	0x9999802d, /*   LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */
+	0x70000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+	0x034cfc4e, /*     DRD2B1: var13 = EU3(); EU3(*idx1,var14)  */
+	0x00008868, /*     DRD1A: idx2 = var13; FN=0 init=0 WS=0 RS=0 */
+	0x99198341, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var13; idx2 += inc0, idx3 += inc1 */
+	0x007ecf80, /*     DRD1A: *idx3 = *idx0; FN=0 init=3 WS=3 RS=3 */
+	0x99198272, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc6, idx3 += inc2 */
+	0x046acf80, /*     DRD1A: *idx3 = *idx0; FN=0 INT init=3 WS=1 RS=1 */
+	0x9819002d, /*   LCD: idx2 = idx0; idx2 once var0; idx2 += inc5 */
 	0x0060c790, /*     DRD1A: *idx1 = *idx2; FN=0 init=3 WS=0 RS=0 */
 	0x000001f8, /*   NOP */
 
-	/* VAR[9]-VAR[10] */
+	/* VAR[9]-VAR[14] */
 	0x40000000,
 	0x7fff7fff,
+	0x00000000,
+	0x00000003,
+	0x40000008,
+	0x43ffffff,
 
-	/* INC[0]-INC[3] */
+	/* INC[0]-INC[6] */
 	0x40000000,
 	0xe0000000,
+	0xe0000000,
 	0xa0000008,
 	0x20000000,
+	0x00000000,
+	0x4000ffff,
 };
diff -Nru a/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c
--- a/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c	2004-11-20 23:21:06 +01:00
+++ b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c	2005-03-22 12:59:04 +01:00
@@ -1,8 +1,8 @@
 /*
  * sdma_fec_tx_task.c
  *
- * Automatically created by split_dma_image based on dma_image.hex
- * on Wed Sep  8 00:37:22 2004 GMT
+ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
+ * on Tue Mar 22 11:19:29 2005 GMT
  */
 
 #include <linux/types.h>
@@ -22,46 +22,56 @@
 uint32_t sdma_fec_tx_task[] = {
 	/* header */
 	0x4243544b,
-	0x1b06070c,
+	0x2407070d,
 	0x00000000,
 	0x00000000,
 
 	/* Task descriptors */
 	0x8018001b, /* LCD: idx0 = var0; idx0 <= var0; idx0 += inc3 */
 	0x60000005, /*   DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
-	0x01ccfc0c, /*   DRD2B1: var7 = EU3(); EU3(*idx0,var12)  */
+	0x01ccfc0d, /*   DRD2B1: var7 = EU3(); EU3(*idx0,var13)  */
 	0x8082a123, /* LCD: idx0 = var1, idx1 = var5; idx1 <= var4; idx0 += inc4, idx1 += inc3 */
 	0x10801418, /*   DRD1A: var5 = var3; FN=0 MORE init=4 WS=0 RS=0 */
-	0xf8810364, /*   LCDEXT: idx2 = *idx1, idx3 = var2; idx2 < var13; idx2 += inc4, idx3 += inc4 */
+	0xf88103a4, /*   LCDEXT: idx2 = *idx1, idx3 = var2; idx2 < var14; idx2 += inc4, idx3 += inc4 */
 	0x801a6024, /*   LCD: idx4 = var0; ; idx4 += inc4 */
 	0x10001708, /*     DRD1A: var5 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
 	0x60140002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
-	0x0cccfcce, /*     DRD2B1: *idx3 = EU3(); EU3(*idx3,var14)  */
+	0x0cccfccf, /*     DRD2B1: *idx3 = EU3(); EU3(*idx3,var15)  */
 	0x991a002c, /*   LCD: idx2 = idx2, idx3 = idx4; idx2 once var0; idx2 += inc5, idx3 += inc4 */
-	0x60000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */
-	0x088cfc4f, /*     DRD2B1: idx2 = EU3(); EU3(*idx1,var15)  */
-	0x9919802c, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 once var0; idx2 += inc5, idx3 += inc4 */
 	0x70000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
-	0x024cfc4c, /*     DRD2B1: var9 = EU3(); EU3(*idx1,var12)  */
+	0x024cfc4d, /*     DRD2B1: var9 = EU3(); EU3(*idx1,var13)  */
 	0x60000003, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */
 	0x0cccf247, /*     DRD2B1: *idx3 = EU3(); EU3(var9,var7)  */
-	0xd9190440, /*   LCDEXT: idx2 = idx2; idx2 > var17; idx2 += inc0 */
-	0xb8c86009, /*   LCD: idx3 = *(idx1 + var0000001a); ; idx3 += inc1 */
+	0x80004000, /*   LCDEXT: idx2 = 0x00000000; ; */
+	0xb8c80029, /*   LCD: idx3 = *(idx1 + var0000001a); idx3 once var0; idx3 += inc5 */
+	0x70000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+	0x088cf8d1, /*     DRD2B1: idx2 = EU3(); EU3(idx3,var17)  */
+	0x00002f10, /*     DRD1A: var11 = idx2; FN=0 init=0 WS=0 RS=0 */
+	0x99198432, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var16; idx2 += inc6, idx3 += inc2 */
+	0x008ac398, /*     DRD1A: *idx0 = *idx3; FN=0 init=4 WS=1 RS=1 */
+	0x80004000, /*   LCDEXT: idx2 = 0x00000000; ; */
+	0x9999802d, /*   LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */
+	0x70000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+	0x048cfc53, /*     DRD2B1: var18 = EU3(); EU3(*idx1,var19)  */
+	0x60000008, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=8 EXT init=0 WS=0 RS=0 */
+	0x088cf48b, /*     DRD2B1: idx2 = EU3(); EU3(var18,var11)  */
+	0x99198481, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var18; idx2 += inc0, idx3 += inc1 */
 	0x009ec398, /*     DRD1A: *idx0 = *idx3; FN=0 init=4 WS=3 RS=3 */
-	0x99198372, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var13; idx2 += inc6, idx3 += inc2 */
+	0x991983b2, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var14; idx2 += inc6, idx3 += inc2 */
 	0x088ac398, /*     DRD1A: *idx0 = *idx3; FN=0 TFD init=4 WS=1 RS=1 */
 	0x9919002d, /*   LCD: idx2 = idx2; idx2 once var0; idx2 += inc5 */
 	0x60000005, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
-	0x0c4cf88d, /*     DRD2B1: *idx1 = EU3(); EU3(idx2,var13)  */
+	0x0c4cf88e, /*     DRD2B1: *idx1 = EU3(); EU3(idx2,var14)  */
 	0x000001f8, /*   NOP */
 
-	/* VAR[12]-VAR[17] */
+	/* VAR[13]-VAR[19] */
 	0x0c000000,
 	0x40000000,
 	0x7fff7fff,
-	0x43ffffff,
 	0x00000000,
+	0x00000003,
 	0x40000004,
+	0x43ffffff,
 
 	/* INC[0]-INC[6] */
 	0x40000000,
diff -Nru a/drivers/net/fec_mpc52xx/fec.c b/drivers/net/fec_mpc52xx/fec.c
--- a/drivers/net/fec_mpc52xx/fec.c	2005-03-03 16:06:51 +01:00
+++ b/drivers/net/fec_mpc52xx/fec.c	2005-03-22 12:59:04 +01:00
@@ -202,41 +202,6 @@
 	return -EAGAIN;
 }
 
-/* The BestComm hardware requires data to be 32-bit aligned.
- * We also pad to minimum ethernet packet length, ETH_ZLEN.
- */
-static inline struct sk_buff *fec_skb_align_and_pad(struct sk_buff *skb)
-{
-	void *data = skb->data;
-	int len = skb->len;
-	int pad = (int)data & 0x3;
-	struct sk_buff *nskb;
-	int nlen;
-
-	if (pad == 0)
-		return skb;
-
-	if (!skb_cloned(skb)) {
-		skb_push(skb, pad);
-		memmove(skb->data, data, len);
-		skb_trim(skb, len);
-		skb = skb_padto(skb, ETH_ZLEN);
-		return skb;
-	}
-
-	/* ensure skb_padto doesn't have to reallocate */
-	nlen = (len >= ETH_ZLEN) ? len : ETH_ZLEN;
-
-	nskb = alloc_skb(nlen, GFP_ATOMIC);
-	if (nskb) {
-		skb_put(nskb, len);
-		memcpy(nskb->data, data, len);
-		nskb = skb_padto(nskb, ETH_ZLEN);
-	}
-	kfree_skb(skb);
-	return nskb;
-}
-
 /* This will only be invoked if your driver is _not_ in XOFF state.
  * What this means is that you need not check it, and that this
  * invariant will hold if you make sure that the netif_*_queue()
@@ -250,12 +215,6 @@
 	if (sdma_queue_full(priv->tx_sdma))
 		panic("MPC52xx transmit queue overrun\n");
 
-	skb = fec_skb_align_and_pad(skb);
-	if (!skb) {
-		priv->stats.tx_dropped++;
-		return 0;
-	}
-
 	spin_lock_irq(&priv->lock);
 	dev->trans_start = jiffies;
 
@@ -639,7 +598,7 @@
 		ret = -ENOMEM;
 		goto probe_error;
 	}
-	
+
 	/* SDMA init */
 	priv->rx_sdma = sdma_alloc(FEC_RX_NUM_BD);
 	priv->tx_sdma = sdma_alloc(FEC_TX_NUM_BD);

^ permalink raw reply

* arch/ppc/82xx_io/uart.c bug found
From: Wojciech Kromer @ 2006-02-13 13:51 UTC (permalink / raw)
  To: linuxppc-embedded

here is orignal uart.c

#ifdef SCC_CONSOLE
                                switch (state->smc_scc_num) {
                                case 0:
                                        page = CPM_CR_SCC1_PAGE;
                                        sblock = CPM_CR_SCC1_SBLOCK;
                                        break;
                                case 1:
                                        page = CPM_CR_SCC2_PAGE;
                                        sblock = CPM_CR_SCC2_SBLOCK;
                                        break;
                                case 2:
                                        page = CPM_CR_SCC3_PAGE;
                                        sblock = CPM_CR_SCC3_SBLOCK;
                                        break;
                                }
....


 so SCC4 is unusable, here is missing code:

                                case 3:
                                        page = CPM_CR_SCC4_PAGE;
                                        sblock = CPM_CR_SCC4_SBLOCK;
                                        break;
                                }

^ permalink raw reply

* Re: arch/ppc/82xx_io/uart.c bug found
From: Dan Malek @ 2006-02-13 16:14 UTC (permalink / raw)
  To: Wojciech Kromer; +Cc: linuxppc-embedded
In-Reply-To: <43F08EF7.3060109@dgt.com.pl>


On Feb 13, 2006, at 8:51 AM, Wojciech Kromer wrote:

> here is orignal uart.c

Three things....

One, this code is obsolete and isn't used any more.
Two, it's not a bug, just a feature enhancement.
Three, if you want us to actually do something about
this I need a real patch against an up to date
public source tree and indication it was actually
tested on some platform.

Thanks.

	-- Dan

^ permalink raw reply

* Re: Flattened device tree for Pegasos
From: Mark A. Greer @ 2006-02-13 18:03 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1139782333.5247.44.camel@localhost.localdomain>

On Mon, Feb 13, 2006 at 09:12:12AM +1100, Benjamin Herrenschmidt wrote:
> On Fri, 2006-02-10 at 18:46 -0600, Kumar Gala wrote:
> > On Fri, 10 Feb 2006, Mark A. Greer wrote:
> > 
> > > If anyone happens to have a Pegasos running the merged powerpc kernel
> > > handy, I would greatly appreciate a dump of flattened device tree that
> > > it uses.
> > 
> > We really need to put OF tree's somewhere that people can get to, maybe 
> > penguinppc.org.
> > 
> > Ben, Segher, Paul:
> > 
> > You guys have either access to HW or tree dump's already.  Would you be 
> > willing to share them?
> 
> There is an unresolved issue about what is the (c) for those
> device-tree, especially since the Apple ones may contain driver blobs...

Is that still an issue for the flattened dev tree version(s)?

I'd still like a flattened dev tree for the pegasos if that's legal. :)

Mark

^ permalink raw reply

* unsubscribe
From: Moloko Vellocet @ 2006-02-13 18:39 UTC (permalink / raw)
  To: linuxppc-embedded

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

unsubscribe

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

^ permalink raw reply

* Re: SPI Katix subsytem
From: Kate Alhola @ 2006-02-13 21:31 UTC (permalink / raw)
  To: dibacco@inwind.it; +Cc: linuxppc-embedded
In-Reply-To: <IULG07$EC9BCBEDC5067C42C017F8A6DF5C1559@libero.it>

> Hi,
>
> I would like to use a SPI subsystem on 2.4 but katix framework seems to be
> not  continuosly updated. Katix is also present in 2.6 or is there another
> more supported framework there?

I really think that i need update my SPI subsystem more frequently.
I have got wery little feedback so i have not been so active releasind
new versions. May be it is time for release my current additions.

At the moment i have drivers only for mpc5200 because it is hw that i have
use for PPC architecture.  May be i should set up public cvs so that
it will be easier to add third party SPI driver modules.

I have planning to port it for 2.6 kernel. May be it is time once
again check if the 2.6 is enough mature for 5200. Least i should
take latest snapshot from Denx and saw that there is.


Kate


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

^ permalink raw reply

* Re: Flattened device tree for Pegasos
From: Benjamin Herrenschmidt @ 2006-02-13 22:27 UTC (permalink / raw)
  To: Mark A. Greer; +Cc: linuxppc-dev
In-Reply-To: <20060213180320.GB4530@mag.az.mvista.com>

On Mon, 2006-02-13 at 11:03 -0700, Mark A. Greer wrote:
> On Mon, Feb 13, 2006 at 09:12:12AM +1100, Benjamin Herrenschmidt wrote:
> > On Fri, 2006-02-10 at 18:46 -0600, Kumar Gala wrote:
> > > On Fri, 10 Feb 2006, Mark A. Greer wrote:
> > > 
> > > > If anyone happens to have a Pegasos running the merged powerpc kernel
> > > > handy, I would greatly appreciate a dump of flattened device tree that
> > > > it uses.
> > > 
> > > We really need to put OF tree's somewhere that people can get to, maybe 
> > > penguinppc.org.
> > > 
> > > Ben, Segher, Paul:
> > > 
> > > You guys have either access to HW or tree dump's already.  Would you be 
> > > willing to share them?
> > 
> > There is an unresolved issue about what is the (c) for those
> > device-tree, especially since the Apple ones may contain driver blobs...
> 
> Is that still an issue for the flattened dev tree version(s)?
> 
> I'd still like a flattened dev tree for the pegasos if that's legal. :)

The issue is the (c) of Apple trees mostly... that is, I don't think I
can post my collection of Apple device-tree snapshots online.

Ben.

^ permalink raw reply

* How to access uboot environment variables from Linux?
From: Bizhan Gholikhamseh (bgholikh) @ 2006-02-14  0:53 UTC (permalink / raw)
  To: linuxppc-dev

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

All,
How could I access the uboot environment variables from Linux? For
example I would like to access the "serverip"
and change that to a different ip address during run time.
 
Many thanks in advance,
Bizhan

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

^ permalink raw reply

* 82xx_io UART BRG's vs BUS CLK
From: Russell McGuire @ 2006-02-14  4:02 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <mailman.1.1139818094.16671.linuxppc-embedded@ozlabs.org>

Anyone,

Recently I found that the value I was passing to Linux for the BUS CLK
frequency was incorrect. Previously I was passing in from U-boot (66 * 1000
* 1000) 66Mhz, it had been brought up this can cause incorrect SOF
transmission rates with the 82xx USB driver, so after measuring our 'exact'
clock, I made the adjustment to ( 66,666,666 Hz ) 66.66Mhz .

Hoping this would correct the issue, however now I cannot run the serial
console baud rate (on SMC2) any higher than 115200 without corruption,
however 57600 works on. This worked great before I changed the U-boot BUS
clock to the correct value.

I did some math on the BRG calculations and with 66Mhz the BRG divisor is
17.8 I am assuming 17 gets written, and with 66.666Mhz then its 18.02 so
thus 18 probably gets written. Should perhaps a constant minus 1 be added to
the code?

Using:
U-boot 1.1.2
DENX Linux 2.4.25

Is anyone aware of similar issues, or are there bug fixes past the 2.4.25
Kernel for this?

-Russ

^ permalink raw reply

* [patch 07/47] generic __{, test_and_}{set, clear, change}_bit() and test_bit()
From: Akinobu Mita @ 2006-02-14  5:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: akpm, linux-mips, dev-etrax, ultralinux, Ian Molton,
	Hirokazu Takata, Akinobu Mita, linuxppc-dev, linuxsh-dev,
	sparclinux, Chris Zankel, linuxsh-shmedia-dev, Russell King,
	parisc-linux
In-Reply-To: <20060214050351.252615000@localhost.localdomain>

This patch introduces the C-language equivalents of the functions below:

void __set_bit(int nr, volatile unsigned long *addr);
void __clear_bit(int nr, volatile unsigned long *addr);
void __change_bit(int nr, volatile unsigned long *addr);
int __test_and_set_bit(int nr, volatile unsigned long *addr);
int __test_and_clear_bit(int nr, volatile unsigned long *addr);
int __test_and_change_bit(int nr, volatile unsigned long *addr);
int test_bit(int nr, const volatile unsigned long *addr);

In include/asm-generic/bitops/non-atomic.h

This code largely copied from:
asm-powerpc/bitops.h

Signed-off-by: Akinobu Mita <mita@miraclelinux.com>
 include/asm-generic/bitops/non-atomic.h |  111 ++++++++++++++++++++++++++++++++
 1 files changed, 111 insertions(+)

Index: 2.6-rc/include/asm-generic/bitops/non-atomic.h
===================================================================
--- /dev/null
+++ 2.6-rc/include/asm-generic/bitops/non-atomic.h
@@ -0,0 +1,111 @@
+#ifndef _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
+#define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
+
+#include <asm/types.h>
+
+#define BITOP_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))
+#define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)
+
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static inline void __set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+
+	*p  |= mask;
+}
+
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+
+	*p &= ~mask;
+}
+
+/**
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to change
+ * @addr: the address to start counting from
+ *
+ * Unlike change_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static inline void __change_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+
+	*p ^= mask;
+}
+
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old | mask;
+	return (old & mask) != 0;
+}
+
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old & ~mask;
+	return (old & mask) != 0;
+}
+
+/* WARNING: non atomic and it can be reordered! */
+static inline int __test_and_change_bit(int nr,
+					    volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old ^ mask;
+	return (old & mask) != 0;
+}
+
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static inline int test_bit(int nr, const volatile unsigned long *addr)
+{
+	return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
+}
+
+#endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */

--

^ permalink raw reply

* [patch 15/47] generic hweight{64,32,16,8}()
From: Akinobu Mita @ 2006-02-14  5:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: akpm, linux-mips, linux-ia64, Ian Molton, Andi Kleen,
	David Howells, linuxppc-dev, Greg Ungerer, sparclinux,
	Miles Bader, Yoshinori Sato, Hirokazu Takata, linuxsh-shmedia-dev,
	linux-m68k, Ivan Kokshaysky, Richard Henderson, Akinobu Mita,
	Chris Zankel, dev-etrax, ultralinux, Linus Torvalds, linuxsh-dev,
	linux390, Russell King, parisc-linux
In-Reply-To: <20060214050351.252615000@localhost.localdomain>


This patch introduces the C-language equivalents of the functions below:

unsigned int hweight32(unsigned int w);
unsigned int hweight16(unsigned int w);
unsigned int hweight8(unsigned int w);
unsigned long hweight64(__u64 w);

In include/asm-generic/bitops/hweight.h

This code largely copied from:
include/linux/bitops.h

Signed-off-by: Akinobu Mita <mita@miraclelinux.com>
 include/asm-generic/bitops/hweight.h |    9 +++++
 lib/Makefile                         |    1 
 lib/hweight.c                        |   54 +++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+)

Index: 2.6-rc/include/asm-generic/bitops/hweight.h
===================================================================
--- /dev/null
+++ 2.6-rc/include/asm-generic/bitops/hweight.h
@@ -0,0 +1,9 @@
+#ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
+#define _ASM_GENERIC_BITOPS_HWEIGHT_H_
+
+extern unsigned int hweight32(unsigned int w);
+extern unsigned int hweight16(unsigned int w);
+extern unsigned int hweight8(unsigned int w);
+extern unsigned long hweight64(__u64 w);
+
+#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
Index: 2.6-rc/lib/Makefile
===================================================================
--- 2.6-rc.orig/lib/Makefile
+++ 2.6-rc/lib/Makefile
@@ -21,6 +21,7 @@ lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += 
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_SEMAPHORE_SLEEPERS) += semaphore-sleepers.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
+lib-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 
Index: 2.6-rc/lib/hweight.c
===================================================================
--- /dev/null
+++ 2.6-rc/lib/hweight.c
@@ -0,0 +1,54 @@
+#include <linux/module.h>
+#include <asm/types.h>
+
+/**
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
+ */
+
+unsigned int hweight32(unsigned int w)
+{
+	unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+	res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+	res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+	return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+EXPORT_SYMBOL(hweight32);
+
+unsigned int hweight16(unsigned int w)
+{
+	unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
+	res = (res & 0x3333) + ((res >> 2) & 0x3333);
+	res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
+	return (res & 0x00FF) + ((res >> 8) & 0x00FF);
+}
+EXPORT_SYMBOL(hweight16);
+
+unsigned int hweight8(unsigned int w)
+{
+	unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
+	res = (res & 0x33) + ((res >> 2) & 0x33);
+	return (res & 0x0F) + ((res >> 4) & 0x0F);
+}
+EXPORT_SYMBOL(hweight8);
+
+unsigned long hweight64(__u64 w)
+{
+#if BITS_PER_LONG == 32
+	return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
+#elif BITS_PER_LONG == 64
+	u64 res;
+	res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul);
+	res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
+	res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful);
+	res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul);
+	res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul);
+	return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul);
+#else
+#error BITS_PER_LONG not defined
+#endif
+}
+EXPORT_SYMBOL(hweight64);

--

^ permalink raw reply

* [patch 13/47] generic sched_find_first_bit()
From: Akinobu Mita @ 2006-02-14  5:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: akpm, linux-mips, linux-ia64, Ian Molton, David Howells,
	linuxppc-dev, Greg Ungerer, sparclinux, Miles Bader,
	Linus Torvalds, Yoshinori Sato, Hirokazu Takata, linuxsh-dev,
	linux-m68k, Akinobu Mita, Chris Zankel, dev-etrax, ultralinux,
	Andi Kleen, linuxsh-shmedia-dev, linux390, Russell King,
	parisc-linux
In-Reply-To: <20060214050351.252615000@localhost.localdomain>

This patch introduces the C-language equivalent of the function:
int sched_find_first_bit(const unsigned long *b);

In include/asm-generic/bitops/sched.h

This code largely copied from:
include/asm-powerpc/bitops.h

Signed-off-by: Akinobu Mita <mita@miraclelinux.com>
 include/asm-generic/bitops/sched.h |   36 ++++++++++++++++++++++++++++++++++++
 1 files changed, 36 insertions(+)

Index: 2.6-rc/include/asm-generic/bitops/sched.h
===================================================================
--- /dev/null
+++ 2.6-rc/include/asm-generic/bitops/sched.h
@@ -0,0 +1,36 @@
+#ifndef _ASM_GENERIC_BITOPS_SCHED_H_
+#define _ASM_GENERIC_BITOPS_SCHED_H_
+
+#include <linux/compiler.h>	/* unlikely() */
+#include <asm/types.h>
+
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 140-bit bitmap where the first 100 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 140
+ * bits is cleared.
+ */
+static inline int sched_find_first_bit(const unsigned long *b)
+{
+#if BITS_PER_LONG == 64
+	if (unlikely(b[0]))
+		return __ffs(b[0]);
+	if (unlikely(b[1]))
+		return __ffs(b[1]) + 64;
+	return __ffs(b[2]) + 128;
+#elif BITS_PER_LONG == 32
+	if (unlikely(b[0]))
+		return __ffs(b[0]);
+	if (unlikely(b[1]))
+		return __ffs(b[1]) + 32;
+	if (unlikely(b[2]))
+		return __ffs(b[2]) + 64;
+	if (b[3])
+		return __ffs(b[3]) + 96;
+	return __ffs(b[4]) + 128;
+#else
+#error BITS_PER_LONG not defined
+#endif
+}
+
+#endif /* _ASM_GENERIC_BITOPS_SCHED_H_ */

--

^ permalink raw reply

* [patch 32/47] powerpc: use generic bitops
From: Akinobu Mita @ 2006-02-14  5:04 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, linuxppc-dev, Akinobu Mita
In-Reply-To: <20060214050351.252615000@localhost.localdomain>

- remove __{,test_and_}{set,clear,change}_bit() and test_bit()
- remove generic_fls64()
- remove generic_hweight{64,32,16,8}()
- remove sched_find_first_bit()

Signed-off-by: Akinobu Mita <mita@miraclelinux.com>
 arch/powerpc/Kconfig         |    4 +
 include/asm-powerpc/bitops.h |  105 +------------------------------------------
 2 files changed, 8 insertions(+), 101 deletions(-)

Index: 2.6-rc/include/asm-powerpc/bitops.h
===================================================================
--- 2.6-rc.orig/include/asm-powerpc/bitops.h
+++ 2.6-rc/include/asm-powerpc/bitops.h
@@ -184,72 +184,7 @@ static __inline__ void set_bits(unsigned
 	: "cc");
 }
 
-/* Non-atomic versions */
-static __inline__ int test_bit(unsigned long nr,
-			       __const__ volatile unsigned long *addr)
-{
-	return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
-}
-
-static __inline__ void __set_bit(unsigned long nr,
-				 volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-	*p  |= mask;
-}
-
-static __inline__ void __clear_bit(unsigned long nr,
-				   volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-	*p &= ~mask;
-}
-
-static __inline__ void __change_bit(unsigned long nr,
-				    volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-	*p ^= mask;
-}
-
-static __inline__ int __test_and_set_bit(unsigned long nr,
-					 volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-	unsigned long old = *p;
-
-	*p = old | mask;
-	return (old & mask) != 0;
-}
-
-static __inline__ int __test_and_clear_bit(unsigned long nr,
-					   volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-	unsigned long old = *p;
-
-	*p = old & ~mask;
-	return (old & mask) != 0;
-}
-
-static __inline__ int __test_and_change_bit(unsigned long nr,
-					    volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-	unsigned long old = *p;
-
-	*p = old ^ mask;
-	return (old & mask) != 0;
-}
+#include <asm-generic/bitops/non-atomic.h>
 
 /*
  * Return the zero-based bit position (LE, not IBM bit numbering) of
@@ -310,16 +245,9 @@ static __inline__ int fls(unsigned int x
 	asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
 	return 32 - lz;
 }
-#define fls64(x)   generic_fls64(x)
+#include <asm-generic/bitops/fls64.h>
 
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-#define hweight64(x) generic_hweight64(x)
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
+#include <asm-generic/bitops/hweight.h>
 
 #define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
 unsigned long find_next_zero_bit(const unsigned long *addr,
@@ -397,32 +325,7 @@ unsigned long find_next_zero_le_bit(cons
 #define minix_find_first_zero_bit(addr,size) \
 	find_first_zero_le_bit((unsigned long *)addr, size)
 
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-#ifdef CONFIG_PPC64
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 64;
-	return __ffs(b[2]) + 128;
-#else
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-#endif
-}
+#include <asm-generic/bitops/sched.h>
 
 #endif /* __KERNEL__ */
 
Index: 2.6-rc/arch/powerpc/Kconfig
===================================================================
--- 2.6-rc.orig/arch/powerpc/Kconfig
+++ 2.6-rc/arch/powerpc/Kconfig
@@ -37,6 +37,10 @@ config RWSEM_XCHGADD_ALGORITHM
 	bool
 	default y
 
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y

--

^ permalink raw reply

* [patch 11/47] generic fls64()
From: Akinobu Mita @ 2006-02-14  5:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: akpm, linux-mips, linux-ia64, Ian Molton, Andi Kleen,
	David Howells, linuxppc-dev, Greg Ungerer, sparclinux,
	Miles Bader, Yoshinori Sato, Hirokazu Takata, linuxsh-shmedia-dev,
	linux-m68k, Ivan Kokshaysky, Richard Henderson, Akinobu Mita,
	Chris Zankel, dev-etrax, ultralinux, Linus Torvalds, linuxsh-dev,
	linux390, Russell King, parisc-linux
In-Reply-To: <20060214050351.252615000@localhost.localdomain>

This patch introduces the C-language equivalent of the function:
int fls64(__u64 x);

In include/asm-generic/bitops/fls64.h

This code largely copied from:
include/linux/bitops.h

Signed-off-by: Akinobu Mita <mita@miraclelinux.com>
 include/asm-generic/bitops/fls64.h |   12 ++++++++++++
 1 files changed, 12 insertions(+)

Index: 2.6-rc/include/asm-generic/bitops/fls64.h
===================================================================
--- /dev/null
+++ 2.6-rc/include/asm-generic/bitops/fls64.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_GENERIC_BITOPS_FLS64_H_
+#define _ASM_GENERIC_BITOPS_FLS64_H_
+
+static inline int fls64(__u64 x)
+{
+	__u32 h = x >> 32;
+	if (h)
+		return fls(h) + 32;
+	return fls(x);
+}
+
+#endif /* _ASM_GENERIC_BITOPS_FLS64_H_ */

--

^ permalink raw reply

* 440gx GPIO
From: Ed Goforth @ 2006-02-14  5:20 UTC (permalink / raw)
  To: linuxppc-embedded

I am struggling with a problem and I hope someone can give me some
pointers.  We have a custom board with a 440gx.  I need to drive GPIO11
low.  The best as I can tell from the docs, I need to set bit 11 of the
TCR to 1 and bit 11 of the OR to 0 to do this.  I'm using kernel
2.4.18-timesys-4.0

Here's what I've tried:

Prior to making an calls, the values of the registers are:
or      0x00101000
tcr     0x00101700
odr     0x00000000
ir      0xeffff820


(from ibm440gx.h)
#define PPC440GX_GPIO0_ADDR  0x0000000140000700


Attempt one: write the bit directly:

  volatile gpio_t *gpio;
  volatile u32 or_reg;

  gpio = (gpio_t *) ioremap_nocache(0x40000700,
                                    sizeof(gpio_t));

  or_reg = gpio->or;
  or_reg &= 0x00100000;
  gpio->or = or_reg;


Attempt two: use the accessor routine:
  extern int ibm_gpio_out(__u32 device, __u32 mask, __u32 data);

  rc = ibm_gpio_out(0, 0x00100000, 0);


With either approach, I can read the registers fine.  But as soon as I
either modify gpio->or or call ibm_gpio_out(), the board hangs hard.

Any hints would be greatly appreciated.  On-list replies are fine; I am
a subscriber.

Thanks,
Ed

^ permalink raw reply

* Re: 440gx GPIO
From: Eugene Surovegin @ 2006-02-14  6:59 UTC (permalink / raw)
  To: Ed Goforth; +Cc: linuxppc-embedded
In-Reply-To: <43F168A3.4020808@gmail.com>

On Tue, Feb 14, 2006 at 12:20:35AM -0500, Ed Goforth wrote:
> I am struggling with a problem and I hope someone can give me some
> pointers.  We have a custom board with a 440gx.  I need to drive GPIO11
> low.  The best as I can tell from the docs, I need to set bit 11 of the
> TCR to 1 and bit 11 of the OR to 0 to do this.

Check that this pin is enabled as GPIO not as a function pin 
(SDR0_PFC0 register).

Also, just to be sure that you remapped GPIO registers correctly, use 
ioremap64 with full physical address (not just low 32 bits).

-- 
Eugene

^ permalink raw reply

* SD/MMC card driver?
From: Eberhard Stoll @ 2006-02-14  8:00 UTC (permalink / raw)
  To: linuxppc-embedded

Hi,
I've got a mpc5200 based board with a SD card socket connected to PSC2. 
I'd like to use this SD Card as a block device, but didn't find any 
driver for SD/MMC Cards in kernel 2.4 (denx 2.4.15). So my question is:
Are there any drivers for linux & SD/MMC Cards attached to a spi 
interface (e.g. mpc5200)?

thanks in advance!
Eberhard

^ permalink raw reply

* [PATCH] unify pfn_to_page take3 [4/23] powerpc pfn_to_page
From: KAMEZAWA Hiroyuki @ 2006-02-14 10:02 UTC (permalink / raw)
  To: Linux Kernel Mailing List; +Cc: Andrew Morton, linuxppc-dev
In-Reply-To: <43F1A753.2020003@jp.fujitsu.com>

PowerPC can use generic ones.

Signed-Off-By: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>

Index: testtree/include/asm-powerpc/page.h
===================================================================
--- testtree.orig/include/asm-powerpc/page.h
+++ testtree/include/asm-powerpc/page.h
@@ -69,8 +69,6 @@
  #endif

  #ifdef CONFIG_FLATMEM
-#define pfn_to_page(pfn)	(mem_map + (pfn))
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map))
  #define pfn_valid(pfn)		((pfn) < max_mapnr)
  #endif

@@ -200,6 +198,7 @@ extern void copy_user_page(void *to, voi
  		struct page *p);
  extern int page_is_ram(unsigned long pfn);

+#include <asm-generic/memory_model.h>
  #endif /* __ASSEMBLY__ */

  #endif /* __KERNEL__ */

^ permalink raw reply

* RE: How to access uboot environment variables from Linux?
From: atul.sabharwal @ 2006-02-14  1:09 UTC (permalink / raw)
  To: bgholikh, linuxppc-dev

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

I think you will have to write a program to access and decode u-boot
environment setup format in linux.

If you come across some open source app for this, plz. share with me. It
should be a standard method

but typically a small optimization if you want your main code to be
independent of the boot loader

your are using or if you have common code base which works across
multiple processors/multiple loaders.

 

--

Atul

________________________________

From: linuxppc-dev-bounces+atul.sabharwal=tek.com@ozlabs.org
[mailto:linuxppc-dev-bounces+atul.sabharwal=tek.com@ozlabs.org] On
Behalf Of Bizhan Gholikhamseh (bgholikh)
Sent: Monday, February 13, 2006 4:54 PM
To: linuxppc-dev@ozlabs.org
Subject: How to access uboot environment variables from Linux?

 

All,

How could I access the uboot environment variables from Linux? For
example I would like to access the "serverip"

and change that to a different ip address during run time.

 

Many thanks in advance,

Bizhan


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

^ permalink raw reply

* [PATCH] unify pfn_to_page take3 [14/23] ppc pfn_to_page
From: KAMEZAWA Hiroyuki @ 2006-02-14 10:43 UTC (permalink / raw)
  To: Linux Kernel Mailing List; +Cc: Andrew Morton, linuxppc-dev
In-Reply-To: <43F1A753.2020003@jp.fujitsu.com>

PPC can use generic funcs.

Signed-Off-By: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>

Index: testtree/include/asm-ppc/page.h
===================================================================
--- testtree.orig/include/asm-ppc/page.h
+++ testtree/include/asm-ppc/page.h
@@ -149,8 +149,7 @@ extern int page_is_ram(unsigned long pfn
  #define __pa(x) ___pa((unsigned long)(x))
  #define __va(x) ((void *)(___va((unsigned long)(x))))

-#define pfn_to_page(pfn)	(mem_map + ((pfn) - PPC_PGSTART))
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map) + PPC_PGSTART)
+#define ARCH_PFN_OFFSET		(PPC_PGSTART)
  #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
  #define page_to_virt(page)	__va(page_to_pfn(page) << PAGE_SHIFT)

@@ -175,5 +174,6 @@ extern __inline__ int get_order(unsigned
  /* We do define AT_SYSINFO_EHDR but don't use the gate mecanism */
  #define __HAVE_ARCH_GATE_AREA		1

+#include <asm-generic/memory_model.h>
  #endif /* __KERNEL__ */
  #endif /* _PPC_PAGE_H */

^ permalink raw reply

* RE: 82xx_io UART BRG's vs BUS CLK
From: Jenkins, Clive @ 2006-02-14 11:23 UTC (permalink / raw)
  To: Russell McGuire, linuxppc-embedded

> I did some math on the BRG calculations and with 66Mhz the BRG divisor
is
> 17.8 I am assuming 17 gets written, and with 66.666Mhz then its 18.02
so
> thus 18 probably gets written. Should perhaps a constant minus 1 be
added to
> the code?

> Using:
> U-boot 1.1.2
> DENX Linux 2.4.25

> Is anyone aware of similar issues, or are there bug fixes past the
2.4.25
> Kernel for this?

> -Russ

Hi Russ

I am not familiar with your hardware, nor have I checked the code that
calculated the Baud rate divisor.

I would advise against "adding a constant -1", in favour of rounding
to the nearest integer. From your figures:

  divisor =3D clock / (baudrate * 32)

To get a rounded result using real numbers:

  divisor =3D integer_part_of((clock / (baudrate * 32)) + 1/2)

Using integer arithmetic, you can code this in C as:

  divisor =3D ((clock / baudrate /16) + 1) >> 1;

I would check whether or not the code is doing this, or the equivalent,
and if not, change it. If the code is doing this, the divisor should be
18 in both cases.

Clive

^ permalink raw reply

* RE: How to access uboot environment variables from Linux?
From: Jenkins, Clive @ 2006-02-14 10:56 UTC (permalink / raw)
  To: atul.sabharwal, bgholikh, linuxppc-dev

Have you not discovered internet search engines?
If you paste the original question ("How could I access the uboot
environment variables from Linux?") into Google, you get the answer as
the first result:
http://www.denx.de/wiki/view/DULG/HowCanIAccessUBootEnvironmentVariables
InLinux

[Continuing the current style of top-posting. Sorry]
Clive
=20
-----Original Message-----
From: linuxppc-dev-bounces+clive.jenkins=3Dxerox.com@ozlabs.org
[mailto:linuxppc-dev-bounces+clive.jenkins=3Dxerox.com@ozlabs.org] On
Behalf Of atul.sabharwal@exgate.tek.com
Sent: 14 February 2006 01:09
To: bgholikh@cisco.com; linuxppc-dev@ozlabs.org
Subject: RE: How to access uboot environment variables from Linux?


I think you will have to write a program to access and decode u-boot
environment setup format in linux.
If you come across some open source app for this, plz. share with me. It
should be a standard method
but typically a small optimization if you want your main code to be
independent of the boot loader
your are using or if you have common code base which works across
multiple processors/multiple loaders.
=20
--
Atul



From: linuxppc-dev-bounces+atul.sabharwal=3Dtek.com@ozlabs.org
[mailto:linuxppc-dev-bounces+atul.sabharwal=3Dtek.com@ozlabs.org] On
Behalf Of Bizhan Gholikhamseh (bgholikh)
Sent: Monday, February 13, 2006 4:54 PM
To: linuxppc-dev@ozlabs.org
Subject: How to access uboot environment variables from Linux?
=20
All,
How could I access the uboot environment variables from Linux? For
example I would like to access the "serverip"
and change that to a different ip address during run time.
=20
Many thanks in advance,
Bizhan

^ permalink raw reply

* How to access uboot environment variables from Linux?
From: Heiko Schocher @ 2006-02-14 11:31 UTC (permalink / raw)
  To: linuxppc-dev

Hello Bizhan,

> How could I access the uboot environment variables from Linux? For
> example I would like to access the "serverip"

have a look at

http://www.denx.de/wiki/view/DULG/HowCanIAccessUBootEnvironmentVariablesInLinux

Best regards,

Heiko

^ 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