1 /* $NetBSD: mips_softint.c,v 1.8 2020/01/08 17:38:42 ad Exp $ */
2
3 /*-
4 * Copyright (c) 2009, 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 <matt@3am-software.com>.
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: mips_softint.c,v 1.8 2020/01/08 17:38:42 ad Exp $");
34
35 #include <sys/param.h>
36 #include <sys/cpu.h>
37 #include <sys/intr.h>
38 #include <sys/lwp.h>
39 #include <sys/atomic.h>
40
41 #include <uvm/uvm_extern.h>
42
43 #include <mips/locore.h>
44
45 #ifdef __HAVE_FAST_SOFTINTS
46
47 #define SOFTINT_BIO_MASK (1 << SOFTINT_BIO)
48 #define SOFTINT_CLOCK_MASK (1 << SOFTINT_CLOCK)
49 #define SOFTINT_NET_MASK (1 << SOFTINT_NET)
50 #define SOFTINT_SERIAL_MASK (1 << SOFTINT_SERIAL)
51
52 /*
53 * This is more complex than usual since we want the fast softint threads
54 * to have stacks that are direct-mapped and avoid the TLB. This means we
55 * can avoid changing the TLB entry that maps the current lwp's kernel stack.
56 *
57 * This is a very big win so it's worth going through this effort.
58 */
59 void
softint_init_md(lwp_t * l,u_int si_level,uintptr_t * machdep)60 softint_init_md(lwp_t *l, u_int si_level, uintptr_t *machdep)
61 {
62 struct cpu_info * const ci = l->l_cpu;
63
64 *machdep = si_level;
65 ci->ci_softlwps[si_level] = l;
66 }
67
68 void
softint_trigger(uintptr_t si)69 softint_trigger(uintptr_t si)
70 {
71 /*
72 * Set the appropriate cause bit. serial & net are 1 bit higher than
73 * clock & bio. This avoid a branch and is fast.
74 */
75 const uint32_t int_mask = MIPS_SOFT_INT_MASK_0
76 << (((SOFTINT_NET_MASK | SOFTINT_SERIAL_MASK) >> si) & 1);
77
78 /*
79 * Use atomic_or since it's faster than splhigh/splx
80 */
81 atomic_or_uint(&curcpu()->ci_softints, 1 << si);
82
83 /*
84 * Now update cause.
85 */
86 _setsoftintr(int_mask);
87 }
88
89 #define SOFTINT_MASK_1 (SOFTINT_SERIAL_MASK | SOFTINT_NET_MASK)
90 #define SOFTINT_MASK_0 (SOFTINT_CLOCK_MASK | SOFTINT_BIO_MASK)
91
92 /*
93 * Helper macro.
94 *
95 * Dispatch a softint and then restart the loop so that higher
96 * priority softints are always done first.
97 */
98 #define DOSOFTINT(level) \
99 if (softints & SOFTINT_##level## _MASK) { \
100 ci->ci_softints ^= SOFTINT_##level##_MASK; \
101 softint_fast_dispatch(ci->ci_softlwps[SOFTINT_##level], \
102 IPL_SOFT##level); \
103 KASSERTMSG(ci->ci_cpl == IPL_HIGH, "cpl (%d) != HIGH", ci->ci_cpl); \
104 continue; \
105 }
106
107 void
softint_process(uint32_t ipending)108 softint_process(uint32_t ipending)
109 {
110 struct cpu_info * const ci = curcpu();
111 u_int mask;
112
113 KASSERT((ipending & MIPS_SOFT_INT_MASK) != 0);
114 KASSERT((ipending & ~MIPS_SOFT_INT_MASK) == 0);
115 KASSERT(ci->ci_cpl == IPL_HIGH);
116 KDASSERT(mips_cp0_status_read() & MIPS_SR_INT_IE);
117 KASSERTMSG(ci->ci_mtx_count == 0,
118 "%s: cpu%u (%p): ci_mtx_count (%d) != 0",
119 __func__, cpu_index(ci), ci, ci->ci_mtx_count);
120
121 if (ipending & MIPS_SOFT_INT_MASK_0) {
122 /*
123 * Since we run at splhigh,
124 */
125 mask = SOFTINT_MASK_1 | SOFTINT_MASK_0;
126 ipending |= MIPS_SOFT_INT_MASK_1;
127 } else {
128 KASSERT(ipending & MIPS_SOFT_INT_MASK_1);
129 mask = SOFTINT_MASK_1;
130 }
131
132 for (;;) {
133 u_int softints = ci->ci_softints & mask;
134 if (softints == 0)
135 break;
136
137 DOSOFTINT(SERIAL);
138 DOSOFTINT(NET);
139 DOSOFTINT(BIO);
140 DOSOFTINT(CLOCK);
141 }
142
143 KASSERT(ci->ci_mtx_count == 0);
144
145 _clrsoftintr(ipending);
146 }
147
148 #endif /* __HAVE_FAST_SOFTINTS */
149