1c1dac77fSApple OSS Distributions /* 214e3d835SApple OSS Distributions * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved. 3c1dac77fSApple OSS Distributions * 4e13b1fa5SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5c1dac77fSApple OSS Distributions * 6e13b1fa5SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code 7e13b1fa5SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License 8e13b1fa5SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in 9e13b1fa5SApple OSS Distributions * compliance with the License. The rights granted to you under the License 10e13b1fa5SApple OSS Distributions * may not be used to create, or enable the creation or redistribution of, 11e13b1fa5SApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to 12e13b1fa5SApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any 13e13b1fa5SApple OSS Distributions * terms of an Apple operating system software license agreement. 14c1dac77fSApple OSS Distributions * 15e13b1fa5SApple OSS Distributions * Please obtain a copy of the License at 16e13b1fa5SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file. 17e13b1fa5SApple OSS Distributions * 18e13b1fa5SApple OSS Distributions * The Original Code and all software distributed under the License are 19e13b1fa5SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20c1dac77fSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21c1dac77fSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22e13b1fa5SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23e13b1fa5SApple OSS Distributions * Please see the License for the specific language governing rights and 24e13b1fa5SApple OSS Distributions * limitations under the License. 25c1dac77fSApple OSS Distributions * 26e13b1fa5SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27c1dac77fSApple OSS Distributions */ 28c1dac77fSApple OSS Distributions /* 29c1dac77fSApple OSS Distributions Copyright (c) 1998 Apple Computer, Inc. All rights reserved. 30c1dac77fSApple OSS Distributions 31c1dac77fSApple OSS Distributions HISTORY 32c1dac77fSApple OSS Distributions 1998-7-13 Godfrey van der Linden(gvdl) 33c1dac77fSApple OSS Distributions Created. 34c1dac77fSApple OSS Distributions ]*/ 35*3ca3bd55SApple OSS Distributions 36*3ca3bd55SApple OSS Distributions #if !defined(__LP64__) 37*3ca3bd55SApple OSS Distributions 38c1dac77fSApple OSS Distributions #include <IOKit/IOCommandQueue.h> 39c1dac77fSApple OSS Distributions #include <IOKit/IOWorkLoop.h> 40c1dac77fSApple OSS Distributions #include <IOKit/IOTimeStamp.h> 41c1dac77fSApple OSS Distributions 42c1dac77fSApple OSS Distributions #include <mach/sync_policy.h> 43c1dac77fSApple OSS Distributions 44*3ca3bd55SApple OSS Distributions 45c1dac77fSApple OSS Distributions #define NUM_FIELDS_IN_COMMAND 4 46c1dac77fSApple OSS Distributions typedef struct commandEntryTag { 47c1dac77fSApple OSS Distributions void *f[NUM_FIELDS_IN_COMMAND]; 48c1dac77fSApple OSS Distributions } commandEntryT; 49c1dac77fSApple OSS Distributions 50c1dac77fSApple OSS Distributions #define super IOEventSource 51c1dac77fSApple OSS Distributions 52c1dac77fSApple OSS Distributions OSDefineMetaClassAndStructors(IOCommandQueue, IOEventSource) 53c1dac77fSApple OSS Distributions 54c1dac77fSApple OSS Distributions /*[ 55c1dac77fSApple OSS Distributions Instance Methods 56c1dac77fSApple OSS Distributions 57c1dac77fSApple OSS Distributions initWithNext:owner:action:size: 58c1dac77fSApple OSS Distributions - initWithNext: (IOEventSource *) inNext 59c1dac77fSApple OSS Distributions owner: (id) inOwner 60c1dac77fSApple OSS Distributions action: (SEL) inAction 61c1dac77fSApple OSS Distributions size: (int) inSize; 62c1dac77fSApple OSS Distributions 63c1dac77fSApple OSS Distributions Primary initialiser for the IOCommandQueue class. Returns an 64c1dac77fSApple OSS Distributions IOCommandQueue object that is initialised with the next object in 65c1dac77fSApple OSS Distributions the chain and the owner and action. On return the signalWorkAvailableIMP 66c1dac77fSApple OSS Distributions has been cached for this function. 67c1dac77fSApple OSS Distributions 68c1dac77fSApple OSS Distributions If the object fails to initialise for some reason then [self free] will 69c1dac77fSApple OSS Distributions be called and nil will be returned. 70c1dac77fSApple OSS Distributions 71c1dac77fSApple OSS Distributions See also: initWithNext:owner:action:(IOEventSource) 72c1dac77fSApple OSS Distributions ]*/ 73c1dac77fSApple OSS Distributions bool IOCommandQueue::init(OSObject *inOwner, 74c1dac77fSApple OSS Distributions IOCommandQueueAction inAction, 75c1dac77fSApple OSS Distributions int inSize) 76c1dac77fSApple OSS Distributions { 77c1dac77fSApple OSS Distributions if ( !super::init(inOwner, (IOEventSourceAction) inAction) ) 78c1dac77fSApple OSS Distributions return false; 79c1dac77fSApple OSS Distributions 80c1dac77fSApple OSS Distributions if (KERN_SUCCESS 81c1dac77fSApple OSS Distributions != semaphore_create(kernel_task, &producerSema, SYNC_POLICY_FIFO, inSize)) 82c1dac77fSApple OSS Distributions return false; 83c1dac77fSApple OSS Distributions 84c1dac77fSApple OSS Distributions size = inSize + 1; /* Allocate one more entry than needed */ 85c1dac77fSApple OSS Distributions 86c1dac77fSApple OSS Distributions queue = (void *)kalloc(size * sizeof(commandEntryT)); 87c1dac77fSApple OSS Distributions if (!queue) 88c1dac77fSApple OSS Distributions return false; 89c1dac77fSApple OSS Distributions 90c1dac77fSApple OSS Distributions producerLock = IOLockAlloc(); 91c1dac77fSApple OSS Distributions if (!producerLock) 92c1dac77fSApple OSS Distributions return false; 93c1dac77fSApple OSS Distributions 94c1dac77fSApple OSS Distributions producerIndex = consumerIndex = 0; 95c1dac77fSApple OSS Distributions 96c1dac77fSApple OSS Distributions return true; 97c1dac77fSApple OSS Distributions } 98c1dac77fSApple OSS Distributions 99c1dac77fSApple OSS Distributions IOCommandQueue * 100c1dac77fSApple OSS Distributions IOCommandQueue::commandQueue(OSObject *inOwner, 101c1dac77fSApple OSS Distributions IOCommandQueueAction inAction, 102c1dac77fSApple OSS Distributions int inSize) 103c1dac77fSApple OSS Distributions { 104c1dac77fSApple OSS Distributions IOCommandQueue *me = new IOCommandQueue; 105c1dac77fSApple OSS Distributions 106c1dac77fSApple OSS Distributions if (me && !me->init(inOwner, inAction, inSize)) { 107c1dac77fSApple OSS Distributions me->free(); 108c1dac77fSApple OSS Distributions return 0; 109c1dac77fSApple OSS Distributions } 110c1dac77fSApple OSS Distributions 111c1dac77fSApple OSS Distributions return me; 112c1dac77fSApple OSS Distributions } 113c1dac77fSApple OSS Distributions 114c1dac77fSApple OSS Distributions /*[ 115c1dac77fSApple OSS Distributions free 116c1dac77fSApple OSS Distributions - free 117c1dac77fSApple OSS Distributions 118c1dac77fSApple OSS Distributions Mandatory free of the object independent of the current retain count. 119c1dac77fSApple OSS Distributions Returns nil. 120c1dac77fSApple OSS Distributions ]*/ 121c1dac77fSApple OSS Distributions void IOCommandQueue::free() 122c1dac77fSApple OSS Distributions { 123c1dac77fSApple OSS Distributions if (queue) 12414e3d835SApple OSS Distributions kfree(queue, size * sizeof(commandEntryT)); 125c1dac77fSApple OSS Distributions if (producerSema) 126c1dac77fSApple OSS Distributions semaphore_destroy(kernel_task, producerSema); 127c1dac77fSApple OSS Distributions if (producerLock) 128c1dac77fSApple OSS Distributions IOLockFree(producerLock); 129c1dac77fSApple OSS Distributions 130c1dac77fSApple OSS Distributions super::free(); 131c1dac77fSApple OSS Distributions } 132c1dac77fSApple OSS Distributions 133c1dac77fSApple OSS Distributions #if NUM_FIELDS_IN_COMMAND != 4 134c1dac77fSApple OSS Distributions #error IOCommandQueue::checkForWork needs to be updated for new command size 135c1dac77fSApple OSS Distributions #endif 136c1dac77fSApple OSS Distributions 137c1dac77fSApple OSS Distributions bool IOCommandQueue::checkForWork() 138c1dac77fSApple OSS Distributions { 139c1dac77fSApple OSS Distributions void *field0, *field1, *field2, *field3; 140c1dac77fSApple OSS Distributions 141c1dac77fSApple OSS Distributions if (!enabled || consumerIndex == producerIndex) 142c1dac77fSApple OSS Distributions return false; 143c1dac77fSApple OSS Distributions 144c1dac77fSApple OSS Distributions { 145c1dac77fSApple OSS Distributions commandEntryT *q = (commandEntryT *) queue; 146c1dac77fSApple OSS Distributions int localIndex = consumerIndex; 147c1dac77fSApple OSS Distributions 148c1dac77fSApple OSS Distributions field0 = q[localIndex].f[0]; field1 = q[localIndex].f[1]; 149c1dac77fSApple OSS Distributions field2 = q[localIndex].f[2]; field3 = q[localIndex].f[3]; 150c1dac77fSApple OSS Distributions semaphore_signal(producerSema); 151c1dac77fSApple OSS Distributions } 152c1dac77fSApple OSS Distributions 153c1dac77fSApple OSS Distributions if (++consumerIndex >= size) 154c1dac77fSApple OSS Distributions consumerIndex = 0; 155c1dac77fSApple OSS Distributions 156c1dac77fSApple OSS Distributions IOTimeStampConstant(IODBG_CMDQ(IOCMDQ_ACTION), 157*3ca3bd55SApple OSS Distributions (uintptr_t) action, (uintptr_t) owner); 158c1dac77fSApple OSS Distributions 159c1dac77fSApple OSS Distributions (*(IOCommandQueueAction) action)(owner, field0, field1, field2, field3); 160c1dac77fSApple OSS Distributions 161c1dac77fSApple OSS Distributions return (consumerIndex != producerIndex); 162c1dac77fSApple OSS Distributions } 163c1dac77fSApple OSS Distributions 164c1dac77fSApple OSS Distributions /*[ 165c1dac77fSApple OSS Distributions enqueueSleep:command: 166c1dac77fSApple OSS Distributions - (kern_return_t) enqueueSleepRaw: (BOOL) gotoSleep 167c1dac77fSApple OSS Distributions field0: (void *) field0 field1: (void *) field1 168c1dac77fSApple OSS Distributions field2: (void *) field2 field3: (void *) field3; 169c1dac77fSApple OSS Distributions 170c1dac77fSApple OSS Distributions Key method that enqueues the four input fields onto the command queue 171c1dac77fSApple OSS Distributions and calls signalWorkAvailable to indicate that work is available to the 172c1dac77fSApple OSS Distributions consumer. This routine is safe against multiple threaded producers. 173c1dac77fSApple OSS Distributions 174c1dac77fSApple OSS Distributions A family of convenience functions have been provided to assist with the 175c1dac77fSApple OSS Distributions enqueueing of an method selector and an integer tag. This relies on the 176c1dac77fSApple OSS Distributions IODevice rawCommandOccurred... command to forward on the requests. 177c1dac77fSApple OSS Distributions 178c1dac77fSApple OSS Distributions See also: signalWorkAvailable, checkForWork 179c1dac77fSApple OSS Distributions ]*/ 180c1dac77fSApple OSS Distributions #if NUM_FIELDS_IN_COMMAND != 4 181c1dac77fSApple OSS Distributions #error IOCommandQueue::enqueueCommand needs to be updated 182c1dac77fSApple OSS Distributions #endif 183c1dac77fSApple OSS Distributions 184c1dac77fSApple OSS Distributions kern_return_t 185c1dac77fSApple OSS Distributions IOCommandQueue::enqueueCommand(bool gotoSleep, 186c1dac77fSApple OSS Distributions void *field0, void *field1, 187c1dac77fSApple OSS Distributions void *field2, void *field3) 188c1dac77fSApple OSS Distributions { 189c1dac77fSApple OSS Distributions kern_return_t rtn = KERN_SUCCESS; 190c1dac77fSApple OSS Distributions int retry; 191c1dac77fSApple OSS Distributions 192c1dac77fSApple OSS Distributions /* Make sure there is room in the queue before doing anything else */ 193c1dac77fSApple OSS Distributions 194c1dac77fSApple OSS Distributions if (gotoSleep) { 195c1dac77fSApple OSS Distributions retry = 0; 196c1dac77fSApple OSS Distributions do 197c1dac77fSApple OSS Distributions rtn = semaphore_wait(producerSema); 198c1dac77fSApple OSS Distributions while( (KERN_SUCCESS != rtn) 199c1dac77fSApple OSS Distributions && (KERN_OPERATION_TIMED_OUT != rtn) 200c1dac77fSApple OSS Distributions && (KERN_SEMAPHORE_DESTROYED != rtn) 201c1dac77fSApple OSS Distributions && (KERN_TERMINATED != rtn) 202c1dac77fSApple OSS Distributions && ((retry++) < 4)); 203c1dac77fSApple OSS Distributions } else 204c1dac77fSApple OSS Distributions rtn = semaphore_timedwait(producerSema, MACH_TIMESPEC_ZERO); 205c1dac77fSApple OSS Distributions 206c1dac77fSApple OSS Distributions if (KERN_SUCCESS != rtn) 207c1dac77fSApple OSS Distributions return rtn; 208c1dac77fSApple OSS Distributions 209c1dac77fSApple OSS Distributions /* Block other producers */ 210c1dac77fSApple OSS Distributions IOTakeLock(producerLock); 211c1dac77fSApple OSS Distributions 212c1dac77fSApple OSS Distributions /* 213c1dac77fSApple OSS Distributions * Make sure that we update the current producer entry before we 214c1dac77fSApple OSS Distributions * increment the producer pointer. This avoids a nasty race as the 215c1dac77fSApple OSS Distributions * as the test for work is producerIndex != consumerIndex and a signal. 216c1dac77fSApple OSS Distributions */ 217c1dac77fSApple OSS Distributions { 218c1dac77fSApple OSS Distributions commandEntryT *q = (commandEntryT *) queue; 219c1dac77fSApple OSS Distributions int localIndex = producerIndex; 220c1dac77fSApple OSS Distributions 221c1dac77fSApple OSS Distributions q[localIndex].f[0] = field0; q[localIndex].f[1] = field1; 222c1dac77fSApple OSS Distributions q[localIndex].f[2] = field2; q[localIndex].f[3] = field3; 223c1dac77fSApple OSS Distributions } 224c1dac77fSApple OSS Distributions if (++producerIndex >= size) 225c1dac77fSApple OSS Distributions producerIndex = 0; 226c1dac77fSApple OSS Distributions 227c1dac77fSApple OSS Distributions /* Clear to allow other producers to go now */ 228c1dac77fSApple OSS Distributions IOUnlock(producerLock); 229c1dac77fSApple OSS Distributions 230c1dac77fSApple OSS Distributions /* 231c1dac77fSApple OSS Distributions * Right we have created some new work, we had better make sure that 232c1dac77fSApple OSS Distributions * we notify the work loop that it has to test producerIndex. 233c1dac77fSApple OSS Distributions */ 234c1dac77fSApple OSS Distributions signalWorkAvailable(); 235c1dac77fSApple OSS Distributions return rtn; 236c1dac77fSApple OSS Distributions } 237c1dac77fSApple OSS Distributions 238c1dac77fSApple OSS Distributions int IOCommandQueue::performAndFlush(OSObject *target, 239c1dac77fSApple OSS Distributions IOCommandQueueAction inAction) 240c1dac77fSApple OSS Distributions { 241c1dac77fSApple OSS Distributions int numEntries; 242c1dac77fSApple OSS Distributions kern_return_t rtn; 243c1dac77fSApple OSS Distributions 244c1dac77fSApple OSS Distributions // Set the defaults if necessary 245c1dac77fSApple OSS Distributions if (!target) 246c1dac77fSApple OSS Distributions target = owner; 247c1dac77fSApple OSS Distributions if (!inAction) 248c1dac77fSApple OSS Distributions inAction = (IOCommandQueueAction) action; 249c1dac77fSApple OSS Distributions 250c1dac77fSApple OSS Distributions // Lock out the producers first 251c1dac77fSApple OSS Distributions do { 252c1dac77fSApple OSS Distributions rtn = semaphore_timedwait(producerSema, MACH_TIMESPEC_ZERO); 253c1dac77fSApple OSS Distributions } while (rtn == KERN_SUCCESS); 254c1dac77fSApple OSS Distributions 255c1dac77fSApple OSS Distributions // now step over all remaining entries in the command queue 256c1dac77fSApple OSS Distributions for (numEntries = 0; consumerIndex != producerIndex; ) { 257c1dac77fSApple OSS Distributions void *field0, *field1, *field2, *field3; 258c1dac77fSApple OSS Distributions 259c1dac77fSApple OSS Distributions { 260c1dac77fSApple OSS Distributions commandEntryT *q = (commandEntryT *) queue; 261c1dac77fSApple OSS Distributions int localIndex = consumerIndex; 262c1dac77fSApple OSS Distributions 263c1dac77fSApple OSS Distributions field0 = q[localIndex].f[0]; field1 = q[localIndex].f[1]; 264c1dac77fSApple OSS Distributions field2 = q[localIndex].f[2]; field3 = q[localIndex].f[3]; 265c1dac77fSApple OSS Distributions } 266c1dac77fSApple OSS Distributions 267c1dac77fSApple OSS Distributions if (++consumerIndex >= size) 268c1dac77fSApple OSS Distributions consumerIndex = 0; 269c1dac77fSApple OSS Distributions 270c1dac77fSApple OSS Distributions (*inAction)(target, field0, field1, field2, field3); 271c1dac77fSApple OSS Distributions } 272c1dac77fSApple OSS Distributions 273c1dac77fSApple OSS Distributions // finally refill the producer semaphore to size - 1 274c1dac77fSApple OSS Distributions for (int i = 1; i < size; i++) 275c1dac77fSApple OSS Distributions semaphore_signal(producerSema); 276c1dac77fSApple OSS Distributions 277c1dac77fSApple OSS Distributions return numEntries; 278c1dac77fSApple OSS Distributions } 279*3ca3bd55SApple OSS Distributions 280*3ca3bd55SApple OSS Distributions #endif /* !defined(__LP64__) */ 281