All of lore.kernel.org
 help / color / mirror / Atom feed
From: Divy Le Ray <divy@chelsio.com>
To: davem@davemloft.net
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	swise@opengridcomputing.com
Subject: [PATCH net-next 5/10] cxgb3: separate TX and RX reclaim handlers
Date: Fri, 13 Mar 2009 00:14:04 -0700	[thread overview]
Message-ID: <20090313071404.21994.97427.stgit@speedy5> (raw)
In-Reply-To: <20090313071343.21994.85719.stgit@speedy5>

From: Divy Le Ray <divy@chelsio.com>

Separate TX and RX reclaim handlers
Don't disable interrupts in RX reclaim handler.

Signed-off-by: Divy Le Ray <divy@chelsio.com>
---

 drivers/net/cxgb3/adapter.h |    1 
 drivers/net/cxgb3/sge.c     |  128 ++++++++++++++++++++++++++++++-------------
 2 files changed, 89 insertions(+), 40 deletions(-)

diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 95dce48..66ce456 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -197,6 +197,7 @@ struct sge_qset {		/* an SGE queue set */
 	struct netdev_queue *tx_q;	/* associated netdev TX queue */
 	unsigned long txq_stopped;	/* which Tx queues are stopped */
 	struct timer_list tx_reclaim_timer;	/* reclaims TX buffers */
+	struct timer_list rx_reclaim_timer;	/* reclaims RX buffers */
 	unsigned long port_stats[SGE_PSTAT_MAX];
 } ____cacheline_aligned;
 
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index a482429..7d779d1 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -61,6 +61,7 @@
 #define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1)
 
 #define SGE_RX_DROP_THRES 16
+#define RX_RECLAIM_PERIOD (HZ/4)
 
 /*
  * Max number of Rx buffers we replenish at a time.
@@ -71,6 +72,8 @@
  * frequently as Tx buffers are usually reclaimed by new Tx packets.
  */
 #define TX_RECLAIM_PERIOD (HZ / 4)
+#define TX_RECLAIM_TIMER_CHUNK 64U
+#define TX_RECLAIM_CHUNK 16U
 
 /* WR size in bytes */
 #define WR_LEN (WR_FLITS * 8)
@@ -308,21 +311,25 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *q,
  *	reclaim_completed_tx - reclaims completed Tx descriptors
  *	@adapter: the adapter
  *	@q: the Tx queue to reclaim completed descriptors from
+ *	@chunk: maximum number of descriptors to reclaim
  *
  *	Reclaims Tx descriptors that the SGE has indicated it has processed,
  *	and frees the associated buffers if possible.  Called with the Tx
  *	queue's lock held.
  */
-static inline void reclaim_completed_tx(struct adapter *adapter,
-					struct sge_txq *q)
+static inline unsigned int reclaim_completed_tx(struct adapter *adapter,
+						struct sge_txq *q,
+						unsigned int chunk)
 {
 	unsigned int reclaim = q->processed - q->cleaned;
 
+	reclaim = min(chunk, reclaim);
 	if (reclaim) {
 		free_tx_desc(adapter, q, reclaim);
 		q->cleaned += reclaim;
 		q->in_use -= reclaim;
 	}
+	return q->processed - q->cleaned;
 }
 
 /**
@@ -601,6 +608,7 @@ static void t3_reset_qset(struct sge_qset *q)
 	memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET);
 	q->txq_stopped = 0;
 	q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */
+	q->rx_reclaim_timer.function = NULL;
 	q->lro_frag_tbl.nr_frags = q->lro_frag_tbl.len = 0;
 }
 
@@ -1179,7 +1187,7 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
 	txq = netdev_get_tx_queue(dev, qidx);
 
 	spin_lock(&q->lock);
-	reclaim_completed_tx(adap, q);
+	reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
 
 	credits = q->size - q->in_use;
 	ndesc = calc_tx_descs(skb);
