lkml.org 
[lkml]   [2015]   [Jan]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.18 100/183] net: ethernet: cpsw: fix hangs with interrupts
    Date
    3.18-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Felipe Balbi <balbi@ti.com>

    commit 7ce67a38f799d1fb332f672b117efbadedaa5352 upstream.

    The CPSW IP implements pulse-signaled interrupts. Due to
    that we must write a correct, pre-defined value to the
    CPDMA_MACEOIVECTOR register so the controller generates
    a pulse on the correct IRQ line to signal the End Of
    Interrupt.

    The way the driver is written today, all four IRQ lines
    are requested using the same IRQ handler and, because of
    that, we could fall into situations where a TX IRQ fires
    but we tell the controller that we ended an RX IRQ (or
    vice-versa). This situation triggers an IRQ storm on the
    reserved IRQ 127 of INTC which will in turn call ack_bad_irq()
    which will, then, print a ton of:

    unexpected IRQ trap at vector 00

    In order to fix the problem, we are moving all calls to
    cpdma_ctlr_eoi() inside the IRQ handler and making sure
    we *always* write the correct value to the CPDMA_MACEOIVECTOR
    register. Note that the algorithm assumes that IRQ numbers and
    value-to-be-written-to-EOI are proportional, meaning that a
    write of value 0 would trigger an EOI pulse for the RX_THRESHOLD
    Interrupt and that's the IRQ number sitting in the 0-th index
    of our irqs_table array.

    This, however, is safe at least for current implementations of
    CPSW so we will refrain from making the check smarter (and, as
    a side-effect, slower) until we actually have a platform where
    IRQ lines are swapped.

    This patch has been tested for several days with AM335x- and
    AM437x-based platforms. AM57x was left out because there are
    still pending patches to enable ethernet in mainline for that
    platform. A read of the TRM confirms the statement on previous
    paragraph.

    Reported-by: Yegor Yefremov <yegorslists@googlemail.com>
    Fixes: 510a1e7 (drivers: net: davinci_cpdma: acknowledge interrupt properly)
    Signed-off-by: Felipe Balbi <balbi@ti.com>
    Acked-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/net/ethernet/ti/cpsw.c | 19 ++++++++-----------
    1 file changed, 8 insertions(+), 11 deletions(-)

    --- a/drivers/net/ethernet/ti/cpsw.c
    +++ b/drivers/net/ethernet/ti/cpsw.c
    @@ -757,6 +757,14 @@ requeue:
    static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
    {
    struct cpsw_priv *priv = dev_id;
    + int value = irq - priv->irqs_table[0];
    +
    + /* NOTICE: Ending IRQ here. The trick with the 'value' variable above
    + * is to make sure we will always write the correct value to the EOI
    + * register. Namely 0 for RX_THRESH Interrupt, 1 for RX Interrupt, 2
    + * for TX Interrupt and 3 for MISC Interrupt.
    + */
    + cpdma_ctlr_eoi(priv->dma, value);

    cpsw_intr_disable(priv);
    if (priv->irq_enabled == true) {
    @@ -786,8 +794,6 @@ static int cpsw_poll(struct napi_struct
    int num_tx, num_rx;

    num_tx = cpdma_chan_process(priv->txch, 128);
    - if (num_tx)
    - cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);

    num_rx = cpdma_chan_process(priv->rxch, budget);
    if (num_rx < budget) {
    @@ -795,7 +801,6 @@ static int cpsw_poll(struct napi_struct

    napi_complete(napi);
    cpsw_intr_enable(priv);
    - cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
    prim_cpsw = cpsw_get_slave_priv(priv, 0);
    if (prim_cpsw->irq_enabled == false) {
    prim_cpsw->irq_enabled = true;
    @@ -1310,8 +1315,6 @@ static int cpsw_ndo_open(struct net_devi
    napi_enable(&priv->napi);
    cpdma_ctlr_start(priv->dma);
    cpsw_intr_enable(priv);
    - cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
    - cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);

    prim_cpsw = cpsw_get_slave_priv(priv, 0);
    if (prim_cpsw->irq_enabled == false) {
    @@ -1578,9 +1581,6 @@ static void cpsw_ndo_tx_timeout(struct n
    cpdma_chan_start(priv->txch);
    cpdma_ctlr_int_ctrl(priv->dma, true);
    cpsw_intr_enable(priv);
    - cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
    - cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
    -
    }

    static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p)
    @@ -1620,9 +1620,6 @@ static void cpsw_ndo_poll_controller(str
    cpsw_interrupt(ndev->irq, priv);
    cpdma_ctlr_int_ctrl(priv->dma, true);
    cpsw_intr_enable(priv);
    - cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
    - cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
    -
    }
    #endif




    \
     
     \ /
      Last update: 2015-01-25 20:01    [W:4.095 / U:0.032 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site