return received;
}
+static bool macb_rx_pending(struct macb_queue *queue)
+{
+ struct macb *bp = queue->bp;
+ unsigned int entry;
+ struct macb_dma_desc *desc;
+
+ entry = macb_rx_ring_wrap(bp, queue->rx_tail);
+ desc = macb_rx_desc(queue, entry);
+
+ /* Make hw descriptor updates visible to CPU */
+ rmb();
+
+ return (desc->addr & MACB_BIT(RX_USED)) != 0;
+}
+
static int macb_poll(struct napi_struct *napi, int budget)
{
struct macb_queue *queue = container_of(napi, struct macb_queue, napi);
struct macb *bp = queue->bp;
int work_done;
- u32 status;
- status = macb_readl(bp, RSR);
- macb_writel(bp, RSR, status);
+ work_done = bp->macbgem_ops.mog_rx(queue, napi, budget);
- netdev_vdbg(bp->dev, "poll: status = %08lx, budget = %d\n",
- (unsigned long)status, budget);
+ netdev_vdbg(bp->dev, "poll: queue = %u, work_done = %d, budget = %d\n",
+ (unsigned int)(queue - bp->queues), work_done, budget);
- work_done = bp->macbgem_ops.mog_rx(queue, napi, budget);
- if (work_done < budget) {
- napi_complete_done(napi, work_done);
+ if (work_done < budget && napi_complete_done(napi, work_done)) {
+ queue_writel(queue, IER, bp->rx_intr_mask);
- /* 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,
+ /* Packet completions only seem to propagate to raise
+ * interrupts when interrupts are enabled at the time, so if
+ * packets were 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.
+ * Check for this case here 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 (status) {
+ if (macb_rx_pending(queue)) {
+ 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_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);
- }
+ netdev_vdbg(bp->dev, "poll: packets pending, reschedule\n");
+ napi_schedule(napi);
}
}