Loading drivers/net/cxgb3/adapter.h +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading drivers/net/cxgb3/sge.c +88 −40 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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) Loading Loading @@ -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; } /** Loading Loading @@ -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; } Loading Loading @@ -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); Loading Loading @@ -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)) { Loading Loading @@ -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; Loading Loading @@ -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 Loading @@ -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]); 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) { refill_rspq(adap, &qs->rspq, 1); 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); } } } 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); } mod_timer(&qs->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); out: mod_timer(&qs->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD); } /** Loading Loading @@ -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), Loading Loading @@ -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; Loading @@ -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); } } Loading Loading
drivers/net/cxgb3/adapter.h +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
drivers/net/cxgb3/sge.c +88 −40 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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) Loading Loading @@ -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; } /** Loading Loading @@ -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; } Loading Loading @@ -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); Loading Loading @@ -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)) { Loading Loading @@ -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; Loading Loading @@ -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 Loading @@ -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]); 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) { refill_rspq(adap, &qs->rspq, 1); 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); } } } 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); } mod_timer(&qs->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); out: mod_timer(&qs->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD); } /** Loading Loading @@ -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), Loading Loading @@ -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; Loading @@ -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); } } Loading