OsdSchedule.c revision 133627
1/*- 2 * Copyright (c) 2000 Michael Smith 3 * Copyright (c) 2000 BSDi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/dev/acpica/Osd/OsdSchedule.c 133627 2004-08-13 06:22:26Z njl $ 28 */ 29 30/* 31 * 6.3 : Scheduling services 32 */ 33 34#include "opt_acpi.h" 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38#include <sys/interrupt.h> 39#include <sys/kernel.h> 40#include <sys/kthread.h> 41#include <sys/malloc.h> 42#include <sys/proc.h> 43#include <sys/taskqueue.h> 44#include <machine/clock.h> 45 46#include "acpi.h" 47#include <dev/acpica/acpivar.h> 48 49#define _COMPONENT ACPI_OS_SERVICES 50ACPI_MODULE_NAME("SCHEDULE") 51 52/* 53 * This is a little complicated due to the fact that we need to build and then 54 * free a 'struct task' for each task we enqueue. 55 */ 56 57MALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task"); 58 59static void AcpiOsExecuteQueue(void *arg, int pending); 60 61struct acpi_task { 62 struct task at_task; 63 OSD_EXECUTION_CALLBACK at_function; 64 void *at_context; 65}; 66 67struct acpi_task_queue { 68 STAILQ_ENTRY(acpi_task_queue) at_q; 69 struct acpi_task *at; 70}; 71 72/* 73 * Private task queue definition for ACPI 74 */ 75TASKQUEUE_DECLARE(acpi); 76static void *taskqueue_acpi_ih; 77 78static void 79taskqueue_acpi_enqueue(void *context) 80{ 81 swi_sched(taskqueue_acpi_ih, 0); 82} 83 84static void 85taskqueue_acpi_run(void *dummy) 86{ 87 taskqueue_run(taskqueue_acpi); 88} 89 90TASKQUEUE_DEFINE(acpi, taskqueue_acpi_enqueue, 0, 91 swi_add(NULL, "acpitaskq", taskqueue_acpi_run, NULL, 92 SWI_TQ, 0, &taskqueue_acpi_ih)); 93 94static STAILQ_HEAD(, acpi_task_queue) acpi_task_queue; 95ACPI_LOCK_DECL(taskq, "ACPI task queue"); 96 97static void 98acpi_task_thread(void *arg) 99{ 100 struct acpi_task_queue *atq; 101 OSD_EXECUTION_CALLBACK Function; 102 void *Context; 103 104 ACPI_LOCK(taskq); 105 for (;;) { 106 while ((atq = STAILQ_FIRST(&acpi_task_queue)) == NULL) 107 msleep(&acpi_task_queue, &taskq_mutex, PCATCH, "actask", 0); 108 STAILQ_REMOVE_HEAD(&acpi_task_queue, at_q); 109 ACPI_UNLOCK(taskq); 110 111 Function = (OSD_EXECUTION_CALLBACK)atq->at->at_function; 112 Context = atq->at->at_context; 113 114 Function(Context); 115 116 free(atq->at, M_ACPITASK); 117 free(atq, M_ACPITASK); 118 ACPI_LOCK(taskq); 119 } 120 121 kthread_exit(0); 122} 123 124int 125acpi_task_thread_init(void) 126{ 127 int i, err; 128 struct proc *acpi_kthread_proc; 129 130 err = 0; 131 STAILQ_INIT(&acpi_task_queue); 132 133 for (i = 0; i < ACPI_MAX_THREADS; i++) { 134 err = kthread_create(acpi_task_thread, NULL, &acpi_kthread_proc, 135 0, 0, "acpi_task%d", i); 136 if (err != 0) { 137 printf("%s: kthread_create failed(%d)\n", __func__, err); 138 break; 139 } 140 } 141 return (err); 142} 143 144/* This function is called in interrupt context. */ 145ACPI_STATUS 146AcpiOsQueueForExecution(UINT32 Priority, OSD_EXECUTION_CALLBACK Function, 147 void *Context) 148{ 149 struct acpi_task *at; 150 int pri; 151 152 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 153 154 if (Function == NULL) 155 return_ACPI_STATUS (AE_BAD_PARAMETER); 156 157 at = malloc(sizeof(*at), M_ACPITASK, M_NOWAIT | M_ZERO); 158 if (at == NULL) 159 return_ACPI_STATUS (AE_NO_MEMORY); 160 161 at->at_function = Function; 162 at->at_context = Context; 163 switch (Priority) { 164 case OSD_PRIORITY_GPE: 165 pri = 4; 166 break; 167 case OSD_PRIORITY_HIGH: 168 pri = 3; 169 break; 170 case OSD_PRIORITY_MED: 171 pri = 2; 172 break; 173 case OSD_PRIORITY_LO: 174 pri = 1; 175 break; 176 default: 177 free(at, M_ACPITASK); 178 return_ACPI_STATUS (AE_BAD_PARAMETER); 179 } 180 TASK_INIT(&at->at_task, pri, AcpiOsExecuteQueue, at); 181 182 taskqueue_enqueue(taskqueue_acpi, (struct task *)at); 183 184 return_ACPI_STATUS (AE_OK); 185} 186 187static void 188AcpiOsExecuteQueue(void *arg, int pending) 189{ 190 struct acpi_task_queue *atq; 191 OSD_EXECUTION_CALLBACK Function; 192 void *Context; 193 194 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 195 196 atq = NULL; 197 Function = NULL; 198 Context = NULL; 199 200 atq = malloc(sizeof(*atq), M_ACPITASK, M_NOWAIT); 201 if (atq == NULL) { 202 printf("%s: no memory\n", __func__); 203 return; 204 } 205 atq->at = (struct acpi_task *)arg; 206 207 ACPI_LOCK(taskq); 208 STAILQ_INSERT_TAIL(&acpi_task_queue, atq, at_q); 209 wakeup_one(&acpi_task_queue); 210 ACPI_UNLOCK(taskq); 211 212 return_VOID; 213} 214 215void 216AcpiOsSleep(UINT32 Seconds, UINT32 Milliseconds) 217{ 218 int timo; 219 static int dummy; 220 221 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 222 223 timo = (Seconds * hz) + Milliseconds * hz / 1000; 224 225 /* 226 * If requested sleep time is less than our hz resolution, use 227 * DELAY instead for better granularity. 228 */ 229 if (timo > 0) 230 tsleep(&dummy, 0, "acpislp", timo); 231 else 232 DELAY(Milliseconds * 1000); 233 234 return_VOID; 235} 236 237void 238AcpiOsStall(UINT32 Microseconds) 239{ 240 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