OsdSchedule.c revision 249132
175374Sbp/*- 275374Sbp * Copyright (c) 2000 Michael Smith 375374Sbp * Copyright (c) 2000 BSDi 475374Sbp * Copyright (c) 2007-2009 Jung-uk Kim <jkim@FreeBSD.org> 5124087Stjr * All rights reserved. 6124087Stjr * 7124087Stjr * Redistribution and use in source and binary forms, with or without 875374Sbp * modification, are permitted provided that the following conditions 975374Sbp * are met: 1075374Sbp * 1. Redistributions of source code must retain the above copyright 1175374Sbp * notice, this list of conditions and the following disclaimer. 1275374Sbp * 2. Redistributions in binary form must reproduce the above copyright 1375374Sbp * notice, this list of conditions and the following disclaimer in the 1475374Sbp * documentation and/or other materials provided with the distribution. 1575374Sbp * 1675374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1775374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1875374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1975374Sbp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2075374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2175374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2275374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2375374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2475374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2575374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2675374Sbp * SUCH DAMAGE. 2775374Sbp */ 2875374Sbp 2975374Sbp/* 3075374Sbp * 6.3 : Scheduling services 3175374Sbp */ 3275374Sbp 3375374Sbp#include <sys/cdefs.h> 3475374Sbp__FBSDID("$FreeBSD: stable/9/sys/dev/acpica/Osd/OsdSchedule.c 249132 2013-04-05 08:22:11Z mav $"); 35116189Sobrien 36116189Sobrien#include "opt_acpi.h" 37116189Sobrien#include <sys/param.h> 38116189Sobrien#include <sys/systm.h> 3975374Sbp#include <sys/bus.h> 4075374Sbp#include <sys/interrupt.h> 4175374Sbp#include <sys/kernel.h> 4275374Sbp#include <sys/kthread.h> 4375374Sbp#include <sys/malloc.h> 4475374Sbp#include <sys/proc.h> 4575374Sbp#include <sys/taskqueue.h> 4675374Sbp 4775374Sbp#include <contrib/dev/acpica/include/acpi.h> 4875374Sbp#include <contrib/dev/acpica/include/accommon.h> 49124087Stjr 50124087Stjr#include <dev/acpica/acpivar.h> 51124087Stjr 5275374Sbp#define _COMPONENT ACPI_OS_SERVICES 53124087StjrACPI_MODULE_NAME("SCHEDULE") 5475374Sbp 5575374Sbp/* 5675374Sbp * Allow the user to tune the maximum number of tasks we may enqueue. 5775374Sbp */ 5875374Sbpstatic int acpi_max_tasks = ACPI_MAX_TASKS; 59124087StjrTUNABLE_INT("debug.acpi.max_tasks", &acpi_max_tasks); 6075374Sbp 6175374Sbp/* 6275374Sbp * Allow the user to tune the number of task threads we start. It seems 6375374Sbp * some systems have problems with increased parallelism. 6475374Sbp */ 6575374Sbpstatic int acpi_max_threads = ACPI_MAX_THREADS; 6675374SbpTUNABLE_INT("debug.acpi.max_threads", &acpi_max_threads); 6775374Sbp 6875374Sbpstatic MALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task"); 6975374Sbp 7075374Sbpstruct acpi_task_ctx { 7175374Sbp struct task at_task; 7275374Sbp ACPI_OSD_EXEC_CALLBACK at_function; 7375374Sbp void *at_context; 7475374Sbp int at_flag; 7575374Sbp#define ACPI_TASK_FREE 0 7675374Sbp#define ACPI_TASK_USED 1 7775374Sbp#define ACPI_TASK_ENQUEUED 2 7875374Sbp}; 7975374Sbp 8075374Sbpstruct taskqueue *acpi_taskq; 8175374Sbpstatic struct acpi_task_ctx *acpi_tasks; 8275374Sbpstatic int acpi_task_count; 8375374Sbpstatic int acpi_taskq_started; 8475374Sbp 85111119Simp/* 8678064Sume * Preallocate some memory for tasks early enough. 8778064Sume * malloc(9) cannot be used with spin lock held. 8875374Sbp */ 8975374Sbpstatic void 9075374Sbpacpi_task_init(void *arg) 9175374Sbp{ 9275374Sbp 9375374Sbp acpi_tasks = malloc(sizeof(*acpi_tasks) * acpi_max_tasks, M_ACPITASK, 9475374Sbp M_WAITOK | M_ZERO); 9575374Sbp} 9675374Sbp 9775374SbpSYSINIT(acpi_tasks, SI_SUB_DRIVERS, SI_ORDER_FIRST, acpi_task_init, NULL); 9875374Sbp 99111119Simp/* 10075374Sbp * Initialize ACPI task queue. 10175374Sbp */ 10275374Sbpstatic void 10375374Sbpacpi_taskq_init(void *arg) 10475374Sbp{ 10575374Sbp int i; 10675374Sbp 10775374Sbp acpi_taskq = taskqueue_create_fast("acpi_task", M_NOWAIT, 10875374Sbp &taskqueue_thread_enqueue, &acpi_taskq); 10975374Sbp taskqueue_start_threads(&acpi_taskq, acpi_max_threads, PWAIT, "acpi_task"); 11075374Sbp if (acpi_task_count > 0) { 11175374Sbp if (bootverbose) 11275374Sbp printf("AcpiOsExecute: enqueue %d pending tasks\n", 11375374Sbp acpi_task_count); 11475374Sbp for (i = 0; i < acpi_max_tasks; i++) 11575374Sbp if (atomic_cmpset_int(&acpi_tasks[i].at_flag, ACPI_TASK_USED, 11675374Sbp ACPI_TASK_USED | ACPI_TASK_ENQUEUED)) 11775374Sbp taskqueue_enqueue(acpi_taskq, &acpi_tasks[i].at_task); 11875374Sbp } 11975374Sbp acpi_taskq_started = 1; 12075374Sbp} 12175374Sbp 12275374SbpSYSINIT(acpi_taskq, SI_SUB_CONFIGURE, SI_ORDER_SECOND, acpi_taskq_init, NULL); 12375374Sbp 12475374Sbp/* 12575374Sbp * Bounce through this wrapper function since ACPI-CA doesn't understand 12675374Sbp * the pending argument for its callbacks. 12775374Sbp */ 12875374Sbpstatic void 12975374Sbpacpi_task_execute(void *context, int pending) 13075374Sbp{ 13175374Sbp struct acpi_task_ctx *at; 132111119Simp 13375374Sbp at = (struct acpi_task_ctx *)context; 13475374Sbp at->at_function(at->at_context); 13575374Sbp atomic_clear_int(&at->at_flag, ACPI_TASK_USED | ACPI_TASK_ENQUEUED); 13675374Sbp acpi_task_count--; 137111119Simp} 13875374Sbp 13975374Sbpstatic ACPI_STATUS 14075374Sbpacpi_task_enqueue(int priority, ACPI_OSD_EXEC_CALLBACK Function, void *Context) 14175374Sbp{ 14275374Sbp struct acpi_task_ctx *at; 14375374Sbp int i; 14475374Sbp 14575374Sbp for (at = NULL, i = 0; i < acpi_max_tasks; i++) 14675374Sbp if (atomic_cmpset_int(&acpi_tasks[i].at_flag, ACPI_TASK_FREE, 14775374Sbp ACPI_TASK_USED)) { 14875374Sbp at = &acpi_tasks[i]; 14975374Sbp acpi_task_count++; 15075374Sbp break; 15175374Sbp } 15275374Sbp if (at == NULL) { 15375374Sbp printf("AcpiOsExecute: failed to enqueue task, consider increasing " 15475374Sbp "the debug.acpi.max_tasks tunable\n"); 15575374Sbp return (AE_NO_MEMORY); 156124087Stjr } 157124087Stjr 158124087Stjr TASK_INIT(&at->at_task, priority, acpi_task_execute, at); 159124087Stjr at->at_function = Function; 160124087Stjr at->at_context = Context; 161124087Stjr 162124087Stjr /* 163124087Stjr * If the task queue is ready, enqueue it now. 164124087Stjr */ 165124087Stjr if (acpi_taskq_started) { 166124087Stjr atomic_set_int(&at->at_flag, ACPI_TASK_ENQUEUED); 167124087Stjr taskqueue_enqueue(acpi_taskq, &at->at_task); 168124087Stjr return (AE_OK); 169124087Stjr } 170124087Stjr if (bootverbose) 171124087Stjr printf("AcpiOsExecute: task queue not started\n"); 172124087Stjr 173124087Stjr return (AE_OK); 174124087Stjr} 175124087Stjr 176124087Stjr/* 177124087Stjr * This function may be called in interrupt context, i.e. when a GPE fires. 178124087Stjr * We allocate and queue a task for one of our taskqueue threads to process. 179124087Stjr */ 180124087StjrACPI_STATUS 181124087StjrAcpiOsExecute(ACPI_EXECUTE_TYPE Type, ACPI_OSD_EXEC_CALLBACK Function, 182124087Stjr void *Context) 183124087Stjr{ 184124087Stjr int pri; 185124087Stjr 186124087Stjr ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 187124087Stjr 188124087Stjr if (Function == NULL) 189124087Stjr return_ACPI_STATUS (AE_BAD_PARAMETER); 190124087Stjr 191124087Stjr switch (Type) { 192124087Stjr case OSL_GPE_HANDLER: 193124087Stjr case OSL_NOTIFY_HANDLER: 194124087Stjr /* 195124087Stjr * Run GPEs and Notifies at the same priority. This allows 196124087Stjr * Notifies that are generated by running a GPE's method (e.g., _L00) 197124087Stjr * to not be pre-empted by a later GPE that arrives during the 198124087Stjr * Notify handler execution. 199124087Stjr */ 200124087Stjr pri = 10; 201124087Stjr break; 202124087Stjr case OSL_GLOBAL_LOCK_HANDLER: 203124087Stjr case OSL_EC_POLL_HANDLER: 204124087Stjr case OSL_EC_BURST_HANDLER: 205124087Stjr pri = 5; 206124087Stjr break; 207124087Stjr case OSL_DEBUGGER_THREAD: 208124087Stjr pri = 0; 209124087Stjr break; 210124087Stjr default: 211124087Stjr return_ACPI_STATUS (AE_BAD_PARAMETER); 212124087Stjr } 213124087Stjr 214124087Stjr return_ACPI_STATUS (acpi_task_enqueue(pri, Function, Context)); 215124087Stjr} 216124087Stjr 217124087Stjrvoid 218124087StjrAcpiOsSleep(UINT64 Milliseconds) 219124087Stjr{ 220124087Stjr int timo; 221124087Stjr 222124087Stjr ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 223124087Stjr 224124087Stjr timo = Milliseconds * hz / 1000; 225124087Stjr 226124087Stjr /* 227124087Stjr * If requested sleep time is less than our hz resolution, use 228124087Stjr * DELAY instead for better granularity. 229124087Stjr */ 230124087Stjr if (timo > 0) 231124087Stjr pause("acpislp", timo); 232124087Stjr else 233124087Stjr DELAY(Milliseconds * 1000); 234124087Stjr 235124087Stjr return_VOID; 236124087Stjr} 237124087Stjr 238124087Stjr/* 239124087Stjr * Return the current time in 100 nanosecond units 240124087Stjr */ 241124087StjrUINT64 242124087StjrAcpiOsGetTimer(void) 243124087Stjr{ 244124087Stjr struct bintime bt; 245124087Stjr UINT64 t; 246124087Stjr 247124087Stjr /* XXX During early boot there is no (decent) timer available yet. */ 248124087Stjr KASSERT(cold == 0, ("acpi: timer op not yet supported during boot")); 249124087Stjr 250124087Stjr binuptime(&bt); 251124087Stjr t = ((UINT64)10000000 * (uint32_t)(bt.frac >> 32)) >> 32; 252124087Stjr t += bt.sec * 10000000; 253124087Stjr 254124087Stjr return (t); 255124087Stjr} 256124087Stjr 257124087Stjrvoid 258124087StjrAcpiOsStall(UINT32 Microseconds) 259124087Stjr{ 260124087Stjr ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 261124087Stjr 262124087Stjr DELAY(Microseconds); 263124087Stjr return_VOID; 264124087Stjr} 265124087Stjr 266124087StjrACPI_THREAD_ID 267124087StjrAcpiOsGetThreadId(void) 268124087Stjr{ 269124087Stjr 270124087Stjr /* XXX do not add ACPI_FUNCTION_TRACE here, results in recursive call. */ 271124087Stjr 272124087Stjr /* Returning 0 is not allowed. */ 273124087Stjr return (curthread->td_tid); 274124087Stjr} 275124087Stjr