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