xref: /freebsd/sys/dev/acpica/Osd/OsdSchedule.c (revision a3e8fd0b7f663db7eafff527d5c3ca3bcfa8a537)
1 /*-
2  * Copyright (c) 2000 Michael Smith
3  * Copyright (c) 2000 BSDi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *	$FreeBSD$
28  */
29 
30 /*
31  * 6.3 : Scheduling services
32  */
33 
34 #include "acpi.h"
35 
36 #include "opt_acpi.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/bus.h>
40 #include <sys/interrupt.h>
41 #include <sys/kernel.h>
42 #include <sys/kthread.h>
43 #include <sys/malloc.h>
44 #include <sys/proc.h>
45 #include <sys/taskqueue.h>
46 #include <machine/clock.h>
47 
48 #include <sys/bus.h>
49 
50 #include <dev/acpica/acpivar.h>
51 
52 #define _COMPONENT	ACPI_OS_SERVICES
53 ACPI_MODULE_NAME("SCHEDULE")
54 
55 /*
56  * This is a little complicated due to the fact that we need to build and then
57  * free a 'struct task' for each task we enqueue.
58  */
59 
60 MALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task");
61 
62 static void	AcpiOsExecuteQueue(void *arg, int pending);
63 
64 struct acpi_task {
65     struct task			at_task;
66     OSD_EXECUTION_CALLBACK	at_function;
67     void			*at_context;
68 };
69 
70 struct acpi_task_queue {
71     STAILQ_ENTRY(acpi_task_queue) at_q;
72     struct acpi_task		*at;
73 };
74 
75 #if __FreeBSD_version >= 500000
76 /*
77  * Private task queue definition for ACPI
78  */
79 TASKQUEUE_DECLARE(acpi);
80 static void	*taskqueue_acpi_ih;
81 
82 static void
83 taskqueue_acpi_enqueue(void *context)
84 {
85     swi_sched(taskqueue_acpi_ih, 0);
86 }
87 
88 static void
89 taskqueue_acpi_run(void *dummy)
90 {
91     taskqueue_run(taskqueue_acpi);
92 }
93 
94 TASKQUEUE_DEFINE(acpi, taskqueue_acpi_enqueue, 0,
95 		 swi_add(NULL, "acpitaskq", taskqueue_acpi_run, NULL,
96 		     SWI_TQ, 0, &taskqueue_acpi_ih));
97 
98 #if defined(ACPI_MAX_THREADS) && ACPI_MAX_THREADS > 0
99 #define ACPI_USE_THREADS
100 #endif
101 
102 #ifdef ACPI_USE_THREADS
103 STAILQ_HEAD(, acpi_task_queue) acpi_task_queue;
104 static struct mtx	acpi_task_mtx;
105 
106 static void
107 acpi_task_thread(void *arg)
108 {
109     struct acpi_task_queue	*atq;
110     OSD_EXECUTION_CALLBACK	Function;
111     void			*Context;
112 
113     for (;;) {
114 	mtx_lock(&acpi_task_mtx);
115 	if ((atq = STAILQ_FIRST(&acpi_task_queue)) == NULL) {
116 	    msleep(&acpi_task_queue, &acpi_task_mtx, PCATCH, "actask", 0);
117 	    mtx_unlock(&acpi_task_mtx);
118 	    continue;
119 	}
120 
121 	STAILQ_REMOVE_HEAD(&acpi_task_queue, at_q);
122 	mtx_unlock(&acpi_task_mtx);
123 
124 	Function = (OSD_EXECUTION_CALLBACK)atq->at->at_function;
125 	Context = atq->at->at_context;
126 
127 	mtx_lock(&Giant);
128 	Function(Context);
129 
130 	free(atq->at, M_ACPITASK);
131 	free(atq, M_ACPITASK);
132 	mtx_unlock(&Giant);
133     }
134 
135     kthread_exit(0);
136 }
137 
138 int
139 acpi_task_thread_init(void)
140 {
141     int		i, err;
142     struct proc	*acpi_kthread_proc;
143 
144     err = 0;
145     STAILQ_INIT(&acpi_task_queue);
146     mtx_init(&acpi_task_mtx, "ACPI task", NULL, MTX_DEF);
147 
148     for (i = 0; i < ACPI_MAX_THREADS; i++) {
149 	err = kthread_create(acpi_task_thread, NULL, &acpi_kthread_proc,
150 			     0, 0, "acpi_task%d", i);
151 	if (err != 0) {
152 	    printf("%s: kthread_create failed(%d)\n", __func__, err);
153 	    break;
154 	}
155     }
156     return (err);
157 }
158 #endif
159 #endif
160 
161 ACPI_STATUS
162 AcpiOsQueueForExecution(UINT32 Priority, OSD_EXECUTION_CALLBACK Function, void *Context)
163 {
164     struct acpi_task	*at;
165     int pri;
166 
167     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
168 
169     if (Function == NULL)
170 	return_ACPI_STATUS(AE_BAD_PARAMETER);
171 
172     at = malloc(sizeof(*at), M_ACPITASK, M_NOWAIT);	/* Interrupt Context */
173     if (at == NULL)
174 	return_ACPI_STATUS(AE_NO_MEMORY);
175     bzero(at, sizeof(*at));
176 
177     at->at_function = Function;
178     at->at_context = Context;
179     switch (Priority) {
180     case OSD_PRIORITY_GPE:
181 	pri = 4;
182 	break;
183     case OSD_PRIORITY_HIGH:
184 	pri = 3;
185 	break;
186     case OSD_PRIORITY_MED:
187 	pri = 2;
188 	break;
189     case OSD_PRIORITY_LO:
190 	pri = 1;
191 	break;
192     default:
193 	free(at, M_ACPITASK);
194 	return_ACPI_STATUS(AE_BAD_PARAMETER);
195     }
196     TASK_INIT(&at->at_task, pri, AcpiOsExecuteQueue, at);
197 
198 #if __FreeBSD_version < 500000
199     taskqueue_enqueue(taskqueue_swi, (struct task *)at);
200 #else
201     taskqueue_enqueue(taskqueue_acpi, (struct task *)at);
202 #endif
203     return_ACPI_STATUS(AE_OK);
204 }
205 
206 static void
207 AcpiOsExecuteQueue(void *arg, int pending)
208 {
209     struct acpi_task		*at;
210     struct acpi_task_queue	*atq;
211     OSD_EXECUTION_CALLBACK	Function;
212     void			*Context;
213 
214     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
215 
216     at = (struct acpi_task *)arg;
217     atq = NULL;
218     Function = NULL;
219     Context = NULL;
220 
221 #ifdef ACPI_USE_THREADS
222     atq = malloc(sizeof(*atq), M_ACPITASK, M_NOWAIT);
223     if (atq == NULL) {
224 	printf("%s: no memory\n", __func__);
225 	return;
226     }
227 
228     atq->at = at;
229 
230     mtx_lock(&acpi_task_mtx);
231     STAILQ_INSERT_TAIL(&acpi_task_queue, atq, at_q);
232     mtx_unlock(&acpi_task_mtx);
233     wakeup_one(&acpi_task_queue);
234 #else
235     Function = (OSD_EXECUTION_CALLBACK)at->at_function;
236     Context = at->at_context;
237 
238     Function(Context);
239     free(at, M_ACPITASK);
240 #endif
241 
242     return_VOID;
243 }
244 
245 /*
246  * We don't have any sleep granularity better than hz, so
247  * make do with that.
248  */
249 void
250 AcpiOsSleep (UINT32 Seconds, UINT32 Milliseconds)
251 {
252     int		timo;
253     static int	dummy;
254 
255     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
256 
257     timo = (Seconds * hz) + Milliseconds * hz / 1000;
258     if (timo == 0)
259 	timo = 1;
260     tsleep(&dummy, 0, "acpislp", timo);
261     return_VOID;
262 }
263 
264 void
265 AcpiOsStall (UINT32 Microseconds)
266 {
267     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
268 
269     DELAY(Microseconds);
270     return_VOID;
271 }
272 
273 UINT32
274 AcpiOsGetThreadId (void)
275 {
276     struct proc *p;
277     /* XXX do not add FUNCTION_TRACE here, results in recursive call */
278 
279     p = curproc;
280 #if __FreeBSD_version < 500000
281     if (p == NULL)
282 	p = &proc0;
283 #endif
284     KASSERT(p != NULL, ("%s: curproc is NULL!", __func__));
285     return(p->p_pid + 1);	/* can't return 0 */
286 }
287