@@ -508,40 +508,29 @@ static int macb_poll(struct napi_struct
u32 status;
status = macb_readl(bp, RSR);
- macb_writel(bp, RSR, status);
-
- work_done = 0;
- if (!status) {
- /*
- * This may happen if an interrupt was pending before
- * this function was called last time, and no packets
- * have been received since.
- */
- netif_rx_complete(dev, napi);
- goto out;
- }
+ macb_writel(bp, RSR, status); /* not atomic read-clear! */
dev_dbg(&bp->pdev->dev, "poll: status = %08lx, budget = %d\n",
(unsigned long)status, budget);
- if (!(status & MACB_BIT(REC))) {
- dev_warn(&bp->pdev->dev,
- "No RX buffers complete, status = %02lx\n",
- (unsigned long)status);
- netif_rx_complete(dev, napi);
- goto out;
- }
-
work_done = macb_rx(bp, budget);
- if (work_done < budget)
+ if ((work_done < budget) && !macb_readl(bp, RSR)) {
+ /*
+ * We've done what we can to clean the buffers.
+ * Make sure there's no new RX activity during transition
+ * from poll mode back to interrupt mode.
+ */
netif_rx_complete(dev, napi);
-
- /*
- * We've done what we can to clean the buffers. Make sure we
- * get notified when new packets arrive.
- */
-out:
- macb_writel(bp, IER, MACB_RX_INT_FLAGS);
+ macb_writel(bp, IER, MACB_RX_INT_FLAGS);
+ status = macb_readl(bp, RSR);
+ if (status) {
+ /* new RX, undo the polling-done operations */
+ macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
+ netif_rx_reschedule(dev, napi);
+ dev_dbg(&bp->pdev->dev, "poll: undo status =
%08lx\n",
+ (unsigned long)status);
+ }
+ }
/* TODO: Handle errors */