From 0083c564ba18a3a6914eec003965cb3d44b44143 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 27 Mar 2013 18:23:16 +0800 Subject: ENGR00255406 net: fec: Workaround tx hang due to TDAR bit cleared by uDMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MTIP enet IP have one IC issue recorded at PDM ticket:TKT168103 The issue description: The TDAR bit after being set by software is not acted upon by the ENET module due to the timing of when the ENET state machine clearing the TDAR bit occurring coincident or momentarily after the software sets the bit. The result: The corresponding transmit packet for an incoming ping is delayed. Workaround: This forces the ENET module to check the Transmit buffer descriptor and take action if the “ready” flag is set. Otherwise the ENET module returns to idle mode. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 4b5818e4d71e..5f0e4e0e3a3e 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -19,7 +19,7 @@ * Copyright (c) 2004-2006 Macq Electronique SA. * * Support for FEC IEEE 1588. - * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. + * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. */ #include @@ -69,11 +69,13 @@ #define FEC_QUIRK_ENET_MAC (1 << 0) /* Controller needs driver to swap frame */ #define FEC_QUIRK_SWAP_FRAME (1 << 1) +/* ENET IP errata ticket TKT168103 */ +#define FEC_QUIRK_BUG_TKT168103 (1 << 2) static struct platform_device_id fec_devtype[] = { { .name = "enet", - .driver_data = FEC_QUIRK_ENET_MAC, + .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_BUG_TKT168103, }, { .name = "fec", @@ -81,7 +83,8 @@ static struct platform_device_id fec_devtype[] = { }, { .name = "imx28-fec", - .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME, + .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME | + FEC_QUIRK_BUG_TKT168103, }, { } }; @@ -228,6 +231,7 @@ struct fec_enet_private { int link; int full_duplex; struct completion mdio_done; + struct delayed_work fixup_trigger_tx; struct fec_ptp_private *ptp_priv; uint ptimer_present; @@ -277,13 +281,44 @@ static void *swap_buffer(void *bufaddr, int len) return bufaddr; } +static inline +void *fec_enet_get_pre_txbd(struct net_device *ndev) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + struct bufdesc *bdp = fep->cur_tx; + + if (bdp == fep->tx_bd_base) + return bdp + TX_RING_SIZE; + else + return bdp - 1; + +} + +/* MTIP enet IP have one IC issue recorded at PDM ticket:TKT168103 + * The TDAR bit after being set by software is not acted upon by the + * ENET module due to the timing of when the ENET state machine + * clearing the TDAR bit occurring coincident or momentarily after + * the software sets the bit. + * This forces ENET module to check the Transmit buffer descriptor + * and take action if the “ready” flag is set. Otherwise the ENET + * returns to idle mode. + */ +static void fixup_trigger_tx_func(struct work_struct *work) +{ + struct fec_enet_private *fep = + container_of(work, struct fec_enet_private, + fixup_trigger_tx.work); + + writel(0, fep->hwp + FEC_X_DES_ACTIVE); +} + static netdev_tx_t fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); const struct platform_device_id *id_entry = platform_get_device_id(fep->pdev); - struct bufdesc *bdp; + struct bufdesc *bdp, *bdp_pre; void *bufaddr; unsigned short status; unsigned long estatus; @@ -299,7 +334,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* Fill in a Tx ring entry */ bdp = fep->cur_tx; - status = bdp->cbd_sc; if (status & BD_ENET_TX_READY) { @@ -372,6 +406,12 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* Trigger transmission start */ writel(0, fep->hwp + FEC_X_DES_ACTIVE); + bdp_pre = fec_enet_get_pre_txbd(ndev); + if ((id_entry->driver_data & FEC_QUIRK_BUG_TKT168103) && + !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) + schedule_delayed_work(&fep->fixup_trigger_tx, + msecs_to_jiffies(1)); + /* If this was the last BD in the ring, start at the beginning again. */ if (status & BD_ENET_TX_WRAP) bdp = fep->tx_bd_base; @@ -1872,6 +1912,8 @@ fec_probe(struct platform_device *pdev) netif_carrier_off(ndev); clk_disable(fep->clk); + INIT_DELAYED_WORK(&fep->fixup_trigger_tx, fixup_trigger_tx_func); + ret = register_netdev(ndev); if (ret) goto failed_register; @@ -1910,6 +1952,7 @@ fec_drv_remove(struct platform_device *pdev) struct fec_enet_private *fep = netdev_priv(ndev); struct resource *r; + cancel_delayed_work_sync(&fep->fixup_trigger_tx); fec_stop(ndev); fec_enet_mii_remove(fep); clk_disable(fep->clk); -- cgit v1.2.3 From 573bab0be2427d6664420eaf9d8e272dbe9d840f Mon Sep 17 00:00:00 2001 From: Ranjani Vaidyanathan Date: Mon, 1 Apr 2013 16:03:31 -0500 Subject: ENGR00256893-2 MX6Q/DL-Fix Ethernet performance issue when WAIT mode is active All of the interrupts from the ENET block are not routed to the GPC block. Hence ENET interrupts are not able to wake up the SOC when the system is in WAIT mode. And the ENET interrupt gets serviced only when another interrupt causes the SOC to exit WAIT mode. This impacts the ENET performance. To fix the issue two options: 1. Route the ENET interrupt to a GPIO. Need to enable the CONFIG_MX6_ENET_IRQ_TO_GPIO in the config. This patch provides support for routing the ENET interrupt to GPIO_1_6. Routing to this GPIO requires no HW board mods. If the GPIO_1_6 is being used for some other peripheral, this patch can be followed to route the ENET interrupt to any other GPIO though a HW mode maybe required. 2. If the GPIO mechanism cannot be used and is not enabled by the above mentioned config, the patch will disable entry to WAIT mode until ENET clock is active. When the ENET clock is disabled, WAIT mode will be automatically enetered. Signed-off-by: Ranjani Vaidyanathan --- drivers/net/fec.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 5f0e4e0e3a3e..fc65bdc96241 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1866,6 +1867,17 @@ fec_probe(struct platform_device *pdev) if (pdata) fep->phy_interface = pdata->phy; +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + gpio_request(pdata->gpio_irq, "gpio_enet_irq"); + gpio_direction_input(pdata->gpio_irq); + + irq = gpio_to_irq(pdata->gpio_irq); + ret = request_irq(irq, fec_enet_interrupt, + IRQF_TRIGGER_RISING, + pdev->name, ndev); + if (ret) + goto failed_irq; +#else /* This device has up to three irqs on some platforms */ for (i = 0; i < 3; i++) { irq = platform_get_irq(pdev, i); @@ -1880,6 +1892,7 @@ fec_probe(struct platform_device *pdev) goto failed_irq; } } +#endif fep->clk = clk_get(&pdev->dev, "fec_clk"); if (IS_ERR(fep->clk)) { @@ -1930,11 +1943,15 @@ failed_init: clk_disable(fep->clk); clk_put(fep->clk); failed_clk: +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + free_irq(irq, ndev); +#else for (i = 0; i < 3; i++) { irq = platform_get_irq(pdev, i); if (irq > 0) free_irq(irq, ndev); } +#endif failed_irq: iounmap(fep->hwp); failed_ioremap: -- cgit v1.2.3