forked from Minki/linux
ionic: dynamic interrupt moderation
Use the dim library to manage dynamic interrupt moderation in ionic. v3: rebase v2: untangled declarations in ionic_dim_work() Signed-off-by: Shannon Nelson <snelson@pensando.io> Acked-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ddcc9b7feb
commit
04a834592b
@ -189,6 +189,8 @@ void ionic_debugfs_add_qcq(struct ionic_lif *lif, struct ionic_qcq *qcq)
|
||||
&intr->index);
|
||||
debugfs_create_u32("vector", 0400, intr_dentry,
|
||||
&intr->vector);
|
||||
debugfs_create_u32("dim_coal_hw", 0400, intr_dentry,
|
||||
&intr->dim_coal_hw);
|
||||
|
||||
intr_ctrl_regset = devm_kzalloc(dev, sizeof(*intr_ctrl_regset),
|
||||
GFP_KERNEL);
|
||||
|
@ -237,6 +237,7 @@ struct ionic_intr_info {
|
||||
u64 rearm_count;
|
||||
unsigned int cpu;
|
||||
cpumask_t affinity_mask;
|
||||
u32 dim_coal_hw;
|
||||
};
|
||||
|
||||
struct ionic_cq {
|
||||
|
@ -406,6 +406,13 @@ static int ionic_get_coalesce(struct net_device *netdev,
|
||||
coalesce->tx_coalesce_usecs = lif->tx_coalesce_usecs;
|
||||
coalesce->rx_coalesce_usecs = lif->rx_coalesce_usecs;
|
||||
|
||||
if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
|
||||
coalesce->use_adaptive_tx_coalesce = test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
|
||||
else
|
||||
coalesce->use_adaptive_tx_coalesce = 0;
|
||||
|
||||
coalesce->use_adaptive_rx_coalesce = test_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -414,10 +421,9 @@ static int ionic_set_coalesce(struct net_device *netdev,
|
||||
{
|
||||
struct ionic_lif *lif = netdev_priv(netdev);
|
||||
struct ionic_identity *ident;
|
||||
struct ionic_qcq *qcq;
|
||||
u32 rx_coal, rx_dim;
|
||||
u32 tx_coal, tx_dim;
|
||||
unsigned int i;
|
||||
u32 rx_coal;
|
||||
u32 tx_coal;
|
||||
|
||||
ident = &lif->ionic->ident;
|
||||
if (ident->dev.intr_coal_div == 0) {
|
||||
@ -426,10 +432,11 @@ static int ionic_set_coalesce(struct net_device *netdev,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Tx normally shares Rx interrupt, so only change Rx */
|
||||
/* Tx normally shares Rx interrupt, so only change Rx if not split */
|
||||
if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state) &&
|
||||
coalesce->tx_coalesce_usecs != lif->rx_coalesce_usecs) {
|
||||
netdev_warn(netdev, "only the rx-usecs can be changed\n");
|
||||
(coalesce->tx_coalesce_usecs != lif->rx_coalesce_usecs ||
|
||||
coalesce->use_adaptive_tx_coalesce)) {
|
||||
netdev_warn(netdev, "only rx parameters can be changed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -449,32 +456,44 @@ static int ionic_set_coalesce(struct net_device *netdev,
|
||||
|
||||
/* Save the new values */
|
||||
lif->rx_coalesce_usecs = coalesce->rx_coalesce_usecs;
|
||||
if (rx_coal != lif->rx_coalesce_hw) {
|
||||
lif->rx_coalesce_hw = rx_coal;
|
||||
|
||||
if (test_bit(IONIC_LIF_F_UP, lif->state)) {
|
||||
for (i = 0; i < lif->nxqs; i++) {
|
||||
qcq = lif->rxqcqs[i];
|
||||
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
|
||||
qcq->intr.index,
|
||||
lif->rx_coalesce_hw);
|
||||
}
|
||||
}
|
||||
}
|
||||
lif->rx_coalesce_hw = rx_coal;
|
||||
|
||||
if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
|
||||
lif->tx_coalesce_usecs = coalesce->tx_coalesce_usecs;
|
||||
else
|
||||
lif->tx_coalesce_usecs = coalesce->rx_coalesce_usecs;
|
||||
if (tx_coal != lif->tx_coalesce_hw) {
|
||||
lif->tx_coalesce_hw = tx_coal;
|
||||
lif->tx_coalesce_hw = tx_coal;
|
||||
|
||||
if (test_bit(IONIC_LIF_F_UP, lif->state)) {
|
||||
for (i = 0; i < lif->nxqs; i++) {
|
||||
qcq = lif->txqcqs[i];
|
||||
if (coalesce->use_adaptive_rx_coalesce) {
|
||||
set_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
|
||||
rx_dim = rx_coal;
|
||||
} else {
|
||||
clear_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
|
||||
rx_dim = 0;
|
||||
}
|
||||
|
||||
if (coalesce->use_adaptive_tx_coalesce) {
|
||||
set_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
|
||||
tx_dim = tx_coal;
|
||||
} else {
|
||||
clear_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
|
||||
tx_dim = 0;
|
||||
}
|
||||
|
||||
if (test_bit(IONIC_LIF_F_UP, lif->state)) {
|
||||
for (i = 0; i < lif->nxqs; i++) {
|
||||
if (lif->rxqcqs[i]->flags & IONIC_QCQ_F_INTR) {
|
||||
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
|
||||
qcq->intr.index,
|
||||
lif->rxqcqs[i]->intr.index,
|
||||
lif->rx_coalesce_hw);
|
||||
lif->rxqcqs[i]->intr.dim_coal_hw = rx_dim;
|
||||
}
|
||||
|
||||
if (lif->txqcqs[i]->flags & IONIC_QCQ_F_INTR) {
|
||||
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
|
||||
lif->txqcqs[i]->intr.index,
|
||||
lif->tx_coalesce_hw);
|
||||
lif->txqcqs[i]->intr.dim_coal_hw = tx_dim;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -850,7 +869,9 @@ static int ionic_nway_reset(struct net_device *netdev)
|
||||
}
|
||||
|
||||
static const struct ethtool_ops ionic_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
||||
ETHTOOL_COALESCE_USE_ADAPTIVE_RX |
|
||||
ETHTOOL_COALESCE_USE_ADAPTIVE_TX,
|
||||
.get_drvinfo = ionic_get_drvinfo,
|
||||
.get_regs_len = ionic_get_regs_len,
|
||||
.get_regs = ionic_get_regs,
|
||||
|
@ -42,6 +42,20 @@ static int ionic_start_queues(struct ionic_lif *lif);
|
||||
static void ionic_stop_queues(struct ionic_lif *lif);
|
||||
static void ionic_lif_queue_identify(struct ionic_lif *lif);
|
||||
|
||||
static void ionic_dim_work(struct work_struct *work)
|
||||
{
|
||||
struct dim *dim = container_of(work, struct dim, work);
|
||||
struct dim_cq_moder cur_moder;
|
||||
struct ionic_qcq *qcq;
|
||||
u32 new_coal;
|
||||
|
||||
cur_moder = net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
|
||||
qcq = container_of(dim, struct ionic_qcq, dim);
|
||||
new_coal = ionic_coal_usec_to_hw(qcq->q.lif->ionic, cur_moder.usec);
|
||||
qcq->intr.dim_coal_hw = new_coal ? new_coal : 1;
|
||||
dim->state = DIM_START_MEASURE;
|
||||
}
|
||||
|
||||
static void ionic_lif_deferred_work(struct work_struct *work)
|
||||
{
|
||||
struct ionic_lif *lif = container_of(work, struct ionic_lif, deferred.work);
|
||||
@ -270,6 +284,7 @@ static int ionic_qcq_disable(struct ionic_qcq *qcq)
|
||||
ctx.cmd.q_control.index, ctx.cmd.q_control.type);
|
||||
|
||||
if (qcq->flags & IONIC_QCQ_F_INTR) {
|
||||
cancel_work_sync(&qcq->dim.work);
|
||||
ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
|
||||
IONIC_INTR_MASK_SET);
|
||||
synchronize_irq(qcq->intr.vector);
|
||||
@ -542,6 +557,9 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type,
|
||||
ionic_q_sg_map(&new->q, sg_base, sg_base_pa);
|
||||
}
|
||||
|
||||
INIT_WORK(&new->dim.work, ionic_dim_work);
|
||||
new->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
|
||||
|
||||
*qcq = new;
|
||||
|
||||
return 0;
|
||||
@ -834,7 +852,7 @@ static int ionic_adminq_napi(struct napi_struct *napi, int budget)
|
||||
work_done = max(n_work, a_work);
|
||||
if (work_done < budget && napi_complete_done(napi, work_done)) {
|
||||
flags |= IONIC_INTR_CRED_UNMASK;
|
||||
DEBUG_STATS_INTR_REARM(intr);
|
||||
lif->adminqcq->cq.bound_intr->rearm_count++;
|
||||
}
|
||||
|
||||
if (work_done || flags) {
|
||||
@ -1639,10 +1657,13 @@ static int ionic_txrx_alloc(struct ionic_lif *lif)
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
if (flags & IONIC_QCQ_F_INTR)
|
||||
if (flags & IONIC_QCQ_F_INTR) {
|
||||
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
|
||||
lif->txqcqs[i]->intr.index,
|
||||
lif->tx_coalesce_hw);
|
||||
if (test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state))
|
||||
lif->txqcqs[i]->intr.dim_coal_hw = lif->tx_coalesce_hw;
|
||||
}
|
||||
|
||||
ionic_debugfs_add_qcq(lif, lif->txqcqs[i]);
|
||||
}
|
||||
@ -1661,6 +1682,8 @@ static int ionic_txrx_alloc(struct ionic_lif *lif)
|
||||
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
|
||||
lif->rxqcqs[i]->intr.index,
|
||||
lif->rx_coalesce_hw);
|
||||
if (test_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state))
|
||||
lif->rxqcqs[i]->intr.dim_coal_hw = lif->rx_coalesce_hw;
|
||||
|
||||
if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
|
||||
ionic_link_qcq_interrupts(lif->rxqcqs[i],
|
||||
@ -2234,6 +2257,8 @@ int ionic_reconfigure_queues(struct ionic_lif *lif,
|
||||
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
|
||||
lif->txqcqs[i]->intr.index,
|
||||
lif->tx_coalesce_hw);
|
||||
if (test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state))
|
||||
lif->txqcqs[i]->intr.dim_coal_hw = lif->tx_coalesce_hw;
|
||||
} else {
|
||||
lif->txqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
|
||||
ionic_link_qcq_interrupts(lif->rxqcqs[i], lif->txqcqs[i]);
|
||||
@ -2361,6 +2386,8 @@ int ionic_lif_alloc(struct ionic *ionic)
|
||||
lif->rx_coalesce_usecs);
|
||||
lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
|
||||
lif->tx_coalesce_hw = lif->rx_coalesce_hw;
|
||||
set_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
|
||||
set_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
|
||||
|
||||
snprintf(lif->name, sizeof(lif->name), "lif%u", lif->index);
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef _IONIC_LIF_H_
|
||||
#define _IONIC_LIF_H_
|
||||
|
||||
#include <linux/dim.h>
|
||||
#include <linux/pci.h>
|
||||
#include "ionic_rx_filter.h"
|
||||
|
||||
@ -66,6 +67,7 @@ struct ionic_qcq {
|
||||
void *sg_base;
|
||||
dma_addr_t sg_base_pa;
|
||||
u32 sg_size;
|
||||
struct dim dim;
|
||||
struct ionic_queue q;
|
||||
struct ionic_cq cq;
|
||||
struct ionic_intr_info intr;
|
||||
@ -131,6 +133,8 @@ enum ionic_lif_state_flags {
|
||||
IONIC_LIF_F_LINK_CHECK_REQUESTED,
|
||||
IONIC_LIF_F_FW_RESET,
|
||||
IONIC_LIF_F_SPLIT_INTR,
|
||||
IONIC_LIF_F_TX_DIM_INTR,
|
||||
IONIC_LIF_F_RX_DIM_INTR,
|
||||
|
||||
/* leave this as last */
|
||||
IONIC_LIF_F_STATE_SIZE
|
||||
@ -288,7 +292,6 @@ static inline void debug_stats_napi_poll(struct ionic_qcq *qcq,
|
||||
|
||||
#define DEBUG_STATS_CQE_CNT(cq) ((cq)->compl_count++)
|
||||
#define DEBUG_STATS_RX_BUFF_CNT(q) ((q)->lif->rxqstats[q->index].buffers_posted++)
|
||||
#define DEBUG_STATS_INTR_REARM(intr) ((intr)->rearm_count++)
|
||||
#define DEBUG_STATS_TXQ_POST(q, dbell) debug_stats_txq_post(q, dbell)
|
||||
#define DEBUG_STATS_NAPI_POLL(qcq, work_done) \
|
||||
debug_stats_napi_poll(qcq, work_done)
|
||||
|
@ -432,6 +432,30 @@ void ionic_rx_empty(struct ionic_queue *q)
|
||||
}
|
||||
}
|
||||
|
||||
static void ionic_dim_update(struct ionic_qcq *qcq)
|
||||
{
|
||||
struct dim_sample dim_sample;
|
||||
struct ionic_lif *lif;
|
||||
unsigned int qi;
|
||||
|
||||
if (!qcq->intr.dim_coal_hw)
|
||||
return;
|
||||
|
||||
lif = qcq->q.lif;
|
||||
qi = qcq->cq.bound_q->index;
|
||||
|
||||
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
|
||||
lif->rxqcqs[qi]->intr.index,
|
||||
qcq->intr.dim_coal_hw);
|
||||
|
||||
dim_update_sample(qcq->cq.bound_intr->rearm_count,
|
||||
lif->txqstats[qi].pkts,
|
||||
lif->txqstats[qi].bytes,
|
||||
&dim_sample);
|
||||
|
||||
net_dim(&qcq->dim, dim_sample);
|
||||
}
|
||||
|
||||
int ionic_tx_napi(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct ionic_qcq *qcq = napi_to_qcq(napi);
|
||||
@ -448,8 +472,9 @@ int ionic_tx_napi(struct napi_struct *napi, int budget)
|
||||
ionic_tx_service, NULL, NULL);
|
||||
|
||||
if (work_done < budget && napi_complete_done(napi, work_done)) {
|
||||
ionic_dim_update(qcq);
|
||||
flags |= IONIC_INTR_CRED_UNMASK;
|
||||
DEBUG_STATS_INTR_REARM(cq->bound_intr);
|
||||
cq->bound_intr->rearm_count++;
|
||||
}
|
||||
|
||||
if (work_done || flags) {
|
||||
@ -483,8 +508,9 @@ int ionic_rx_napi(struct napi_struct *napi, int budget)
|
||||
ionic_rx_fill(cq->bound_q);
|
||||
|
||||
if (work_done < budget && napi_complete_done(napi, work_done)) {
|
||||
ionic_dim_update(qcq);
|
||||
flags |= IONIC_INTR_CRED_UNMASK;
|
||||
DEBUG_STATS_INTR_REARM(cq->bound_intr);
|
||||
cq->bound_intr->rearm_count++;
|
||||
}
|
||||
|
||||
if (work_done || flags) {
|
||||
@ -524,8 +550,9 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget)
|
||||
ionic_rx_fill_cb(rxcq->bound_q);
|
||||
|
||||
if (rx_work_done < budget && napi_complete_done(napi, rx_work_done)) {
|
||||
ionic_dim_update(qcq);
|
||||
flags |= IONIC_INTR_CRED_UNMASK;
|
||||
DEBUG_STATS_INTR_REARM(rxcq->bound_intr);
|
||||
rxcq->bound_intr->rearm_count++;
|
||||
}
|
||||
|
||||
if (rx_work_done || flags) {
|
||||
|
Loading…
Reference in New Issue
Block a user