summaryrefslogtreecommitdiff
path: root/recipes-kernel/linux/linux-3.12.70/linux-3.12-cadence-macb.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-kernel/linux/linux-3.12.70/linux-3.12-cadence-macb.patch')
-rw-r--r--recipes-kernel/linux/linux-3.12.70/linux-3.12-cadence-macb.patch106
1 files changed, 106 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-3.12.70/linux-3.12-cadence-macb.patch b/recipes-kernel/linux/linux-3.12.70/linux-3.12-cadence-macb.patch
new file mode 100644
index 0000000..c814ed1
--- /dev/null
+++ b/recipes-kernel/linux/linux-3.12.70/linux-3.12-cadence-macb.patch
@@ -0,0 +1,106 @@
+--- linux-3.12.27/drivers/net/ethernet/cadence/macb.c 2014-08-26 07:12:26.000000000 -0500
++++ linux-3.12.27/drivers/net/ethernet/cadence/macb.c 2016-09-26 13:36:54.760657601 -0500
+@@ -755,7 +755,10 @@
+ unsigned int frag_len = bp->rx_buffer_size;
+
+ if (offset + frag_len > len) {
+- BUG_ON(frag != last_frag);
++ if (unlikely(frag != last_frag)) {
++ dev_kfree_skb_any(skb);
++ return -1;
++ }
+ frag_len = len - offset;
+ }
+ skb_copy_to_linear_data_offset(skb, offset,
+@@ -783,11 +786,27 @@
+ return 0;
+ }
+
++static inline void macb_init_rx_ring(struct macb *bp)
++{
++ int i;
++ dma_addr_t addr;
++
++ addr = bp->rx_buffers_dma;
++ for (i = 0; i < RX_RING_SIZE; i++) {
++ bp->rx_ring[i].addr = addr;
++ bp->rx_ring[i].ctrl = 0;
++ addr += bp->rx_buffer_size;
++ }
++ bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
++ bp->rx_tail = 0;
++}
++
+ static int macb_rx(struct macb *bp, int budget)
+ {
+ int received = 0;
+ unsigned int tail;
+ int first_frag = -1;
++ int reset_rx_queue = 0;
+
+ for (tail = bp->rx_tail; budget > 0; tail++) {
+ struct macb_dma_desc *desc = macb_rx_desc(bp, tail);
+@@ -810,10 +829,18 @@
+
+ if (ctrl & MACB_BIT(RX_EOF)) {
+ int dropped;
+- BUG_ON(first_frag == -1);
++
++ if (unlikely(first_frag == -1)) {
++ reset_rx_queue = 1;
++ continue;
++ }
+
+ dropped = macb_rx_frame(bp, first_frag, tail);
+ first_frag = -1;
++ if (unlikely(dropped < 0)) {
++ reset_rx_queue = 1;
++ continue;
++ }
+ if (!dropped) {
+ received++;
+ budget--;
+@@ -821,6 +848,26 @@
+ }
+ }
+
++ if (unlikely(reset_rx_queue)) {
++ unsigned long flags;
++ u32 ctrl;
++
++ netdev_err(bp->dev, "RX queue corruption: reset it\n");
++
++ spin_lock_irqsave(&bp->lock, flags);
++
++ ctrl = macb_readl(bp, NCR);
++ macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE));
++
++ macb_init_rx_ring(bp);
++ macb_writel(bp, RBQP, bp->rx_ring_dma);
++
++ macb_writel(bp, NCR, ctrl | MACB_BIT(RE));
++
++ spin_unlock_irqrestore(&bp->lock, flags);
++ return received;
++ }
++
+ if (first_frag != -1)
+ bp->rx_tail = first_frag;
+ else
+@@ -1189,15 +1236,8 @@
+ static void macb_init_rings(struct macb *bp)
+ {
+ int i;
+- dma_addr_t addr;
+
+- addr = bp->rx_buffers_dma;
+- for (i = 0; i < RX_RING_SIZE; i++) {
+- bp->rx_ring[i].addr = addr;
+- bp->rx_ring[i].ctrl = 0;
+- addr += bp->rx_buffer_size;
+- }
+- bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
++ macb_init_rx_ring(bp);
+
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ bp->tx_ring[i].addr = 0;