xref: /titanic_50/usr/src/uts/common/os/softint.c (revision 0a1278f26ea4b7c8c0285d4f2d6c5b680904aa01)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/t_lock.h>
29 #include <sys/systm.h>
30 #include <sys/spl.h>
31 #include <sys/cmn_err.h>
32 #include <sys/debug.h>
33 #include <sys/kdi_impl.h>
34 #include <sys/cpuvar.h>
35 #include <sys/cpuvar.h>
36 #include <sys/archsystm.h>
37 
38 /*
39  * Handle software interrupts through 'softcall' mechanism
40  *
41  * At present softcall mechanism uses a global list headed by softhead.
42  * Entries are added to tail and removed from head so as to preserve FIFO
43  * nature of entries in the softcall list. softcall() takes care of adding
44  * entries to the softtail.
45  *
46  * softint must take care of executing the entries in the FIFO
47  * order. It could be called simultaneously from multiple cpus, however only
48  * one instance of softint should process the softcall list with the exception
49  * when CPU is stuck due to high interrupt load and can't execute callbacks.
50  * State diagram is as follows :-
51  *
52  *	- Upper half which is same as old state machine
53  *	  (IDLE->PEND->DRAIN->IDLE)
54  *
55  *	- Lower half which steals the entries from softcall queue and execute
56  *        in the context of softint interrupt handler. The interrupt handler
57  *        is fired on a different CPU by sending a cross-call.
58  *
59  * Starting state is IDLE.
60  *
61  * 				softint()
62  *
63  *
64  *				(c)
65  * 	____________________________________________________
66  * 	|                          ^                         ^
67  * 	v            (a)           |           (b)           |
68  * 	IDLE--------------------->PEND--------------------->DRAIN
69  *	^                         |                         |
70  * 	|                         |                         |
71  * 	|                         |                         |
72  * 	|                         |                         |
73  * 	|                         |                         |
74  * 	|                         d                         d
75  * 	|                         |                         |
76  * 	|                         v                         v
77  * 	|                         PEND                      DRAIN
78  * 	|            (e)           &                          &
79  * 	|<-----------------------STEAL                      STEAL
80  * 	^                                                    |
81  * 	|                                                    |
82  * 	|                         (e)                        v
83  * 	|_________________________<__________________________|
84  *
85  *
86  *
87  * Edge (a)->(b)->(c) are same as old state machine and these
88  * are mutually exclusive state.
89  *
90  * a - When an entry is being enqueued to softcall queue then the state
91  *     moves from IDLE to PEND.
92  *
93  * b - When interrupt handler has started processing softcall queue.
94  *
95  * c - When interrupt handler finished processing softcall queue, the
96  *     state of machines goes back to IDLE.
97  *
98  * d - softcall() generates another softlevel1 iff interrupt handler
99  *     hasn't run recently.
100  *
101  * e - Either PEND|STEAL or DRAIN|STEAL is set. We let softlevel1
102  *     handler exit because we have processed all the entries.
103  *
104  * When CPU is being pinned by higher level interrupts for more than
105  * softcall_delay clock ticks, SOFT_STEAL is OR'ed so that softlevel1
106  * handler on the other CPU can drain the queue.
107  *
108  * These states are needed for softcall mechanism since Solaris has only
109  * one interface (ie. siron ) as of now for :
110  *
111  * - raising a soft interrupt architecture independently (ie not through
112  *   setsoftint(..) )
113  * - to process the softcall queue.
114  */
115 
116 #define	NSOFTCALLS	200
117 
118 /*
119  * Defined states for softcall processing.
120  */
121 #define	SOFT_IDLE		0x01	/* no processing is needed */
122 #define	SOFT_PEND		0x02	/* softcall list needs processing */
123 #define	SOFT_DRAIN		0x04	/* list is being processed */
124 #define	SOFT_STEAL		0x08	/* list is being stolen for draining */
125 
126 typedef struct softcall {
127 	void (*sc_func)(void *);	/* function to call */
128 	void *sc_arg;			/* arg to pass to func */
129 	struct softcall *sc_next;	/* next in list */
130 } softcall_t;
131 
132 /*
133  * softcall list and state variables.
134  */
135 static softcall_t *softcalls;
136 static softcall_t *softhead, *softtail, *softfree;
137 static uint_t	softcall_state;
138 static clock_t softcall_tick;
139 static clock_t softcall_countstart, softcall_lastpoke;
140 static uint_t softcall_pokecount;
141 
142 /*
143  * Max number of pokes per second before increasing softcall_delay
144  */
145 uint_t softcall_pokemax = 10;
146 
147 /*
148  * This ensures that softcall entries don't get stuck for long. It's expressed
149  * in 10 milliseconds as 1 unit. When hires_tick is set or other clock frequency
150  * is used, softcall_init() ensures that it's still expressed as 1 =  10 milli
151  * seconds.
152  */
153 unsigned int softcall_delay = 1;
154 
155 /*
156  * The last CPU which will drain softcall queue.
157  */
158 static int softcall_latest_cpuid = -1;
159 
160 /*
161  * CPUSET to hold the CPU which is processing softcall queue
162  * currently. There can be more than one CPU having bit set
163  * but it will happen only when they are stuck.
164  */
165 static cpuset_t *softcall_cpuset = NULL;
166 
167 /*
168  * protects softcall lists and control variable softcall_state.
169  */
170 static kmutex_t	softcall_lock;
171 
172 static void (*kdi_softcall_func)(void);
173 extern void siron_poke_cpu(cpuset_t);
174 
175 extern void siron(void);
176 extern void kdi_siron(void);
177 
178 
179 void
180 softcall_init(void)
181 {
182 	softcall_t *sc;
183 
184 	softcalls = kmem_zalloc(sizeof (softcall_t) * NSOFTCALLS, KM_SLEEP);
185 	softcall_cpuset = kmem_zalloc(sizeof (cpuset_t), KM_SLEEP);
186 	for (sc = softcalls; sc < &softcalls[NSOFTCALLS]; sc++) {
187 		sc->sc_next = softfree;
188 		softfree = sc;
189 	}
190 	mutex_init(&softcall_lock, NULL, MUTEX_SPIN,
191 	    (void *)ipltospl(SPL8));
192 	softcall_state = SOFT_IDLE;
193 	softcall_tick = ddi_get_lbolt();
194 
195 	/*
196 	 * Since softcall_delay is expressed as 1 = 10 milliseconds.
197 	 */
198 	softcall_delay = softcall_delay * (hz/100);
199 	CPUSET_ZERO(*softcall_cpuset);
200 }
201 
202 /*
203  * Gets called when softcall queue is not moving forward. We choose
204  * a CPU and poke except the ones which are already poked.
205  */
206 static int
207 softcall_choose_cpu()
208 {
209 	cpu_t *cplist = CPU;
210 	cpu_t *cp;
211 	int intr_load = INT_MAX;
212 	int cpuid = -1;
213 	cpuset_t poke;
214 	int s;
215 
216 	ASSERT(getpil() >= DISP_LEVEL);
217 	ASSERT(ncpus > 1);
218 	ASSERT(MUTEX_HELD(&softcall_lock));
219 
220 	CPUSET_ZERO(poke);
221 
222 	/*
223 	 * The hint is to start from current CPU.
224 	 */
225 	cp = cplist;
226 	do {
227 		/*
228 		 * Don't select this CPU if :
229 		 *   - in cpuset already
230 		 *   - CPU is not accepting interrupts
231 		 *   - CPU is being offlined
232 		 */
233 		if (CPU_IN_SET(*softcall_cpuset, cp->cpu_id) ||
234 		    (cp->cpu_flags & CPU_ENABLE) == 0 ||
235 		    (cp == cpu_inmotion))
236 			continue;
237 #if defined(__x86)
238 		/*
239 		 * Don't select this CPU if a hypervisor indicates it
240 		 * isn't currently scheduled onto a physical cpu.  We are
241 		 * looking for a cpu that can respond quickly and the time
242 		 * to get the virtual cpu scheduled and switched to running
243 		 * state is likely to be relatively lengthy.
244 		 */
245 		if (vcpu_on_pcpu(cp->cpu_id) == VCPU_NOT_ON_PCPU)
246 			continue;
247 #endif	/* __x86 */
248 
249 		/* if CPU is not busy */
250 		if (cp->cpu_intrload == 0) {
251 			cpuid = cp->cpu_id;
252 			break;
253 		}
254 
255 		if (cp->cpu_intrload < intr_load) {
256 			cpuid = cp->cpu_id;
257 			intr_load = cp->cpu_intrload;
258 		} else if (cp->cpu_intrload == intr_load) {
259 			/*
260 			 * We want to poke CPUs having similar
261 			 * load because we don't know which CPU is
262 			 * can acknowledge level1 interrupt. The
263 			 * list of such CPUs should not be large.
264 			 */
265 			if (cpuid != -1) {
266 				/*
267 				 * Put the last CPU chosen because
268 				 * it also has same interrupt load.
269 				 */
270 				CPUSET_ADD(poke, cpuid);
271 				cpuid = -1;
272 			}
273 
274 			CPUSET_ADD(poke, cp->cpu_id);
275 		}
276 	} while ((cp = cp->cpu_next_onln) != cplist);
277 
278 	/* if we found a CPU which suits best to poke */
279 	if (cpuid != -1) {
280 		CPUSET_ZERO(poke);
281 		CPUSET_ADD(poke, cpuid);
282 	}
283 
284 	if (CPUSET_ISNULL(poke)) {
285 		mutex_exit(&softcall_lock);
286 		return (0);
287 	}
288 
289 	/*
290 	 * We first set the bit in cpuset and then poke.
291 	 */
292 	CPUSET_XOR(*softcall_cpuset, poke);
293 	mutex_exit(&softcall_lock);
294 
295 	/*
296 	 * If softcall() was called at low pil then we may
297 	 * get preempted before we raise PIL. It should be okay
298 	 * because we are just going to poke CPUs now or at most
299 	 * another thread may start choosing CPUs in this routine.
300 	 */
301 	s = splhigh();
302 	siron_poke_cpu(poke);
303 	splx(s);
304 	return (1);
305 }
306 
307 
308 /*
309  * Call function func with argument arg
310  * at some later time at software interrupt priority
311  */
312 void
313 softcall(void (*func)(void *), void *arg)
314 {
315 	softcall_t *sc;
316 	clock_t w, now;
317 
318 	/*
319 	 * protect against cross-calls
320 	 */
321 	mutex_enter(&softcall_lock);
322 	/* coalesce identical softcalls */
323 	for (sc = softhead; sc != 0; sc = sc->sc_next) {
324 		if (sc->sc_func == func && sc->sc_arg == arg) {
325 			goto intr;
326 		}
327 	}
328 
329 	if ((sc = softfree) == 0)
330 		panic("too many softcalls");
331 
332 	softfree = sc->sc_next;
333 	sc->sc_func = func;
334 	sc->sc_arg = arg;
335 	sc->sc_next = 0;
336 
337 	if (softhead) {
338 		softtail->sc_next = sc;
339 		softtail = sc;
340 	} else
341 		softhead = softtail = sc;
342 
343 intr:
344 	if (softcall_state & SOFT_IDLE) {
345 		softcall_state = SOFT_PEND;
346 		softcall_tick = ddi_get_lbolt();
347 		mutex_exit(&softcall_lock);
348 		siron();
349 	} else if (softcall_state & (SOFT_DRAIN|SOFT_PEND)) {
350 		now = ddi_get_lbolt();
351 		w = now - softcall_tick;
352 		if (w <= softcall_delay || ncpus == 1) {
353 			mutex_exit(&softcall_lock);
354 			return;
355 		}
356 		/*
357 		 * Did we poke less than a second ago?
358 		 */
359 		if (now - softcall_lastpoke < hz) {
360 			/*
361 			 * We did, increment the poke count and
362 			 * see if we are poking too often
363 			 */
364 			if (softcall_pokecount++ == 0)
365 				softcall_countstart = now;
366 			if (softcall_pokecount > softcall_pokemax) {
367 				/*
368 				 * If poking too much increase the delay
369 				 */
370 				if (now - softcall_countstart <= hz)
371 					softcall_delay++;
372 				softcall_pokecount = 0;
373 			}
374 		} else {
375 			/*
376 			 * poke rate has dropped off, reset the poke monitor
377 			 */
378 			softcall_pokecount = 0;
379 		}
380 		softcall_lastpoke = now;
381 		if (!(softcall_state & SOFT_STEAL)) {
382 			softcall_state |= SOFT_STEAL;
383 
384 			/*
385 			 * We want to give some more chance before
386 			 * fishing around again.
387 			 */
388 			softcall_tick = now;
389 		}
390 
391 		/* softcall_lock will be released by this routine */
392 		(void) softcall_choose_cpu();
393 	}
394 }
395 
396 void
397 kdi_softcall(void (*func)(void))
398 {
399 	kdi_softcall_func = func;
400 
401 	if (softhead == NULL)
402 		kdi_siron();
403 }
404 
405 /*
406  * Called to process software interrupts take one off queue, call it,
407  * repeat.
408  *
409  * Note queue may change during call; softcall_lock, state variables
410  * softcall_state and softcall_latest_cpuid ensures that -
411  * - we don't have multiple cpus pulling from the list (thus causing
412  *   a violation of FIFO order with an exception when we are stuck).
413  * - we don't miss a new entry having been added to the head.
414  * - we don't miss a wakeup.
415  */
416 
417 void
418 softint(void)
419 {
420 	softcall_t *sc = NULL;
421 	void (*func)();
422 	caddr_t arg;
423 	int cpu_id = CPU->cpu_id;
424 
425 	/*
426 	 * Don't process softcall queue if current CPU is quiesced or
427 	 * offlined. This can happen when a CPU is running pause
428 	 * thread but softcall already sent a xcall.
429 	 */
430 	if (CPU->cpu_flags & (CPU_QUIESCED|CPU_OFFLINE)) {
431 		if (softcall_cpuset != NULL &&
432 		    CPU_IN_SET(*softcall_cpuset, cpu_id)) {
433 			CPUSET_DEL(*softcall_cpuset, cpu_id);
434 			goto out;
435 		}
436 	}
437 
438 	mutex_enter(&softcall_lock);
439 
440 	if (softcall_state & (SOFT_STEAL|SOFT_PEND)) {
441 		softcall_state = SOFT_DRAIN;
442 	} else  {
443 		/*
444 		 * The check for softcall_cpuset being
445 		 * NULL is required because it may get
446 		 * called very early during boot.
447 		 */
448 		if (softcall_cpuset != NULL &&
449 		    CPU_IN_SET(*softcall_cpuset, cpu_id))
450 			CPUSET_DEL(*softcall_cpuset, cpu_id);
451 		mutex_exit(&softcall_lock);
452 		goto out;
453 	}
454 
455 	/*
456 	 * Setting softcall_latest_cpuid to current CPU ensures
457 	 * that there is only one active softlevel1 handler to
458 	 * process softcall queues.
459 	 *
460 	 * Since softcall_lock lock is dropped before calling
461 	 * func (callback), we need softcall_latest_cpuid
462 	 * to prevent two softlevel1 hanlders working on the
463 	 * queue when the first softlevel1 handler gets
464 	 * stuck due to high interrupt load.
465 	 */
466 	softcall_latest_cpuid = cpu_id;
467 
468 	/* add ourself to the cpuset */
469 	if (!CPU_IN_SET(*softcall_cpuset, cpu_id))
470 		CPUSET_ADD(*softcall_cpuset, cpu_id);
471 
472 	for (;;) {
473 		softcall_tick = ddi_get_lbolt();
474 		if ((sc = softhead) != NULL) {
475 			func = sc->sc_func;
476 			arg = sc->sc_arg;
477 			softhead = sc->sc_next;
478 			sc->sc_next = softfree;
479 			softfree = sc;
480 		}
481 
482 		if (sc == NULL) {
483 			if (CPU_IN_SET(*softcall_cpuset, cpu_id))
484 				CPUSET_DEL(*softcall_cpuset, cpu_id);
485 
486 			softcall_state = SOFT_IDLE;
487 			ASSERT(softcall_latest_cpuid == cpu_id);
488 			softcall_latest_cpuid = -1;
489 
490 			mutex_exit(&softcall_lock);
491 			break;
492 		}
493 
494 		mutex_exit(&softcall_lock);
495 		func(arg);
496 		mutex_enter(&softcall_lock);
497 
498 		/*
499 		 * No longer need softcall processing from current
500 		 * interrupt handler because either
501 		 *  (a) softcall is in SOFT_IDLE state or
502 		 *  (b) There is a CPU already draining softcall
503 		 *	queue and the current softlevel1 is no
504 		 *	longer required.
505 		 */
506 		if (softcall_latest_cpuid != cpu_id) {
507 			if (CPU_IN_SET(*softcall_cpuset, cpu_id))
508 				CPUSET_DEL(*softcall_cpuset, cpu_id);
509 
510 			mutex_exit(&softcall_lock);
511 			break;
512 		}
513 	}
514 
515 out:
516 	if ((func = kdi_softcall_func) != NULL) {
517 		kdi_softcall_func = NULL;
518 		func();
519 	}
520 }
521