Patch: fix rotting packet OKI PCH_GBE switch
From: Tom Walsh <hidden>
Date: 2016-07-27 15:59:08
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 <redacted>
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.cb/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(structpch_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) {