11.4Sriastrad/*	$NetBSD: linux_stop_machine.c,v 1.4 2022/04/09 23:38:33 riastradh Exp $	*/
21.1Sriastrad
31.1Sriastrad/*-
41.1Sriastrad * Copyright (c) 2018 The NetBSD Foundation, Inc.
51.1Sriastrad * All rights reserved.
61.1Sriastrad *
71.1Sriastrad * This code is derived from software contributed to The NetBSD Foundation
81.1Sriastrad * by Taylor R. Campbell.
91.1Sriastrad *
101.1Sriastrad * Redistribution and use in source and binary forms, with or without
111.1Sriastrad * modification, are permitted provided that the following conditions
121.1Sriastrad * are met:
131.1Sriastrad * 1. Redistributions of source code must retain the above copyright
141.1Sriastrad *    notice, this list of conditions and the following disclaimer.
151.1Sriastrad * 2. Redistributions in binary form must reproduce the above copyright
161.1Sriastrad *    notice, this list of conditions and the following disclaimer in the
171.1Sriastrad *    documentation and/or other materials provided with the distribution.
181.1Sriastrad *
191.1Sriastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201.1Sriastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211.1Sriastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221.1Sriastrad * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231.1Sriastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241.1Sriastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251.1Sriastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261.1Sriastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271.1Sriastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281.1Sriastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291.1Sriastrad * POSSIBILITY OF SUCH DAMAGE.
301.1Sriastrad */
311.1Sriastrad
321.1Sriastrad#include <sys/cdefs.h>
331.4Sriastrad__KERNEL_RCSID(0, "$NetBSD: linux_stop_machine.c,v 1.4 2022/04/09 23:38:33 riastradh Exp $");
341.2Sriastrad
351.2Sriastrad#include <sys/mutex.h> /* XXX work around cycle x86/mutex.h<->x86/intr.h */
361.1Sriastrad
371.1Sriastrad#include <sys/atomic.h>
381.1Sriastrad#include <sys/intr.h>
391.1Sriastrad#include <sys/lock.h>
401.1Sriastrad#include <sys/systm.h>
411.1Sriastrad#include <sys/xcall.h>
421.1Sriastrad
431.1Sriastrad#include <linux/stop_machine.h>
441.1Sriastrad
451.1Sriastradstruct stop_machine {
461.1Sriastrad	int			(*callback)(void *);
471.1Sriastrad	void			*cookie;
481.1Sriastrad	volatile unsigned	ncpu;
491.1Sriastrad	volatile bool		done;
501.1Sriastrad};
511.1Sriastrad
521.1Sriastradstatic void
531.1Sriastradstop_machine_xcall(void *a, void *b)
541.1Sriastrad{
551.1Sriastrad	struct stop_machine *S = a;
561.1Sriastrad	int s;
571.1Sriastrad
581.1Sriastrad	/* Block all activity on this CPU.  */
591.1Sriastrad	s = splhigh();
601.1Sriastrad
611.1Sriastrad	/* Note that we're ready, and see whether we're the chosen one.  */
621.4Sriastrad	membar_release();
631.1Sriastrad	if (atomic_dec_uint_nv(&S->ncpu) != 0) {
641.3Sriastrad		while (!atomic_load_acquire(&S->done))
651.1Sriastrad			SPINLOCK_BACKOFF_HOOK;
661.1Sriastrad		goto out;
671.1Sriastrad	}
681.4Sriastrad	membar_acquire();
691.1Sriastrad
701.1Sriastrad	/* It's time.  Call the callback.  */
711.1Sriastrad	S->callback(S->cookie);
721.1Sriastrad
731.1Sriastrad	/* Notify everyone else that we're done.  */
741.3Sriastrad	atomic_store_release(&S->done, true);
751.1Sriastrad
761.1Sriastrad	/* Allow activity again.  */
771.1Sriastradout:	splx(s);
781.1Sriastrad}
791.1Sriastrad
801.1Sriastradvoid
811.1Sriastradstop_machine(int (*callback)(void *), void *cookie, const struct kcpuset *cpus)
821.1Sriastrad{
831.1Sriastrad	struct stop_machine stop, *S = &stop;
841.1Sriastrad
851.1Sriastrad	KASSERT(cpus == NULL);	/* not implemented */
861.1Sriastrad
871.1Sriastrad	S->callback = callback;
881.1Sriastrad	S->cookie = cookie;
891.1Sriastrad	S->ncpu = ncpu;		/* XXX cpu hotplug */
901.1Sriastrad	S->done = false;
911.1Sriastrad
921.1Sriastrad	xc_wait(xc_broadcast(0, stop_machine_xcall, &S, NULL));
931.1Sriastrad}
94