Commit 1f6d768a authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents df428e40 e982ae6a
...@@ -19,31 +19,30 @@ static int ionic_dl_info_get(struct devlink *dl, struct devlink_info_req *req, ...@@ -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); err = devlink_info_driver_name_put(req, IONIC_DRV_NAME);
if (err) if (err)
goto info_out; return err;
err = devlink_info_version_running_put(req, err = devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW, DEVLINK_INFO_VERSION_GENERIC_FW,
idev->dev_info.fw_version); idev->dev_info.fw_version);
if (err) if (err)
goto info_out; return err;
snprintf(buf, sizeof(buf), "0x%x", idev->dev_info.asic_type); snprintf(buf, sizeof(buf), "0x%x", idev->dev_info.asic_type);
err = devlink_info_version_fixed_put(req, err = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
buf); buf);
if (err) if (err)
goto info_out; return err;
snprintf(buf, sizeof(buf), "0x%x", idev->dev_info.asic_rev); snprintf(buf, sizeof(buf), "0x%x", idev->dev_info.asic_rev);
err = devlink_info_version_fixed_put(req, err = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, DEVLINK_INFO_VERSION_GENERIC_ASIC_REV,
buf); buf);
if (err) if (err)
goto info_out; return err;
err = devlink_info_serial_number_put(req, idev->dev_info.serial_num); err = devlink_info_serial_number_put(req, idev->dev_info.serial_num);
info_out:
return err; return err;
} }
......
...@@ -254,12 +254,9 @@ static int ionic_set_link_ksettings(struct net_device *netdev, ...@@ -254,12 +254,9 @@ static int ionic_set_link_ksettings(struct net_device *netdev,
struct ionic_lif *lif = netdev_priv(netdev); struct ionic_lif *lif = netdev_priv(netdev);
struct ionic *ionic = lif->ionic; struct ionic *ionic = lif->ionic;
struct ionic_dev *idev; struct ionic_dev *idev;
u32 req_rs, req_fc;
u8 fec_type;
int err = 0; int err = 0;
idev = &lif->ionic->idev; idev = &lif->ionic->idev;
fec_type = IONIC_PORT_FEC_TYPE_NONE;
/* set autoneg */ /* set autoneg */
if (ks->base.autoneg != idev->port_info->config.an_enable) { if (ks->base.autoneg != idev->port_info->config.an_enable) {
...@@ -281,29 +278,6 @@ static int ionic_set_link_ksettings(struct net_device *netdev, ...@@ -281,29 +278,6 @@ static int ionic_set_link_ksettings(struct net_device *netdev,
return err; 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; return 0;
} }
...@@ -353,6 +327,70 @@ static int ionic_set_pauseparam(struct net_device *netdev, ...@@ -353,6 +327,70 @@ static int ionic_set_pauseparam(struct net_device *netdev,
return 0; 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, static int ionic_get_coalesce(struct net_device *netdev,
struct ethtool_coalesce *coalesce) struct ethtool_coalesce *coalesce)
{ {
...@@ -372,7 +410,6 @@ static int ionic_set_coalesce(struct net_device *netdev, ...@@ -372,7 +410,6 @@ static int ionic_set_coalesce(struct net_device *netdev,
struct ionic_identity *ident; struct ionic_identity *ident;
struct ionic_qcq *qcq; struct ionic_qcq *qcq;
unsigned int i; unsigned int i;
u32 usecs;
u32 coal; u32 coal;
if (coalesce->rx_max_coalesced_frames || if (coalesce->rx_max_coalesced_frames ||
...@@ -410,26 +447,27 @@ static int ionic_set_coalesce(struct net_device *netdev, ...@@ -410,26 +447,27 @@ static int ionic_set_coalesce(struct net_device *netdev,
return -EINVAL; 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); coal = ionic_coal_usec_to_hw(lif->ionic, coalesce->rx_coalesce_usecs);
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) if (!coal && coalesce->rx_coalesce_usecs)
coal = 1; coal = 1;
/* Convert it back to get device resolution */ if (coal > IONIC_INTR_CTRL_COAL_MAX)
usecs = ionic_coal_hw_to_usec(lif->ionic, coal); return -ERANGE;
if (usecs != lif->rx_coalesce_usecs) { /* Save the new value */
lif->rx_coalesce_usecs = usecs; 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)) { if (test_bit(IONIC_LIF_UP, lif->state)) {
for (i = 0; i < lif->nxqs; i++) { for (i = 0; i < lif->nxqs; i++) {
qcq = lif->rxqcqs[i].qcq; qcq = lif->rxqcqs[i].qcq;
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl, 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, ...@@ -453,6 +491,7 @@ static int ionic_set_ringparam(struct net_device *netdev,
{ {
struct ionic_lif *lif = netdev_priv(netdev); struct ionic_lif *lif = netdev_priv(netdev);
bool running; bool running;
int err;
if (ring->rx_mini_pending || ring->rx_jumbo_pending) { if (ring->rx_mini_pending || ring->rx_jumbo_pending) {
netdev_info(netdev, "Changing jumbo or mini descriptors not supported\n"); netdev_info(netdev, "Changing jumbo or mini descriptors not supported\n");
...@@ -470,8 +509,9 @@ static int ionic_set_ringparam(struct net_device *netdev, ...@@ -470,8 +509,9 @@ static int ionic_set_ringparam(struct net_device *netdev,
ring->rx_pending == lif->nrxq_descs) ring->rx_pending == lif->nrxq_descs)
return 0; return 0;
if (!ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET)) err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET);
return -EBUSY; if (err)
return err;
running = test_bit(IONIC_LIF_UP, lif->state); running = test_bit(IONIC_LIF_UP, lif->state);
if (running) if (running)
...@@ -504,6 +544,7 @@ static int ionic_set_channels(struct net_device *netdev, ...@@ -504,6 +544,7 @@ static int ionic_set_channels(struct net_device *netdev,
{ {
struct ionic_lif *lif = netdev_priv(netdev); struct ionic_lif *lif = netdev_priv(netdev);
bool running; bool running;
int err;
if (!ch->combined_count || ch->other_count || if (!ch->combined_count || ch->other_count ||
ch->rx_count || ch->tx_count) ch->rx_count || ch->tx_count)
...@@ -512,8 +553,9 @@ static int ionic_set_channels(struct net_device *netdev, ...@@ -512,8 +553,9 @@ static int ionic_set_channels(struct net_device *netdev,
if (ch->combined_count == lif->nxqs) if (ch->combined_count == lif->nxqs)
return 0; return 0;
if (!ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET)) err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET);
return -EBUSY; if (err)
return err;
running = test_bit(IONIC_LIF_UP, lif->state); running = test_bit(IONIC_LIF_UP, lif->state);
if (running) if (running)
...@@ -747,6 +789,7 @@ static const struct ethtool_ops ionic_ethtool_ops = { ...@@ -747,6 +789,7 @@ static const struct ethtool_ops ionic_ethtool_ops = {
.get_regs = ionic_get_regs, .get_regs = ionic_get_regs,
.get_link = ethtool_op_get_link, .get_link = ethtool_op_get_link,
.get_link_ksettings = ionic_get_link_ksettings, .get_link_ksettings = ionic_get_link_ksettings,
.set_link_ksettings = ionic_set_link_ksettings,
.get_coalesce = ionic_get_coalesce, .get_coalesce = ionic_get_coalesce,
.set_coalesce = ionic_set_coalesce, .set_coalesce = ionic_set_coalesce,
.get_ringparam = ionic_get_ringparam, .get_ringparam = ionic_get_ringparam,
...@@ -769,7 +812,8 @@ static const struct ethtool_ops ionic_ethtool_ops = { ...@@ -769,7 +812,8 @@ static const struct ethtool_ops ionic_ethtool_ops = {
.get_module_eeprom = ionic_get_module_eeprom, .get_module_eeprom = ionic_get_module_eeprom,
.get_pauseparam = ionic_get_pauseparam, .get_pauseparam = ionic_get_pauseparam,
.set_pauseparam = ionic_set_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, .nway_reset = ionic_nway_reset,
}; };
......
...@@ -242,6 +242,21 @@ static int ionic_qcq_disable(struct ionic_qcq *qcq) ...@@ -242,6 +242,21 @@ static int ionic_qcq_disable(struct ionic_qcq *qcq)
return ionic_adminq_post_wait(lif, &ctx); 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) static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
{ {
struct ionic_dev *idev = &lif->ionic->idev; struct ionic_dev *idev = &lif->ionic->idev;
...@@ -1430,7 +1445,6 @@ static int ionic_txrx_alloc(struct ionic_lif *lif) ...@@ -1430,7 +1445,6 @@ static int ionic_txrx_alloc(struct ionic_lif *lif)
unsigned int flags; unsigned int flags;
unsigned int i; unsigned int i;
int err = 0; int err = 0;
u32 coal;
flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG; flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG;
for (i = 0; i < lif->nxqs; i++) { for (i = 0; i < lif->nxqs; i++) {
...@@ -1447,7 +1461,6 @@ static int ionic_txrx_alloc(struct ionic_lif *lif) ...@@ -1447,7 +1461,6 @@ static int ionic_txrx_alloc(struct ionic_lif *lif)
} }
flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_INTR; 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++) { for (i = 0; i < lif->nxqs; i++) {
err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags, err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
lif->nrxq_descs, lif->nrxq_descs,
...@@ -1460,7 +1473,8 @@ static int ionic_txrx_alloc(struct ionic_lif *lif) ...@@ -1460,7 +1473,8 @@ static int ionic_txrx_alloc(struct ionic_lif *lif)
lif->rxqcqs[i].qcq->stats = lif->rxqcqs[i].stats; lif->rxqcqs[i].qcq->stats = lif->rxqcqs[i].stats;
ionic_intr_coal_init(lif->ionic->idev.intr_ctrl, 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, ionic_link_qcq_interrupts(lif->rxqcqs[i].qcq,
lif->txqcqs[i].qcq); lif->txqcqs[i].qcq);
} }
...@@ -1590,6 +1604,7 @@ int ionic_stop(struct net_device *netdev) ...@@ -1590,6 +1604,7 @@ int ionic_stop(struct net_device *netdev)
netif_tx_disable(netdev); netif_tx_disable(netdev);
ionic_txrx_disable(lif); ionic_txrx_disable(lif);
ionic_lif_quiesce(lif);
ionic_txrx_deinit(lif); ionic_txrx_deinit(lif);
ionic_txrx_free(lif); ionic_txrx_free(lif);
...@@ -1619,8 +1634,9 @@ int ionic_reset_queues(struct ionic_lif *lif) ...@@ -1619,8 +1634,9 @@ int ionic_reset_queues(struct ionic_lif *lif)
/* Put off the next watchdog timeout */ /* Put off the next watchdog timeout */
netif_trans_update(lif->netdev); netif_trans_update(lif->netdev);
if (!ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET)) err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET);
return -EBUSY; if (err)
return err;
running = netif_running(lif->netdev); running = netif_running(lif->netdev);
if (running) if (running)
...@@ -1639,7 +1655,6 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index ...@@ -1639,7 +1655,6 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index
struct net_device *netdev; struct net_device *netdev;
struct ionic_lif *lif; struct ionic_lif *lif;
int tbl_sz; int tbl_sz;
u32 coal;
int err; int err;
netdev = alloc_etherdev_mqs(sizeof(*lif), netdev = alloc_etherdev_mqs(sizeof(*lif),
...@@ -1670,8 +1685,9 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index ...@@ -1670,8 +1685,9 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index
lif->nrxq_descs = IONIC_DEF_TXRX_DESC; lif->nrxq_descs = IONIC_DEF_TXRX_DESC;
/* Convert the default coalesce value to actual hw resolution */ /* 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_ITR_COAL_USEC_DEFAULT;
lif->rx_coalesce_usecs = ionic_coal_hw_to_usec(lif->ionic, coal); lif->rx_coalesce_hw = ionic_coal_hw_to_usec(lif->ionic,
lif->rx_coalesce_usecs);
snprintf(lif->name, sizeof(lif->name), "lif%u", index); snprintf(lif->name, sizeof(lif->name), "lif%u", index);
......
...@@ -175,7 +175,9 @@ struct ionic_lif { ...@@ -175,7 +175,9 @@ struct ionic_lif {
unsigned long *dbid_inuse; unsigned long *dbid_inuse;
unsigned int dbid_count; unsigned int dbid_count;
struct dentry *dentry; 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; u32 flags;
struct work_struct tx_timeout_work; struct work_struct tx_timeout_work;
}; };
...@@ -185,15 +187,10 @@ struct ionic_lif { ...@@ -185,15 +187,10 @@ struct ionic_lif {
#define lif_to_txq(lif, i) (&lif_to_txqcq((lif), i)->q) #define lif_to_txq(lif, i) (&lif_to_txqcq((lif), i)->q)
#define lif_to_rxq(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) static inline int ionic_wait_for_bit(struct ionic_lif *lif, int bitname)
{ {
unsigned long tlimit = jiffies + HZ; return wait_on_bit_lock(lif->state, bitname, TASK_INTERRUPTIBLE);
while (test_and_set_bit(bitname, lif->state) &&
time_before(jiffies, tlimit))
usleep_range(100, 200);
return test_bit(bitname, lif->state);
} }
static inline u32 ionic_coal_usec_to_hw(struct ionic *ionic, u32 usecs) static inline u32 ionic_coal_usec_to_hw(struct ionic *ionic, u32 usecs)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment