From aa1e1c812c40947644f9fa17d892d9daf67e6ae7 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Fri, 13 Apr 2012 16:57:10 +0800 Subject: ENGR00179636-01 - FEC : Enet RX FIFO overruns issue. - Add NAPI methods. NAPI can improve the performance of high-speed networking, which can reduce the cpu loading of interrupt generate and drop packets. - Enet RX FIFO overruns number has been reduced by NAPI method. Signed-off-by: Fugang Duan --- drivers/net/Kconfig | 7 ++ drivers/net/fec.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 206 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index cec12046b8a7..da594eac38aa 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1951,6 +1951,13 @@ config FEC Say Y here if you want to use the built-in 10/100 Fast ethernet controller on some Motorola ColdFire and Freescale i.MX processors. +config FEC_NAPI + bool "Use NAPI for FEC driver" + depends on FEC + help + This option enables NAPI support for the FEC's on-chip + Fast Ethernet Controller driver. + config FEC_1588 bool "Enable FEC 1588 timestamping" depends on FEC diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 2078ef8d25f0..a93ac31e690f 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -230,10 +230,22 @@ struct fec_enet_private { struct fec_ptp_private *ptp_priv; uint ptimer_present; + + struct napi_struct napi; + int napi_weight; + bool use_napi; }; +#define FEC_NAPI_WEIGHT 64 +#ifdef CONFIG_FEC_NAPI +#define FEC_NAPI_ENABLE TRUE +#else +#define FEC_NAPI_ENABLE FALSE +#endif + static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); static void fec_enet_tx(struct net_device *dev); +static int fec_rx_poll(struct napi_struct *napi, int budget); static void fec_enet_rx(struct net_device *dev); static int fec_enet_close(struct net_device *dev); static void fec_restart(struct net_device *dev, int duplex); @@ -389,6 +401,29 @@ fec_timeout(struct net_device *ndev) netif_wake_queue(ndev); } +static void +fec_rx_int_is_enabled(struct net_device *ndev, bool enabled) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + uint int_events; + + int_events = readl(fep->hwp + FEC_IMASK); + if (enabled) + int_events |= FEC_ENET_RXF; + else + int_events &= ~FEC_ENET_RXF; + writel(int_events, fep->hwp + FEC_IMASK); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void fec_enet_netpoll(struct net_device *ndev) +{ + disable_irq(ndev->irq); + fec_enet_interrupt(ndev->irq, ndev); + enable_irq(ndev->irq); +} +#endif + static void fec_enet_tx(struct net_device *ndev) { @@ -478,6 +513,144 @@ fec_enet_tx(struct net_device *ndev) spin_unlock(&fep->hw_lock); } +/*NAPI polling Receive packets */ +static int fec_rx_poll(struct napi_struct *napi, int budget) +{ + struct fec_enet_private *fep = + container_of(napi, struct fec_enet_private, napi); + struct net_device *ndev = napi->dev; + struct fec_ptp_private *fpp = fep->ptp_priv; + const struct platform_device_id *id_entry = + platform_get_device_id(fep->pdev); + int pkt_received = 0; + struct bufdesc *bdp; + unsigned short status; + struct sk_buff *skb; + ushort pkt_len; + __u8 *data; + + if (fep->use_napi) + WARN_ON(!budget); + +#ifdef CONFIG_M532x + flush_cache_all(); +#endif + + /* First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = fep->cur_rx; + + while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { + if (pkt_received >= budget) + break; + pkt_received++; + + /* Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((status & BD_ENET_RX_LAST) == 0) + dev_err(&ndev->dev, "FEC ENET: rcv is not +last\n"); + + if (!fep->opened) + goto rx_processing_done; + + /* Check for errors. */ + if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | + BD_ENET_RX_CR | BD_ENET_RX_OV)) { + ndev->stats.rx_errors++; + if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { + /* Frame too long or too short. */ + ndev->stats.rx_length_errors++; + } + if (status & BD_ENET_RX_NO) /* Frame alignment */ + ndev->stats.rx_frame_errors++; + if (status & BD_ENET_RX_CR) /* CRC Error */ + ndev->stats.rx_crc_errors++; + if (status & BD_ENET_RX_OV) /* FIFO overrun */ + ndev->stats.rx_fifo_errors++; + } + + /* Report late collisions as a frame error. + * On this error, the BD is closed, but we don't know what we + * have in the buffer. So, just drop this frame on the floor. + */ + if (status & BD_ENET_RX_CL) { + ndev->stats.rx_errors++; + ndev->stats.rx_frame_errors++; + goto rx_processing_done; + } + + /* Process the incoming frame. */ + ndev->stats.rx_packets++; + pkt_len = bdp->cbd_datlen; + ndev->stats.rx_bytes += pkt_len; + data = (__u8 *)__va(bdp->cbd_bufaddr); + + if (bdp->cbd_bufaddr) + dma_unmap_single(&ndev->dev, bdp->cbd_bufaddr, + FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); + + if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) + swap_buffer(data, pkt_len); + + /* This does 16 byte alignment, exactly what we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len - 4 + NET_IP_ALIGN); + + if (unlikely(!skb)) { + dev_err(&ndev->dev, + "%s: Memory squeeze, dropping packet.\n", ndev->name); + ndev->stats.rx_dropped++; + } else { + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, pkt_len - 4); /* Make room */ + skb_copy_to_linear_data(skb, data, pkt_len - 4); + /* 1588 messeage TS handle */ + if (fep->ptimer_present) + fec_ptp_store_rxstamp(fpp, skb, bdp); + skb->protocol = eth_type_trans(skb, ndev); + netif_receive_skb(skb); + } + + bdp->cbd_bufaddr = dma_map_single(&ndev->dev, data, + FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); +rx_processing_done: + /* Clear the status flags for this buffer */ + status &= ~BD_ENET_RX_STATS; + + /* Mark the buffer empty */ + status |= BD_ENET_RX_EMPTY; + bdp->cbd_sc = status; +#ifdef CONFIG_ENHANCED_BD + bdp->cbd_esc = BD_ENET_RX_INT; + bdp->cbd_prot = 0; + bdp->cbd_bdu = 0; +#endif + + /* Update BD pointer to next entry */ + if (status & BD_ENET_RX_WRAP) + bdp = fep->rx_bd_base; + else + bdp++; + /* Doing this here will keep the FEC running while we process + * incoming frames. On a heavily loaded network, we should be + * able to keep up at the expense of system resources. + */ + writel(0, fep->hwp + FEC_R_DES_ACTIVE); + } + fep->cur_rx = bdp; + + if (pkt_received < budget) { + napi_complete(napi); + fec_rx_int_is_enabled(ndev, true); + } + + return pkt_received; +} /* During a receive, the cur_rx points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has @@ -501,8 +674,6 @@ fec_enet_rx(struct net_device *ndev) flush_cache_all(); #endif - spin_lock(&fep->hw_lock); - /* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. */ @@ -607,8 +778,6 @@ rx_processing_done: writel(0, fep->hwp + FEC_R_DES_ACTIVE); } fep->cur_rx = bdp; - - spin_unlock(&fep->hw_lock); } static irqreturn_t @@ -618,6 +787,7 @@ fec_enet_interrupt(int irq, void *dev_id) struct fec_enet_private *fep = netdev_priv(ndev); struct fec_ptp_private *fpp = fep->ptp_priv; uint int_events; + ulong flags; irqreturn_t ret = IRQ_NONE; do { @@ -626,7 +796,18 @@ fec_enet_interrupt(int irq, void *dev_id) if (int_events & FEC_ENET_RXF) { ret = IRQ_HANDLED; - fec_enet_rx(ndev); + spin_lock_irqsave(&fep->hw_lock, flags); + + if (fep->use_napi) { + /* Disable the RX interrupt */ + if (napi_schedule_prep(&fep->napi)) { + fec_rx_int_is_enabled(ndev, false); + __napi_schedule(&fep->napi); + } + } else + fec_enet_rx(ndev); + + spin_unlock_irqrestore(&fep->hw_lock, flags); } /* Transmit OK, or non-fatal error. Update the buffer @@ -1106,6 +1287,9 @@ fec_enet_open(struct net_device *ndev) struct fec_platform_data *pdata = fep->pdev->dev.platform_data; int ret; + if (fep->use_napi) + napi_enable(&fep->napi); + /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */ @@ -1266,6 +1450,9 @@ static const struct net_device_ops fec_netdev_ops = { .ndo_tx_timeout = fec_timeout, .ndo_set_mac_address = fec_set_mac_address, .ndo_do_ioctl = fec_enet_ioctl, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = fec_enet_netpoll, +#endif }; /* @@ -1303,6 +1490,13 @@ static int fec_enet_init(struct net_device *ndev) ndev->netdev_ops = &fec_netdev_ops; ndev->ethtool_ops = &fec_enet_ethtool_ops; + fep->use_napi = FEC_NAPI_ENABLE; + fep->napi_weight = FEC_NAPI_WEIGHT; + if (fep->use_napi) { + fec_rx_int_is_enabled(ndev, false); + netif_napi_add(ndev, &fep->napi, fec_rx_poll, fep->napi_weight); + } + /* Initialize the receive buffer descriptors. */ bdp = fep->rx_bd_base; for (i = 0; i < RX_RING_SIZE; i++) { -- cgit v1.2.3 From 87e5c8a237f189e507e32623c536462c00e9ede7 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Fri, 20 Apr 2012 18:16:24 +0800 Subject: ENGR00179636-02 - FEC : Enet RX FIFO overruns issue. - Increase RX BD size to 384 entrys from 16 entrys, which can reduce the overruns number in busy system. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index a93ac31e690f..0fe11753b4c0 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -119,7 +119,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); * We don't need to allocate pages for the transmitter. We just use * the skbuffer directly. */ -#define FEC_ENET_RX_PAGES 8 +#define FEC_ENET_RX_PAGES 192 #define FEC_ENET_RX_FRSIZE 2048 #define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) #define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) -- cgit v1.2.3 From 3a227e2db36aa075eb7534fa5d83ae17011a57dc Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Fri, 4 May 2012 15:48:42 +0800 Subject: ENGR00181514 - FEC : fix kernel dump warning with suspend/resume. - Fix clock enable/disable match operation to avoid kernel dump warning "clock enable/disable mismatch". Signed-off-by: Fugang Duan --- drivers/net/fec.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 0fe11753b4c0..7897de31b9a0 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -906,8 +906,6 @@ static void fec_enet_adjust_link(struct net_device *ndev) /* Duplex link change */ if (phy_dev->link) { - if (!clk_get_usecount(fep->clk)) - clk_enable(fep->clk); if (fep->full_duplex != phy_dev->duplex) { fec_restart(ndev, phy_dev->duplex); status_change = 1; @@ -1293,8 +1291,7 @@ fec_enet_open(struct net_device *ndev) /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */ - if (!clk_get_usecount(fep->clk)) - clk_enable(fep->clk); + clk_enable(fep->clk); ret = fec_enet_alloc_buffers(ndev); if (ret) return ret; @@ -1325,6 +1322,10 @@ fec_enet_close(struct net_device *ndev) /* Don't know what to do yet. */ fep->opened = 0; netif_stop_queue(ndev); + netif_carrier_off(ndev); + if (fep->use_napi) + napi_disable(&fep->napi); + fec_stop(ndev); if (fep->phy_dev) { @@ -1335,8 +1336,7 @@ fec_enet_close(struct net_device *ndev) fec_enet_free_buffers(ndev); /* Clock gate close for saving power */ - if (clk_get_usecount(fep->clk)) - clk_disable(fep->clk); + clk_disable(fep->clk); return 0; } @@ -1798,6 +1798,7 @@ fec_probe(struct platform_device *pdev) /* Carrier starts down, phylib will bring it up */ netif_carrier_off(ndev); + clk_disable(fep->clk); ret = register_netdev(ndev); if (ret) @@ -1865,10 +1866,11 @@ fec_suspend(struct device *dev) struct fec_enet_private *fep = netdev_priv(ndev); if (netif_running(ndev)) { - fec_stop(ndev); netif_device_detach(ndev); + fec_stop(ndev); + netif_carrier_off(ndev); + clk_disable(fep->clk); } - clk_disable(fep->clk); return 0; } @@ -1879,8 +1881,8 @@ fec_resume(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct fec_enet_private *fep = netdev_priv(ndev); - clk_enable(fep->clk); if (netif_running(ndev)) { + clk_enable(fep->clk); fec_restart(ndev, fep->full_duplex); netif_device_attach(ndev); } -- cgit v1.2.3 From 3d629fdd4caf3dc28835ec89f5fbaefa3997bfe0 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Mon, 7 May 2012 15:14:23 +0800 Subject: ENGR00179636-04 - FEC : allocate the enough DMA size for BD. - Increase RX BD size to 384 entrys from 16 entrys, and allocate the enough DMA memory for buffer description. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 7897de31b9a0..6e710e11f1a4 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -128,9 +128,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define TX_RING_SIZE 16 /* Must be power of two */ #define TX_RING_MOD_MASK 15 /* for this to work */ -#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE) -#error "FEC: descriptor ring size constants too large" -#endif +#define BUFDES_SIZE ((RX_RING_SIZE + TX_RING_SIZE) * sizeof(struct bufdesc)) /* Interrupt events/masks. */ #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ @@ -1467,7 +1465,7 @@ static int fec_enet_init(struct net_device *ndev) int i; /* Allocate memory for buffer descriptors. */ - cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, + cbd_base = dma_alloc_coherent(NULL, BUFDES_SIZE, &fep->bd_dma, GFP_KERNEL); if (!cbd_base) { printk("FEC: allocate descriptor memory failed?\n"); -- cgit v1.2.3 From dfcf626fefa855256ee49ecb4370388423df6b29 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 16 May 2012 16:59:03 +0800 Subject: ENGR00171114 flexcan: enable can2 remote wakeup for mx6q The root cause is missed to set CAN2_STOP_REQ in iomuxc group register which is used to support can wakeup feature. Signed-off-by: Dong Aisheng --- drivers/net/can/flexcan.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 27dcf755debc..467b5355de89 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -195,6 +195,7 @@ struct flexcan_priv { struct clk *clk; struct flexcan_platform_data *pdata; enum flexcan_ip_version version; + int id; }; static struct can_bittiming_const flexcan_bittiming_const = { @@ -580,7 +581,8 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) if (reg_esr & FLEXCAN_ESR_WAK_INT) { /* first clear stop request then wakeup irq status */ if (priv->version >= FLEXCAN_VER_10_0_12) - mxc_iomux_set_gpr_register(13, 28, 1, 0); + /* CAN1/CAN2_STOP_REQ bit 28/29 in group 13 */ + mxc_iomux_set_gpr_register(13, 28 + priv->id, 1, 0); writel(FLEXCAN_ESR_WAK_INT, ®s->esr); } @@ -960,6 +962,9 @@ static int __devinit flexcan_probe(struct platform_device *pdev) resource_size_t mem_size; int err, irq; + if (pdev->id < 0) + return -ENODEV; + clk = clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "no clock defined\n"); @@ -1007,6 +1012,7 @@ static int __devinit flexcan_probe(struct platform_device *pdev) priv->base = base; priv->dev = dev; priv->clk = clk; + priv->id = pdev->id; priv->pdata = pdev->dev.platform_data; priv->version = pdev->id_entry->driver_data; @@ -1074,7 +1080,8 @@ static int flexcan_suspend(struct platform_device *pdev, pm_message_t state) /* enable stop request for wakeup */ if (priv->version >= FLEXCAN_VER_10_0_12) - mxc_iomux_set_gpr_register(13, 28, 1, 1); + /* CAN1/CAN2_STOP_REQ bit 28/29 in group 13 */ + mxc_iomux_set_gpr_register(13, 28 + priv->id, 1, 1); ret = irq_set_irq_wake(dev->irq, 1); if (ret) -- cgit v1.2.3 From 1776a2f3ee24cff0cf4ed140eabff2bd48eaad6f Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 16 May 2012 17:57:53 +0800 Subject: ENGR00209520-03 - FEC : Add support for MX6SL MSL. - Modify the the platform macro define like as cpu_is_xxx() for supporting Mergrez chip. - Config MIIGSK for FEC IP to enable RMII mode. MX25,MX53, and MX6Sololite use FEC IP, which need to config the MIIGSK registers memory map for RMII and MII. - Correct device id_table entry name for differnt IP. - Rewrite FEC MAC address by net_device address when reset FEC, which can avoid invalid MAC address to result in FEC cannot work. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 75 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 33 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 6e710e11f1a4..acb2965ae77d 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -71,17 +71,14 @@ #define FEC_QUIRK_SWAP_FRAME (1 << 1) static struct platform_device_id fec_devtype[] = { -#ifdef CONFIG_SOC_IMX6Q { - .name = DRIVER_NAME, + .name = "enet", .driver_data = FEC_QUIRK_ENET_MAC, }, -#else { - .name = DRIVER_NAME, + .name = "fec", .driver_data = 0, }, -#endif { .name = "imx28-fec", .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME, @@ -146,12 +143,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_ENET_MII_CLK ((uint)2500000) #define FEC_ENET_HOLD_TIME ((uint)0x100) /* 2 internal clock cycle*/ -#if defined(CONFIG_FEC_1588) && (defined(CONFIG_ARCH_MX28) || \ - defined(CONFIG_ARCH_MX6)) -#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | \ - FEC_ENET_TS_AVAIL | FEC_ENET_TS_TIMER) -#else #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII) +#if defined(CONFIG_FEC_1588) +#define FEC_1588_IMASK (FEC_ENET_TS_AVAIL | FEC_ENET_TS_TIMER) +#else +#define FEC_1588_IMASK 0 #endif /* The FEC stores dest/src/type, data, and checksum for receive packets. @@ -1032,7 +1028,7 @@ static int fec_enet_mii_probe(struct net_device *ndev) } /* mask with MAC supported features */ - if (cpu_is_mx6()) + if (cpu_is_mx6q() || cpu_is_mx6dl()) phy_dev->supported &= PHY_GBIT_FEATURES; else phy_dev->supported &= PHY_BASIC_FEATURES; @@ -1091,7 +1087,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) (FEC_ENET_MII_CLK << 2)) << 1; /* set hold time to 2 internal clock cycle */ - if (cpu_is_mx6()) + if (cpu_is_mx6q() || cpu_is_mx6dl()) fep->phy_speed |= FEC_ENET_HOLD_TIME; writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); @@ -1546,14 +1542,14 @@ fec_restart(struct net_device *dev, int duplex) udelay(10); /* - * enet-mac reset will reset mac address registers too, - * so need to reconfigure it. + /* if uboot don't set MAC address, get MAC address + * from command line; if command line don't set MAC + * address, get from OCOTP; otherwise, allocate random + * address. */ - if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { - memcpy(&temp_mac, dev->dev_addr, ETH_ALEN); - writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); - writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); - } + memcpy(&temp_mac, dev->dev_addr, ETH_ALEN); + writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); + writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); /* Clear any outstanding interrupt. */ writel(0xffc00000, fep->hwp + FEC_IEVENT); @@ -1623,23 +1619,24 @@ fec_restart(struct net_device *dev, int duplex) val |= (1 << 9); writel(val, fep->hwp + FEC_R_CNTRL); + } - if (fep->ptimer_present) { - /* Set Timer count */ - ret = fec_ptp_start(fep->ptp_priv); - if (ret) { - fep->ptimer_present = 0; - reg = 0x0; - } else + if (fep->ptimer_present) { + /* Set Timer count */ + ret = fec_ptp_start(fep->ptp_priv); + if (ret) { + fep->ptimer_present = 0; + reg = 0x0; + } else #if defined(CONFIG_SOC_IMX28) || defined(CONFIG_ARCH_MX6) - reg = 0x00000010; + reg = 0x00000010; #else - reg = 0x0; + reg = 0x0; #endif } else reg = 0x0; -#ifdef FEC_MIIGSK_ENR + if (cpu_is_mx25() || cpu_is_mx53() || cpu_is_mx6sl()) { if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) { /* disable the gasket and wait */ writel(0, fep->hwp + FEC_MIIGSK_ENR); @@ -1654,8 +1651,14 @@ fec_restart(struct net_device *dev, int duplex) /* re-enable the gasket */ writel(2, fep->hwp + FEC_MIIGSK_ENR); + udelay(10); + if (!(readl(fep->hwp + FEC_MIIGSK_ENR) & 4)) { + udelay(100); + if (!(readl(fep->hwp + FEC_MIIGSK_ENR) & 4)) + dev_err(&fep->pdev->dev, + "switch to RMII failed!\n"); + } } -#endif } /* ENET enable */ @@ -1668,7 +1671,7 @@ fec_restart(struct net_device *dev, int duplex) fep->phy_dev->speed == SPEED_1000) val |= (0x1 << 5); - if (cpu_is_mx6()) { + if (cpu_is_mx6q() || cpu_is_mx6dl()) { /* enable endian swap */ val |= (0x1 << 8); /* enable ENET store and forward mode */ @@ -1679,7 +1682,11 @@ fec_restart(struct net_device *dev, int duplex) writel(0, fep->hwp + FEC_R_DES_ACTIVE); /* Enable interrupts we wish to service */ - writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); + if (cpu_is_mx6q() || cpu_is_mx6dl() || cpu_is_mx2() || cpu_is_mx3()) + val = (FEC_1588_IMASK | FEC_DEFAULT_IMASK); + else + val = FEC_DEFAULT_IMASK; + writel(val, fep->hwp + FEC_IMASK); } static void @@ -1699,7 +1706,7 @@ fec_stop(struct net_device *dev) writel(1, fep->hwp + FEC_ECNTRL); udelay(10); - if (cpu_is_mx6()) + if (cpu_is_mx6q() || cpu_is_mx6dl()) /* FIXME: we have to enable enet to keep mii interrupt works. */ writel(2, fep->hwp + FEC_ECNTRL); @@ -1707,6 +1714,8 @@ fec_stop(struct net_device *dev) if (fep->ptimer_present) fec_ptp_stop(fep->ptp_priv); writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); + netif_stop_queue(dev); + fep->link = 0; } static int __devinit -- cgit v1.2.3