Home | History | Annotate | Line # | Download | only in riscv
      1 /*	$NetBSD: ipifuncs.c,v 1.3 2026/07/24 12:18:17 skrll Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Matt Thomas of 3am Software Foundry.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.3 2026/07/24 12:18:17 skrll Exp $");
     34 
     35 #include <sys/param.h>
     36 
     37 #include <sys/cpu.h>
     38 #include <sys/device.h>
     39 #include <sys/intr.h>
     40 #include <sys/ipi.h>
     41 #include <sys/xcall.h>
     42 
     43 #include <uvm/uvm_extern.h>
     44 
     45 static void ipi_halt(void) __dead;
     46 
     47 static const char * const ipi_names[] = {
     48 	[IPI_NOP]	= "ipi nop",
     49 	[IPI_AST]	= "ipi ast",
     50 	[IPI_KPREEMPT]	= "ipi kpreempt",
     51 	[IPI_SUSPEND]	= "ipi suspend",
     52 	[IPI_HALT]	= "ipi halt",
     53 	[IPI_XCALL]	= "ipi xcall",
     54 	[IPI_GENERIC]	= "ipi generic",
     55 };
     56 
     57 static void
     58 ipi_nop(struct cpu_info *ci)
     59 {
     60 	/*
     61 	 * This is just a reason to get an interrupt so we get
     62 	 * kicked out of cpu_idle().
     63 	 */
     64 }
     65 
     66 static void
     67 ipi_ast(struct cpu_info *ci)
     68 {
     69 	ci->ci_onproc->l_md.md_astpending = 1;
     70 }
     71 
     72 #ifdef __HAVE_PREEMPTION
     73 static inline void
     74 ipi_kpreempt(struct cpu_info *ci)
     75 {
     76 	softint_trigger(SOFTINT_KPREEMPT);
     77 }
     78 #endif
     79 
     80 /*
     81  * Process cpu stop-self event.
     82  * XXX could maybe add/use locoresw halt function?
     83  */
     84 static void
     85 ipi_halt(void)
     86 {
     87 	const u_int my_cpu = cpu_index(curcpu());
     88 	printf("cpu%u: shutting down\n", my_cpu);
     89 	kcpuset_set(cpus_halted, my_cpu);
     90 	splhigh();
     91 	for (;;)
     92 		;
     93 	/* NOTREACHED */
     94 }
     95 
     96 void
     97 ipi_process(struct cpu_info *ci, unsigned long ipi_mask)
     98 {
     99 	KASSERT(cpu_intr_p());
    100 
    101 	if (ipi_mask & __BIT(IPI_NOP)) {
    102 		ci->ci_evcnt_per_ipi[IPI_NOP].ev_count++;
    103 		ipi_nop(ci);
    104 	}
    105 	if (ipi_mask & __BIT(IPI_AST)) {
    106 		ci->ci_evcnt_per_ipi[IPI_AST].ev_count++;
    107 		ipi_ast(ci);
    108 	}
    109 	if (ipi_mask & __BIT(IPI_SUSPEND)) {
    110 		ci->ci_evcnt_per_ipi[IPI_SUSPEND].ev_count++;
    111 		cpu_pause();
    112 	}
    113 	if (ipi_mask & __BIT(IPI_HALT)) {
    114 		ci->ci_evcnt_per_ipi[IPI_HALT].ev_count++;
    115 		ipi_halt();
    116 	}
    117 	if (ipi_mask & __BIT(IPI_XCALL)) {
    118 		ci->ci_evcnt_per_ipi[IPI_XCALL].ev_count++;
    119 		xc_ipi_handler();
    120 	}
    121 	if (ipi_mask & __BIT(IPI_GENERIC)) {
    122 		ci->ci_evcnt_per_ipi[IPI_GENERIC].ev_count++;
    123 		ipi_cpu_handler();
    124 	}
    125 #ifdef __HAVE_PREEMPTION
    126 	if (ipi_mask & __BIT(IPI_KPREEMPT)) {
    127 		ci->ci_evcnt_per_ipi[IPI_KPREEMPT].ev_count++;
    128 		ipi_kpreempt(ci);
    129 	}
    130 #endif
    131 }
    132 
    133 void
    134 ipi_init(struct cpu_info *ci)
    135 {
    136 	evcnt_attach_dynamic(&ci->ci_evcnt_all_ipis, EVCNT_TYPE_INTR,
    137 	    NULL, device_xname(ci->ci_dev), "ipi");
    138 
    139 	for (size_t i = 0; i < NIPIS; i++) {
    140 		KASSERTMSG(ipi_names[i] != NULL, "%zu", i);
    141 		evcnt_attach_dynamic(&ci->ci_evcnt_per_ipi[i], EVCNT_TYPE_INTR,
    142 		    NULL, device_xname(ci->ci_dev), ipi_names[i]);
    143 	}
    144 }
    145