xref: /dflybsd-src/sys/dev/acpica/Osd/OsdSchedule.c (revision 5db2f26edd92ab4befeb61802687554b3ee6769a)
1*5db2f26eSSascha Wildner /*-
2*5db2f26eSSascha Wildner  * Copyright (c) 2000 Michael Smith
3*5db2f26eSSascha Wildner  * Copyright (c) 2000 BSDi
4*5db2f26eSSascha Wildner  * All rights reserved.
5*5db2f26eSSascha Wildner  *
6*5db2f26eSSascha Wildner  * Redistribution and use in source and binary forms, with or without
7*5db2f26eSSascha Wildner  * modification, are permitted provided that the following conditions
8*5db2f26eSSascha Wildner  * are met:
9*5db2f26eSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
10*5db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
11*5db2f26eSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
12*5db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
13*5db2f26eSSascha Wildner  *    documentation and/or other materials provided with the distribution.
14*5db2f26eSSascha Wildner  *
15*5db2f26eSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*5db2f26eSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*5db2f26eSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*5db2f26eSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*5db2f26eSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*5db2f26eSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*5db2f26eSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*5db2f26eSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*5db2f26eSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*5db2f26eSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*5db2f26eSSascha Wildner  * SUCH DAMAGE.
26*5db2f26eSSascha Wildner  *
27*5db2f26eSSascha Wildner  * $FreeBSD: src/sys/dev/acpica/Osd/OsdSchedule.c,v 1.28 2004/05/06 02:18:58 njl Exp $
28*5db2f26eSSascha Wildner  */
29*5db2f26eSSascha Wildner 
30*5db2f26eSSascha Wildner /*
31*5db2f26eSSascha Wildner  * 6.3 : Scheduling services
32*5db2f26eSSascha Wildner  */
33*5db2f26eSSascha Wildner 
34*5db2f26eSSascha Wildner #include "opt_acpi.h"
35*5db2f26eSSascha Wildner #include <sys/param.h>
36*5db2f26eSSascha Wildner #include <sys/systm.h>
37*5db2f26eSSascha Wildner #include <sys/bus.h>
38*5db2f26eSSascha Wildner #include <sys/interrupt.h>
39*5db2f26eSSascha Wildner #include <sys/kernel.h>
40*5db2f26eSSascha Wildner #include <sys/kthread.h>
41*5db2f26eSSascha Wildner #include <sys/malloc.h>
42*5db2f26eSSascha Wildner #include <sys/proc.h>
43*5db2f26eSSascha Wildner #include <sys/msgport.h>
44*5db2f26eSSascha Wildner #include <sys/taskqueue.h>
45*5db2f26eSSascha Wildner #include <machine/clock.h>
46*5db2f26eSSascha Wildner 
47*5db2f26eSSascha Wildner #include <sys/thread2.h>
48*5db2f26eSSascha Wildner #include <sys/msgport2.h>
49*5db2f26eSSascha Wildner #include <sys/mplock2.h>
50*5db2f26eSSascha Wildner 
51*5db2f26eSSascha Wildner #include "acpi.h"
52*5db2f26eSSascha Wildner #include "accommon.h"
53*5db2f26eSSascha Wildner #include <dev/acpica/acpivar.h>
54*5db2f26eSSascha Wildner 
55*5db2f26eSSascha Wildner #define _COMPONENT	ACPI_OS_SERVICES
56*5db2f26eSSascha Wildner ACPI_MODULE_NAME("SCHEDULE")
57*5db2f26eSSascha Wildner 
58*5db2f26eSSascha Wildner /*
59*5db2f26eSSascha Wildner  * This is a little complicated due to the fact that we need to build and then
60*5db2f26eSSascha Wildner  * free a 'struct task' for each task we enqueue.
61*5db2f26eSSascha Wildner  */
62*5db2f26eSSascha Wildner 
63*5db2f26eSSascha Wildner MALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task");
64*5db2f26eSSascha Wildner 
65*5db2f26eSSascha Wildner static void	acpi_task_thread(void *arg);
66*5db2f26eSSascha Wildner static void	acpi_autofree_reply(lwkt_port_t port, lwkt_msg_t msg);
67*5db2f26eSSascha Wildner 
68*5db2f26eSSascha Wildner struct acpi_task {
69*5db2f26eSSascha Wildner     struct lwkt_msg		at_msg;
70*5db2f26eSSascha Wildner     ACPI_OSD_EXEC_CALLBACK	at_function;
71*5db2f26eSSascha Wildner     void			*at_context;
72*5db2f26eSSascha Wildner     ACPI_EXECUTE_TYPE		at_type;
73*5db2f26eSSascha Wildner };
74*5db2f26eSSascha Wildner 
75*5db2f26eSSascha Wildner static struct thread *acpi_task_td;
76*5db2f26eSSascha Wildner struct lwkt_port acpi_afree_rport;
77*5db2f26eSSascha Wildner 
78*5db2f26eSSascha Wildner /*
79*5db2f26eSSascha Wildner  * Initialize the ACPI helper thread.
80*5db2f26eSSascha Wildner  */
81*5db2f26eSSascha Wildner int
82*5db2f26eSSascha Wildner acpi_task_thread_init(void)
83*5db2f26eSSascha Wildner {
84*5db2f26eSSascha Wildner     lwkt_initport_replyonly(&acpi_afree_rport, acpi_autofree_reply);
85*5db2f26eSSascha Wildner     kthread_create(acpi_task_thread, NULL, &acpi_task_td, "acpi_task");
86*5db2f26eSSascha Wildner     return (0);
87*5db2f26eSSascha Wildner }
88*5db2f26eSSascha Wildner 
89*5db2f26eSSascha Wildner /*
90*5db2f26eSSascha Wildner  * The ACPI helper thread processes OSD execution callback messages.
91*5db2f26eSSascha Wildner  */
92*5db2f26eSSascha Wildner static void
93*5db2f26eSSascha Wildner acpi_task_thread(void *arg)
94*5db2f26eSSascha Wildner {
95*5db2f26eSSascha Wildner     ACPI_OSD_EXEC_CALLBACK func;
96*5db2f26eSSascha Wildner     struct acpi_task *at;
97*5db2f26eSSascha Wildner 
98*5db2f26eSSascha Wildner     get_mplock();
99*5db2f26eSSascha Wildner     for (;;) {
100*5db2f26eSSascha Wildner 	at = (void *)lwkt_waitport(&curthread->td_msgport, 0);
101*5db2f26eSSascha Wildner 	func = at->at_function;
102*5db2f26eSSascha Wildner 	func(at->at_context);
103*5db2f26eSSascha Wildner 	lwkt_replymsg(&at->at_msg, 0);
104*5db2f26eSSascha Wildner     }
105*5db2f26eSSascha Wildner     rel_mplock();
106*5db2f26eSSascha Wildner }
107*5db2f26eSSascha Wildner 
108*5db2f26eSSascha Wildner /*
109*5db2f26eSSascha Wildner  * Queue an ACPI message for execution by allocating a LWKT message structure
110*5db2f26eSSascha Wildner  * and sending the message to the helper thread.  The reply port is setup
111*5db2f26eSSascha Wildner  * to automatically free the message.
112*5db2f26eSSascha Wildner  */
113*5db2f26eSSascha Wildner ACPI_STATUS
114*5db2f26eSSascha Wildner AcpiOsExecute(ACPI_EXECUTE_TYPE Type, ACPI_OSD_EXEC_CALLBACK Function,
115*5db2f26eSSascha Wildner 	      void *Context)
116*5db2f26eSSascha Wildner {
117*5db2f26eSSascha Wildner     struct acpi_task	*at;
118*5db2f26eSSascha Wildner 
119*5db2f26eSSascha Wildner     switch (Type) {
120*5db2f26eSSascha Wildner     case OSL_GLOBAL_LOCK_HANDLER:
121*5db2f26eSSascha Wildner     case OSL_NOTIFY_HANDLER:
122*5db2f26eSSascha Wildner     case OSL_GPE_HANDLER:
123*5db2f26eSSascha Wildner     case OSL_DEBUGGER_THREAD:
124*5db2f26eSSascha Wildner     case OSL_EC_POLL_HANDLER:
125*5db2f26eSSascha Wildner     case OSL_EC_BURST_HANDLER:
126*5db2f26eSSascha Wildner 	break;
127*5db2f26eSSascha Wildner     default:
128*5db2f26eSSascha Wildner 	return_ACPI_STATUS (AE_BAD_PARAMETER);
129*5db2f26eSSascha Wildner     }
130*5db2f26eSSascha Wildner 
131*5db2f26eSSascha Wildner     /* Note: Interrupt Context */
132*5db2f26eSSascha Wildner     at = kmalloc(sizeof(*at), M_ACPITASK, M_INTWAIT | M_ZERO);
133*5db2f26eSSascha Wildner     lwkt_initmsg(&at->at_msg, &acpi_afree_rport, 0);
134*5db2f26eSSascha Wildner     at->at_function = Function;
135*5db2f26eSSascha Wildner     at->at_context = Context;
136*5db2f26eSSascha Wildner     at->at_type = Type;
137*5db2f26eSSascha Wildner     lwkt_sendmsg(&acpi_task_td->td_msgport, &at->at_msg);
138*5db2f26eSSascha Wildner     return_ACPI_STATUS (AE_OK);
139*5db2f26eSSascha Wildner }
140*5db2f26eSSascha Wildner 
141*5db2f26eSSascha Wildner /*
142*5db2f26eSSascha Wildner  * The message's reply port just frees the message.
143*5db2f26eSSascha Wildner  */
144*5db2f26eSSascha Wildner static void
145*5db2f26eSSascha Wildner acpi_autofree_reply(lwkt_port_t port, lwkt_msg_t msg)
146*5db2f26eSSascha Wildner {
147*5db2f26eSSascha Wildner     kfree(msg, M_ACPITASK);
148*5db2f26eSSascha Wildner }
149*5db2f26eSSascha Wildner 
150*5db2f26eSSascha Wildner UINT64
151*5db2f26eSSascha Wildner AcpiOsGetTimer (void)
152*5db2f26eSSascha Wildner {
153*5db2f26eSSascha Wildner     struct timeval  time;
154*5db2f26eSSascha Wildner 
155*5db2f26eSSascha Wildner     microtime(&time);
156*5db2f26eSSascha Wildner 
157*5db2f26eSSascha Wildner     /* Seconds * 10^7 = 100ns(10^-7), Microseconds(10^-6) * 10^1 = 100ns */
158*5db2f26eSSascha Wildner 
159*5db2f26eSSascha Wildner     return (((UINT64) time.tv_sec * 10000000) + ((UINT64) time.tv_usec * 10));
160*5db2f26eSSascha Wildner }
161*5db2f26eSSascha Wildner 
162*5db2f26eSSascha Wildner void
163*5db2f26eSSascha Wildner AcpiOsSleep(ACPI_INTEGER Milliseconds)
164*5db2f26eSSascha Wildner {
165*5db2f26eSSascha Wildner     int		timo;
166*5db2f26eSSascha Wildner     static int	dummy;
167*5db2f26eSSascha Wildner 
168*5db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
169*5db2f26eSSascha Wildner 
170*5db2f26eSSascha Wildner     timo = Milliseconds * hz / 1000;
171*5db2f26eSSascha Wildner 
172*5db2f26eSSascha Wildner     /*
173*5db2f26eSSascha Wildner      * If requested sleep time is less than our hz resolution, or if
174*5db2f26eSSascha Wildner      * the system is in early boot before the system tick is operational,
175*5db2f26eSSascha Wildner      * use DELAY instead for better granularity.
176*5db2f26eSSascha Wildner      */
177*5db2f26eSSascha Wildner     if (clocks_running == 0) {
178*5db2f26eSSascha Wildner 	while (timo > 1000000) {
179*5db2f26eSSascha Wildner 	    DELAY(1000000);
180*5db2f26eSSascha Wildner 	    timo -= 1000000;
181*5db2f26eSSascha Wildner 	}
182*5db2f26eSSascha Wildner 	if (timo)
183*5db2f26eSSascha Wildner 	    DELAY(timo * 1000);
184*5db2f26eSSascha Wildner     } else if (timo > 0) {
185*5db2f26eSSascha Wildner 	tsleep(&dummy, 0, "acpislp", timo);
186*5db2f26eSSascha Wildner     } else {
187*5db2f26eSSascha Wildner 	DELAY(Milliseconds * 1000);
188*5db2f26eSSascha Wildner     }
189*5db2f26eSSascha Wildner     return_VOID;
190*5db2f26eSSascha Wildner }
191*5db2f26eSSascha Wildner 
192*5db2f26eSSascha Wildner void
193*5db2f26eSSascha Wildner AcpiOsStall(UINT32 Microseconds)
194*5db2f26eSSascha Wildner {
195*5db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
196*5db2f26eSSascha Wildner 
197*5db2f26eSSascha Wildner     DELAY(Microseconds);
198*5db2f26eSSascha Wildner     return_VOID;
199*5db2f26eSSascha Wildner }
200*5db2f26eSSascha Wildner 
201*5db2f26eSSascha Wildner ACPI_THREAD_ID
202*5db2f26eSSascha Wildner AcpiOsGetThreadId(void)
203*5db2f26eSSascha Wildner {
204*5db2f26eSSascha Wildner     struct proc *p;
205*5db2f26eSSascha Wildner 
206*5db2f26eSSascha Wildner     /* XXX do not add ACPI_FUNCTION_TRACE here, results in recursive call. */
207*5db2f26eSSascha Wildner 
208*5db2f26eSSascha Wildner     p = curproc;
209*5db2f26eSSascha Wildner     if (p == NULL)
210*5db2f26eSSascha Wildner 	p = &proc0;
211*5db2f26eSSascha Wildner     KASSERT(p != NULL, ("%s: curproc is NULL!", __func__));
212*5db2f26eSSascha Wildner 
213*5db2f26eSSascha Wildner     /* Returning 0 is not allowed. */
214*5db2f26eSSascha Wildner     return (p->p_pid + 1);
215*5db2f26eSSascha Wildner }
216