-/* $OpenBSD: qle.c,v 1.44 2018/07/30 07:30:54 jmatthew Exp $ */
+/* $OpenBSD: qle.c,v 1.45 2018/07/30 07:34:37 jmatthew Exp $ */
/*
* Copyright (c) 2013, 2014 Jonathan Matthew <jmatthew@openbsd.org>
#include <sys/sensors.h>
#include <sys/rwlock.h>
#include <sys/task.h>
+#include <sys/timeout.h>
#include <machine/bus.h>
struct taskq *sc_update_taskq;
struct task sc_update_task;
+ struct timeout sc_update_timeout;
int sc_update;
int sc_update_tasks;
#define QLE_UPDATE_TASK_CLEAR_ALL 0x00000001
void qle_fabric_plogo(struct qle_softc *, struct qle_fc_port *);
void qle_update_start(struct qle_softc *, int);
+void qle_update_defer(struct qle_softc *, int);
+void qle_update_cancel(struct qle_softc *);
void qle_update_done(struct qle_softc *, int);
void qle_do_update(void *);
+void qle_deferred_update(void *);
int qle_async(struct qle_softc *, u_int16_t);
int qle_load_fwchunk(struct qle_softc *,
sc->sc_update_taskq = taskq_create(DEVNAME(sc), 1, IPL_BIO, 0);
task_set(&sc->sc_update_task, qle_do_update, sc);
+ timeout_set(&sc->sc_update_timeout, qle_deferred_update, sc);
/* wait a bit for link to come up so we can scan and attach devices */
for (i = 0; i < QLE_WAIT_FOR_LOOP * 1000; i++) {
atomic_clearbits_int(&sc->sc_update_tasks, task);
}
+void
+qle_update_cancel(struct qle_softc *sc)
+{
+ atomic_swap_uint(&sc->sc_update_tasks, 0);
+ timeout_del(&sc->sc_update_timeout);
+ task_del(sc->sc_update_taskq, &sc->sc_update_task);
+}
+
void
qle_update_start(struct qle_softc *sc, int task)
{
atomic_setbits_int(&sc->sc_update_tasks, task);
- task_add(sc->sc_update_taskq, &sc->sc_update_task);
+ if (!timeout_pending(&sc->sc_update_timeout))
+ task_add(sc->sc_update_taskq, &sc->sc_update_task);
+}
+
+void
+qle_update_defer(struct qle_softc *sc, int task)
+{
+ atomic_setbits_int(&sc->sc_update_tasks, task);
+ timeout_del(&sc->sc_update_timeout);
+ task_del(sc->sc_update_taskq, &sc->sc_update_task);
+ timeout_add_msec(&sc->sc_update_timeout, QLE_LOOP_SETTLE);
}
void
}
}
+void
+qle_deferred_update(void *xsc)
+{
+ struct qle_softc *sc = xsc;
+ task_add(sc->sc_update_taskq, &sc->sc_update_task);
+}
+
void
qle_do_update(void *xsc)
{
DPRINTF(QLE_D_PORT, "%s: loop up\n", DEVNAME(sc));
sc->sc_loop_up = 1;
sc->sc_marker_required = 1;
- qle_update_start(sc, QLE_UPDATE_TASK_UPDATE_TOPO |
+ qle_update_defer(sc, QLE_UPDATE_TASK_UPDATE_TOPO |
QLE_UPDATE_TASK_GET_PORT_LIST);
break;
case QLE_ASYNC_LOOP_DOWN:
DPRINTF(QLE_D_PORT, "%s: loop down\n", DEVNAME(sc));
sc->sc_loop_up = 0;
+ qle_update_cancel(sc);
qle_update_start(sc, QLE_UPDATE_TASK_CLEAR_ALL);
break;
case QLE_ASYNC_LIP_RESET:
DPRINTF(QLE_D_PORT, "%s: lip reset\n", DEVNAME(sc));
sc->sc_marker_required = 1;
- qle_update_start(sc, QLE_UPDATE_TASK_FABRIC_RELOGIN);
+ qle_update_defer(sc, QLE_UPDATE_TASK_FABRIC_RELOGIN);
break;
case QLE_ASYNC_PORT_DB_CHANGE: