aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/cns3xxx
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2014-02-27 23:02:37 +0000
committerFelix Fietkau <nbd@openwrt.org>2014-02-27 23:02:37 +0000
commitcc53fad0065de6422d7a8ff8104fd6769513811c (patch)
treeacd8c4b2b4590fead3dd0cc182c989ae92259847 /target/linux/cns3xxx
parent6531bde627f10327ba1db14f2114866f4d866333 (diff)
downloadupstream-cc53fad0065de6422d7a8ff8104fd6769513811c.tar.gz
upstream-cc53fad0065de6422d7a8ff8104fd6769513811c.tar.bz2
upstream-cc53fad0065de6422d7a8ff8104fd6769513811c.zip
cns3xxx: ethernet - resolve SMP issue
The combination of r35942 and r35952 causes an issue where eth_schedule_poll() can be called from a different CPU between the call to napi_complete() and the setting of cur_index which can break the rx ring accounting and cause ethernet latency and/or ethernet stalls. The issue can be easilly created by adding a couple of artificial delays such as: @@ -715,6 +715,7 @@ static int eth_poll(struct napi_struct *napi, int budget) if (!received) { napi_complete(napi); +udelay(1000); enable_irq(IRQ_CNS3XXX_SW_R0RXC); } @@ -727,6 +728,7 @@ static int eth_poll(struct napi_struct *napi, int budget) rx_ring->cur_index = i; wmb(); +udelay(1000); enable_rx_dma(sw); return received; This patch moves the setting of cur_index back up where it needs to be and addresses the original corner case that r35942 was trying to catch in an improved fashion by checking to see if the rx descriptor ring has become full before interrupts were re-enabled so that a poll can be scheduled again and avoid an rx stall caused by rx interrupts ceasing to fire again. Signed-off-by: Tim Harvey <tharvey@gateworks.com> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@39761 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/cns3xxx')
-rw-r--r--target/linux/cns3xxx/files/drivers/net/ethernet/cavium/cns3xxx_eth.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/target/linux/cns3xxx/files/drivers/net/ethernet/cavium/cns3xxx_eth.c b/target/linux/cns3xxx/files/drivers/net/ethernet/cavium/cns3xxx_eth.c
index db15a2e2e5..bbbbf5c091 100644
--- a/target/linux/cns3xxx/files/drivers/net/ethernet/cavium/cns3xxx_eth.c
+++ b/target/linux/cns3xxx/files/drivers/net/ethernet/cavium/cns3xxx_eth.c
@@ -713,9 +713,14 @@ static int eth_poll(struct napi_struct *napi, int budget)
}
}
+ rx_ring->cur_index = i;
if (!received) {
napi_complete(napi);
enable_irq(IRQ_CNS3XXX_SW_R0RXC);
+
+ /* if rx descriptors are full schedule another poll */
+ if (rx_ring->desc[(i-1) & (RX_DESCS-1)].cown)
+ eth_schedule_poll(sw);
}
spin_lock_bh(&tx_lock);
@@ -724,8 +729,6 @@ static int eth_poll(struct napi_struct *napi, int budget)
cns3xxx_alloc_rx_buf(sw, received);
- rx_ring->cur_index = i;
-
wmb();
enable_rx_dma(sw);