diff options
Diffstat (limited to 'drivers/net/ethernet/cadence/macb_main.c')
| -rw-r--r-- | drivers/net/ethernet/cadence/macb_main.c | 27 | 
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index a363da928e8b..d13f06cf0308 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -1573,7 +1573,14 @@ static int macb_poll(struct napi_struct *napi, int budget)  	if (work_done < budget) {  		napi_complete_done(napi, work_done); -		/* Packets received while interrupts were disabled */ +		/* RSR bits only seem to propagate to raise interrupts when +		 * interrupts are enabled at the time, so if bits are already +		 * set due to packets received while interrupts were disabled, +		 * they will not cause another interrupt to be generated when +		 * interrupts are re-enabled. +		 * Check for this case here. This has been seen to happen +		 * around 30% of the time under heavy network load. +		 */  		status = macb_readl(bp, RSR);  		if (status) {  			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) @@ -1581,6 +1588,22 @@ static int macb_poll(struct napi_struct *napi, int budget)  			napi_reschedule(napi);  		} else {  			queue_writel(queue, IER, bp->rx_intr_mask); + +			/* In rare cases, packets could have been received in +			 * the window between the check above and re-enabling +			 * interrupts. Therefore, a double-check is required +			 * to avoid losing a wakeup. This can potentially race +			 * with the interrupt handler doing the same actions +			 * if an interrupt is raised just after enabling them, +			 * but this should be harmless. +			 */ +			status = macb_readl(bp, RSR); +			if (unlikely(status)) { +				queue_writel(queue, IDR, bp->rx_intr_mask); +				if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) +					queue_writel(queue, ISR, MACB_BIT(RCOMP)); +				napi_schedule(napi); +			}  		}  	} @@ -4712,7 +4735,7 @@ static int macb_probe(struct platform_device *pdev)  #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT  	if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) { -		dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); +		dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44));  		bp->hw_dma_cap |= HW_DMA_CAP_64B;  	}  #endif  |