Merge branch 'ionic-driver-updates'

Shannon Nelson says:

====================
ionic: driver updates

These patches are a few updates to clean up some code
issues and add an ethtool feature.

v3: drop the Fixes tags as they really aren't fixing bugs
    simplify ionic_lif_quiesce() as no return is necessary

v2: add cover letter
    edit a couple of patch descriptions for clarity
      and add Fixes: tags
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2019-10-02 11:55:12 -04:00
commit 1f6d768a09
4 changed files with 119 additions and 63 deletions

View File

@ -19,31 +19,30 @@ static int ionic_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
err = devlink_info_driver_name_put(req, IONIC_DRV_NAME);
if (err)
goto info_out;
return err;
err = devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW,
idev->dev_info.fw_version);
if (err)
goto info_out;
return err;
snprintf(buf, sizeof(buf), "0x%x", idev->dev_info.asic_type);
err = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
buf);
if (err)
goto info_out;
return err;
snprintf(buf, sizeof(buf), "0x%x", idev->dev_info.asic_rev);
err = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_ASIC_REV,
buf);
if (err)
goto info_out;
return err;
err = devlink_info_serial_number_put(req, idev->dev_info.serial_num);
info_out:
return err;
}

View File

@ -254,12 +254,9 @@ static int ionic_set_link_ksettings(struct net_device *netdev,
struct ionic_lif *lif = netdev_priv(netdev);
struct ionic *ionic = lif->ionic;
struct ionic_dev *idev;
u32 req_rs, req_fc;
u8 fec_type;
int err = 0;
idev = &lif->ionic->idev;
fec_type = IONIC_PORT_FEC_TYPE_NONE;
/* set autoneg */
if (ks->base.autoneg != idev->port_info->config.an_enable) {
@ -281,29 +278,6 @@ static int ionic_set_link_ksettings(struct net_device *netdev,
return err;
}
/* set FEC */
req_rs = ethtool_link_ksettings_test_link_mode(ks, advertising, FEC_RS);
req_fc = ethtool_link_ksettings_test_link_mode(ks, advertising, FEC_BASER);
if (req_rs && req_fc) {
netdev_info(netdev, "Only select one FEC mode at a time\n");
return -EINVAL;
} else if (req_fc) {
fec_type = IONIC_PORT_FEC_TYPE_FC;
} else if (req_rs) {
fec_type = IONIC_PORT_FEC_TYPE_RS;
} else if (!(req_rs | req_fc)) {
fec_type = IONIC_PORT_FEC_TYPE_NONE;
}
if (fec_type != idev->port_info->config.fec_type) {
mutex_lock(&ionic->dev_cmd_lock);
ionic_dev_cmd_port_fec(idev, fec_type);
err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
mutex_unlock(&ionic->dev_cmd_lock);
if (err)
return err;
}
return 0;
}
@ -353,6 +327,70 @@ static int ionic_set_pauseparam(struct net_device *netdev,
return 0;
}
static int ionic_get_fecparam(struct net_device *netdev,
struct ethtool_fecparam *fec)
{
struct ionic_lif *lif = netdev_priv(netdev);
switch (lif->ionic->idev.port_info->config.fec_type) {
case IONIC_PORT_FEC_TYPE_NONE:
fec->active_fec = ETHTOOL_FEC_OFF;
break;
case IONIC_PORT_FEC_TYPE_RS:
fec->active_fec = ETHTOOL_FEC_RS;
break;
case IONIC_PORT_FEC_TYPE_FC:
fec->active_fec = ETHTOOL_FEC_BASER;
break;
}
fec->fec = ETHTOOL_FEC_OFF | ETHTOOL_FEC_RS | ETHTOOL_FEC_BASER;
return 0;
}
static int ionic_set_fecparam(struct net_device *netdev,
struct ethtool_fecparam *fec)
{
struct ionic_lif *lif = netdev_priv(netdev);
u8 fec_type;
int ret = 0;
if (lif->ionic->idev.port_info->config.an_enable) {
netdev_err(netdev, "FEC request not allowed while autoneg is enabled\n");
return -EINVAL;
}
switch (fec->fec) {
case ETHTOOL_FEC_NONE:
fec_type = IONIC_PORT_FEC_TYPE_NONE;
break;
case ETHTOOL_FEC_OFF:
fec_type = IONIC_PORT_FEC_TYPE_NONE;
break;
case ETHTOOL_FEC_RS:
fec_type = IONIC_PORT_FEC_TYPE_RS;
break;
case ETHTOOL_FEC_BASER:
fec_type = IONIC_PORT_FEC_TYPE_FC;
break;
case ETHTOOL_FEC_AUTO:
default:
netdev_err(netdev, "FEC request 0x%04x not supported\n",
fec->fec);
return -EINVAL;
}
if (fec_type != lif->ionic->idev.port_info->config.fec_type) {
mutex_lock(&lif->ionic->dev_cmd_lock);
ionic_dev_cmd_port_fec(&lif->ionic->idev, fec_type);
ret = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
mutex_unlock(&lif->ionic->dev_cmd_lock);
}
return ret;
}
static int ionic_get_coalesce(struct net_device *netdev,
struct ethtool_coalesce *coalesce)
{
@ -372,7 +410,6 @@ static int ionic_set_coalesce(struct net_device *netdev,
struct ionic_identity *ident;
struct ionic_qcq *qcq;
unsigned int i;
u32 usecs;
u32 coal;
if (coalesce->rx_max_coalesced_frames ||
@ -410,26 +447,27 @@ static int ionic_set_coalesce(struct net_device *netdev,
return -EINVAL;
}
/* Convert the usec request to a HW useable value. If they asked
* for non-zero and it resolved to zero, bump it up
*/
coal = ionic_coal_usec_to_hw(lif->ionic, coalesce->rx_coalesce_usecs);
if (!coal && coalesce->rx_coalesce_usecs)
coal = 1;
if (coal > IONIC_INTR_CTRL_COAL_MAX)
return -ERANGE;
/* If they asked for non-zero and it resolved to zero, bump it up */
if (!coal && coalesce->rx_coalesce_usecs)
coal = 1;
/* Convert it back to get device resolution */
usecs = ionic_coal_hw_to_usec(lif->ionic, coal);
if (usecs != lif->rx_coalesce_usecs) {
lif->rx_coalesce_usecs = usecs;
/* Save the new value */
lif->rx_coalesce_usecs = coalesce->rx_coalesce_usecs;
if (coal != lif->rx_coalesce_hw) {
lif->rx_coalesce_hw = coal;
if (test_bit(IONIC_LIF_UP, lif->state)) {
for (i = 0; i < lif->nxqs; i++) {
qcq = lif->rxqcqs[i].qcq;
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
qcq->intr.index, coal);
qcq->intr.index,
lif->rx_coalesce_hw);
}
}
}
@ -453,6 +491,7 @@ static int ionic_set_ringparam(struct net_device *netdev,
{
struct ionic_lif *lif = netdev_priv(netdev);
bool running;
int err;
if (ring->rx_mini_pending || ring->rx_jumbo_pending) {
netdev_info(netdev, "Changing jumbo or mini descriptors not supported\n");
@ -470,8 +509,9 @@ static int ionic_set_ringparam(struct net_device *netdev,
ring->rx_pending == lif->nrxq_descs)
return 0;
if (!ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET))
return -EBUSY;
err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET);
if (err)
return err;
running = test_bit(IONIC_LIF_UP, lif->state);
if (running)
@ -504,6 +544,7 @@ static int ionic_set_channels(struct net_device *netdev,
{
struct ionic_lif *lif = netdev_priv(netdev);
bool running;
int err;
if (!ch->combined_count || ch->other_count ||
ch->rx_count || ch->tx_count)
@ -512,8 +553,9 @@ static int ionic_set_channels(struct net_device *netdev,
if (ch->combined_count == lif->nxqs)
return 0;
if (!ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET))
return -EBUSY;
err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET);
if (err)
return err;
running = test_bit(IONIC_LIF_UP, lif->state);
if (running)
@ -747,6 +789,7 @@ static const struct ethtool_ops ionic_ethtool_ops = {
.get_regs = ionic_get_regs,
.get_link = ethtool_op_get_link,
.get_link_ksettings = ionic_get_link_ksettings,
.set_link_ksettings = ionic_set_link_ksettings,
.get_coalesce = ionic_get_coalesce,
.set_coalesce = ionic_set_coalesce,
.get_ringparam = ionic_get_ringparam,
@ -769,7 +812,8 @@ static const struct ethtool_ops ionic_ethtool_ops = {
.get_module_eeprom = ionic_get_module_eeprom,
.get_pauseparam = ionic_get_pauseparam,
.set_pauseparam = ionic_set_pauseparam,
.set_link_ksettings = ionic_set_link_ksettings,
.get_fecparam = ionic_get_fecparam,
.set_fecparam = ionic_set_fecparam,
.nway_reset = ionic_nway_reset,
};

View File

@ -242,6 +242,21 @@ static int ionic_qcq_disable(struct ionic_qcq *qcq)
return ionic_adminq_post_wait(lif, &ctx);
}
static void ionic_lif_quiesce(struct ionic_lif *lif)
{
struct ionic_admin_ctx ctx = {
.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
.cmd.lif_setattr = {
.opcode = IONIC_CMD_LIF_SETATTR,
.attr = IONIC_LIF_ATTR_STATE,
.index = lif->index,
.state = IONIC_LIF_DISABLE
},
};
ionic_adminq_post_wait(lif, &ctx);
}
static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
{
struct ionic_dev *idev = &lif->ionic->idev;
@ -1430,7 +1445,6 @@ static int ionic_txrx_alloc(struct ionic_lif *lif)
unsigned int flags;
unsigned int i;
int err = 0;
u32 coal;
flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG;
for (i = 0; i < lif->nxqs; i++) {
@ -1447,7 +1461,6 @@ static int ionic_txrx_alloc(struct ionic_lif *lif)
}
flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_INTR;
coal = ionic_coal_usec_to_hw(lif->ionic, lif->rx_coalesce_usecs);
for (i = 0; i < lif->nxqs; i++) {
err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
lif->nrxq_descs,
@ -1460,7 +1473,8 @@ static int ionic_txrx_alloc(struct ionic_lif *lif)
lif->rxqcqs[i].qcq->stats = lif->rxqcqs[i].stats;
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
lif->rxqcqs[i].qcq->intr.index, coal);
lif->rxqcqs[i].qcq->intr.index,
lif->rx_coalesce_hw);
ionic_link_qcq_interrupts(lif->rxqcqs[i].qcq,
lif->txqcqs[i].qcq);
}
@ -1590,6 +1604,7 @@ int ionic_stop(struct net_device *netdev)
netif_tx_disable(netdev);
ionic_txrx_disable(lif);
ionic_lif_quiesce(lif);
ionic_txrx_deinit(lif);
ionic_txrx_free(lif);
@ -1619,8 +1634,9 @@ int ionic_reset_queues(struct ionic_lif *lif)
/* Put off the next watchdog timeout */
netif_trans_update(lif->netdev);
if (!ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET))
return -EBUSY;
err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET);
if (err)
return err;
running = netif_running(lif->netdev);
if (running)
@ -1639,7 +1655,6 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index
struct net_device *netdev;
struct ionic_lif *lif;
int tbl_sz;
u32 coal;
int err;
netdev = alloc_etherdev_mqs(sizeof(*lif),
@ -1670,8 +1685,9 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index
lif->nrxq_descs = IONIC_DEF_TXRX_DESC;
/* Convert the default coalesce value to actual hw resolution */
coal = ionic_coal_usec_to_hw(lif->ionic, IONIC_ITR_COAL_USEC_DEFAULT);
lif->rx_coalesce_usecs = ionic_coal_hw_to_usec(lif->ionic, coal);
lif->rx_coalesce_usecs = IONIC_ITR_COAL_USEC_DEFAULT;
lif->rx_coalesce_hw = ionic_coal_hw_to_usec(lif->ionic,
lif->rx_coalesce_usecs);
snprintf(lif->name, sizeof(lif->name), "lif%u", index);

View File

@ -175,7 +175,9 @@ struct ionic_lif {
unsigned long *dbid_inuse;
unsigned int dbid_count;
struct dentry *dentry;
u32 rx_coalesce_usecs;
u32 rx_coalesce_usecs; /* what the user asked for */
u32 rx_coalesce_hw; /* what the hw is using */
u32 flags;
struct work_struct tx_timeout_work;
};
@ -185,15 +187,10 @@ struct ionic_lif {
#define lif_to_txq(lif, i) (&lif_to_txqcq((lif), i)->q)
#define lif_to_rxq(lif, i) (&lif_to_txqcq((lif), i)->q)
/* return 0 if successfully set the bit, else non-zero */
static inline int ionic_wait_for_bit(struct ionic_lif *lif, int bitname)
{
unsigned long tlimit = jiffies + HZ;
while (test_and_set_bit(bitname, lif->state) &&
time_before(jiffies, tlimit))
usleep_range(100, 200);
return test_bit(bitname, lif->state);
return wait_on_bit_lock(lif->state, bitname, TASK_INTERRUPTIBLE);
}
static inline u32 ionic_coal_usec_to_hw(struct ionic *ionic, u32 usecs)