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