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

Reply via email to