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