* Stability of MPC5200 FEC
@ 2006-02-10 17:20 Asier Llano Palacios
2006-02-10 18:22 ` John Rigby
2006-02-11 15:28 ` Sylvain Munaut
0 siblings, 2 replies; 6+ messages in thread
From: Asier Llano Palacios @ 2006-02-10 17:20 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: Sylvain Munaut, John Rigby
We are working with MPC5200 cpu.=20
We've been using it since early 2.6 kernel versions.
We're currently quite stabilished with the version of the kernel Sylvain
had before the Platform Device rework. But the problem is that we are
experiencing that the FEC stops working after a long uptime.
So, do you think that the current git version is more stable than the
one we are using? Do you think that there is anything that could stop us
upgrading to the latest version?
The problem is that we have a custom board, with some custom devices, so
it is not so easy to upgrade. We need to know that a new version, is
more stable than the previous one, before we upgrade. As soon as we
upgrade, we can help if we find any problem.
Thank you,
Asier Llano
--=20
Asier Llano Palacios
ZIV I+D Smart Energy Networks
Dpto. Ingenier=EDa de Desarrollo.
ZIV, Aplicaciones y Tecnolog=EDa.
Parque Tecnol=F3gico, 210
48170 ZAMUDIO (Bizkaia)
E-mail: a.llano@ziv.es
Tlfno: (+34)944037400=20
=20
----------------------------------------- PLEASE NOTE =
-------------------------------------------
This message, along with any attachments, may be confidential or legally =
privileged.=20
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.
=B5SysCom uses virus scanning software but excludes any liability for =
viruses contained in any attachment.
=20
------------------------------------ ROGAMOS LEA ESTE TEXTO =
-------------------------------
Este mensaje y sus anexos pueden contener informaci=F3n confidencial y/o =
con derecho legal.=20
Est=E1 dirigido =FAnicamente a la/s persona/s o entidad/es rese=F1adas =
como =FAnico destinatario autorizado.
Si este mensaje le hubiera llegado por error, por favor elim=EDnelo sin =
revisarlo ni reenviarlo y notif=EDquelo inmediatamente al remitente. =
Gracias por su colaboraci=F3n. =20
=B5SysCom utiliza software antivirus, pero no se hace responsable de los =
virus contenidos en los ficheros anexos.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Stability of MPC5200 FEC
2006-02-10 17:20 Stability of MPC5200 FEC Asier Llano Palacios
@ 2006-02-10 18:22 ` John Rigby
2006-02-11 15:28 ` Sylvain Munaut
1 sibling, 0 replies; 6+ messages in thread
From: John Rigby @ 2006-02-10 18:22 UTC (permalink / raw)
To: Asier Llano Palacios; +Cc: Sylvain Munaut, linuxppc-embedded
Do you have a lite5200 board that exhibits the same bad FEC behavior.
If so you could try the new
version on it and see if things improve.
Asier Llano Palacios wrote:
>We are working with MPC5200 cpu.
>We've been using it since early 2.6 kernel versions.
>We're currently quite stabilished with the version of the kernel Sylvain
>had before the Platform Device rework. But the problem is that we are
>experiencing that the FEC stops working after a long uptime.
>
>So, do you think that the current git version is more stable than the
>one we are using? Do you think that there is anything that could stop us
>upgrading to the latest version?
>
>The problem is that we have a custom board, with some custom devices, so
>it is not so easy to upgrade. We need to know that a new version, is
>more stable than the previous one, before we upgrade. As soon as we
>upgrade, we can help if we find any problem.
>
>Thank you,
>Asier Llano
>
>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Stability of MPC5200 FEC
2006-02-10 17:20 Stability of MPC5200 FEC Asier Llano Palacios
2006-02-10 18:22 ` John Rigby
@ 2006-02-11 15:28 ` Sylvain Munaut
2006-02-11 16:08 ` Wolfgang Denk
2006-02-13 8:08 ` Asier Llano Palacios
1 sibling, 2 replies; 6+ messages in thread
From: Sylvain Munaut @ 2006-02-11 15:28 UTC (permalink / raw)
To: Asier Llano Palacios; +Cc: John Rigby, linuxppc-embedded
Asier Llano Palacios wrote:
> We are working with MPC5200 cpu.
> We've been using it since early 2.6 kernel versions.
> We're currently quite stabilished with the version of the kernel Sylvain
> had before the Platform Device rework. But the problem is that we are
> experiencing that the FEC stops working after a long uptime.
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).
Also, what are the 'symptoms' ? (anything in dmesg ?)
> So, do you think that the current git version is more stable than the
> one we are using? Do you think that there is anything that could stop us
> upgrading to the latest version?
Doubtfull, I haven't touched the FEC code much except to remove the
aligment code (newer bestcomm microcode doesn't require alignement of
the skb). It should be reworked to use the generic phy code and remove
some "bugs" (like the fact when we down the interface, we stop the task
but not deactivate the MAC IIRC, which cause warning in dmesg).
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.
> The problem is that we have a custom board, with some custom devices, so
> it is not so easy to upgrade. We need to know that a new version, is
> more stable than the previous one, before we upgrade. As soon as we
> upgrade, we can help if we find any problem.
Sylvain
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Stability of MPC5200 FEC
2006-02-11 15:28 ` Sylvain Munaut
@ 2006-02-11 16:08 ` Wolfgang Denk
2006-02-13 8:08 ` Asier Llano Palacios
1 sibling, 0 replies; 6+ messages in thread
From: Wolfgang Denk @ 2006-02-11 16:08 UTC (permalink / raw)
To: Sylvain Munaut; +Cc: Asier Llano Palacios, John Rigby, linuxppc-embedded
In message <43EE029A.5040504@246tNt.com> you wrote:
>
> > had before the Platform Device rework. But the problem is that we are
> > experiencing that the FEC stops working after a long uptime.
>
> 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).
This is a well-known problem, I'm afraid. To trigger it, it is
usually (*) sufficient to transfer a large file (700 MB or so) over
FTP to the target. Note that I've encountered the problem in the
context of the 2.4 kernel.
(*) In some cases you can run several such transfers in a row without
problem. Power-cycling the board will bring it back to "normal" mode.
It's probably Bestcomm related. See the previous discussions with
Freescale about known issues with the 2.6 Bestcomm code.
> Also, what are the 'symptoms' ? (anything in dmesg ?)
No, nothing.
Best regards,
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Like winter snow on summer lawn, time past is time gone.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Stability of MPC5200 FEC
2006-02-11 15:28 ` Sylvain Munaut
2006-02-11 16:08 ` Wolfgang Denk
@ 2006-02-13 8:08 ` Asier Llano Palacios
2006-02-14 17:35 ` John Rigby
1 sibling, 1 reply; 6+ messages in thread
From: Asier Llano Palacios @ 2006-02-13 8:08 UTC (permalink / raw)
To: Sylvain Munaut; +Cc: John Rigby, linuxppc-embedded
[-- 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(ðcmd, 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 [flat|nested] 6+ messages in thread
* Re: Stability of MPC5200 FEC
2006-02-13 8:08 ` Asier Llano Palacios
@ 2006-02-14 17:35 ` John Rigby
0 siblings, 0 replies; 6+ messages in thread
From: John Rigby @ 2006-02-14 17:35 UTC (permalink / raw)
To: Asier Llano Palacios; +Cc: John Rigby, linuxppc-embedded
Asier,
I tried copying 700MB files to my lite board with ftp on sylvain's
latest kernel
and was not able to reproduce the problem. One thing I did see
though were lots of RX framing errors. I will investigate this further.
I consulted with someone in Freescale who knows a lot more about
bestcomm dma and the 5200 than me and his best guess was
that there is a problem in error handling. Can you have your
partner report what the error counts reported by ifconfig are?
This might give us some clue about what is leading to the problem.
Thanks
John
jrigby@freescale.com
jcrigby@gmail.com
On 2/13/06, Asier Llano Palacios <a.llano@ziv.es> wrote:
> El s=E1b, 11-02-2006 a las 16:28 +0100, Sylvain Munaut escribi=F3:
> > 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=EDa de Desarrollo.
>
> ZIV, Aplicaciones y Tecnolog=EDa.
> Parque Tecnol=F3gico, 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 authoriz=
ed recipients.
> If this message has reached you in error, kindly destroy it without revie=
w and notify the sender immediately.
> Thank you for your help.
> =B5SysCom uses virus scanning software but excludes any liability for vir=
uses contained in any attachment.
>
> ------------------------------------ ROGAMOS LEA ESTE TEXTO -------------=
------------------
> Este mensaje y sus anexos pueden contener informaci=F3n confidencial y/o =
con derecho legal.
> Est=E1 dirigido =FAnicamente a la/s persona/s o entidad/es rese=F1adas co=
mo =FAnico destinatario autorizado.
> Si este mensaje le hubiera llegado por error, por favor elim=EDnelo sin r=
evisarlo ni reenviarlo y notif=EDquelo inmediatamente al remitente. Gracias=
por su colaboraci=F3n.
> =B5SysCom utiliza software antivirus, pero no se hace responsable de los =
virus contenidos en los ficheros anexos.
>
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2006-02-14 17:35 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-02-10 17:20 Stability of MPC5200 FEC Asier Llano Palacios
2006-02-10 18:22 ` John Rigby
2006-02-11 15:28 ` Sylvain Munaut
2006-02-11 16:08 ` Wolfgang Denk
2006-02-13 8:08 ` Asier Llano Palacios
2006-02-14 17:35 ` John Rigby
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).