@@ -1588,7 +1596,7 @@ static int ofld_xmit(struct adapter *adap, struct sge_txq *q,
 	unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen;
 
 	spin_lock(&q->lock);
-      again:reclaim_completed_tx(adap, q);
+again:	reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
 
 	ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD);
 	if (unlikely(ret)) {
@@ -1630,7 +1638,7 @@ static void restart_offloadq(unsigned long data)
 	struct adapter *adap = pi->adapter;
 
 	spin_lock(&q->lock);
-      again:reclaim_completed_tx(adap, q);
+again:	reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
 
 	while ((skb = skb_peek(&q->sendq)) != NULL) {
 		unsigned int gen, pidx;
@@ -2747,13 +2755,13 @@ void t3_sge_err_intr_handler(struct adapter *adapter)
 }
 
 /**
- *	sge_timer_cb - perform periodic maintenance of an SGE qset
+ *	sge_timer_tx - perform periodic maintenance of an SGE qset
  *	@data: the SGE queue set to maintain
  *
  *	Runs periodically from a timer to perform maintenance of an SGE queue
  *	set.  It performs two tasks:
  *
- *	a) Cleans up any completed Tx descriptors that may still be pending.
+ *	Cleans up any completed Tx descriptors that may still be pending.
  *	Normal descriptor cleanup happens when new packets are added to a Tx
  *	queue so this timer is relatively infrequent and does any cleanup only
  *	if the Tx queue has not seen any new packets in a while.  We make a
@@ -2763,51 +2771,87 @@ void t3_sge_err_intr_handler(struct adapter *adapter)
  *	up).  Since control queues use immediate data exclusively we don't
  *	bother cleaning them up here.
  *
- *	b) Replenishes Rx queues that have run out due to memory shortage.
- *	Normally new Rx buffers are added when existing ones are consumed but
- *	when out of memory a queue can become empty.  We try to add only a few
- *	buffers here, the queue will be replenished fully as these new buffers
- *	are used up if memory shortage has subsided.
  */
-static void sge_timer_cb(unsigned long data)
+static void sge_timer_tx(unsigned long data)
 {
-	spinlock_t *lock;
 	struct sge_qset *qs = (struct sge_qset *)data;
-	struct adapter *adap = qs->adap;
+	struct port_info *pi = netdev_priv(qs->netdev);
+	struct adapter *adap = pi->adapter;
+	unsigned int tbd[SGE_TXQ_PER_SET] = {0, 0};
+	unsigned long next_period;
 
 	if (spin_trylock(&qs->txq[TXQ_ETH].lock)) {
-		reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]);
+		tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH],
+						    TX_RECLAIM_TIMER_CHUNK);
 		spin_unlock(&qs->txq[TXQ_ETH].lock);
 	}
 	if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) {
-		reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD]);
+		tbd[TXQ_OFLD] = reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD],
+						     TX_RECLAIM_TIMER_CHUNK);
 		spin_unlock(&qs->txq[TXQ_OFLD].lock);
 	}
-	lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock :
-					    &adap->sge.qs[0].rspq.lock;
-	if (spin_trylock_irq(lock)) {
-		if (!napi_is_scheduled(&qs->napi)) {
-			u32 status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS);
-
-			if (qs->fl[0].credits < qs->fl[0].size)
-				__refill_fl(adap, &qs->fl[0]);
-			if (qs->fl[1].credits < qs->fl[1].size)
-				__refill_fl(adap, &qs->fl[1]);
-
-			if (status & (1 << qs->rspq.cntxt_id)) {
-				qs->rspq.starved++;
-				if (qs->rspq.credits) {
-					refill_rspq(adap, &qs->rspq, 1);
-					qs->rspq.credits--;
-					qs->rspq.restarted++;
-					t3_write_reg(adap, A_SG_RSPQ_FL_STATUS,
-						     1 << qs->rspq.cntxt_id);
-				}
+
+	next_period = TX_RECLAIM_PERIOD >>
+		      (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) /
+		       TX_RECLAIM_TIMER_CHUNK);
+	mod_timer(&qs->tx_reclaim_timer, jiffies + next_period);
+}
+
+/*
+ *	sge_timer_rx - perform periodic maintenance of an SGE qset
+ *	@data: the SGE queue set to maintain
+ *
+ *	a) Replenishes Rx queues that have run out due to memory shortage.
+ *	Normally new Rx buffers are added when existing ones are consumed but
+ *	when out of memory a queue can become empty.  We try to add only a few
+ *	buffers here, the queue will be replenished fully as these new buffers
+ *	are used up if memory shortage has subsided.
+ *
+ *	b) Return coalesced response queue credits in case a response queue is
+ *	starved.
+ *
+ */
+static void sge_timer_rx(unsigned long data)
+{
+	spinlock_t *lock;
+	struct sge_qset *qs = (struct sge_qset *)data;
+	struct port_info *pi = netdev_priv(qs->netdev);
+	struct adapter *adap = pi->adapter;
+	u32 status;
+
+	lock = adap->params.rev > 0 ?
+	       &qs->rspq.lock : &adap->sge.qs[0].rspq.lock;
+
+	if (!spin_trylock_irq(lock))
+		goto out;
+
+	if (napi_is_scheduled(&qs->napi))
+		goto unlock;
+
+	if (adap->params.rev < 4) {
+		status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS);
+
+		if (status & (1 << qs->rspq.cntxt_id)) {
+			qs->rspq.starved++;
+			if (qs->rspq.credits) {
+				qs->rspq.credits--;
+				refill_rspq(adap, &qs->rspq, 1);
+				qs->rspq.restarted++;
+				t3_write_reg(adap, A_SG_RSPQ_FL_STATUS,
+					     1 << qs->rspq.cntxt_id);
 			}
 		}
-		spin_unlock_irq(lock);
 	}
