xref: /dflybsd-src/sys/dev/acpica/Osd/OsdSchedule.c (revision 417dc5a4ca57ab931d8a048e758e6771e6ffb7e5)
15db2f26eSSascha Wildner /*-
25db2f26eSSascha Wildner  * Copyright (c) 2000 Michael Smith
35db2f26eSSascha Wildner  * Copyright (c) 2000 BSDi
45db2f26eSSascha Wildner  * All rights reserved.
55db2f26eSSascha Wildner  *
65db2f26eSSascha Wildner  * Redistribution and use in source and binary forms, with or without
75db2f26eSSascha Wildner  * modification, are permitted provided that the following conditions
85db2f26eSSascha Wildner  * are met:
95db2f26eSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
105db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
115db2f26eSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
125db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
135db2f26eSSascha Wildner  *    documentation and/or other materials provided with the distribution.
145db2f26eSSascha Wildner  *
155db2f26eSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165db2f26eSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175db2f26eSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185db2f26eSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195db2f26eSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205db2f26eSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215db2f26eSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225db2f26eSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235db2f26eSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245db2f26eSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255db2f26eSSascha Wildner  * SUCH DAMAGE.
265db2f26eSSascha Wildner  *
275db2f26eSSascha Wildner  * $FreeBSD: src/sys/dev/acpica/Osd/OsdSchedule.c,v 1.28 2004/05/06 02:18:58 njl Exp $
285db2f26eSSascha Wildner  */
295db2f26eSSascha Wildner 
305db2f26eSSascha Wildner /*
315db2f26eSSascha Wildner  * 6.3 : Scheduling services
325db2f26eSSascha Wildner  */
335db2f26eSSascha Wildner 
345db2f26eSSascha Wildner #include "opt_acpi.h"
355db2f26eSSascha Wildner #include <sys/param.h>
365db2f26eSSascha Wildner #include <sys/systm.h>
375db2f26eSSascha Wildner #include <sys/bus.h>
385db2f26eSSascha Wildner #include <sys/interrupt.h>
395db2f26eSSascha Wildner #include <sys/kernel.h>
405db2f26eSSascha Wildner #include <sys/kthread.h>
415db2f26eSSascha Wildner #include <sys/malloc.h>
425db2f26eSSascha Wildner #include <sys/proc.h>
435db2f26eSSascha Wildner #include <sys/msgport.h>
445db2f26eSSascha Wildner #include <sys/taskqueue.h>
455db2f26eSSascha Wildner #include <machine/clock.h>
465db2f26eSSascha Wildner 
475db2f26eSSascha Wildner #include <sys/thread2.h>
485db2f26eSSascha Wildner #include <sys/msgport2.h>
495db2f26eSSascha Wildner #include <sys/mplock2.h>
505db2f26eSSascha Wildner 
515db2f26eSSascha Wildner #include "acpi.h"
525db2f26eSSascha Wildner #include "accommon.h"
535db2f26eSSascha Wildner #include <dev/acpica/acpivar.h>
545db2f26eSSascha Wildner 
555db2f26eSSascha Wildner #define _COMPONENT	ACPI_OS_SERVICES
565db2f26eSSascha Wildner ACPI_MODULE_NAME("SCHEDULE")
575db2f26eSSascha Wildner 
585db2f26eSSascha Wildner /*
595db2f26eSSascha Wildner  * This is a little complicated due to the fact that we need to build and then
605db2f26eSSascha Wildner  * free a 'struct task' for each task we enqueue.
615db2f26eSSascha Wildner  */
625db2f26eSSascha Wildner 
635db2f26eSSascha Wildner MALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task");
645db2f26eSSascha Wildner 
655db2f26eSSascha Wildner static void	acpi_task_thread(void *arg);
665db2f26eSSascha Wildner static void	acpi_autofree_reply(lwkt_port_t port, lwkt_msg_t msg);
675db2f26eSSascha Wildner 
685db2f26eSSascha Wildner struct acpi_task {
695db2f26eSSascha Wildner     struct lwkt_msg		at_msg;
705db2f26eSSascha Wildner     ACPI_OSD_EXEC_CALLBACK	at_function;
715db2f26eSSascha Wildner     void			*at_context;
725db2f26eSSascha Wildner     ACPI_EXECUTE_TYPE		at_type;
735db2f26eSSascha Wildner };
745db2f26eSSascha Wildner 
755db2f26eSSascha Wildner static struct thread *acpi_task_td;
765db2f26eSSascha Wildner struct lwkt_port acpi_afree_rport;
775db2f26eSSascha Wildner 
785db2f26eSSascha Wildner /*
795db2f26eSSascha Wildner  * Initialize the ACPI helper thread.
805db2f26eSSascha Wildner  */
815db2f26eSSascha Wildner int
825db2f26eSSascha Wildner acpi_task_thread_init(void)
835db2f26eSSascha Wildner {
845db2f26eSSascha Wildner     lwkt_initport_replyonly(&acpi_afree_rport, acpi_autofree_reply);
85bde01544SSepherosa Ziehau     acpi_task_td = kmalloc(sizeof(struct thread), M_DEVBUF, M_INTWAIT | M_ZERO);
86bde01544SSepherosa Ziehau     lwkt_create(acpi_task_thread, NULL, NULL, acpi_task_td, TDF_NOSTART, 0,
87bde01544SSepherosa Ziehau 	"acpi_task");
885db2f26eSSascha Wildner     return (0);
895db2f26eSSascha Wildner }
905db2f26eSSascha Wildner 
91bde01544SSepherosa Ziehau void
92bde01544SSepherosa Ziehau acpi_task_thread_schedule(void)
93bde01544SSepherosa Ziehau {
94bde01544SSepherosa Ziehau     lwkt_schedule(acpi_task_td);
95bde01544SSepherosa Ziehau }
96bde01544SSepherosa Ziehau 
975db2f26eSSascha Wildner /*
985db2f26eSSascha Wildner  * The ACPI helper thread processes OSD execution callback messages.
995db2f26eSSascha Wildner  */
1005db2f26eSSascha Wildner static void
1015db2f26eSSascha Wildner acpi_task_thread(void *arg)
1025db2f26eSSascha Wildner {
1035db2f26eSSascha Wildner     ACPI_OSD_EXEC_CALLBACK func;
1045db2f26eSSascha Wildner     struct acpi_task *at;
1055db2f26eSSascha Wildner 
1065db2f26eSSascha Wildner     get_mplock();
1075db2f26eSSascha Wildner     for (;;) {
1085db2f26eSSascha Wildner 	at = (void *)lwkt_waitport(&curthread->td_msgport, 0);
1095db2f26eSSascha Wildner 	func = at->at_function;
1105db2f26eSSascha Wildner 	func(at->at_context);
1115db2f26eSSascha Wildner 	lwkt_replymsg(&at->at_msg, 0);
1125db2f26eSSascha Wildner     }
1135db2f26eSSascha Wildner     rel_mplock();
1145db2f26eSSascha Wildner }
1155db2f26eSSascha Wildner 
1165db2f26eSSascha Wildner /*
1175db2f26eSSascha Wildner  * Queue an ACPI message for execution by allocating a LWKT message structure
1185db2f26eSSascha Wildner  * and sending the message to the helper thread.  The reply port is setup
1195db2f26eSSascha Wildner  * to automatically free the message.
1205db2f26eSSascha Wildner  */
1215db2f26eSSascha Wildner ACPI_STATUS
1225db2f26eSSascha Wildner AcpiOsExecute(ACPI_EXECUTE_TYPE Type, ACPI_OSD_EXEC_CALLBACK Function,
1235db2f26eSSascha Wildner 	      void *Context)
1245db2f26eSSascha Wildner {
1255db2f26eSSascha Wildner     struct acpi_task	*at;
1265db2f26eSSascha Wildner 
1275db2f26eSSascha Wildner     switch (Type) {
1285db2f26eSSascha Wildner     case OSL_GLOBAL_LOCK_HANDLER:
1295db2f26eSSascha Wildner     case OSL_NOTIFY_HANDLER:
1305db2f26eSSascha Wildner     case OSL_GPE_HANDLER:
1315db2f26eSSascha Wildner     case OSL_DEBUGGER_THREAD:
1325db2f26eSSascha Wildner     case OSL_EC_POLL_HANDLER:
1335db2f26eSSascha Wildner     case OSL_EC_BURST_HANDLER:
1345db2f26eSSascha Wildner 	break;
1355db2f26eSSascha Wildner     default:
1365db2f26eSSascha Wildner 	return_ACPI_STATUS (AE_BAD_PARAMETER);
1375db2f26eSSascha Wildner     }
1385db2f26eSSascha Wildner 
1395db2f26eSSascha Wildner     /* Note: Interrupt Context */
1405db2f26eSSascha Wildner     at = kmalloc(sizeof(*at), M_ACPITASK, M_INTWAIT | M_ZERO);
1415db2f26eSSascha Wildner     lwkt_initmsg(&at->at_msg, &acpi_afree_rport, 0);
1425db2f26eSSascha Wildner     at->at_function = Function;
1435db2f26eSSascha Wildner     at->at_context = Context;
1445db2f26eSSascha Wildner     at->at_type = Type;
1455db2f26eSSascha Wildner     lwkt_sendmsg(&acpi_task_td->td_msgport, &at->at_msg);
1465db2f26eSSascha Wildner     return_ACPI_STATUS (AE_OK);
1475db2f26eSSascha Wildner }
1485db2f26eSSascha Wildner 
1495db2f26eSSascha Wildner /*
1505db2f26eSSascha Wildner  * The message's reply port just frees the message.
1515db2f26eSSascha Wildner  */
1525db2f26eSSascha Wildner static void
1535db2f26eSSascha Wildner acpi_autofree_reply(lwkt_port_t port, lwkt_msg_t msg)
1545db2f26eSSascha Wildner {
1555db2f26eSSascha Wildner     kfree(msg, M_ACPITASK);
1565db2f26eSSascha Wildner }
1575db2f26eSSascha Wildner 
1585db2f26eSSascha Wildner UINT64
1595db2f26eSSascha Wildner AcpiOsGetTimer (void)
1605db2f26eSSascha Wildner {
1615db2f26eSSascha Wildner     struct timeval  time;
1625db2f26eSSascha Wildner 
1635db2f26eSSascha Wildner     microtime(&time);
1645db2f26eSSascha Wildner 
1655db2f26eSSascha Wildner     /* Seconds * 10^7 = 100ns(10^-7), Microseconds(10^-6) * 10^1 = 100ns */
1665db2f26eSSascha Wildner 
1675db2f26eSSascha Wildner     return (((UINT64) time.tv_sec * 10000000) + ((UINT64) time.tv_usec * 10));
1685db2f26eSSascha Wildner }
1695db2f26eSSascha Wildner 
1705db2f26eSSascha Wildner void
171*417dc5a4SSascha Wildner AcpiOsSleep(UINT64 Milliseconds)
1725db2f26eSSascha Wildner {
1735db2f26eSSascha Wildner     int		timo;
1745db2f26eSSascha Wildner     static int	dummy;
1755db2f26eSSascha Wildner 
1765db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1775db2f26eSSascha Wildner 
1785db2f26eSSascha Wildner     timo = Milliseconds * hz / 1000;
1795db2f26eSSascha Wildner 
1805db2f26eSSascha Wildner     /*
1815db2f26eSSascha Wildner      * If requested sleep time is less than our hz resolution, or if
1825db2f26eSSascha Wildner      * the system is in early boot before the system tick is operational,
1835db2f26eSSascha Wildner      * use DELAY instead for better granularity.
1845db2f26eSSascha Wildner      */
1855db2f26eSSascha Wildner     if (clocks_running == 0) {
1865db2f26eSSascha Wildner 	while (timo > 1000000) {
1875db2f26eSSascha Wildner 	    DELAY(1000000);
1885db2f26eSSascha Wildner 	    timo -= 1000000;
1895db2f26eSSascha Wildner 	}
1905db2f26eSSascha Wildner 	if (timo)
1915db2f26eSSascha Wildner 	    DELAY(timo * 1000);
1925db2f26eSSascha Wildner     } else if (timo > 0) {
1935db2f26eSSascha Wildner 	tsleep(&dummy, 0, "acpislp", timo);
1945db2f26eSSascha Wildner     } else {
1955db2f26eSSascha Wildner 	DELAY(Milliseconds * 1000);
1965db2f26eSSascha Wildner     }
1975db2f26eSSascha Wildner     return_VOID;
1985db2f26eSSascha Wildner }
1995db2f26eSSascha Wildner 
2005db2f26eSSascha Wildner void
2015db2f26eSSascha Wildner AcpiOsStall(UINT32 Microseconds)
2025db2f26eSSascha Wildner {
2035db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
2045db2f26eSSascha Wildner 
2055db2f26eSSascha Wildner     DELAY(Microseconds);
2065db2f26eSSascha Wildner     return_VOID;
2075db2f26eSSascha Wildner }
2085db2f26eSSascha Wildner 
2095db2f26eSSascha Wildner ACPI_THREAD_ID
2105db2f26eSSascha Wildner AcpiOsGetThreadId(void)
2115db2f26eSSascha Wildner {
2125db2f26eSSascha Wildner     struct proc *p;
2135db2f26eSSascha Wildner 
2145db2f26eSSascha Wildner     /* XXX do not add ACPI_FUNCTION_TRACE here, results in recursive call. */
2155db2f26eSSascha Wildner 
2165db2f26eSSascha Wildner     p = curproc;
2175db2f26eSSascha Wildner     if (p == NULL)
2185db2f26eSSascha Wildner 	p = &proc0;
2195db2f26eSSascha Wildner     KASSERT(p != NULL, ("%s: curproc is NULL!", __func__));
2205db2f26eSSascha Wildner 
2215db2f26eSSascha Wildner     /* Returning 0 is not allowed. */
2225db2f26eSSascha Wildner     return (p->p_pid + 1);
2235db2f26eSSascha Wildner }
224