OsdSchedule.c revision 104354
1218885Sdim/*- 2218885Sdim * Copyright (c) 2000 Michael Smith 3218885Sdim * Copyright (c) 2000 BSDi 4218885Sdim * All rights reserved. 5218885Sdim * 6218885Sdim * Redistribution and use in source and binary forms, with or without 7218885Sdim * modification, are permitted provided that the following conditions 8218885Sdim * are met: 9218885Sdim * 1. Redistributions of source code must retain the above copyright 10218885Sdim * notice, this list of conditions and the following disclaimer. 11218885Sdim * 2. Redistributions in binary form must reproduce the above copyright 12263508Sdim * notice, this list of conditions and the following disclaimer in the 13218885Sdim * documentation and/or other materials provided with the distribution. 14218885Sdim * 15218885Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16218885Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17218885Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18218885Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19218885Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20218885Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21249423Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22218885Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23218885Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24218885Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25218885Sdim * SUCH DAMAGE. 26218885Sdim * 27218885Sdim * $FreeBSD: head/sys/dev/acpica/Osd/OsdSchedule.c 104354 2002-10-02 07:44:29Z scottl $ 28218885Sdim */ 29218885Sdim 30218885Sdim/* 31218885Sdim * 6.3 : Scheduling services 32218885Sdim */ 33218885Sdim 34218885Sdim#include "acpi.h" 35218885Sdim 36218885Sdim#include "opt_acpi.h" 37218885Sdim#include <sys/param.h> 38218885Sdim#include <sys/systm.h> 39218885Sdim#include <sys/bus.h> 40218885Sdim#include <sys/interrupt.h> 41218885Sdim#include <sys/kernel.h> 42218885Sdim#include <sys/kthread.h> 43263508Sdim#include <sys/lock.h> 44218885Sdim#include <sys/malloc.h> 45218885Sdim#include <sys/mutex.h> 46263508Sdim#include <sys/proc.h> 47218885Sdim#include <sys/taskqueue.h> 48218885Sdim#include <machine/clock.h> 49218885Sdim 50218885Sdim#include <sys/bus.h> 51218885Sdim 52218885Sdim#include <dev/acpica/acpivar.h> 53218885Sdim 54218885Sdim#define _COMPONENT ACPI_OS_SERVICES 55218885SdimACPI_MODULE_NAME("SCHEDULE") 56218885Sdim 57218885Sdim/* 58263508Sdim * This is a little complicated due to the fact that we need to build and then 59218885Sdim * free a 'struct task' for each task we enqueue. 60263508Sdim */ 61218885Sdim 62218885SdimMALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task"); 63218885Sdim 64218885Sdimstatic void AcpiOsExecuteQueue(void *arg, int pending); 65218885Sdim 66218885Sdimstruct acpi_task { 67218885Sdim struct task at_task; 68218885Sdim OSD_EXECUTION_CALLBACK at_function; 69218885Sdim void *at_context; 70218885Sdim}; 71218885Sdim 72218885Sdimstruct acpi_task_queue { 73263508Sdim STAILQ_ENTRY(acpi_task_queue) at_q; 74218885Sdim struct acpi_task *at; 75263508Sdim}; 76218885Sdim 77218885Sdim/* 78218885Sdim * Private task queue definition for ACPI 79218885Sdim */ 80218885SdimTASKQUEUE_DECLARE(acpi); 81263508Sdimstatic void *taskqueue_acpi_ih; 82218885Sdim 83218885Sdimstatic void 84218885Sdimtaskqueue_acpi_enqueue(void *context) 85218885Sdim{ 86218885Sdim swi_sched(taskqueue_acpi_ih, 0); 87218885Sdim} 88218885Sdim 89218885Sdimstatic void 90218885Sdimtaskqueue_acpi_run(void *dummy) 91218885Sdim{ 92218885Sdim taskqueue_run(taskqueue_acpi); 93218885Sdim} 94218885Sdim 95218885SdimTASKQUEUE_DEFINE(acpi, taskqueue_acpi_enqueue, 0, 96218885Sdim swi_add(NULL, "acpitaskq", taskqueue_acpi_run, NULL, 97218885Sdim SWI_TQ, 0, &taskqueue_acpi_ih)); 98218885Sdim 99218885Sdim#if defined(ACPI_MAX_THREADS) && ACPI_MAX_THREADS > 0 100218885Sdim#define ACPI_USE_THREADS 101218885Sdim#endif 102218885Sdim 103218885Sdim#ifdef ACPI_USE_THREADS 104218885SdimSTAILQ_HEAD(, acpi_task_queue) acpi_task_queue; 105218885Sdimstatic struct mtx acpi_task_mtx; 106218885Sdim 107263508Sdimstatic void 108218885Sdimacpi_task_thread(void *arg) 109218885Sdim{ 110218885Sdim struct acpi_task_queue *atq; 111218885Sdim OSD_EXECUTION_CALLBACK Function; 112218885Sdim void *Context; 113218885Sdim 114218885Sdim for (;;) { 115218885Sdim mtx_lock(&acpi_task_mtx); 116218885Sdim if ((atq = STAILQ_FIRST(&acpi_task_queue)) == NULL) { 117218885Sdim msleep(&acpi_task_queue, &acpi_task_mtx, PCATCH, "actask", 0); 118218885Sdim mtx_unlock(&acpi_task_mtx); 119218885Sdim continue; 120263508Sdim } 121218885Sdim 122218885Sdim STAILQ_REMOVE_HEAD(&acpi_task_queue, at_q); 123218885Sdim mtx_unlock(&acpi_task_mtx); 124218885Sdim 125218885Sdim Function = (OSD_EXECUTION_CALLBACK)atq->at->at_function; 126218885Sdim Context = atq->at->at_context; 127218885Sdim 128263508Sdim mtx_lock(&Giant); 129218885Sdim Function(Context); 130263508Sdim 131263508Sdim free(atq->at, M_ACPITASK); 132218885Sdim free(atq, M_ACPITASK); 133218885Sdim mtx_unlock(&Giant); 134218885Sdim } 135263508Sdim 136218885Sdim kthread_exit(0); 137263508Sdim} 138263508Sdim 139218885Sdimint 140218885Sdimacpi_task_thread_init(void) 141218885Sdim{ 142218885Sdim int i, err; 143263508Sdim struct proc *acpi_kthread_proc; 144218885Sdim 145263508Sdim err = 0; 146263508Sdim STAILQ_INIT(&acpi_task_queue); 147263508Sdim mtx_init(&acpi_task_mtx, "ACPI task", NULL, MTX_DEF); 148218885Sdim 149218885Sdim for (i = 0; i < ACPI_MAX_THREADS; i++) { 150218885Sdim err = kthread_create(acpi_task_thread, NULL, &acpi_kthread_proc, 151218885Sdim 0, 0, "acpi_task%d", i); 152263508Sdim if (err != 0) { 153218885Sdim printf("%s: kthread_create failed(%d)\n", __func__, err); 154263508Sdim break; 155263508Sdim } 156263508Sdim } 157218885Sdim return (err); 158218885Sdim} 159218885Sdim#endif 160263508Sdim 161218885SdimACPI_STATUS 162218885SdimAcpiOsQueueForExecution(UINT32 Priority, OSD_EXECUTION_CALLBACK Function, void *Context) 163218885Sdim{ 164263508Sdim struct acpi_task *at; 165263508Sdim int pri; 166263508Sdim 167263508Sdim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 168218885Sdim 169218885Sdim if (Function == NULL) 170218885Sdim return_ACPI_STATUS(AE_BAD_PARAMETER); 171218885Sdim 172218885Sdim at = malloc(sizeof(*at), M_ACPITASK, M_NOWAIT); /* Interrupt Context */ 173218885Sdim if (at == NULL) 174218885Sdim return_ACPI_STATUS(AE_NO_MEMORY); 175218885Sdim bzero(at, sizeof(*at)); 176218885Sdim 177218885Sdim at->at_function = Function; 178218885Sdim at->at_context = Context; 179218885Sdim switch (Priority) { 180218885Sdim case OSD_PRIORITY_GPE: 181218885Sdim pri = 4; 182218885Sdim break; 183218885Sdim case OSD_PRIORITY_HIGH: 184218885Sdim pri = 3; 185218885Sdim break; 186218885Sdim case OSD_PRIORITY_MED: 187218885Sdim pri = 2; 188218885Sdim break; 189218885Sdim case OSD_PRIORITY_LO: 190218885Sdim pri = 1; 191263508Sdim break; 192263508Sdim default: 193263508Sdim free(at, M_ACPITASK); 194263508Sdim return_ACPI_STATUS(AE_BAD_PARAMETER); 195218885Sdim } 196218885Sdim TASK_INIT(&at->at_task, pri, AcpiOsExecuteQueue, at); 197218885Sdim 198263508Sdim taskqueue_enqueue(taskqueue_acpi, (struct task *)at); 199218885Sdim return_ACPI_STATUS(AE_OK); 200263508Sdim} 201263508Sdim 202218885Sdimstatic void 203218885SdimAcpiOsExecuteQueue(void *arg, int pending) 204218885Sdim{ 205263508Sdim struct acpi_task *at; 206218885Sdim struct acpi_task_queue *atq; 207263508Sdim OSD_EXECUTION_CALLBACK Function; 208263508Sdim void *Context; 209218885Sdim 210263508Sdim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 211263508Sdim 212218885Sdim at = (struct acpi_task *)arg; 213263508Sdim atq = NULL; 214263508Sdim Function = NULL; 215263508Sdim Context = NULL; 216218885Sdim 217218885Sdim#ifdef ACPI_USE_THREADS 218218885Sdim atq = malloc(sizeof(*atq), M_ACPITASK, M_NOWAIT); 219218885Sdim if (atq == NULL) { 220263508Sdim printf("%s: no memory\n", __func__); 221218885Sdim return; 222218885Sdim } 223263508Sdim 224263508Sdim atq->at = at; 225218885Sdim 226218885Sdim mtx_lock(&acpi_task_mtx); 227218885Sdim STAILQ_INSERT_TAIL(&acpi_task_queue, atq, at_q); 228263508Sdim mtx_unlock(&acpi_task_mtx); 229218885Sdim wakeup_one(&acpi_task_queue); 230218885Sdim#else 231218885Sdim Function = (OSD_EXECUTION_CALLBACK)at->at_function; 232218885Sdim Context = at->at_context; 233218885Sdim 234263508Sdim Function(Context); 235218885Sdim free(at, M_ACPITASK); 236218885Sdim#endif 237263508Sdim 238263508Sdim return_VOID; 239218885Sdim} 240218885Sdim 241218885Sdim/* 242263508Sdim * We don't have any sleep granularity better than hz, so 243218885Sdim * make do with that. 244263508Sdim */ 245263508Sdimvoid 246263508SdimAcpiOsSleep (UINT32 Seconds, UINT32 Milliseconds) 247218885Sdim{ 248263508Sdim int timo; 249263508Sdim static int dummy; 250263508Sdim 251218885Sdim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 252218885Sdim 253218885Sdim timo = (Seconds * hz) + Milliseconds * hz / 1000; 254218885Sdim if (timo == 0) 255218885Sdim timo = 1; 256218885Sdim tsleep(&dummy, 0, "acpislp", timo); 257218885Sdim return_VOID; 258218885Sdim} 259218885Sdim 260263508Sdimvoid 261218885SdimAcpiOsStall (UINT32 Microseconds) 262263508Sdim{ 263263508Sdim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 264218885Sdim 265218885Sdim DELAY(Microseconds); 266218885Sdim return_VOID; 267218885Sdim} 268218885Sdim 269218885SdimUINT32 270218885SdimAcpiOsGetThreadId (void) 271218885Sdim{ 272218885Sdim /* XXX do not add FUNCTION_TRACE here, results in recursive call */ 273263508Sdim 274218885Sdim KASSERT(curproc != NULL, ("%s: curproc is NULL!", __func__)); 275263508Sdim return(curproc->p_pid + 1); /* can't return 0 */ 276218885Sdim} 277218885Sdim