-	mod_timer(&qs->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+
+	if (qs->fl[0].credits < qs->fl[0].size)
+		__refill_fl(adap, &qs->fl[0]);
+	if (qs->fl[1].credits < qs->fl[1].size)
+		__refill_fl(adap, &qs->fl[1]);
+
+unlock:
+	spin_unlock_irq(lock);
+out:
+	mod_timer(&qs->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD);
 }
 
 /**
@@ -2850,7 +2894,8 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
 	struct sge_qset *q = &adapter->sge.qs[id];
 
 	init_qset_cntxt(q, id);
-	setup_timer(&q->tx_reclaim_timer, sge_timer_cb, (unsigned long)q);
+	setup_timer(&q->tx_reclaim_timer, sge_timer_tx, (unsigned long)q);
+	setup_timer(&q->rx_reclaim_timer, sge_timer_rx, (unsigned long)q);
 
 	q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size,
 				   sizeof(struct rx_desc),
@@ -2999,6 +3044,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
 		     V_NEWTIMER(q->rspq.holdoff_tmr));
 
 	mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+	mod_timer(&q->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD);
 
 	return 0;
 
@@ -3024,6 +3070,8 @@ void t3_stop_sge_timers(struct adapter *adap)
 
 		if (q->tx_reclaim_timer.function)
 			del_timer_sync(&q->tx_reclaim_timer);
+		if (q->rx_reclaim_timer.function)
+			del_timer_sync(&q->rx_reclaim_timer);
 	}
 }
 


  parent reply	other threads:[~2009-03-13  7:16 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-03-13  7:13 [PATCH net-next 1/10] cxgb3: ring rx door bell less frequently Divy Le Ray
2009-03-13  7:13 ` [PATCH net-next 2/10] cxgb3: release page ref on mapping error Divy Le Ray
2009-03-13  7:13 ` [PATCH net-next 3/10] cxgb3: fix skb truesize in jumbo mode Divy Le Ray
2009-03-13  7:13 ` [PATCH net-next 4/10] cxgb3: prefetch buffer access in GRO mode Divy Le Ray
2009-03-13  7:14 ` Divy Le Ray [this message]
2009-03-13  7:14 ` [PATCH net-next 6/10] cxgb3: disable high freq non-data interrupts Divy Le Ray
2009-03-13  7:14 ` [PATCH net-next 7/10] cxgb3: Update Rev3 mac workaround Divy Le Ray
2009-03-13  7:14 ` [PATCH net-next 8/10] cxgb3: detect mac link faults Divy Le Ray
2009-03-13  7:14 ` [PATCH net-next 9/10] cxgb3: update FW Divy Le Ray
2009-03-13  7:14 ` [PATCH net-next 10/10] cxgb3: update driver version Divy Le Ray

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090313071404.21994.97427.stgit@speedy5 \
    --to=divy@chelsio.com \
    --cc=davem@davemloft.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=swise@opengridcomputing.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.