xref: /dflybsd-src/sys/dev/acpica/Osd/OsdSchedule.c (revision fcf6efefc03a35111797b109fa4994034ebe39ba)
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 /*
31178f054bSSascha Wildner  * Multithreading and 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/msgport.h>
435db2f26eSSascha Wildner #include <sys/taskqueue.h>
445db2f26eSSascha Wildner #include <machine/clock.h>
455db2f26eSSascha Wildner 
465db2f26eSSascha Wildner #include <sys/msgport2.h>
475db2f26eSSascha Wildner 
485db2f26eSSascha Wildner #include "acpi.h"
495db2f26eSSascha Wildner #include "accommon.h"
505db2f26eSSascha Wildner #include <dev/acpica/acpivar.h>
515db2f26eSSascha Wildner 
525db2f26eSSascha Wildner #define _COMPONENT	ACPI_OS_SERVICES
535db2f26eSSascha Wildner ACPI_MODULE_NAME("SCHEDULE")
545db2f26eSSascha Wildner 
555db2f26eSSascha Wildner /*
565db2f26eSSascha Wildner  * This is a little complicated due to the fact that we need to build and then
575db2f26eSSascha Wildner  * free a 'struct task' for each task we enqueue.
585db2f26eSSascha Wildner  */
595db2f26eSSascha Wildner 
605db2f26eSSascha Wildner MALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task");
615db2f26eSSascha Wildner 
625db2f26eSSascha Wildner static void	acpi_task_thread(void *arg);
635db2f26eSSascha Wildner static void	acpi_autofree_reply(lwkt_port_t port, lwkt_msg_t msg);
645db2f26eSSascha Wildner 
655db2f26eSSascha Wildner struct acpi_task {
665db2f26eSSascha Wildner     struct lwkt_msg		at_msg;
675db2f26eSSascha Wildner     ACPI_OSD_EXEC_CALLBACK	at_function;
685db2f26eSSascha Wildner     void			*at_context;
695db2f26eSSascha Wildner     ACPI_EXECUTE_TYPE		at_type;
705db2f26eSSascha Wildner };
715db2f26eSSascha Wildner 
725db2f26eSSascha Wildner static struct thread *acpi_task_td;
735db2f26eSSascha Wildner struct lwkt_port acpi_afree_rport;
745db2f26eSSascha Wildner 
755db2f26eSSascha Wildner /*
765db2f26eSSascha Wildner  * Initialize the ACPI helper thread.
775db2f26eSSascha Wildner  */
785db2f26eSSascha Wildner int
acpi_task_thread_init(void)795db2f26eSSascha Wildner acpi_task_thread_init(void)
805db2f26eSSascha Wildner {
815db2f26eSSascha Wildner     lwkt_initport_replyonly(&acpi_afree_rport, acpi_autofree_reply);
82bde01544SSepherosa Ziehau     acpi_task_td = kmalloc(sizeof(struct thread), M_DEVBUF, M_INTWAIT | M_ZERO);
83bde01544SSepherosa Ziehau     lwkt_create(acpi_task_thread, NULL, NULL, acpi_task_td, TDF_NOSTART, 0,
84bde01544SSepherosa Ziehau 	"acpi_task");
855db2f26eSSascha Wildner     return (0);
865db2f26eSSascha Wildner }
875db2f26eSSascha Wildner 
88bde01544SSepherosa Ziehau void
acpi_task_thread_schedule(void)89bde01544SSepherosa Ziehau acpi_task_thread_schedule(void)
90bde01544SSepherosa Ziehau {
91bde01544SSepherosa Ziehau     lwkt_schedule(acpi_task_td);
92bde01544SSepherosa Ziehau }
93bde01544SSepherosa Ziehau 
945db2f26eSSascha Wildner /*
955db2f26eSSascha Wildner  * The ACPI helper thread processes OSD execution callback messages.
965db2f26eSSascha Wildner  */
975db2f26eSSascha Wildner static void
acpi_task_thread(void * arg)985db2f26eSSascha Wildner acpi_task_thread(void *arg)
995db2f26eSSascha Wildner {
1005db2f26eSSascha Wildner     ACPI_OSD_EXEC_CALLBACK func;
1015db2f26eSSascha Wildner     struct acpi_task *at;
1025db2f26eSSascha Wildner 
103a639f788SMatthew Dillon     lwkt_gettoken(&acpi_token);
1045db2f26eSSascha Wildner     for (;;) {
1055db2f26eSSascha Wildner 	at = (void *)lwkt_waitport(&curthread->td_msgport, 0);
1065db2f26eSSascha Wildner 	func = at->at_function;
1075db2f26eSSascha Wildner 	func(at->at_context);
1085db2f26eSSascha Wildner 	lwkt_replymsg(&at->at_msg, 0);
1095db2f26eSSascha Wildner     }
110a639f788SMatthew Dillon     lwkt_reltoken(&acpi_token);
1115db2f26eSSascha Wildner }
1125db2f26eSSascha Wildner 
1135db2f26eSSascha Wildner /*
1145db2f26eSSascha Wildner  * Queue an ACPI message for execution by allocating a LWKT message structure
1155db2f26eSSascha Wildner  * and sending the message to the helper thread.  The reply port is setup
1165db2f26eSSascha Wildner  * to automatically free the message.
1175db2f26eSSascha Wildner  */
1185db2f26eSSascha Wildner ACPI_STATUS
AcpiOsExecute(ACPI_EXECUTE_TYPE Type,ACPI_OSD_EXEC_CALLBACK Function,void * Context)1195db2f26eSSascha Wildner AcpiOsExecute(ACPI_EXECUTE_TYPE Type, ACPI_OSD_EXEC_CALLBACK Function,
1205db2f26eSSascha Wildner 	      void *Context)
1215db2f26eSSascha Wildner {
1225db2f26eSSascha Wildner     struct acpi_task	*at;
1235db2f26eSSascha Wildner 
1245db2f26eSSascha Wildner     switch (Type) {
1255db2f26eSSascha Wildner     case OSL_GLOBAL_LOCK_HANDLER:
1265db2f26eSSascha Wildner     case OSL_NOTIFY_HANDLER:
1275db2f26eSSascha Wildner     case OSL_GPE_HANDLER:
128820c5b08SSascha Wildner     case OSL_DEBUGGER_EXEC_THREAD:
1295db2f26eSSascha Wildner     case OSL_EC_POLL_HANDLER:
1305db2f26eSSascha Wildner     case OSL_EC_BURST_HANDLER:
1315db2f26eSSascha Wildner 	break;
1325db2f26eSSascha Wildner     default:
1335db2f26eSSascha Wildner 	return_ACPI_STATUS (AE_BAD_PARAMETER);
1345db2f26eSSascha Wildner     }
1355db2f26eSSascha Wildner 
1365db2f26eSSascha Wildner     /* Note: Interrupt Context */
1375db2f26eSSascha Wildner     at = kmalloc(sizeof(*at), M_ACPITASK, M_INTWAIT | M_ZERO);
1385db2f26eSSascha Wildner     lwkt_initmsg(&at->at_msg, &acpi_afree_rport, 0);
1395db2f26eSSascha Wildner     at->at_function = Function;
1405db2f26eSSascha Wildner     at->at_context = Context;
1415db2f26eSSascha Wildner     at->at_type = Type;
1425db2f26eSSascha Wildner     lwkt_sendmsg(&acpi_task_td->td_msgport, &at->at_msg);
1435db2f26eSSascha Wildner     return_ACPI_STATUS (AE_OK);
1445db2f26eSSascha Wildner }
1455db2f26eSSascha Wildner 
1465db2f26eSSascha Wildner /*
1475db2f26eSSascha Wildner  * The message's reply port just frees the message.
1485db2f26eSSascha Wildner  */
1495db2f26eSSascha Wildner static void
acpi_autofree_reply(lwkt_port_t port,lwkt_msg_t msg)1505db2f26eSSascha Wildner acpi_autofree_reply(lwkt_port_t port, lwkt_msg_t msg)
1515db2f26eSSascha Wildner {
1525db2f26eSSascha Wildner     kfree(msg, M_ACPITASK);
1535db2f26eSSascha Wildner }
1545db2f26eSSascha Wildner 
1555db2f26eSSascha Wildner UINT64
AcpiOsGetTimer(void)1565db2f26eSSascha Wildner AcpiOsGetTimer (void)
1575db2f26eSSascha Wildner {
1585db2f26eSSascha Wildner     struct timeval  time;
1595db2f26eSSascha Wildner 
1605db2f26eSSascha Wildner     microtime(&time);
1615db2f26eSSascha Wildner 
1625db2f26eSSascha Wildner     /* Seconds * 10^7 = 100ns(10^-7), Microseconds(10^-6) * 10^1 = 100ns */
1635db2f26eSSascha Wildner 
1645db2f26eSSascha Wildner     return (((UINT64) time.tv_sec * 10000000) + ((UINT64) time.tv_usec * 10));
1655db2f26eSSascha Wildner }
1665db2f26eSSascha Wildner 
1675db2f26eSSascha Wildner void
AcpiOsSleep(UINT64 Milliseconds)168417dc5a4SSascha Wildner AcpiOsSleep(UINT64 Milliseconds)
1695db2f26eSSascha Wildner {
1705db2f26eSSascha Wildner     int		timo;
1715db2f26eSSascha Wildner     static int	dummy;
1725db2f26eSSascha Wildner 
1735db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1745db2f26eSSascha Wildner 
1755db2f26eSSascha Wildner     timo = Milliseconds * hz / 1000;
1765db2f26eSSascha Wildner 
1775db2f26eSSascha Wildner     /*
1785db2f26eSSascha Wildner      * If requested sleep time is less than our hz resolution, or if
1795db2f26eSSascha Wildner      * the system is in early boot before the system tick is operational,
1805db2f26eSSascha Wildner      * use DELAY instead for better granularity.
1815db2f26eSSascha Wildner      */
1825db2f26eSSascha Wildner     if (clocks_running == 0) {
1835db2f26eSSascha Wildner 	while (timo > 1000000) {
1845db2f26eSSascha Wildner 	    DELAY(1000000);
1855db2f26eSSascha Wildner 	    timo -= 1000000;
1865db2f26eSSascha Wildner 	}
1875db2f26eSSascha Wildner 	if (timo)
1885db2f26eSSascha Wildner 	    DELAY(timo * 1000);
1895db2f26eSSascha Wildner     } else if (timo > 0) {
1905db2f26eSSascha Wildner 	tsleep(&dummy, 0, "acpislp", timo);
1915db2f26eSSascha Wildner     } else {
1925db2f26eSSascha Wildner 	DELAY(Milliseconds * 1000);
1935db2f26eSSascha Wildner     }
1945db2f26eSSascha Wildner     return_VOID;
1955db2f26eSSascha Wildner }
1965db2f26eSSascha Wildner 
1975db2f26eSSascha Wildner void
AcpiOsStall(UINT32 Microseconds)1985db2f26eSSascha Wildner AcpiOsStall(UINT32 Microseconds)
1995db2f26eSSascha Wildner {
2005db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
2015db2f26eSSascha Wildner 
2025db2f26eSSascha Wildner     DELAY(Microseconds);
2035db2f26eSSascha Wildner     return_VOID;
2045db2f26eSSascha Wildner }
2055db2f26eSSascha Wildner 
2065db2f26eSSascha Wildner ACPI_THREAD_ID
AcpiOsGetThreadId(void)2075db2f26eSSascha Wildner AcpiOsGetThreadId(void)
2085db2f26eSSascha Wildner {
2095db2f26eSSascha Wildner     /* XXX do not add ACPI_FUNCTION_TRACE here, results in recursive call. */
2105db2f26eSSascha Wildner 
211*f9393b5fSSascha Wildner     return ((uintptr_t)curthread);
2125db2f26eSSascha Wildner }
213