Skip to content

Commit

Permalink
net:cxgb3: replace tasklets with works
Browse files Browse the repository at this point in the history
OFLD and CTRL TX queues can be stopped if there is no room in
their DMA rings. If this happens, they're tried to be restarted
later after having made some room in the corresponding ring.

The tasks of restarting these queues were triggered using
tasklets, but they can be replaced for workqueue works, getting
them out of softirq context.

This queues stop/restart probably doesn't happen often and they
can be quite lengthy because they try to send all pending skbs.
Moreover, given that probably the ring is not empty yet, so the
DMA still has work to do, we don't need to be so fast to justify
using tasklets/softirq instead of running in a thread.

Signed-off-by: Íñigo Huguet <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
ihuguet authored and davem330 committed Jun 3, 2021
1 parent a29cb69 commit 5e0b892
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 17 deletions.
2 changes: 1 addition & 1 deletion drivers/net/ethernet/chelsio/cxgb3/adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ struct sge_txq { /* state for an SGE Tx queue */
unsigned int token; /* WR token */
dma_addr_t phys_addr; /* physical address of the ring */
struct sk_buff_head sendq; /* List of backpressured offload packets */
struct tasklet_struct qresume_tsk; /* restarts the queue */
struct work_struct qresume_task; /* restarts the queue */
unsigned int cntxt_id; /* SGE context id for the Tx q */
unsigned long stops; /* # of times q has been stopped */
unsigned long restarts; /* # of queue restarts */
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/chelsio/cxgb3/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -770,4 +770,6 @@ int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
int phy_addr, const struct mdio_ops *mdio_ops);
int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter,
int phy_addr, const struct mdio_ops *mdio_ops);

extern struct workqueue_struct *cxgb3_wq;
#endif /* __CHELSIO_COMMON_H */
38 changes: 22 additions & 16 deletions drivers/net/ethernet/chelsio/cxgb3/sge.c
Original file line number Diff line number Diff line change
Expand Up @@ -1518,14 +1518,15 @@ static int ctrl_xmit(struct adapter *adap, struct sge_txq *q,

/**
* restart_ctrlq - restart a suspended control queue
* @t: pointer to the tasklet associated with this handler
* @w: pointer to the work associated with this handler
*
* Resumes transmission on a suspended Tx control queue.
*/
static void restart_ctrlq(struct tasklet_struct *t)
static void restart_ctrlq(struct work_struct *w)
{
struct sk_buff *skb;
struct sge_qset *qs = from_tasklet(qs, t, txq[TXQ_CTRL].qresume_tsk);
struct sge_qset *qs = container_of(w, struct sge_qset,
txq[TXQ_CTRL].qresume_task);
struct sge_txq *q = &qs->txq[TXQ_CTRL];

spin_lock(&q->lock);
Expand Down Expand Up @@ -1736,14 +1737,15 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);

/**
* restart_offloadq - restart a suspended offload queue
* @t: pointer to the tasklet associated with this handler
* @w: pointer to the work associated with this handler
*
* Resumes transmission on a suspended Tx offload queue.
*/
static void restart_offloadq(struct tasklet_struct *t)
static void restart_offloadq(struct work_struct *w)
{
struct sk_buff *skb;
struct sge_qset *qs = from_tasklet(qs, t, txq[TXQ_OFLD].qresume_tsk);
struct sge_qset *qs = container_of(w, struct sge_qset,
txq[TXQ_OFLD].qresume_task);
struct sge_txq *q = &qs->txq[TXQ_OFLD];
const struct port_info *pi = netdev_priv(qs->netdev);
struct adapter *adap = pi->adapter;
Expand Down Expand Up @@ -1998,13 +2000,17 @@ static void restart_tx(struct sge_qset *qs)
should_restart_tx(&qs->txq[TXQ_OFLD]) &&
test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) {
qs->txq[TXQ_OFLD].restarts++;
tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk);

/* The work can be quite lengthy so we use driver's own queue */
queue_work(cxgb3_wq, &qs->txq[TXQ_OFLD].qresume_task);
}
if (test_bit(TXQ_CTRL, &qs->txq_stopped) &&
should_restart_tx(&qs->txq[TXQ_CTRL]) &&
test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) {
qs->txq[TXQ_CTRL].restarts++;
tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk);

/* The work can be quite lengthy so we use driver's own queue */
queue_work(cxgb3_wq, &qs->txq[TXQ_CTRL].qresume_task);
}
}

Expand Down Expand Up @@ -3085,8 +3091,8 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
skb_queue_head_init(&q->txq[i].sendq);
}

tasklet_setup(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq);
tasklet_setup(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq);
INIT_WORK(&q->txq[TXQ_OFLD].qresume_task, restart_offloadq);
INIT_WORK(&q->txq[TXQ_CTRL].qresume_task, restart_ctrlq);

q->fl[0].gen = q->fl[1].gen = 1;
q->fl[0].size = p->fl_size;
Expand Down Expand Up @@ -3276,11 +3282,11 @@ void t3_sge_start(struct adapter *adap)
*
* Can be invoked from interrupt context e.g. error handler.
*
* Note that this function cannot disable the restart of tasklets as
* Note that this function cannot disable the restart of works as
* it cannot wait if called from interrupt context, however the
* tasklets will have no effect since the doorbells are disabled. The
* works will have no effect since the doorbells are disabled. The
* driver will call tg3_sge_stop() later from process context, at
* which time the tasklets will be stopped if they are still running.
* which time the works will be stopped if they are still running.
*/
void t3_sge_stop_dma(struct adapter *adap)
{
Expand All @@ -3292,7 +3298,7 @@ void t3_sge_stop_dma(struct adapter *adap)
* @adap: the adapter
*
* Called from process context. Disables the DMA engine and any
* pending queue restart tasklets.
* pending queue restart works.
*/
void t3_sge_stop(struct adapter *adap)
{
Expand All @@ -3303,8 +3309,8 @@ void t3_sge_stop(struct adapter *adap)
for (i = 0; i < SGE_QSETS; ++i) {
struct sge_qset *qs = &adap->sge.qs[i];

tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk);
tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk);
cancel_work_sync(&qs->txq[TXQ_OFLD].qresume_task);
cancel_work_sync(&qs->txq[TXQ_OFLD].qresume_task);
}
}

Expand Down

0 comments on commit 5e0b892

Please sign in to comment.