OsdSchedule.c revision 133627
152284Sobrien/*- 290075Sobrien * Copyright (c) 2000 Michael Smith 3117395Skan * Copyright (c) 2000 BSDi 490075Sobrien * All rights reserved. 552284Sobrien * 6132718Skan * Redistribution and use in source and binary forms, with or without 752284Sobrien * modification, are permitted provided that the following conditions 8132718Skan * are met: 952284Sobrien * 1. Redistributions of source code must retain the above copyright 1052284Sobrien * notice, this list of conditions and the following disclaimer. 1152284Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1252284Sobrien * notice, this list of conditions and the following disclaimer in the 13132718Skan * documentation and/or other materials provided with the distribution. 1452284Sobrien * 1552284Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1652284Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1752284Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1852284Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2252284Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23132718Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2452284Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25132718Skan * SUCH DAMAGE. 2690075Sobrien * 2790075Sobrien * $FreeBSD: head/sys/dev/acpica/Osd/OsdSchedule.c 133627 2004-08-13 06:22:26Z njl $ 28132718Skan */ 2990075Sobrien 30132718Skan/* 31132718Skan * 6.3 : Scheduling services 3290075Sobrien */ 33132718Skan 3490075Sobrien#include "opt_acpi.h" 3552284Sobrien#include <sys/param.h> 3690075Sobrien#include <sys/systm.h> 3790075Sobrien#include <sys/bus.h> 38132718Skan#include <sys/interrupt.h> 39132718Skan#include <sys/kernel.h> 4090075Sobrien#include <sys/kthread.h> 4190075Sobrien#include <sys/malloc.h> 4290075Sobrien#include <sys/proc.h> 4352284Sobrien#include <sys/taskqueue.h> 4452284Sobrien#include <machine/clock.h> 4552284Sobrien 46132718Skan#include "acpi.h" 4752284Sobrien#include <dev/acpica/acpivar.h> 4890075Sobrien 49132718Skan#define _COMPONENT ACPI_OS_SERVICES 50132718SkanACPI_MODULE_NAME("SCHEDULE") 51132718Skan 5252284Sobrien/* 5352284Sobrien * This is a little complicated due to the fact that we need to build and then 5452284Sobrien * free a 'struct task' for each task we enqueue. 5552284Sobrien */ 5652284Sobrien 5752284SobrienMALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task"); 5852284Sobrien 5952284Sobrienstatic void AcpiOsExecuteQueue(void *arg, int pending); 6090075Sobrien 6190075Sobrienstruct acpi_task { 6290075Sobrien struct task at_task; 6390075Sobrien OSD_EXECUTION_CALLBACK at_function; 6490075Sobrien void *at_context; 6590075Sobrien}; 6652284Sobrien 67132718Skanstruct acpi_task_queue { 6890075Sobrien STAILQ_ENTRY(acpi_task_queue) at_q; 6990075Sobrien struct acpi_task *at; 7090075Sobrien}; 7190075Sobrien 7290075Sobrien/* 7390075Sobrien * Private task queue definition for ACPI 7490075Sobrien */ 7590075SobrienTASKQUEUE_DECLARE(acpi); 76132718Skanstatic void *taskqueue_acpi_ih; 7752284Sobrien 78132718Skanstatic void 79132718Skantaskqueue_acpi_enqueue(void *context) 80132718Skan{ 8152284Sobrien swi_sched(taskqueue_acpi_ih, 0); 82132718Skan} 83132718Skan 84132718Skanstatic void 85132718Skantaskqueue_acpi_run(void *dummy) 8652284Sobrien{ 87132718Skan taskqueue_run(taskqueue_acpi); 88132718Skan} 89132718Skan 90132718SkanTASKQUEUE_DEFINE(acpi, taskqueue_acpi_enqueue, 0, 91132718Skan swi_add(NULL, "acpitaskq", taskqueue_acpi_run, NULL, 92132718Skan SWI_TQ, 0, &taskqueue_acpi_ih)); 93132718Skan 94132718Skanstatic STAILQ_HEAD(, acpi_task_queue) acpi_task_queue; 95132718SkanACPI_LOCK_DECL(taskq, "ACPI task queue"); 96132718Skan 9752284Sobrienstatic void 98132718Skanacpi_task_thread(void *arg) 99132718Skan{ 100132718Skan struct acpi_task_queue *atq; 101132718Skan OSD_EXECUTION_CALLBACK Function; 102132718Skan void *Context; 103132718Skan 104132718Skan ACPI_LOCK(taskq); 105132718Skan for (;;) { 106132718Skan while ((atq = STAILQ_FIRST(&acpi_task_queue)) == NULL) 107132718Skan msleep(&acpi_task_queue, &taskq_mutex, PCATCH, "actask", 0); 10852284Sobrien STAILQ_REMOVE_HEAD(&acpi_task_queue, at_q); 109132718Skan ACPI_UNLOCK(taskq); 110132718Skan 111132718Skan Function = (OSD_EXECUTION_CALLBACK)atq->at->at_function; 112132718Skan Context = atq->at->at_context; 113132718Skan 114132718Skan Function(Context); 115132718Skan 116132718Skan free(atq->at, M_ACPITASK); 117132718Skan free(atq, M_ACPITASK); 118132718Skan ACPI_LOCK(taskq); 11952284Sobrien } 120132718Skan 121132718Skan kthread_exit(0); 122132718Skan} 123132718Skan 124132718Skanint 125132718Skanacpi_task_thread_init(void) 126132718Skan{ 127132718Skan int i, err; 128132718Skan struct proc *acpi_kthread_proc; 129132718Skan 13052284Sobrien err = 0; 131132718Skan STAILQ_INIT(&acpi_task_queue); 132132718Skan 133132718Skan for (i = 0; i < ACPI_MAX_THREADS; i++) { 134132718Skan err = kthread_create(acpi_task_thread, NULL, &acpi_kthread_proc, 135132718Skan 0, 0, "acpi_task%d", i); 136132718Skan if (err != 0) { 137132718Skan printf("%s: kthread_create failed(%d)\n", __func__, err); 138132718Skan break; 139132718Skan } 140132718Skan } 14152284Sobrien return (err); 142132718Skan} 143132718Skan 144132718Skan/* This function is called in interrupt context. */ 145132718SkanACPI_STATUS 146132718SkanAcpiOsQueueForExecution(UINT32 Priority, OSD_EXECUTION_CALLBACK Function, 147132718Skan void *Context) 14852284Sobrien{ 149258428Spfg struct acpi_task *at; 150132718Skan int pri; 151132718Skan 152132718Skan ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 153132718Skan 154132718Skan if (Function == NULL) 155132718Skan return_ACPI_STATUS (AE_BAD_PARAMETER); 156132718Skan 157132718Skan at = malloc(sizeof(*at), M_ACPITASK, M_NOWAIT | M_ZERO); 15852284Sobrien if (at == NULL) 159132718Skan return_ACPI_STATUS (AE_NO_MEMORY); 160132718Skan 161132718Skan at->at_function = Function; 162132718Skan at->at_context = Context; 16352284Sobrien switch (Priority) { 164132718Skan case OSD_PRIORITY_GPE: 165132718Skan pri = 4; 166132718Skan break; 167132718Skan case OSD_PRIORITY_HIGH: 168132718Skan pri = 3; 169132718Skan break; 170132718Skan case OSD_PRIORITY_MED: 171132718Skan pri = 2; 17252284Sobrien break; 173132718Skan case OSD_PRIORITY_LO: 174132718Skan pri = 1; 175132718Skan break; 17652284Sobrien default: 177132718Skan free(at, M_ACPITASK); 178132718Skan return_ACPI_STATUS (AE_BAD_PARAMETER); 179132718Skan } 18052284Sobrien TASK_INIT(&at->at_task, pri, AcpiOsExecuteQueue, at); 181132718Skan 182132718Skan taskqueue_enqueue(taskqueue_acpi, (struct task *)at); 183132718Skan 18452284Sobrien return_ACPI_STATUS (AE_OK); 185132718Skan} 186132718Skan 187132718Skanstatic void 18852284SobrienAcpiOsExecuteQueue(void *arg, int pending) 189132718Skan{ 190132718Skan struct acpi_task_queue *atq; 191132718Skan OSD_EXECUTION_CALLBACK Function; 19252284Sobrien void *Context; 193132718Skan 194132718Skan ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 19552284Sobrien 19652284Sobrien atq = NULL; 197132718Skan Function = NULL; 198132718Skan Context = NULL; 199132718Skan 200132718Skan atq = malloc(sizeof(*atq), M_ACPITASK, M_NOWAIT); 20190075Sobrien if (atq == NULL) { 202132718Skan printf("%s: no memory\n", __func__); 203132718Skan return; 204132718Skan } 205132718Skan atq->at = (struct acpi_task *)arg; 206132718Skan 207169689Skan ACPI_LOCK(taskq); 208132718Skan STAILQ_INSERT_TAIL(&acpi_task_queue, atq, at_q); 209132718Skan wakeup_one(&acpi_task_queue); 210132718Skan ACPI_UNLOCK(taskq); 211132718Skan 212132718Skan return_VOID; 213132718Skan} 214132718Skan 215132718Skanvoid 216132718SkanAcpiOsSleep(UINT32 Seconds, UINT32 Milliseconds) 217132718Skan{ 218132718Skan int timo; 219132718Skan static int dummy; 220132718Skan 221132718Skan ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 222132718Skan 223132718Skan timo = (Seconds * hz) + Milliseconds * hz / 1000; 224132718Skan 225132718Skan /* 226132718Skan * If requested sleep time is less than our hz resolution, use 227169689Skan * DELAY instead for better granularity. 228132718Skan */ 229132718Skan if (timo > 0) 23090075Sobrien tsleep(&dummy, 0, "acpislp", timo); 231169689Skan else 232169689Skan DELAY(Milliseconds * 1000); 233169689Skan 234169689Skan return_VOID; 235169689Skan} 236169689Skan 237169689Skanvoid 238169689SkanAcpiOsStall(UINT32 Microseconds) 239169689Skan{ 240169689Skan ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 241 242 DELAY(Microseconds); 243 return_VOID; 244} 245 246UINT32 247AcpiOsGetThreadId(void) 248{ 249 struct proc *p; 250 251 /* XXX do not add ACPI_FUNCTION_TRACE here, results in recursive call. */ 252 253 p = curproc; 254 KASSERT(p != NULL, ("%s: curproc is NULL!", __func__)); 255 256 /* Returning 0 is not allowed. */ 257 return (p->p_pid + 1); 258} 259