Module Name: src
Committed By: yamaguchi
Date: Wed Oct 11 04:44:20 UTC 2023
Modified Files:
src/sys/dev/pci: if_ixl.c
Log Message:
ixl(4): update link status in workqueue
To generate a diff of this commit:
cvs rdiff -u -r1.91 -r1.92 src/sys/dev/pci/if_ixl.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/pci/if_ixl.c
diff -u src/sys/dev/pci/if_ixl.c:1.91 src/sys/dev/pci/if_ixl.c:1.92
--- src/sys/dev/pci/if_ixl.c:1.91 Wed Oct 11 04:29:47 2023
+++ src/sys/dev/pci/if_ixl.c Wed Oct 11 04:44:20 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: if_ixl.c,v 1.91 2023/10/11 04:29:47 yamaguchi Exp $ */
+/* $NetBSD: if_ixl.c,v 1.92 2023/10/11 04:44:20 yamaguchi Exp $ */
/*
* Copyright (c) 2013-2015, Intel Corporation
@@ -74,7 +74,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ixl.c,v 1.91 2023/10/11 04:29:47 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ixl.c,v 1.92 2023/10/11 04:44:20 yamaguchi Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@@ -651,6 +651,7 @@ struct ixl_softc {
unsigned int sc_arq_cons;
struct ixl_work sc_link_state_task;
+ struct ixl_work sc_link_state_done_task;
struct ixl_atq sc_link_state_atq;
struct ixl_dmamem sc_hmc_sd;
@@ -715,6 +716,11 @@ do { \
#define IXL_QUEUE_NUM 0
#endif
+enum ixl_link_flags {
+ IXL_LINK_NOFLAGS = 0,
+ IXL_LINK_FLAG_WAITDONE = __BIT(0),
+};
+
static bool ixl_param_nomsix = false;
static int ixl_param_stats_interval = IXL_STATS_INTERVAL_MSEC;
static int ixl_param_nqps_limit = IXL_QUEUE_NUM;
@@ -738,6 +744,7 @@ static int ixl_atq_poll(struct ixl_softc
unsigned int);
static void ixl_atq_set(struct ixl_atq *,
void (*)(struct ixl_softc *, const struct ixl_aq_desc *));
+static void ixl_wakeup(struct ixl_softc *, const struct ixl_aq_desc *);
static int ixl_atq_post_locked(struct ixl_softc *, struct ixl_atq *);
static void ixl_atq_done(struct ixl_softc *);
static int ixl_atq_exec(struct ixl_softc *, struct ixl_atq *);
@@ -759,10 +766,12 @@ static void ixl_hmc_free(struct ixl_soft
static int ixl_get_vsi(struct ixl_softc *);
static int ixl_set_vsi(struct ixl_softc *);
static void ixl_set_filter_control(struct ixl_softc *);
-static void ixl_get_link_status(void *);
+static int ixl_get_link_status(struct ixl_softc *, enum ixl_link_flags);
+static void ixl_get_link_status_work(void *);
static int ixl_get_link_status_poll(struct ixl_softc *, int *);
static void ixl_get_link_status_done(struct ixl_softc *,
const struct ixl_aq_desc *);
+static void ixl_get_link_status_done_work(void *);
static int ixl_set_link_status_locked(struct ixl_softc *,
const struct ixl_aq_desc *);
static uint64_t ixl_search_link_speed(uint8_t);
@@ -1347,7 +1356,10 @@ ixl_attach(device_t parent, device_t sel
if_link_state_change(ifp, link);
ixl_atq_set(&sc->sc_link_state_atq, ixl_get_link_status_done);
- ixl_work_set(&sc->sc_link_state_task, ixl_get_link_status, sc);
+ ixl_work_set(&sc->sc_link_state_task,
+ ixl_get_link_status_work, sc);
+ ixl_work_set(&sc->sc_link_state_done_task,
+ ixl_get_link_status_done_work, sc);
ixl_config_other_intr(sc);
ixl_enable_other_intr(sc);
@@ -2087,8 +2099,10 @@ ixl_init(struct ifnet *ifp)
error = ixl_init_locked(sc);
mutex_exit(&sc->sc_cfg_lock);
- if (error == 0)
- (void)ixl_get_link_status(sc);
+ if (error == 0) {
+ error = ixl_get_link_status(sc,
+ IXL_LINK_FLAG_WAITDONE);
+ }
return error;
}
@@ -3579,50 +3593,88 @@ ixl_other_intr(void *xsc)
}
static void
-ixl_get_link_status_done(struct ixl_softc *sc,
- const struct ixl_aq_desc *iaq)
+ixl_get_link_status_done_work(void *xsc)
{
- struct ixl_aq_desc iaq_buf;
-
- memcpy(&iaq_buf, iaq, sizeof(iaq_buf));
+ struct ixl_softc *sc = xsc;
+ struct ixl_aq_desc *iaq, iaq_buf;
- /*
- * The lock can be released here
- * because there is no post processing about ATQ
- */
+ mutex_enter(&sc->sc_atq_lock);
+ iaq = &sc->sc_link_state_atq.iatq_desc;
+ iaq_buf = *iaq;
mutex_exit(&sc->sc_atq_lock);
+
ixl_link_state_update(sc, &iaq_buf);
+
mutex_enter(&sc->sc_atq_lock);
+ CLR(iaq->iaq_flags, htole16(IXL_AQ_DD));
+ ixl_wakeup(sc, iaq);
+ mutex_exit(&sc->sc_atq_lock);
}
static void
-ixl_get_link_status(void *xsc)
+ixl_get_link_status_done(struct ixl_softc *sc,
+ const struct ixl_aq_desc *iaq)
{
- struct ixl_softc *sc = xsc;
+
+ ixl_work_add(sc->sc_workq, &sc->sc_link_state_done_task);
+}
+
+static int
+ixl_get_link_status(struct ixl_softc *sc, enum ixl_link_flags flags)
+{
+ struct ixl_atq *iatq;
struct ixl_aq_desc *iaq;
struct ixl_aq_link_param *param;
int error;
mutex_enter(&sc->sc_atq_lock);
- if (sc->sc_link_state_atq.iatq_inuse)
- goto done;
+ iatq = &sc->sc_link_state_atq;
+ iaq = &iatq->iatq_desc;
- iaq = &sc->sc_link_state_atq.iatq_desc;
- memset(iaq, 0, sizeof(*iaq));
- iaq->iaq_opcode = htole16(IXL_AQ_OP_PHY_LINK_STATUS);
- param = (struct ixl_aq_link_param *)iaq->iaq_param;
- param->notify = IXL_AQ_LINK_NOTIFY;
+ if (!sc->sc_link_state_atq.iatq_inuse &&
+ !ISSET(iaq->iaq_flags, htole16(IXL_AQ_DD))) {
+ memset(iaq, 0, sizeof(*iaq));
+ iaq->iaq_opcode = htole16(IXL_AQ_OP_PHY_LINK_STATUS);
+ param = (struct ixl_aq_link_param *)iaq->iaq_param;
+ param->notify = IXL_AQ_LINK_NOTIFY;
- error = ixl_atq_exec_locked(sc, &sc->sc_link_state_atq);
- ixl_atq_set(&sc->sc_link_state_atq, ixl_get_link_status_done);
+ KASSERT(iatq->iatq_fn == ixl_get_link_status_done);
+ error = ixl_atq_post_locked(sc, iatq);
+ if (error != 0)
+ goto out;
+ } else {
+ /* the previous command is not completed */
+ error = EBUSY;
+ }
- if (error == 0) {
- ixl_get_link_status_done(sc, iaq);
+ if (ISSET(flags, IXL_LINK_FLAG_WAITDONE)) {
+ do {
+ error = cv_timedwait(&sc->sc_atq_cv, &sc->sc_atq_lock,
+ IXL_ATQ_EXEC_TIMEOUT);
+ if (error == EWOULDBLOCK)
+ break;
+ } while (iatq->iatq_inuse ||
+ ISSET(iaq->iaq_flags, htole16(IXL_AQ_DD)));
}
-done:
+out:
mutex_exit(&sc->sc_atq_lock);
+
+ return error;
+}
+
+static void
+ixl_get_link_status_work(void *xsc)
+{
+ struct ixl_softc *sc = xsc;
+
+ /*
+ * IXL_LINK_FLAG_WAITDONE causes deadlock
+ * because of doing ixl_gt_link_status_done_work()
+ * in the same workqueue.
+ */
+ (void)ixl_get_link_status(sc, IXL_LINK_NOFLAGS);
}
static void