OsdSchedule.c revision 145352
167760Smsmith/*- 267760Smsmith * Copyright (c) 2000 Michael Smith 367760Smsmith * Copyright (c) 2000 BSDi 467760Smsmith * All rights reserved. 567760Smsmith * 667760Smsmith * Redistribution and use in source and binary forms, with or without 767760Smsmith * modification, are permitted provided that the following conditions 867760Smsmith * are met: 967760Smsmith * 1. Redistributions of source code must retain the above copyright 1067760Smsmith * notice, this list of conditions and the following disclaimer. 1167760Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1267760Smsmith * notice, this list of conditions and the following disclaimer in the 1367760Smsmith * documentation and/or other materials provided with the distribution. 1467760Smsmith * 1567760Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1667760Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1767760Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1867760Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1967760Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2067760Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2167760Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2267760Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2367760Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2467760Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2567760Smsmith * SUCH DAMAGE. 2667760Smsmith * 2767760Smsmith * $FreeBSD: head/sys/dev/acpica/Osd/OsdSchedule.c 145352 2005-04-21 06:13:48Z njl $ 2867760Smsmith */ 2967760Smsmith 3067760Smsmith/* 3167760Smsmith * 6.3 : Scheduling services 3267760Smsmith */ 3367760Smsmith 3488420Siwasaki#include "opt_acpi.h" 3588420Siwasaki#include <sys/param.h> 3688420Siwasaki#include <sys/systm.h> 3788420Siwasaki#include <sys/bus.h> 3888420Siwasaki#include <sys/interrupt.h> 3967760Smsmith#include <sys/kernel.h> 4088420Siwasaki#include <sys/kthread.h> 4167760Smsmith#include <sys/malloc.h> 4277466Smsmith#include <sys/proc.h> 4367760Smsmith#include <sys/taskqueue.h> 4467760Smsmith#include <machine/clock.h> 4567760Smsmith 46128228Snjl#include "acpi.h" 4788420Siwasaki#include <dev/acpica/acpivar.h> 4888420Siwasaki 4977432Smsmith#define _COMPONENT ACPI_OS_SERVICES 5091128SmsmithACPI_MODULE_NAME("SCHEDULE") 5171875Smsmith 5267760Smsmith/* 53145352Snjl * Allow the user to tune the number of task threads we start. It seems 54145352Snjl * some systems have problems with increased parallelism. 55145352Snjl */ 56145352Snjlstatic int acpi_max_threads = ACPI_MAX_THREADS; 57145352SnjlTUNABLE_INT("debug.acpi.max_threads", &acpi_max_threads); 58145352Snjl 59145352Snjl/* 6067760Smsmith * This is a little complicated due to the fact that we need to build and then 6167760Smsmith * free a 'struct task' for each task we enqueue. 6267760Smsmith */ 6367760Smsmith 6467760SmsmithMALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task"); 6567760Smsmith 6667760Smsmithstatic void AcpiOsExecuteQueue(void *arg, int pending); 6767760Smsmith 6867760Smsmithstruct acpi_task { 6967760Smsmith struct task at_task; 70138300Smarks ACPI_OSD_EXEC_CALLBACK at_function; 7167760Smsmith void *at_context; 7267760Smsmith}; 7367760Smsmith 7488420Siwasakistruct acpi_task_queue { 7588420Siwasaki STAILQ_ENTRY(acpi_task_queue) at_q; 7688420Siwasaki struct acpi_task *at; 7788420Siwasaki}; 7888420Siwasaki 7988420Siwasaki/* 8088420Siwasaki * Private task queue definition for ACPI 8188420Siwasaki */ 8288420SiwasakiTASKQUEUE_DECLARE(acpi); 8388420Siwasakistatic void *taskqueue_acpi_ih; 8488420Siwasaki 8588420Siwasakistatic void 8688420Siwasakitaskqueue_acpi_enqueue(void *context) 8788420Siwasaki{ 8888900Sjhb swi_sched(taskqueue_acpi_ih, 0); 8988420Siwasaki} 9088420Siwasaki 9188420Siwasakistatic void 9288420Siwasakitaskqueue_acpi_run(void *dummy) 9388420Siwasaki{ 9488420Siwasaki taskqueue_run(taskqueue_acpi); 9588420Siwasaki} 9688420Siwasaki 9788420SiwasakiTASKQUEUE_DEFINE(acpi, taskqueue_acpi_enqueue, 0, 9888420Siwasaki swi_add(NULL, "acpitaskq", taskqueue_acpi_run, NULL, 9988420Siwasaki SWI_TQ, 0, &taskqueue_acpi_ih)); 10088420Siwasaki 101128990Snjlstatic STAILQ_HEAD(, acpi_task_queue) acpi_task_queue; 102133627SnjlACPI_LOCK_DECL(taskq, "ACPI task queue"); 10388420Siwasaki 10488420Siwasakistatic void 10588420Siwasakiacpi_task_thread(void *arg) 10688420Siwasaki{ 10788420Siwasaki struct acpi_task_queue *atq; 108138300Smarks ACPI_OSD_EXEC_CALLBACK Function; 10988420Siwasaki void *Context; 11088420Siwasaki 111133627Snjl ACPI_LOCK(taskq); 11288420Siwasaki for (;;) { 113133627Snjl while ((atq = STAILQ_FIRST(&acpi_task_queue)) == NULL) 114133627Snjl msleep(&acpi_task_queue, &taskq_mutex, PCATCH, "actask", 0); 11588420Siwasaki STAILQ_REMOVE_HEAD(&acpi_task_queue, at_q); 116133627Snjl ACPI_UNLOCK(taskq); 11788420Siwasaki 118138300Smarks Function = (ACPI_OSD_EXEC_CALLBACK)atq->at->at_function; 11988420Siwasaki Context = atq->at->at_context; 12088420Siwasaki 12188420Siwasaki Function(Context); 12288420Siwasaki 12388420Siwasaki free(atq->at, M_ACPITASK); 12488420Siwasaki free(atq, M_ACPITASK); 125133627Snjl ACPI_LOCK(taskq); 12688420Siwasaki } 12788420Siwasaki 12888420Siwasaki kthread_exit(0); 12988420Siwasaki} 13088420Siwasaki 13188420Siwasakiint 13288420Siwasakiacpi_task_thread_init(void) 13388420Siwasaki{ 13488420Siwasaki int i, err; 13588420Siwasaki struct proc *acpi_kthread_proc; 13688420Siwasaki 13788420Siwasaki err = 0; 13888420Siwasaki STAILQ_INIT(&acpi_task_queue); 13988420Siwasaki 140145352Snjl for (i = 0; i < acpi_max_threads; i++) { 14188420Siwasaki err = kthread_create(acpi_task_thread, NULL, &acpi_kthread_proc, 142104354Sscottl 0, 0, "acpi_task%d", i); 14388420Siwasaki if (err != 0) { 14488420Siwasaki printf("%s: kthread_create failed(%d)\n", __func__, err); 14588420Siwasaki break; 14688420Siwasaki } 14788420Siwasaki } 14888420Siwasaki return (err); 14988420Siwasaki} 15088420Siwasaki 151128228Snjl/* This function is called in interrupt context. */ 15267760SmsmithACPI_STATUS 153138300SmarksAcpiOsQueueForExecution(UINT32 Priority, ACPI_OSD_EXEC_CALLBACK Function, 154128228Snjl void *Context) 15567760Smsmith{ 15667760Smsmith struct acpi_task *at; 15785503Sjhb int pri; 15867760Smsmith 15996926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 16071875Smsmith 16167760Smsmith if (Function == NULL) 162128228Snjl return_ACPI_STATUS (AE_BAD_PARAMETER); 16367760Smsmith 164128228Snjl at = malloc(sizeof(*at), M_ACPITASK, M_NOWAIT | M_ZERO); 16571418Speter if (at == NULL) 166128228Snjl return_ACPI_STATUS (AE_NO_MEMORY); 16767760Smsmith 16867760Smsmith at->at_function = Function; 16967760Smsmith at->at_context = Context; 17067760Smsmith switch (Priority) { 17170236Siwasaki case OSD_PRIORITY_GPE: 17285503Sjhb pri = 4; 17370236Siwasaki break; 17467760Smsmith case OSD_PRIORITY_HIGH: 17585503Sjhb pri = 3; 17667760Smsmith break; 17767760Smsmith case OSD_PRIORITY_MED: 17885503Sjhb pri = 2; 17967760Smsmith break; 18067760Smsmith case OSD_PRIORITY_LO: 18185503Sjhb pri = 1; 18267760Smsmith break; 18367760Smsmith default: 18467760Smsmith free(at, M_ACPITASK); 185128228Snjl return_ACPI_STATUS (AE_BAD_PARAMETER); 18667760Smsmith } 18785503Sjhb TASK_INIT(&at->at_task, pri, AcpiOsExecuteQueue, at); 18867760Smsmith 189128228Snjl taskqueue_enqueue(taskqueue_acpi, (struct task *)at); 190128228Snjl 191128228Snjl return_ACPI_STATUS (AE_OK); 19267760Smsmith} 19367760Smsmith 19467760Smsmithstatic void 19567760SmsmithAcpiOsExecuteQueue(void *arg, int pending) 19667760Smsmith{ 19788420Siwasaki struct acpi_task_queue *atq; 198138300Smarks ACPI_OSD_EXEC_CALLBACK Function; 19967760Smsmith void *Context; 20067760Smsmith 20196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 20271875Smsmith 20388420Siwasaki atq = NULL; 20488420Siwasaki Function = NULL; 20588420Siwasaki Context = NULL; 20688420Siwasaki 20788420Siwasaki atq = malloc(sizeof(*atq), M_ACPITASK, M_NOWAIT); 20888420Siwasaki if (atq == NULL) { 20988420Siwasaki printf("%s: no memory\n", __func__); 21088420Siwasaki return; 21188420Siwasaki } 212133627Snjl atq->at = (struct acpi_task *)arg; 21388420Siwasaki 214133627Snjl ACPI_LOCK(taskq); 21588420Siwasaki STAILQ_INSERT_TAIL(&acpi_task_queue, atq, at_q); 21688420Siwasaki wakeup_one(&acpi_task_queue); 217133627Snjl ACPI_UNLOCK(taskq); 21867760Smsmith 21971875Smsmith return_VOID; 22067760Smsmith} 22167760Smsmith 22267760Smsmithvoid 223138300SmarksAcpiOsSleep(ACPI_INTEGER Milliseconds) 22467760Smsmith{ 22567760Smsmith int timo; 22677432Smsmith static int dummy; 22767760Smsmith 22896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 22971875Smsmith 230138300Smarks timo = Milliseconds * hz / 1000; 231120662Snjl 232120662Snjl /* 233120662Snjl * If requested sleep time is less than our hz resolution, use 234120662Snjl * DELAY instead for better granularity. 235120662Snjl */ 236120662Snjl if (timo > 0) 237120662Snjl tsleep(&dummy, 0, "acpislp", timo); 238120662Snjl else 239120662Snjl DELAY(Milliseconds * 1000); 240120662Snjl 24171875Smsmith return_VOID; 24267760Smsmith} 24367760Smsmith 244138300Smarks/* 245138300Smarks * Return the current time in 100 nanosecond units 246138300Smarks */ 247138300SmarksUINT64 248138300SmarksAcpiOsGetTimer(void) 249138300Smarks{ 250138300Smarks struct bintime bt; 251138300Smarks UINT64 t; 252138300Smarks 253138300Smarks /* XXX During early boot there is no (decent) timer available yet. */ 254138300Smarks if (cold) 255138300Smarks panic("acpi: timer op not yet supported during boot"); 256138300Smarks 257138300Smarks binuptime(&bt); 258138300Smarks t = ((UINT64)10000000 * (uint32_t)(bt.frac >> 32)) >> 32; 259138300Smarks t += bt.sec * 10000000; 260138300Smarks 261138300Smarks return (t); 262138300Smarks} 263138300Smarks 26467760Smsmithvoid 265120662SnjlAcpiOsStall(UINT32 Microseconds) 26667760Smsmith{ 26796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 26871875Smsmith 269120607Snjl DELAY(Microseconds); 27071875Smsmith return_VOID; 27167760Smsmith} 27277432Smsmith 27377432SmsmithUINT32 274120662SnjlAcpiOsGetThreadId(void) 27577432Smsmith{ 276105279Sjhb struct proc *p; 27777432Smsmith 278128228Snjl /* XXX do not add ACPI_FUNCTION_TRACE here, results in recursive call. */ 279128228Snjl 280105279Sjhb p = curproc; 281105279Sjhb KASSERT(p != NULL, ("%s: curproc is NULL!", __func__)); 282128228Snjl 283128228Snjl /* Returning 0 is not allowed. */ 284128228Snjl return (p->p_pid + 1); 28577432Smsmith} 286