@@ -14,11 +14,19 @@
static void ionic_watchdog_cb(struct timer_list *t)
{
struct ionic *ionic = from_timer(ionic, t, watchdog_timer);
+ struct ionic_lif *lif = ionic->master_lif;
+ int hb;
mod_timer(&ionic->watchdog_timer,
round_jiffies(jiffies + ionic->watchdog_period));
- ionic_heartbeat_check(ionic);
+ hb = ionic_heartbeat_check(ionic);
+
+ /* check link if we're waiting for link to come back up */
+ if (hb >= 0 && lif && netif_running(lif->netdev) &&
+ !test_bit(IONIC_LIF_F_UP, lif->state)) {
+ ionic_link_status_check_request(lif);
+ }
}
void ionic_init_devinfo(struct ionic *ionic)
@@ -90,40 +90,44 @@ static void ionic_link_status_check(struct ionic_lif *lif)
link_status = le16_to_cpu(lif->info->status.link_status);
link_up = link_status == IONIC_PORT_OPER_STATUS_UP;
- /* filter out the no-change cases */
- if (link_up == netif_carrier_ok(netdev))
- goto link_out;
-
if (link_up) {
u32 link_speed;
- link_speed = le16_to_cpu(lif->info->status.link_speed);
- netdev_info(netdev, "Link up - %d Gbps\n", link_speed / 1000);
+ if (!netif_carrier_ok(netdev)) {
+ /* force an update in shared structs */
+ ionic_port_identify(lif->ionic);
+
+ link_speed = le32_to_cpu(lif->info->status.link_speed);
+ netdev_info(netdev, "Link up - %d Gbps\n",
+ link_speed / 1000);
+ netif_carrier_on(netdev);
+ }
if (!test_bit(IONIC_LIF_F_UP, lif->state) &&
- netif_running(netdev)) {
+ netif_running(netdev) &&
+ !test_bit(IONIC_LIF_F_TRANS, lif->state)) {
rtnl_lock();
ionic_open(netdev);
rtnl_unlock();
}
-
- netif_carrier_on(netdev);
} else {
- netdev_info(netdev, "Link down\n");
- netif_carrier_off(netdev);
+ if (netif_carrier_ok(netdev)) {
+ netdev_info(netdev, "Link down\n");
+ netif_carrier_off(netdev);
+ }
- if (test_bit(IONIC_LIF_F_UP, lif->state)) {
+ if (test_bit(IONIC_LIF_F_UP, lif->state) &&
+ !test_bit(IONIC_LIF_F_TRANS, lif->state)) {
rtnl_lock();
ionic_stop(netdev);
rtnl_unlock();
}
}
-link_out:
clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
}
-static void ionic_link_status_check_request(struct ionic_lif *lif)
+void ionic_link_status_check_request(struct ionic_lif *lif)
{
struct ionic_deferred_work *work;
@@ -1455,10 +1459,15 @@ static void ionic_lif_rss_deinit(struct ionic_lif *lif)
static void ionic_txrx_disable(struct ionic_lif *lif)
{
unsigned int i;
+ int err;
for (i = 0; i < lif->nxqs; i++) {
- ionic_qcq_disable(lif->txqcqs[i].qcq);
- ionic_qcq_disable(lif->rxqcqs[i].qcq);
+ err = ionic_qcq_disable(lif->txqcqs[i].qcq);
+ if (err == -ETIMEDOUT)
+ break;
+ err = ionic_qcq_disable(lif->rxqcqs[i].qcq);
+ if (err == -ETIMEDOUT)
+ break;
}
}
@@ -1581,7 +1590,7 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
ionic_rx_fill(&lif->rxqcqs[i].qcq->q);
err = ionic_qcq_enable(lif->rxqcqs[i].qcq);
- if (err) {
+ if (err && err != -ETIMEDOUT) {
ionic_qcq_disable(lif->txqcqs[i].qcq);
goto err_out;
}
@@ -1591,8 +1600,12 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
err_out:
while (i--) {
- ionic_qcq_disable(lif->rxqcqs[i].qcq);
- ionic_qcq_disable(lif->txqcqs[i].qcq);
+ err = ionic_qcq_disable(lif->rxqcqs[i].qcq);
+ if (err == -ETIMEDOUT)
+ break;
+ err = ionic_qcq_disable(lif->txqcqs[i].qcq);
+ if (err == -ETIMEDOUT)
+ break;
}
return err;
@@ -1601,7 +1614,7 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
int ionic_open(struct net_device *netdev)
{
struct ionic_lif *lif = netdev_priv(netdev);
- int err;
+ int err = 0;
if (test_bit(IONIC_LIF_F_UP, lif->state)) {
dev_dbg(lif->ionic->dev, "%s: %s called when state=UP\n",
@@ -1609,15 +1622,18 @@ int ionic_open(struct net_device *netdev)
return 0;
}
+ if (test_and_set_bit(IONIC_LIF_F_TRANS, lif->state))
+ return -EBUSY;
+
ionic_link_status_check_request(lif);
/* wait until carrier is up before creating rx and tx queues */
if (!netif_carrier_ok(lif->netdev))
- return 0;
+ goto open_out;
err = ionic_txrx_alloc(lif);
if (err)
- return err;
+ goto open_out;
err = ionic_txrx_init(lif);
if (err)
@@ -1635,25 +1651,30 @@ int ionic_open(struct net_device *netdev)
if (netif_carrier_ok(netdev))
netif_tx_wake_all_queues(netdev);
- return 0;
-
err_txrx_deinit:
- ionic_txrx_deinit(lif);
+ if (err)
+ ionic_txrx_deinit(lif);
err_txrx_free:
- ionic_txrx_free(lif);
+ if (err)
+ ionic_txrx_free(lif);
+open_out:
+ clear_bit(IONIC_LIF_F_TRANS, lif->state);
return err;
}
int ionic_stop(struct net_device *netdev)
{
struct ionic_lif *lif = netdev_priv(netdev);
- int err = 0;
if (!test_bit(IONIC_LIF_F_UP, lif->state)) {
dev_dbg(lif->ionic->dev, "%s: %s called when state=DOWN\n",
__func__, lif->name);
return 0;
}
+
+ if (test_and_set_bit(IONIC_LIF_F_TRANS, lif->state))
+ return -EBUSY;
+
dev_dbg(lif->ionic->dev, "%s: %s state=UP\n", __func__, lif->name);
clear_bit(IONIC_LIF_F_UP, lif->state);
@@ -1667,7 +1688,8 @@ int ionic_stop(struct net_device *netdev)
ionic_txrx_deinit(lif);
ionic_txrx_free(lif);
- return err;
+ clear_bit(IONIC_LIF_F_TRANS, lif->state);
+ return 0;
}
static int ionic_get_vf_config(struct net_device *netdev,
@@ -125,6 +125,7 @@ enum ionic_lif_state_flags {
IONIC_LIF_F_INITED,
IONIC_LIF_F_SW_DEBUG_STATS,
IONIC_LIF_F_UP,
+ IONIC_LIF_F_TRANS,
IONIC_LIF_F_LINK_CHECK_REQUESTED,
IONIC_LIF_F_QUEUE_RESET,
IONIC_LIF_F_FW_RESET,
@@ -228,6 +229,7 @@ static inline u32 ionic_coal_hw_to_usec(struct ionic *ionic, u32 units)
void ionic_lif_deferred_enqueue(struct ionic_deferred *def,
struct ionic_deferred_work *work);
+void ionic_link_status_check_request(struct ionic_lif *lif);
int ionic_lifs_alloc(struct ionic *ionic);
void ionic_lifs_free(struct ionic *ionic);
void ionic_lifs_deinit(struct ionic *ionic);
@@ -364,7 +364,6 @@ int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds)
done, duration / HZ, duration);
if (!done && hb) {
- ionic_dev_cmd_clean(ionic);
dev_warn(ionic->dev, "DEVCMD %s (%d) failed - FW halted\n",
ionic_opcode_to_str(opcode), opcode);
return -ENXIO;
While the link is down, have the heartbeat watchdog also check the link for changes in case no Event is sent. Meanwhile, sometimes the link status check runs into itself or the ionic_open() thread, and can either confuse itself, throw incorrect error messages, or even miss the link message. This patch cleans up the code and gets the right messages out to the log file when they happen. - rearrange the link_up/link_down messages so that we announce link up when we first notice that the link is up when the driver loads, and decouple the link_up/link_down messages from the UP and DOWN netdev state. - add error checking of ionic_qcq_disable() so as to not have to wait too long on shutdown when everything it timeout out. - add a state to indicate transitions between netdev UP and DOWN so as to prevent recursion. - don't clean the dev_cmd when we notice that the fw has halted, it's possible it might still execute the request. Signed-off-by: Shannon Nelson <snelson@pensando.io> --- .../net/ethernet/pensando/ionic/ionic_dev.c | 10 ++- .../net/ethernet/pensando/ionic/ionic_lif.c | 78 ++++++++++++------- .../net/ethernet/pensando/ionic/ionic_lif.h | 2 + .../net/ethernet/pensando/ionic/ionic_main.c | 1 - 4 files changed, 61 insertions(+), 30 deletions(-)