This is against torvalds 4.7.0 repo This resolves a rotting SYN-ACK packet issue with the OKI PCH_GBE switch. The problem showed up intermittently where a client would attempt to establish a TCP connection to the host on an otherwise quiet network. No other activity had occurred for a significant time.
This was a race condition that was finally duplicated using a controlled set of timings between the SYN / ACK / SYN-ACK sequence. We found that by adjusting the timing between the host ACK and the client transmission of the SYN-ACK that we had the SYN-ACK "stuck" in the switch data register. The problem is that pch_gbe_irq_enable() is called when the transmit of the ACK has completed, then pch_gbe_irq_enable() will enable the interrupts of the switch, followed by a read of the INT_ST which results in clearing the status bits. While the device would still issue an interrupt, the pch_gbe_intr() handler would not see any pending requests as the status register had been cleared. Thus, the packet remains "stuck". Signed-off-by: Tom Walsh <tomwals...@gmail.com> diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 3cd87a4..baba31d 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -809,13 +809,16 @@ static void pch_gbe_irq_disable(struct pch_gbe_adapter *adapter) * pch_gbe_irq_enable - Enable default interrupt generation settings * @adapter: Board private structure */ -static void pch_gbe_irq_enable(struct pch_gbe_adapter *adapter) +static void pch_gbe_irq_enable(struct pch_gbe_adapter *adapter, + bool reset_status_register) { struct pch_gbe_hw *hw = &adapter->hw; - if (likely(atomic_dec_and_test(&adapter->irq_sem))) + if (likely(atomic_dec_and_test(&adapter->irq_sem))) { iowrite32(PCH_GBE_INT_ENABLE_MASK, &hw->reg->INT_EN); - ioread32(&hw->reg->INT_ST); + if (reset_status_register) + ioread32(&hw->reg->INT_ST); + } netdev_dbg(adapter->netdev, "INT_EN reg : 0x%08x\n", ioread32(&hw->reg->INT_EN)); } @@ -1976,7 +1979,7 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter) mod_timer(&adapter->watchdog_timer, jiffies); napi_enable(&adapter->napi); - pch_gbe_irq_enable(adapter); + pch_gbe_irq_enable(adapter, true); netif_start_queue(adapter->netdev); return 0; @@ -2392,7 +2395,7 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget) if (poll_end_flag) { napi_complete(napi); - pch_gbe_irq_enable(adapter); + pch_gbe_irq_enable(adapter, false); } if (adapter->rx_stop_flag) {