mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
ionic: use mutex to protect queue operations
The ionic_wait_on_bit_lock() was a open-coded mutex knock-off
used only for protecting the queue reset operations, and there
was no reason not to use the real thing. We can use the lock
more correctly and to better protect the queue stop and start
operations from cross threading. We can also remove a useless
and expensive bit operation from the Rx path.
This fixes a case found where the link_status_check from a link
flap could run into an MTU change and cause a crash.
Fixes: beead698b1
("ionic: Add the basic NDO callbacks for netdev support")
Signed-off-by: Shannon Nelson <snelson@pensando.io>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
bdff46665e
commit
0925e9db4d
3 changed files with 17 additions and 25 deletions
|
@ -96,8 +96,7 @@ static void ionic_link_status_check(struct ionic_lif *lif)
|
|||
u16 link_status;
|
||||
bool link_up;
|
||||
|
||||
if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state) ||
|
||||
test_bit(IONIC_LIF_F_QUEUE_RESET, lif->state))
|
||||
if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
|
||||
return;
|
||||
|
||||
link_status = le16_to_cpu(lif->info->status.link_status);
|
||||
|
@ -114,16 +113,22 @@ static void ionic_link_status_check(struct ionic_lif *lif)
|
|||
netif_carrier_on(netdev);
|
||||
}
|
||||
|
||||
if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev))
|
||||
if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev)) {
|
||||
mutex_lock(&lif->queue_lock);
|
||||
ionic_start_queues(lif);
|
||||
mutex_unlock(&lif->queue_lock);
|
||||
}
|
||||
} else {
|
||||
if (netif_carrier_ok(netdev)) {
|
||||
netdev_info(netdev, "Link down\n");
|
||||
netif_carrier_off(netdev);
|
||||
}
|
||||
|
||||
if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev))
|
||||
if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev)) {
|
||||
mutex_lock(&lif->queue_lock);
|
||||
ionic_stop_queues(lif);
|
||||
mutex_unlock(&lif->queue_lock);
|
||||
}
|
||||
}
|
||||
|
||||
clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
|
||||
|
@ -1990,16 +1995,13 @@ int ionic_reset_queues(struct ionic_lif *lif, ionic_reset_cb cb, void *arg)
|
|||
bool running;
|
||||
int err = 0;
|
||||
|
||||
err = ionic_wait_for_bit(lif, IONIC_LIF_F_QUEUE_RESET);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&lif->queue_lock);
|
||||
running = netif_running(lif->netdev);
|
||||
if (running) {
|
||||
netif_device_detach(lif->netdev);
|
||||
err = ionic_stop(lif->netdev);
|
||||
if (err)
|
||||
goto reset_out;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (cb)
|
||||
|
@ -2009,9 +2011,7 @@ int ionic_reset_queues(struct ionic_lif *lif, ionic_reset_cb cb, void *arg)
|
|||
err = ionic_open(lif->netdev);
|
||||
netif_device_attach(lif->netdev);
|
||||
}
|
||||
|
||||
reset_out:
|
||||
clear_bit(IONIC_LIF_F_QUEUE_RESET, lif->state);
|
||||
mutex_unlock(&lif->queue_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -2158,7 +2158,9 @@ static void ionic_lif_handle_fw_down(struct ionic_lif *lif)
|
|||
|
||||
if (test_bit(IONIC_LIF_F_UP, lif->state)) {
|
||||
dev_info(ionic->dev, "Surprise FW stop, stopping queues\n");
|
||||
mutex_lock(&lif->queue_lock);
|
||||
ionic_stop_queues(lif);
|
||||
mutex_unlock(&lif->queue_lock);
|
||||
}
|
||||
|
||||
if (netif_running(lif->netdev)) {
|
||||
|
@ -2285,6 +2287,7 @@ static void ionic_lif_deinit(struct ionic_lif *lif)
|
|||
ionic_lif_qcq_deinit(lif, lif->notifyqcq);
|
||||
ionic_lif_qcq_deinit(lif, lif->adminqcq);
|
||||
|
||||
mutex_destroy(&lif->queue_lock);
|
||||
ionic_lif_reset(lif);
|
||||
}
|
||||
|
||||
|
@ -2461,6 +2464,7 @@ static int ionic_lif_init(struct ionic_lif *lif)
|
|||
return err;
|
||||
|
||||
lif->hw_index = le16_to_cpu(comp.hw_index);
|
||||
mutex_init(&lif->queue_lock);
|
||||
|
||||
/* now that we have the hw_index we can figure out our doorbell page */
|
||||
lif->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif);
|
||||
|
|
|
@ -135,7 +135,6 @@ enum ionic_lif_state_flags {
|
|||
IONIC_LIF_F_SW_DEBUG_STATS,
|
||||
IONIC_LIF_F_UP,
|
||||
IONIC_LIF_F_LINK_CHECK_REQUESTED,
|
||||
IONIC_LIF_F_QUEUE_RESET,
|
||||
IONIC_LIF_F_FW_RESET,
|
||||
|
||||
/* leave this as last */
|
||||
|
@ -165,6 +164,7 @@ struct ionic_lif {
|
|||
unsigned int hw_index;
|
||||
unsigned int kern_pid;
|
||||
u64 __iomem *kern_dbpage;
|
||||
struct mutex queue_lock; /* lock for queue structures */
|
||||
spinlock_t adminq_lock; /* lock for AdminQ operations */
|
||||
struct ionic_qcq *adminqcq;
|
||||
struct ionic_qcq *notifyqcq;
|
||||
|
@ -213,12 +213,6 @@ 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)
|
||||
{
|
||||
return wait_on_bit_lock(lif->state, bitname, TASK_INTERRUPTIBLE);
|
||||
}
|
||||
|
||||
static inline u32 ionic_coal_usec_to_hw(struct ionic *ionic, u32 usecs)
|
||||
{
|
||||
u32 mult = le32_to_cpu(ionic->ident.dev.intr_coal_mult);
|
||||
|
|
|
@ -161,12 +161,6 @@ static void ionic_rx_clean(struct ionic_queue *q,
|
|||
return;
|
||||
}
|
||||
|
||||
/* no packet processing while resetting */
|
||||
if (unlikely(test_bit(IONIC_LIF_F_QUEUE_RESET, q->lif->state))) {
|
||||
stats->dropped++;
|
||||
return;
|
||||
}
|
||||
|
||||
stats->pkts++;
|
||||
stats->bytes += le16_to_cpu(comp->len);
|
||||
|
||||
|
|
Loading…
Reference in a new issue