diff options
author | Claudiu Manoil <claudiu.manoil@freescale.com> | 2014-02-24 10:13:42 (GMT) |
---|---|---|
committer | Madalin-Cristian Bucur <madalin.bucur@freescale.com> | 2014-02-26 09:29:34 (GMT) |
commit | a426340a9b486420c96dc6cee929474dbfff19ec (patch) | |
tree | 349d295f8d9aa70cd9e7bf354474fdfe1fe82ca9 | |
parent | e09dbeef39d7b168fa0cf4c71256c6898af17a56 (diff) | |
download | linux-fsl-qoriq-a426340a9b486420c96dc6cee929474dbfff19ec.tar.xz |
gianfar: Implement MAC reset and reconfig procedure
The main MAC config registers like: RCTRL/TCTRL, MRBLR,
MAXFRM, RXIC/TXIC, most fields of MACCFG1/2, should not
be changed on-the-fly, but at least after stopping the
DMA and disabling the Rx/Tx blocks and, for increased
reliability, after a MAC soft reset.
Impelement a complete MAC soft reset and reconfig procedure
following the latest HW advisories - gfar_mac_reset() - to
replace gfar_mac_init() and (the confusing) init_registers()
functions.
Factor out separate config functions for RCTRL and TCTRL,
insure programming order of the relevant config regs after
MAC soft reset.
Split gfar_hw_init() into gfar_mac_reset() and the remaining
global regs that don't need to be reconfigured after MAC soft
reset (FIFOCFG, ATTRELI, HW counters a.s.o).
As gfar_hw_init() now makes all the register writes @probe()
time, based on all the device flags and config options, it
must be moved further down, just before register_netdev(),
as the last config step when the config values are comitted
to HW. Also, move netif_carrier_off() after register_netdev(),
because it has no effect if called before.
Signed-off-by: Claudiu Manoil <claudiu.manoil@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Change-Id: I8c89d4eac35553329f99277a6249bf477bbacdf6
Reviewed-on: http://git.am.freescale.net:8181/9147
Reviewed-by: Madalin-Cristian Bucur <madalin.bucur@freescale.com>
Tested-by: Madalin-Cristian Bucur <madalin.bucur@freescale.com>
-rw-r--r-- | drivers/net/ethernet/freescale/gianfar.c | 172 |
1 files changed, 90 insertions, 82 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 4a63717..cf96fb4 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -129,7 +129,6 @@ static irqreturn_t gfar_error(int irq, void *dev_id); static irqreturn_t gfar_transmit(int irq, void *dev_id); static irqreturn_t gfar_interrupt(int irq, void *dev_id); static void adjust_link(struct net_device *dev); -static void init_registers(struct net_device *dev); static int init_phy(struct net_device *dev); static int gfar_probe(struct platform_device *ofdev); static int gfar_remove(struct platform_device *ofdev); @@ -338,18 +337,10 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv) } } -static void gfar_init_mac(struct net_device *ndev) +static void gfar_mac_rx_config(struct gfar_private *priv) { - struct gfar_private *priv = netdev_priv(ndev); struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 rctrl = 0; - u32 tctrl = 0; - - /* write the tx/rx base registers */ - gfar_init_tx_rx_base(priv); - - /* Configure the coalescing support */ - gfar_configure_coalescing_all(priv); /* set this when rx hw offload (TOE) functions are being used */ priv->uses_rxfcb = 0; @@ -361,18 +352,16 @@ static void gfar_init_mac(struct net_device *ndev) } /* Restore PROMISC mode */ - if (ndev->flags & IFF_PROMISC) + if (priv->ndev->flags & IFF_PROMISC) rctrl |= RCTRL_PROM; - if (ndev->features & NETIF_F_RXCSUM) { + if (priv->ndev->features & NETIF_F_RXCSUM) { rctrl |= RCTRL_CHECKSUMMING; priv->uses_rxfcb = 1; } if (priv->extended_hash) { rctrl |= RCTRL_EXTHASH; - - gfar_clear_exact_match(ndev); rctrl |= RCTRL_EMEN; } @@ -387,15 +376,21 @@ static void gfar_init_mac(struct net_device *ndev) priv->uses_rxfcb = 1; } - if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX) { + if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX) { rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; priv->uses_rxfcb = 1; } /* Init rctrl based on our settings */ gfar_write(®s->rctrl, rctrl); +} - if (ndev->features & NETIF_F_IP_CSUM) +static void gfar_mac_tx_config(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 tctrl = 0; + + if (priv->ndev->features & NETIF_F_IP_CSUM) tctrl |= TCTRL_INIT_CSUM; if (priv->prio_sched_en) @@ -1010,28 +1005,94 @@ static void gfar_detect_errata(struct gfar_private *priv) priv->errata); } -static void gfar_hw_init(struct gfar_private *priv) +static void gfar_mac_reset(struct gfar_private *priv) { struct gfar __iomem *regs = priv->gfargrp[0].regs; - u32 tempval, attrs; + u32 tempval; /* Reset MAC layer */ gfar_write(®s->maccfg1, MACCFG1_SOFT_RESET); /* We need to delay at least 3 TX clocks */ - udelay(2); + udelay(3); /* the soft reset bit is not self-resetting, so we need to * clear it before resuming normal operation */ gfar_write(®s->maccfg1, 0); + udelay(3); + + /* Initialize the max receive buffer length */ + gfar_write(®s->mrblr, priv->rx_buffer_size); + + /* Initialize the Minimum Frame Length Register */ + gfar_write(®s->minflr, MINFLR_INIT_SETTINGS); + /* Initialize MACCFG2. */ tempval = MACCFG2_INIT_SETTINGS; if (gfar_has_errata(priv, GFAR_ERRATA_74)) tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK; gfar_write(®s->maccfg2, tempval); + /* Clear mac addr hash registers */ + gfar_write(®s->igaddr0, 0); + gfar_write(®s->igaddr1, 0); + gfar_write(®s->igaddr2, 0); + gfar_write(®s->igaddr3, 0); + gfar_write(®s->igaddr4, 0); + gfar_write(®s->igaddr5, 0); + gfar_write(®s->igaddr6, 0); + gfar_write(®s->igaddr7, 0); + + gfar_write(®s->gaddr0, 0); + gfar_write(®s->gaddr1, 0); + gfar_write(®s->gaddr2, 0); + gfar_write(®s->gaddr3, 0); + gfar_write(®s->gaddr4, 0); + gfar_write(®s->gaddr5, 0); + gfar_write(®s->gaddr6, 0); + gfar_write(®s->gaddr7, 0); + + if (priv->extended_hash) + gfar_clear_exact_match(priv->ndev); + + gfar_mac_rx_config(priv); + + gfar_mac_tx_config(priv); + + gfar_set_mac_address(priv->ndev); + + gfar_set_multi(priv->ndev); + + /* clear ievent and imask before configuring coalescing */ + gfar_ints_disable(priv); + + /* Configure the coalescing support */ + gfar_configure_coalescing_all(priv); +} + +static void gfar_hw_init(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 attrs; + + /* Stop the DMA engine now, in case it was running before + * (The firmware could have used it, and left it running). + */ + gfar_halt(priv); + + gfar_mac_reset(priv); + + /* Zero out the rmon mib registers if it has them */ + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { + memset_io(&(regs->rmon), 0, sizeof(struct rmon_mib)); + + /* Mask off the CAM interrupts */ + gfar_write(®s->rmon.cam1, 0xffffffff); + gfar_write(®s->rmon.cam2, 0xffffffff); + } + /* Initialize ECNTRL */ gfar_write(®s->ecntrl, ECNTRL_INIT_SETTINGS); @@ -1131,13 +1192,6 @@ static int gfar_probe(struct platform_device *ofdev) 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(priv); - - gfar_hw_init(priv); - /* Set the dev->base_addr to the gfar reg region */ dev->base_addr = (unsigned long) priv->gfargrp[0].regs; @@ -1203,8 +1257,7 @@ static int gfar_probe(struct platform_device *ofdev) if (priv->num_tx_queues == 1) priv->prio_sched_en = 1; - /* Carrier starts down, phylib will bring it up */ - netif_carrier_off(dev); + gfar_hw_init(priv); err = register_netdev(dev); @@ -1213,6 +1266,9 @@ static int gfar_probe(struct platform_device *ofdev) goto register_fail; } + /* Carrier starts down, phylib will bring it up */ + netif_carrier_off(dev); + device_init_wakeup(&dev->dev, priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); @@ -1395,9 +1451,10 @@ static int gfar_restore(struct device *dev) return -ENOMEM; } - init_registers(ndev); - gfar_set_mac_address(ndev); - gfar_init_mac(ndev); + gfar_mac_reset(priv); + + gfar_init_tx_rx_base(priv); + gfar_start(priv); priv->oldlink = 0; @@ -1556,48 +1613,6 @@ static void gfar_configure_serdes(struct net_device *dev) BMCR_SPEED1000); } -static void init_registers(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - - gfar_ints_disable(priv); - - /* Init hash registers to zero */ - gfar_write(®s->igaddr0, 0); - gfar_write(®s->igaddr1, 0); - gfar_write(®s->igaddr2, 0); - gfar_write(®s->igaddr3, 0); - gfar_write(®s->igaddr4, 0); - gfar_write(®s->igaddr5, 0); - gfar_write(®s->igaddr6, 0); - gfar_write(®s->igaddr7, 0); - - gfar_write(®s->gaddr0, 0); - gfar_write(®s->gaddr1, 0); - gfar_write(®s->gaddr2, 0); - gfar_write(®s->gaddr3, 0); - gfar_write(®s->gaddr4, 0); - gfar_write(®s->gaddr5, 0); - gfar_write(®s->gaddr6, 0); - gfar_write(®s->gaddr7, 0); - - /* Zero out the rmon mib registers if it has them */ - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { - memset_io(&(regs->rmon), 0, sizeof (struct rmon_mib)); - - /* Mask off the CAM interrupts */ - gfar_write(®s->rmon.cam1, 0xffffffff); - gfar_write(®s->rmon.cam2, 0xffffffff); - } - - /* Initialize the max receive buffer length */ - gfar_write(®s->mrblr, priv->rx_buffer_size); - - /* Initialize the Minimum Frame Length Register */ - gfar_write(®s->minflr, MINFLR_INIT_SETTINGS); -} - static int __gfar_is_rx_idle(struct gfar_private *priv) { u32 res; @@ -1933,13 +1948,13 @@ int startup_gfar(struct net_device *ndev) struct gfar_private *priv = netdev_priv(ndev); int err, i, j; - gfar_ints_disable(priv); + gfar_mac_reset(priv); err = gfar_alloc_skb_resources(ndev); if (err) return err; - gfar_init_mac(ndev); + gfar_init_tx_rx_base(priv); for (i = 0; i < priv->num_grps; i++) { err = register_grp_irqs(&priv->gfargrp[i]); @@ -1955,8 +1970,6 @@ int startup_gfar(struct net_device *ndev) phy_start(priv->phydev); - gfar_configure_coalescing_all(priv); - return 0; irq_fail: @@ -1974,11 +1987,6 @@ static int gfar_enet_open(struct net_device *dev) enable_napi(priv); - /* Initialize a bunch of registers */ - init_registers(dev); - - gfar_set_mac_address(dev); - err = init_phy(dev); if (err) { |