imx6q: high interrupt latencies

Shawn Guo shawn.guo at linaro.org
Mon Oct 8 01:20:45 EDT 2012


On Sat, Sep 29, 2012 at 11:58:57PM +0200, Gilles Chanteperdrix wrote:
> 
> Hi,
> 
> I have been observing high interrupt latencies on imx6q, the problem
> seems to be in the FEC driver, function fec_enet_tx. The following line:
> 
>         while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
> 
> can take 100us or more to execute, during which the local timer
> interrupt are postponed.
> 
> As far as I understand, bdp is a pointer to a "struct bufdesc" shared
> with the hardware and its status member is updated by the hardware when
> the corresponding ethernet packet transmission is complete.
> 
> Adding a call to "mb()" or "outer_sync()" before reading the status
> seems to avoid the issue, though I do not know if this is the proper fix.
> 
> Some more data. The boot logs say:
> CPU: ARMv7 Processor [412fc09a] revision 10 (ARMv7), cr=10c53c7d
> CPU identified as i.MX6Q, silicon rev 1.0
> l2x0: 16 ways, CACHE_ID 0x410000c7
> 
> the kernel is compiled with the following errata enabled:
> CONFIG_PL310_ERRATA_588369
> CONFIG_PL310_ERRATA_727915
> CONFIG_ARM_ERRATA_743622
> CONFIG_ARM_ERRATA_751472
> CONFIG_ARM_ERRATA_754322
> CONFIG_ARM_ERRATA_764369
> CONFIG_PL310_ERRATA_769419
> 
Are you running mainline kernel?  The boot log and the errata settings
are different from what we have with mainline kernel.

I'm using the following patch to measure the time on with v3.6 kernel,
and seeing the output is mostly 2 ~ 4 us.

diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index fffd205..f72955a 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -566,11 +566,13 @@ fec_enet_tx(struct net_device *ndev)
        struct bufdesc *bdp;
        unsigned short status;
        struct  sk_buff *skb;
+       struct timeval time1, time2;

        fep = netdev_priv(ndev);
        spin_lock(&fep->hw_lock);
        bdp = fep->dirty_tx;

+       do_gettimeofday(&time1);
        while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
                if (bdp == fep->cur_tx && fep->tx_full == 0)
                        break;
@@ -627,6 +629,8 @@ fec_enet_tx(struct net_device *ndev)
                                netif_wake_queue(ndev);
                }
        }
+       do_gettimeofday(&time2);
+       printk("*** %s: %lu\n", __func__, timeval_to_ns(&time2) - timeval_to_ns(&time1));
        fep->dirty_tx = bdp;
        spin_unlock(&fep->hw_lock);
 }

Shawn



More information about the linux-arm-kernel mailing list