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