gianfar: Implement workaround for eTSEC74 erratum
MPC8313ECE says: "If MACCFG2[Huge Frame]=0 and the Ethernet controller receives frames which are larger than MAXFRM, the controller truncates the frames to length MAXFRM and marks RxBD[TR]=1 to indicate the error. The controller also erroneously marks RxBD[TR]=1 if the received frame length is MAXFRM or MAXFRM-1, even though those frames are not truncated. No truncation or truncation error occurs if MACCFG2[Huge Frame]=1." There are two options to workaround the issue: "1. Set MACCFG2[Huge Frame]=1, so no truncation occurs for invalid large frames. Software can determine if a frame is larger than MAXFRM by reading RxBD[LG] or RxBD[Data Length]. 2. Set MAXFRM to 1538 (0x602) instead of the default 1536 (0x600), so normal-length frames are not marked as truncated. Software can examine RxBD[Data Length] to determine if the frame was larger than MAXFRM-2." This patch implements the first workaround option by setting HUGEFRAME bit, and gfar_clean_rx_ring() already checks the RxBD[Data Length]. Signed-off-by: Anton Vorontsov <avorontsov@mvista.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
70777d0346
commit
7d3509774c
2 changed files with 38 additions and 2 deletions
|
@ -85,6 +85,7 @@
|
|||
#include <linux/net_tstamp.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/reg.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -928,6 +929,24 @@ static void gfar_init_filer_table(struct gfar_private *priv)
|
|||
}
|
||||
}
|
||||
|
||||
static void gfar_detect_errata(struct gfar_private *priv)
|
||||
{
|
||||
struct device *dev = &priv->ofdev->dev;
|
||||
unsigned int pvr = mfspr(SPRN_PVR);
|
||||
unsigned int svr = mfspr(SPRN_SVR);
|
||||
unsigned int mod = (svr >> 16) & 0xfff6; /* w/o E suffix */
|
||||
unsigned int rev = svr & 0xffff;
|
||||
|
||||
/* MPC8313 Rev 2.0 and higher; All MPC837x */
|
||||
if ((pvr == 0x80850010 && mod == 0x80b0 && rev >= 0x0020) ||
|
||||
(pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
|
||||
priv->errata |= GFAR_ERRATA_74;
|
||||
|
||||
if (priv->errata)
|
||||
dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
|
||||
priv->errata);
|
||||
}
|
||||
|
||||
/* Set up the ethernet device structure, private data,
|
||||
* and anything else we need before we start */
|
||||
static int gfar_probe(struct of_device *ofdev,
|
||||
|
@ -960,6 +979,8 @@ static int gfar_probe(struct of_device *ofdev,
|
|||
dev_set_drvdata(&ofdev->dev, priv);
|
||||
regs = priv->gfargrp[0].regs;
|
||||
|
||||
gfar_detect_errata(priv);
|
||||
|
||||
/* Stop the DMA engine now, in case it was running before */
|
||||
/* (The firmware could have used it, and left it running). */
|
||||
gfar_halt(dev);
|
||||
|
@ -974,7 +995,10 @@ static int gfar_probe(struct of_device *ofdev,
|
|||
gfar_write(®s->maccfg1, tempval);
|
||||
|
||||
/* Initialize MACCFG2. */
|
||||
gfar_write(®s->maccfg2, MACCFG2_INIT_SETTINGS);
|
||||
tempval = MACCFG2_INIT_SETTINGS;
|
||||
if (gfar_has_errata(priv, GFAR_ERRATA_74))
|
||||
tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK;
|
||||
gfar_write(®s->maccfg2, tempval);
|
||||
|
||||
/* Initialize ECNTRL */
|
||||
gfar_write(®s->ecntrl, ECNTRL_INIT_SETTINGS);
|
||||
|
@ -2300,7 +2324,8 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
|
|||
* to allow huge frames, and to check the length */
|
||||
tempval = gfar_read(®s->maccfg2);
|
||||
|
||||
if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE)
|
||||
if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
|
||||
gfar_has_errata(priv, GFAR_ERRATA_74))
|
||||
tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
|
||||
else
|
||||
tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
|
||||
|
|
|
@ -1025,6 +1025,10 @@ struct gfar_priv_grp {
|
|||
char int_name_er[GFAR_INT_NAME_MAX];
|
||||
};
|
||||
|
||||
enum gfar_errata {
|
||||
GFAR_ERRATA_74 = 0x01,
|
||||
};
|
||||
|
||||
/* Struct stolen almost completely (and shamelessly) from the FCC enet source
|
||||
* (Ok, that's not so true anymore, but there is a family resemblence)
|
||||
* The GFAR buffer descriptors track the ring buffers. The rx_bd_base
|
||||
|
@ -1049,6 +1053,7 @@ struct gfar_private {
|
|||
struct device_node *node;
|
||||
struct net_device *ndev;
|
||||
struct of_device *ofdev;
|
||||
enum gfar_errata errata;
|
||||
|
||||
struct gfar_priv_grp gfargrp[MAXGROUPS];
|
||||
struct gfar_priv_tx_q *tx_queue[MAX_TX_QS];
|
||||
|
@ -1111,6 +1116,12 @@ struct gfar_private {
|
|||
extern unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
|
||||
extern unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
|
||||
|
||||
static inline int gfar_has_errata(struct gfar_private *priv,
|
||||
enum gfar_errata err)
|
||||
{
|
||||
return priv->errata & err;
|
||||
}
|
||||
|
||||
static inline u32 gfar_read(volatile unsigned __iomem *addr)
|
||||
{
|
||||
u32 val;
|
||||
|
|
Loading…
Reference in a new issue