ionic: change queue count with no reset
Add to our new ionic_reconfigure_queues() to also be able to change the number of queues in use, and to change the queue interrupt layout between split and combined. Signed-off-by: Shannon Nelson <snelson@pensando.io> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
a34e25ab97
commit
101b40a017
@@ -561,32 +561,15 @@ static void ionic_get_channels(struct net_device *netdev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ionic_set_queuecount(struct ionic_lif *lif, void *arg)
|
|
||||||
{
|
|
||||||
struct ethtool_channels *ch = arg;
|
|
||||||
|
|
||||||
if (ch->combined_count) {
|
|
||||||
lif->nxqs = ch->combined_count;
|
|
||||||
if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) {
|
|
||||||
clear_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
|
|
||||||
lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
|
|
||||||
lif->tx_coalesce_hw = lif->rx_coalesce_hw;
|
|
||||||
netdev_info(lif->netdev, "Sharing queue interrupts\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lif->nxqs = ch->rx_count;
|
|
||||||
if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) {
|
|
||||||
set_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
|
|
||||||
netdev_info(lif->netdev, "Splitting queue interrupts\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ionic_set_channels(struct net_device *netdev,
|
static int ionic_set_channels(struct net_device *netdev,
|
||||||
struct ethtool_channels *ch)
|
struct ethtool_channels *ch)
|
||||||
{
|
{
|
||||||
struct ionic_lif *lif = netdev_priv(netdev);
|
struct ionic_lif *lif = netdev_priv(netdev);
|
||||||
int new_cnt;
|
struct ionic_queue_params qparam;
|
||||||
|
int max_cnt;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
ionic_init_queue_params(lif, &qparam);
|
||||||
|
|
||||||
if (ch->rx_count != ch->tx_count) {
|
if (ch->rx_count != ch->tx_count) {
|
||||||
netdev_info(netdev, "The rx and tx count must be equal\n");
|
netdev_info(netdev, "The rx and tx count must be equal\n");
|
||||||
@@ -594,20 +577,63 @@ static int ionic_set_channels(struct net_device *netdev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ch->combined_count && ch->rx_count) {
|
if (ch->combined_count && ch->rx_count) {
|
||||||
netdev_info(netdev, "Use either combined_count or rx/tx_count, not both\n");
|
netdev_info(netdev, "Use either combined or rx and tx, not both\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch->combined_count)
|
max_cnt = lif->ionic->ntxqs_per_lif;
|
||||||
new_cnt = ch->combined_count;
|
if (ch->combined_count) {
|
||||||
else
|
if (ch->combined_count > max_cnt)
|
||||||
new_cnt = ch->rx_count;
|
return -EINVAL;
|
||||||
|
|
||||||
if (lif->nxqs != new_cnt)
|
if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
|
||||||
netdev_info(netdev, "Changing queue count from %d to %d\n",
|
netdev_info(lif->netdev, "Sharing queue interrupts\n");
|
||||||
lif->nxqs, new_cnt);
|
else if (ch->combined_count == lif->nxqs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return ionic_reset_queues(lif, ionic_set_queuecount, ch);
|
if (lif->nxqs != ch->combined_count)
|
||||||
|
netdev_info(netdev, "Changing queue count from %d to %d\n",
|
||||||
|
lif->nxqs, ch->combined_count);
|
||||||
|
|
||||||
|
qparam.nxqs = ch->combined_count;
|
||||||
|
qparam.intr_split = 0;
|
||||||
|
} else {
|
||||||
|
max_cnt /= 2;
|
||||||
|
if (ch->rx_count > max_cnt)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
|
||||||
|
netdev_info(lif->netdev, "Splitting queue interrupts\n");
|
||||||
|
else if (ch->rx_count == lif->nxqs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (lif->nxqs != ch->rx_count)
|
||||||
|
netdev_info(netdev, "Changing queue count from %d to %d\n",
|
||||||
|
lif->nxqs, ch->rx_count);
|
||||||
|
|
||||||
|
qparam.nxqs = ch->rx_count;
|
||||||
|
qparam.intr_split = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we're not running, just set the values and return */
|
||||||
|
if (!netif_running(lif->netdev)) {
|
||||||
|
lif->nxqs = qparam.nxqs;
|
||||||
|
|
||||||
|
if (qparam.intr_split) {
|
||||||
|
set_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
|
||||||
|
} else {
|
||||||
|
clear_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
|
||||||
|
lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
|
||||||
|
lif->tx_coalesce_hw = lif->rx_coalesce_hw;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ionic_reconfigure_queues(lif, &qparam);
|
||||||
|
if (err)
|
||||||
|
netdev_info(netdev, "Queue reconfiguration failed, changes canceled: %d\n", err);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 ionic_get_priv_flags(struct net_device *netdev)
|
static u32 ionic_get_priv_flags(struct net_device *netdev)
|
||||||
|
@@ -299,6 +299,18 @@ static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
|
|||||||
qcq->flags &= ~IONIC_QCQ_F_INITED;
|
qcq->flags &= ~IONIC_QCQ_F_INITED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ionic_qcq_intr_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
|
||||||
|
{
|
||||||
|
if (!(qcq->flags & IONIC_QCQ_F_INTR) || qcq->intr.vector == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
irq_set_affinity_hint(qcq->intr.vector, NULL);
|
||||||
|
devm_free_irq(lif->ionic->dev, qcq->intr.vector, &qcq->napi);
|
||||||
|
qcq->intr.vector = 0;
|
||||||
|
ionic_intr_free(lif->ionic, qcq->intr.index);
|
||||||
|
qcq->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
|
static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
|
||||||
{
|
{
|
||||||
struct device *dev = lif->ionic->dev;
|
struct device *dev = lif->ionic->dev;
|
||||||
@@ -326,12 +338,7 @@ static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
|
|||||||
qcq->sg_base_pa = 0;
|
qcq->sg_base_pa = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcq->flags & IONIC_QCQ_F_INTR) {
|
ionic_qcq_intr_free(lif, qcq);
|
||||||
irq_set_affinity_hint(qcq->intr.vector, NULL);
|
|
||||||
devm_free_irq(dev, qcq->intr.vector, &qcq->napi);
|
|
||||||
qcq->intr.vector = 0;
|
|
||||||
ionic_intr_free(lif->ionic, qcq->intr.index);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qcq->cq.info) {
|
if (qcq->cq.info) {
|
||||||
devm_kfree(dev, qcq->cq.info);
|
devm_kfree(dev, qcq->cq.info);
|
||||||
@@ -341,7 +348,6 @@ static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
|
|||||||
devm_kfree(dev, qcq->q.info);
|
devm_kfree(dev, qcq->q.info);
|
||||||
qcq->q.info = NULL;
|
qcq->q.info = NULL;
|
||||||
}
|
}
|
||||||
devm_kfree(dev, qcq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ionic_qcqs_free(struct ionic_lif *lif)
|
static void ionic_qcqs_free(struct ionic_lif *lif)
|
||||||
@@ -350,11 +356,13 @@ static void ionic_qcqs_free(struct ionic_lif *lif)
|
|||||||
|
|
||||||
if (lif->notifyqcq) {
|
if (lif->notifyqcq) {
|
||||||
ionic_qcq_free(lif, lif->notifyqcq);
|
ionic_qcq_free(lif, lif->notifyqcq);
|
||||||
|
devm_kfree(dev, lif->notifyqcq);
|
||||||
lif->notifyqcq = NULL;
|
lif->notifyqcq = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lif->adminqcq) {
|
if (lif->adminqcq) {
|
||||||
ionic_qcq_free(lif, lif->adminqcq);
|
ionic_qcq_free(lif, lif->adminqcq);
|
||||||
|
devm_kfree(dev, lif->adminqcq);
|
||||||
lif->adminqcq = NULL;
|
lif->adminqcq = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,6 +393,53 @@ static void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq,
|
|||||||
n_qcq->intr.index = src_qcq->intr.index;
|
n_qcq->intr.index = src_qcq->intr.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ionic_alloc_qcq_interrupt(struct ionic_lif *lif, struct ionic_qcq *qcq)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!(qcq->flags & IONIC_QCQ_F_INTR)) {
|
||||||
|
qcq->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ionic_intr_alloc(lif, &qcq->intr);
|
||||||
|
if (err) {
|
||||||
|
netdev_warn(lif->netdev, "no intr for %s: %d\n",
|
||||||
|
qcq->q.name, err);
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ionic_bus_get_irq(lif->ionic, qcq->intr.index);
|
||||||
|
if (err < 0) {
|
||||||
|
netdev_warn(lif->netdev, "no vector for %s: %d\n",
|
||||||
|
qcq->q.name, err);
|
||||||
|
goto err_out_free_intr;
|
||||||
|
}
|
||||||
|
qcq->intr.vector = err;
|
||||||
|
ionic_intr_mask_assert(lif->ionic->idev.intr_ctrl, qcq->intr.index,
|
||||||
|
IONIC_INTR_MASK_SET);
|
||||||
|
|
||||||
|
err = ionic_request_irq(lif, qcq);
|
||||||
|
if (err) {
|
||||||
|
netdev_warn(lif->netdev, "irq request failed %d\n", err);
|
||||||
|
goto err_out_free_intr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to get the irq on the local numa node first */
|
||||||
|
qcq->intr.cpu = cpumask_local_spread(qcq->intr.index,
|
||||||
|
dev_to_node(lif->ionic->dev));
|
||||||
|
if (qcq->intr.cpu != -1)
|
||||||
|
cpumask_set_cpu(qcq->intr.cpu, &qcq->intr.affinity_mask);
|
||||||
|
|
||||||
|
netdev_dbg(lif->netdev, "%s: Interrupt index %d\n", qcq->q.name, qcq->intr.index);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_out_free_intr:
|
||||||
|
ionic_intr_free(lif->ionic, qcq->intr.index);
|
||||||
|
err_out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type,
|
static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type,
|
||||||
unsigned int index,
|
unsigned int index,
|
||||||
const char *name, unsigned int flags,
|
const char *name, unsigned int flags,
|
||||||
@@ -430,39 +485,9 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type,
|
|||||||
goto err_out_free_q_info;
|
goto err_out_free_q_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & IONIC_QCQ_F_INTR) {
|
err = ionic_alloc_qcq_interrupt(lif, new);
|
||||||
err = ionic_intr_alloc(lif, &new->intr);
|
if (err)
|
||||||
if (err) {
|
goto err_out;
|
||||||
netdev_warn(lif->netdev, "no intr for %s: %d\n",
|
|
||||||
new->q.name, err);
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ionic_bus_get_irq(lif->ionic, new->intr.index);
|
|
||||||
if (err < 0) {
|
|
||||||
netdev_warn(lif->netdev, "no vector for %s: %d\n",
|
|
||||||
new->q.name, err);
|
|
||||||
goto err_out_free_intr;
|
|
||||||
}
|
|
||||||
new->intr.vector = err;
|
|
||||||
ionic_intr_mask_assert(idev->intr_ctrl, new->intr.index,
|
|
||||||
IONIC_INTR_MASK_SET);
|
|
||||||
|
|
||||||
err = ionic_request_irq(lif, new);
|
|
||||||
if (err) {
|
|
||||||
netdev_warn(lif->netdev, "irq request failed for %s: %d\n",
|
|
||||||
new->q.name, err);
|
|
||||||
goto err_out_free_intr;
|
|
||||||
}
|
|
||||||
|
|
||||||
new->intr.cpu = cpumask_local_spread(new->intr.index,
|
|
||||||
dev_to_node(dev));
|
|
||||||
if (new->intr.cpu != -1)
|
|
||||||
cpumask_set_cpu(new->intr.cpu,
|
|
||||||
&new->intr.affinity_mask);
|
|
||||||
} else {
|
|
||||||
new->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED;
|
|
||||||
}
|
|
||||||
|
|
||||||
new->cq.info = devm_kcalloc(dev, num_descs, sizeof(*new->cq.info),
|
new->cq.info = devm_kcalloc(dev, num_descs, sizeof(*new->cq.info),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
@@ -528,11 +553,10 @@ err_out_free_q:
|
|||||||
err_out_free_cq_info:
|
err_out_free_cq_info:
|
||||||
devm_kfree(dev, new->cq.info);
|
devm_kfree(dev, new->cq.info);
|
||||||
err_out_free_irq:
|
err_out_free_irq:
|
||||||
if (flags & IONIC_QCQ_F_INTR)
|
if (flags & IONIC_QCQ_F_INTR) {
|
||||||
devm_free_irq(dev, new->intr.vector, &new->napi);
|
devm_free_irq(dev, new->intr.vector, &new->napi);
|
||||||
err_out_free_intr:
|
|
||||||
if (flags & IONIC_QCQ_F_INTR)
|
|
||||||
ionic_intr_free(lif->ionic, new->intr.index);
|
ionic_intr_free(lif->ionic, new->intr.index);
|
||||||
|
}
|
||||||
err_out_free_q_info:
|
err_out_free_q_info:
|
||||||
devm_kfree(dev, new->q.info);
|
devm_kfree(dev, new->q.info);
|
||||||
err_out_free_qcq:
|
err_out_free_qcq:
|
||||||
@@ -635,7 +659,7 @@ static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
|
|||||||
unsigned int intr_index;
|
unsigned int intr_index;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
|
if (qcq->flags & IONIC_QCQ_F_INTR)
|
||||||
intr_index = qcq->intr.index;
|
intr_index = qcq->intr.index;
|
||||||
else
|
else
|
||||||
intr_index = lif->rxqcqs[q->index]->intr.index;
|
intr_index = lif->rxqcqs[q->index]->intr.index;
|
||||||
@@ -1539,7 +1563,7 @@ static void ionic_txrx_deinit(struct ionic_lif *lif)
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if (lif->txqcqs) {
|
if (lif->txqcqs) {
|
||||||
for (i = 0; i < lif->nxqs; i++) {
|
for (i = 0; i < lif->nxqs && lif->txqcqs[i]; i++) {
|
||||||
ionic_lif_qcq_deinit(lif, lif->txqcqs[i]);
|
ionic_lif_qcq_deinit(lif, lif->txqcqs[i]);
|
||||||
ionic_tx_flush(&lif->txqcqs[i]->cq);
|
ionic_tx_flush(&lif->txqcqs[i]->cq);
|
||||||
ionic_tx_empty(&lif->txqcqs[i]->q);
|
ionic_tx_empty(&lif->txqcqs[i]->q);
|
||||||
@@ -1547,7 +1571,7 @@ static void ionic_txrx_deinit(struct ionic_lif *lif)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lif->rxqcqs) {
|
if (lif->rxqcqs) {
|
||||||
for (i = 0; i < lif->nxqs; i++) {
|
for (i = 0; i < lif->nxqs && lif->rxqcqs[i]; i++) {
|
||||||
ionic_lif_qcq_deinit(lif, lif->rxqcqs[i]);
|
ionic_lif_qcq_deinit(lif, lif->rxqcqs[i]);
|
||||||
ionic_rx_flush(&lif->rxqcqs[i]->cq);
|
ionic_rx_flush(&lif->rxqcqs[i]->cq);
|
||||||
ionic_rx_empty(&lif->rxqcqs[i]->q);
|
ionic_rx_empty(&lif->rxqcqs[i]->q);
|
||||||
@@ -1561,15 +1585,17 @@ static void ionic_txrx_free(struct ionic_lif *lif)
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if (lif->txqcqs) {
|
if (lif->txqcqs) {
|
||||||
for (i = 0; i < lif->nxqs; i++) {
|
for (i = 0; i < lif->ionic->ntxqs_per_lif && lif->txqcqs[i]; i++) {
|
||||||
ionic_qcq_free(lif, lif->txqcqs[i]);
|
ionic_qcq_free(lif, lif->txqcqs[i]);
|
||||||
|
devm_kfree(lif->ionic->dev, lif->txqcqs[i]);
|
||||||
lif->txqcqs[i] = NULL;
|
lif->txqcqs[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lif->rxqcqs) {
|
if (lif->rxqcqs) {
|
||||||
for (i = 0; i < lif->nxqs; i++) {
|
for (i = 0; i < lif->ionic->nrxqs_per_lif && lif->rxqcqs[i]; i++) {
|
||||||
ionic_qcq_free(lif, lif->rxqcqs[i]);
|
ionic_qcq_free(lif, lif->rxqcqs[i]);
|
||||||
|
devm_kfree(lif->ionic->dev, lif->rxqcqs[i]);
|
||||||
lif->rxqcqs[i] = NULL;
|
lif->rxqcqs[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2088,20 +2114,22 @@ int ionic_reconfigure_queues(struct ionic_lif *lif,
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* allocate temporary qcq arrays to hold new queue structs */
|
/* allocate temporary qcq arrays to hold new queue structs */
|
||||||
if (qparam->ntxq_descs != lif->ntxq_descs) {
|
if (qparam->nxqs != lif->nxqs || qparam->ntxq_descs != lif->ntxq_descs) {
|
||||||
tx_qcqs = devm_kcalloc(lif->ionic->dev, lif->nxqs,
|
tx_qcqs = devm_kcalloc(lif->ionic->dev, lif->ionic->ntxqs_per_lif,
|
||||||
sizeof(struct ionic_qcq *), GFP_KERNEL);
|
sizeof(struct ionic_qcq *), GFP_KERNEL);
|
||||||
if (!tx_qcqs)
|
if (!tx_qcqs)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if (qparam->nrxq_descs != lif->nrxq_descs) {
|
if (qparam->nxqs != lif->nxqs || qparam->nrxq_descs != lif->nrxq_descs) {
|
||||||
rx_qcqs = devm_kcalloc(lif->ionic->dev, lif->nxqs,
|
rx_qcqs = devm_kcalloc(lif->ionic->dev, lif->ionic->nrxqs_per_lif,
|
||||||
sizeof(struct ionic_qcq *), GFP_KERNEL);
|
sizeof(struct ionic_qcq *), GFP_KERNEL);
|
||||||
if (!rx_qcqs)
|
if (!rx_qcqs)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate new desc_info and rings with no interrupt flag */
|
/* allocate new desc_info and rings, but leave the interrupt setup
|
||||||
|
* until later so as to not mess with the still-running queues
|
||||||
|
*/
|
||||||
if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 &&
|
if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 &&
|
||||||
lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz ==
|
lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz ==
|
||||||
sizeof(struct ionic_txq_sg_desc_v1))
|
sizeof(struct ionic_txq_sg_desc_v1))
|
||||||
@@ -2110,7 +2138,7 @@ int ionic_reconfigure_queues(struct ionic_lif *lif,
|
|||||||
sg_desc_sz = sizeof(struct ionic_txq_sg_desc);
|
sg_desc_sz = sizeof(struct ionic_txq_sg_desc);
|
||||||
|
|
||||||
if (tx_qcqs) {
|
if (tx_qcqs) {
|
||||||
for (i = 0; i < lif->nxqs; i++) {
|
for (i = 0; i < qparam->nxqs; i++) {
|
||||||
flags = lif->txqcqs[i]->flags & ~IONIC_QCQ_F_INTR;
|
flags = lif->txqcqs[i]->flags & ~IONIC_QCQ_F_INTR;
|
||||||
err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags,
|
err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags,
|
||||||
qparam->ntxq_descs,
|
qparam->ntxq_descs,
|
||||||
@@ -2124,7 +2152,7 @@ int ionic_reconfigure_queues(struct ionic_lif *lif,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rx_qcqs) {
|
if (rx_qcqs) {
|
||||||
for (i = 0; i < lif->nxqs; i++) {
|
for (i = 0; i < qparam->nxqs; i++) {
|
||||||
flags = lif->rxqcqs[i]->flags & ~IONIC_QCQ_F_INTR;
|
flags = lif->rxqcqs[i]->flags & ~IONIC_QCQ_F_INTR;
|
||||||
err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
|
err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
|
||||||
qparam->nrxq_descs,
|
qparam->nrxq_descs,
|
||||||
@@ -2140,33 +2168,90 @@ int ionic_reconfigure_queues(struct ionic_lif *lif,
|
|||||||
/* stop and clean the queues */
|
/* stop and clean the queues */
|
||||||
ionic_stop_queues_reconfig(lif);
|
ionic_stop_queues_reconfig(lif);
|
||||||
|
|
||||||
|
if (qparam->nxqs != lif->nxqs) {
|
||||||
|
err = netif_set_real_num_tx_queues(lif->netdev, qparam->nxqs);
|
||||||
|
if (err)
|
||||||
|
goto err_out_reinit_unlock;
|
||||||
|
err = netif_set_real_num_rx_queues(lif->netdev, qparam->nxqs);
|
||||||
|
if (err) {
|
||||||
|
netif_set_real_num_tx_queues(lif->netdev, lif->nxqs);
|
||||||
|
goto err_out_reinit_unlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* swap new desc_info and rings, keeping existing interrupt config */
|
/* swap new desc_info and rings, keeping existing interrupt config */
|
||||||
if (tx_qcqs) {
|
if (tx_qcqs) {
|
||||||
lif->ntxq_descs = qparam->ntxq_descs;
|
lif->ntxq_descs = qparam->ntxq_descs;
|
||||||
for (i = 0; i < lif->nxqs; i++)
|
for (i = 0; i < qparam->nxqs; i++)
|
||||||
ionic_swap_queues(lif->txqcqs[i], tx_qcqs[i]);
|
ionic_swap_queues(lif->txqcqs[i], tx_qcqs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rx_qcqs) {
|
if (rx_qcqs) {
|
||||||
lif->nrxq_descs = qparam->nrxq_descs;
|
lif->nrxq_descs = qparam->nrxq_descs;
|
||||||
for (i = 0; i < lif->nxqs; i++)
|
for (i = 0; i < qparam->nxqs; i++)
|
||||||
ionic_swap_queues(lif->rxqcqs[i], rx_qcqs[i]);
|
ionic_swap_queues(lif->rxqcqs[i], rx_qcqs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* re-init the queues */
|
/* if we need to change the interrupt layout, this is the time */
|
||||||
err = ionic_start_queues_reconfig(lif);
|
if (qparam->intr_split != test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state) ||
|
||||||
|
qparam->nxqs != lif->nxqs) {
|
||||||
|
if (qparam->intr_split) {
|
||||||
|
set_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
|
||||||
|
} else {
|
||||||
|
clear_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
|
||||||
|
lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
|
||||||
|
lif->tx_coalesce_hw = lif->rx_coalesce_hw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear existing interrupt assignments */
|
||||||
|
for (i = 0; i < lif->ionic->ntxqs_per_lif; i++) {
|
||||||
|
ionic_qcq_intr_free(lif, lif->txqcqs[i]);
|
||||||
|
ionic_qcq_intr_free(lif, lif->rxqcqs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* re-assign the interrupts */
|
||||||
|
for (i = 0; i < qparam->nxqs; i++) {
|
||||||
|
lif->rxqcqs[i]->flags |= IONIC_QCQ_F_INTR;
|
||||||
|
err = ionic_alloc_qcq_interrupt(lif, lif->rxqcqs[i]);
|
||||||
|
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
|
||||||
|
lif->rxqcqs[i]->intr.index,
|
||||||
|
lif->rx_coalesce_hw);
|
||||||
|
|
||||||
|
if (qparam->intr_split) {
|
||||||
|
lif->txqcqs[i]->flags |= IONIC_QCQ_F_INTR;
|
||||||
|
err = ionic_alloc_qcq_interrupt(lif, lif->txqcqs[i]);
|
||||||
|
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
|
||||||
|
lif->txqcqs[i]->intr.index,
|
||||||
|
lif->tx_coalesce_hw);
|
||||||
|
} else {
|
||||||
|
lif->txqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
|
||||||
|
ionic_link_qcq_interrupts(lif->rxqcqs[i], lif->txqcqs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swap(lif->nxqs, qparam->nxqs);
|
||||||
|
|
||||||
|
err_out_reinit_unlock:
|
||||||
|
/* re-init the queues, but don't loose an error code */
|
||||||
|
if (err)
|
||||||
|
ionic_start_queues_reconfig(lif);
|
||||||
|
else
|
||||||
|
err = ionic_start_queues_reconfig(lif);
|
||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
/* free old allocs without cleaning intr */
|
/* free old allocs without cleaning intr */
|
||||||
for (i = 0; i < lif->nxqs; i++) {
|
for (i = 0; i < qparam->nxqs; i++) {
|
||||||
if (tx_qcqs && tx_qcqs[i]) {
|
if (tx_qcqs && tx_qcqs[i]) {
|
||||||
tx_qcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
|
tx_qcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
|
||||||
ionic_qcq_free(lif, tx_qcqs[i]);
|
ionic_qcq_free(lif, tx_qcqs[i]);
|
||||||
|
devm_kfree(lif->ionic->dev, tx_qcqs[i]);
|
||||||
tx_qcqs[i] = NULL;
|
tx_qcqs[i] = NULL;
|
||||||
}
|
}
|
||||||
if (rx_qcqs && rx_qcqs[i]) {
|
if (rx_qcqs && rx_qcqs[i]) {
|
||||||
rx_qcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
|
rx_qcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
|
||||||
ionic_qcq_free(lif, rx_qcqs[i]);
|
ionic_qcq_free(lif, rx_qcqs[i]);
|
||||||
|
devm_kfree(lif->ionic->dev, rx_qcqs[i]);
|
||||||
rx_qcqs[i] = NULL;
|
rx_qcqs[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2181,6 +2266,17 @@ err_out:
|
|||||||
tx_qcqs = NULL;
|
tx_qcqs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* clean the unused dma and info allocations when new set is smaller
|
||||||
|
* than the full array, but leave the qcq shells in place
|
||||||
|
*/
|
||||||
|
for (i = lif->nxqs; i < lif->ionic->ntxqs_per_lif; i++) {
|
||||||
|
lif->txqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
|
||||||
|
ionic_qcq_free(lif, lif->txqcqs[i]);
|
||||||
|
|
||||||
|
lif->rxqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
|
||||||
|
ionic_qcq_free(lif, lif->rxqcqs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user