tpm(4): Fix disabling of rnd source if tpm is deactivated.

Nothing prevents a second worker from being queued when the first one
is about to do rnd_detach_source.  Instead, just set a flag so future
requests don't bother running a new thread; if there's a concurrent
one that's already been scheduled on another CPU, well, too bad, we
get a couple extra log messages but that's fine.

A better way to do this would probably be to detect whether the tpm
is deactivated at attach time, but that requires reading more of the
tpm spec than I care to do when there are alternative ways to
procrastinate like scrubbing the toilet.
This commit is contained in:
riastradh 2021-12-20 23:05:55 +00:00
parent 6b9fd43891
commit 344cf1cc84
2 changed files with 7 additions and 4 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: tpm.c,v 1.22 2021/06/02 21:35:17 riastradh Exp $ */
/* $NetBSD: tpm.c,v 1.23 2021/12/20 23:05:55 riastradh Exp $ */
/*
* Copyright (c) 2019 The NetBSD Foundation, Inc.
@ -48,7 +48,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.22 2021/06/02 21:35:17 riastradh Exp $");
__KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.23 2021/12/20 23:05:55 riastradh Exp $");
#include <sys/param.h>
#include <sys/types.h>
@ -650,7 +650,7 @@ tpm_rng_work(struct work *wk, void *cookie)
*/
if (rv) {
device_printf(sc->sc_dev, "deactivating entropy source\n");
rnd_detach_source(&sc->sc_rnd);
atomic_store_relaxed(&sc->sc_rnddisabled, true);
/* XXX worker thread can't workqueue_destroy its own queue */
}
@ -666,6 +666,8 @@ tpm_rng_get(size_t nbytes, void *cookie)
{
struct tpm_softc *sc = cookie;
if (atomic_load_relaxed(&sc->sc_rnddisabled))
return; /* tough */
if (atomic_swap_uint(&sc->sc_rndpending, MIN(nbytes, UINT_MAX/NBBY))
== 0)
workqueue_enqueue(sc->sc_rndwq, &sc->sc_rndwk, NULL);

View File

@ -1,4 +1,4 @@
/* $NetBSD: tpmvar.h,v 1.9 2021/01/04 18:26:59 riastradh Exp $ */
/* $NetBSD: tpmvar.h,v 1.10 2021/12/20 23:05:55 riastradh Exp $ */
/*
* Copyright (c) 2019 The NetBSD Foundation, Inc.
@ -98,6 +98,7 @@ struct tpm_softc {
struct workqueue *sc_rndwq;
struct work sc_rndwk;
volatile unsigned sc_rndpending;
bool sc_rnddisabled;
};
bool tpm_suspend(device_t, const pmf_qual_t *);