aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2007-10-12 04:39:50 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-12 05:01:20 -0400
commit4fd7ab5949edfdf99be0ceef206c9d0b7f186318 (patch)
treea99042048caea838d5e9af01c7d33307941099cd /drivers/net
parent782e3b3b3804c38d5130c7f21d7ec7bf6709023f (diff)
[TG3]: Refine napi poll loop.
Need to read and store sblk->status_tag before checking for more work. The status tag is later written back to the hardware when enabling interrupts to acknowledge how much work has been processed. If the order is reversed, we can end up acknowledging work we haven't processed. When we detect tx error, it is more correct to return the rx work_done so far instead of 0. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/tg3.c24
1 files changed, 14 insertions, 10 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index e795c33b982d..30b1cca8144c 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3576,7 +3576,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget)
3576 if (sblk->idx[0].tx_consumer != tp->tx_cons) { 3576 if (sblk->idx[0].tx_consumer != tp->tx_cons) {
3577 tg3_tx(tp); 3577 tg3_tx(tp);
3578 if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) 3578 if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
3579 return 0; 3579 return work_done;
3580 } 3580 }
3581 3581
3582 /* run RX thread, within the bounds set by NAPI. 3582 /* run RX thread, within the bounds set by NAPI.
@@ -3593,6 +3593,7 @@ static int tg3_poll(struct napi_struct *napi, int budget)
3593{ 3593{
3594 struct tg3 *tp = container_of(napi, struct tg3, napi); 3594 struct tg3 *tp = container_of(napi, struct tg3, napi);
3595 int work_done = 0; 3595 int work_done = 0;
3596 struct tg3_hw_status *sblk = tp->hw_status;
3596 3597
3597 while (1) { 3598 while (1) {
3598 work_done = tg3_poll_work(tp, work_done, budget); 3599 work_done = tg3_poll_work(tp, work_done, budget);
@@ -3603,15 +3604,17 @@ static int tg3_poll(struct napi_struct *napi, int budget)
3603 if (unlikely(work_done >= budget)) 3604 if (unlikely(work_done >= budget))
3604 break; 3605 break;
3605 3606
3606 if (likely(!tg3_has_work(tp))) { 3607 if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
3607 struct tg3_hw_status *sblk = tp->hw_status; 3608 /* tp->last_tag is used in tg3_restart_ints() below
3608 3609 * to tell the hw how much work has been processed,
3609 if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { 3610 * so we must read it before checking for more work.
3610 tp->last_tag = sblk->status_tag; 3611 */
3611 rmb(); 3612 tp->last_tag = sblk->status_tag;
3612 } else 3613 rmb();
3613 sblk->status &= ~SD_STATUS_UPDATED; 3614 } else
3615 sblk->status &= ~SD_STATUS_UPDATED;
3614 3616
3617 if (likely(!tg3_has_work(tp))) {
3615 netif_rx_complete(tp->dev, napi); 3618 netif_rx_complete(tp->dev, napi);
3616 tg3_restart_ints(tp); 3619 tg3_restart_ints(tp);
3617 break; 3620 break;
@@ -3621,9 +3624,10 @@ static int tg3_poll(struct napi_struct *napi, int budget)
3621 return work_done; 3624 return work_done;
3622 3625
3623tx_recovery: 3626tx_recovery:
3627 /* work_done is guaranteed to be less than budget. */
3624 netif_rx_complete(tp->dev, napi); 3628 netif_rx_complete(tp->dev, napi);
3625 schedule_work(&tp->reset_task); 3629 schedule_work(&tp->reset_task);
3626 return 0; 3630 return work_done;
3627} 3631}
3628 3632
3629static void tg3_irq_quiesce(struct tg3 *tp) 3633static void tg3_irq_quiesce(struct tg3 *tp)