1/* 2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22/* 23 * IOOutputQueue.cpp 24 * 25 * HISTORY 26 * 2-Feb-1999 Joe Liu (jliu) created. 27 * 28 */ 29 30#include <IOKit/assert.h> 31#include <IOKit/IOWorkLoop.h> 32#include <IOKit/network/IOOutputQueue.h> 33#include <IOKit/network/IOBasicOutputQueue.h> 34#include <IOKit/network/IOGatedOutputQueue.h> 35#include <IOKit/network/IONetworkStats.h> 36#include <IOKit/network/IONetworkController.h> 37#include "IOMbufQueue.h" 38#include <libkern/OSAtomic.h> 39 40//=========================================================================== 41// IOOutputQueue 42//=========================================================================== 43 44#define STATE_IS(bits) (_state == (bits)) 45#define STATE_HAS(bits) ((_state & (bits)) == (bits)) 46#define STATE_SET(bits) (_state |= (bits)) 47#define STATE_CLR(bits) (_state &= ~(bits)) 48 49#undef super 50#define super OSObject 51OSDefineMetaClassAndAbstractStructors( IOOutputQueue, OSObject ) 52OSMetaClassDefineReservedUnused( IOOutputQueue, 1); 53OSMetaClassDefineReservedUnused( IOOutputQueue, 2); 54OSMetaClassDefineReservedUnused( IOOutputQueue, 3); 55OSMetaClassDefineReservedUnused( IOOutputQueue, 4); 56OSMetaClassDefineReservedUnused( IOOutputQueue, 5); 57OSMetaClassDefineReservedUnused( IOOutputQueue, 6); 58OSMetaClassDefineReservedUnused( IOOutputQueue, 7); 59OSMetaClassDefineReservedUnused( IOOutputQueue, 8); 60OSMetaClassDefineReservedUnused( IOOutputQueue, 9); 61OSMetaClassDefineReservedUnused( IOOutputQueue, 10); 62OSMetaClassDefineReservedUnused( IOOutputQueue, 11); 63OSMetaClassDefineReservedUnused( IOOutputQueue, 12); 64OSMetaClassDefineReservedUnused( IOOutputQueue, 13); 65OSMetaClassDefineReservedUnused( IOOutputQueue, 14); 66OSMetaClassDefineReservedUnused( IOOutputQueue, 15); 67 68//--------------------------------------------------------------------------- 69// Initialize an IOOutputQueue object. 70 71bool IOOutputQueue::init() 72{ 73 if (super::init() == false) 74 return false; 75 76 // Allocate and initialize the callout entry for async service. 77 78 _callEntry = thread_call_allocate((thread_call_func_t) &runServiceThread, 79 (void *) this); /* param0 */ 80 if (_callEntry == 0) 81 return false; 82 83 return true; 84} 85 86//--------------------------------------------------------------------------- 87// Frees the IOOutputQueue object. 88 89void IOOutputQueue::free() 90{ 91 if (_callEntry) 92 { 93 cancelServiceThread(); 94 thread_call_free(_callEntry); 95 _callEntry = 0; 96 } 97 98 super::free(); 99} 100 101//--------------------------------------------------------------------------- 102// Schedule a service thread callout, which will run the 103// serviceThread() method. 104 105bool IOOutputQueue::scheduleServiceThread(void * param) 106{ 107 return thread_call_enter1(_callEntry, (thread_call_param_t) param); 108} 109 110//--------------------------------------------------------------------------- 111// Cancel any pending service thread callout. 112 113bool IOOutputQueue::cancelServiceThread() 114{ 115 if (_callEntry == 0) 116 return false; 117 else 118 return thread_call_cancel(_callEntry); 119} 120 121//--------------------------------------------------------------------------- 122// A 'C' glue function that is registered as the service thread callout 123// handler. This function in turn will call the serviceThread() method. 124 125void 126IOOutputQueue::runServiceThread(thread_call_param_t param0, /* this */ 127 thread_call_param_t param1) /* param */ 128{ 129 assert(param0); 130 ((IOOutputQueue *) param0)->serviceThread(param1); 131} 132 133//--------------------------------------------------------------------------- 134// Must be implemented by a subclass that calls scheduleServiceThread(). 135// The default implementation is a placeholder and performs no action. 136 137void IOOutputQueue::serviceThread(void * param) 138{ 139} 140 141//--------------------------------------------------------------------------- 142// Return an address of a method that is designated to handle 143// packets sent to the queue object. 144 145IOOutputAction IOOutputQueue::getOutputHandler() const 146{ 147 return (IOOutputAction) &IOOutputQueue::enqueue; 148} 149 150//--------------------------------------------------------------------------- 151// Return an IONetworkData object containing statistics counters. 152 153IONetworkData * IOOutputQueue::getStatisticsData() const 154{ 155 return 0; 156} 157 158OSMetaClassDefineReservedUsed( IOOutputQueue, 0); 159//--------------------------------------------------------------------------- 160// Retrieve a packet's priority, to be overridden by subclasses 161 162UInt32 IOOutputQueue::getMbufPriority(mbuf_t m) 163{ 164 return 0; 165} 166 167//=========================================================================== 168// IOBasicOutputQueue 169//=========================================================================== 170 171#undef super 172#define super IOOutputQueue 173OSDefineMetaClassAndStructors( IOBasicOutputQueue, IOOutputQueue ) 174 175#define QUEUE_LOCK IOLockLock(_queueLock) 176#define QUEUE_UNLOCK IOLockUnlock(_queueLock) 177 178#define kIOOutputQueueSignature ((void *) 0xfacefeed) 179 180//--------------------------------------------------------------------------- 181// 'C' function glue to dispatch the IONetworkData notification. 182 183IOReturn 184IOBasicOutputQueue::dispatchNetworkDataNotification(void * target, 185 void * param, 186 IONetworkData * data, 187 UInt32 type) 188{ 189 IOBasicOutputQueue * self = (IOBasicOutputQueue *) target; 190 return self->handleNetworkDataAccess(data, type, param); 191} 192 193//--------------------------------------------------------------------------- 194// Initialize an IOBasicOutputQueue object. 195 196bool IOBasicOutputQueue::init(OSObject * target, 197 IOOutputAction action, 198 UInt32 capacity, 199 UInt32 priorities) 200{ 201 if (super::init() == false) 202 return false; 203 204 if ((target == 0) || (action == 0) || (priorities == 0) || (priorities > 256)) 205 return false; 206 207 _target = target; 208 _action = action; 209 210 // Create a data object for queue statistics. 211 212 _statsData = IONetworkData::withInternalBuffer( 213 kIOOutputQueueStatsKey, 214 sizeof(IOOutputQueueStats), 215 kIONetworkDataBasicAccessTypes, 216 this, 217 (IONetworkData::Action) 218 &IOBasicOutputQueue::dispatchNetworkDataNotification, 219 kIOOutputQueueSignature); 220 221 if (_statsData == 0) 222 return false; 223 224 _stats = (IOOutputQueueStats *) _statsData->getBuffer(); 225 assert(_stats); 226 227 _stats->capacity = capacity; 228 229 // Create queue objects 230 _priorities = priorities; 231 _primaryQueues = IONew(IOMbufQueue, priorities); 232 _shadowQueues = IONew(IOMbufQueue, priorities); 233 234 if ( (_primaryQueues == 0) || (_shadowQueues == 0) ) 235 return false; 236 237 // Initialize queues 238 for(UInt32 i = 0; i < priorities; i++) 239 { 240 IOMbufQueueInit(&(_primaryQueues[i]), capacity); 241 IOMbufQueueInit(&(_shadowQueues[i]), capacity); 242 } 243 244 _inQueues = _primaryQueues; 245 246 // Create a lock to protect the queue. 247 248 _queueLock = IOLockAlloc(); 249 if (_queueLock == 0) 250 return false; 251 252 return true; 253} 254 255//--------------------------------------------------------------------------- 256// Factory methods that will construct and initialize an IOBasicOutputQueue 257// object. 258 259IOBasicOutputQueue * 260IOBasicOutputQueue::withTarget(IONetworkController * target, 261 UInt32 capacity) 262{ 263 return IOBasicOutputQueue::withTarget(target, capacity, 1 /* priorities */); 264} 265 266IOBasicOutputQueue * 267IOBasicOutputQueue::withTarget(IONetworkController * target, 268 UInt32 capacity, 269 UInt32 priorities) 270{ 271 IOBasicOutputQueue * queue = new IOBasicOutputQueue; 272 273 if (queue && !queue->init(target, target->getOutputHandler(), capacity, priorities)) 274 { 275 queue->release(); 276 queue = 0; 277 } 278 return queue; 279} 280 281IOBasicOutputQueue * 282IOBasicOutputQueue::withTarget(OSObject * target, 283 IOOutputAction action, 284 UInt32 capacity) 285{ 286 return IOBasicOutputQueue::withTarget(target, action, capacity, 1 /* priorities */); 287} 288 289IOBasicOutputQueue * 290IOBasicOutputQueue::withTarget(OSObject * target, 291 IOOutputAction action, 292 UInt32 capacity, 293 UInt32 priorities) 294{ 295 IOBasicOutputQueue * queue = new IOBasicOutputQueue; 296 297 if (queue && !queue->init(target, action, capacity, priorities)) 298 { 299 queue->release(); 300 queue = 0; 301 } 302 return queue; 303} 304 305//--------------------------------------------------------------------------- 306// Release all resources previously allocated before calling super::free(). 307 308void IOBasicOutputQueue::free() 309{ 310 cancelServiceThread(); 311 312 if (_queueLock) 313 { 314 flush(); 315 IOLockFree(_queueLock); 316 _queueLock = 0; 317 } 318 319 if(_primaryQueues) IODelete(_primaryQueues, IOMbufQueue, _priorities); 320 if(_shadowQueues) IODelete(_shadowQueues, IOMbufQueue, _priorities); 321 _primaryQueues = _shadowQueues = 0; 322 323 if (_statsData) 324 { 325 _statsData->release(); 326 _statsData = 0; 327 } 328 329 super::free(); 330} 331 332//--------------------------------------------------------------------------- 333// Provide an implementation for the serviceThread() method defined in 334// IOOutputQueue. This method is called by a callout thread after an 335// asynchronous service was scheduled. 336 337void IOBasicOutputQueue::serviceThread(void * param) 338{ 339 QUEUE_LOCK; 340 STATE_CLR((uintptr_t) param); 341 STATE_SET(kStateOutputActive); 342 dequeue(); 343 QUEUE_UNLOCK; 344} 345 346//--------------------------------------------------------------------------- 347// Add a single packet, or a chain of packets, to the queue object. 348// This method can support multiple clients threads. 349 350UInt32 IOBasicOutputQueue::enqueue(mbuf_t m, void * param) 351{ 352 bool success; 353 354 UInt32 priority = getMbufPriority(m); 355 356 // Set out-of-bounds priority to lowest 357 if ( priority >= _priorities ) 358 { 359 priority = _priorities - 1; 360 } 361 362 QUEUE_LOCK; 363 364 success = IOMbufQueueEnqueue(&(_inQueues[priority]), m); 365 366 if ( STATE_IS( kStateRunning ) ) 367 { 368 STATE_SET( kStateOutputActive ); 369 dequeue(); 370 } 371 372 QUEUE_UNLOCK; 373 374 // Drop the packet if the packet(s) were not queued. 375 // But avoid calling m_free() while holding a simple lock. 376 // This will not be necessary in the future when m_free() 377 // is no longer funneled. 378 379 if (success == false) 380 { 381 OSAddAtomic( IOMbufFree(m), 382 (SInt32 *) &_stats->dropCount ); 383 } 384 385 return 0; 386} 387 388//--------------------------------------------------------------------------- 389// Responsible for removing all packets from the queue and pass each packet 390// removed to our target. This method returns when the queue becomes empty 391// or if the queue is stalled by the target. This method is called with the 392// queue lock held. 393 394void IOBasicOutputQueue::dequeue() 395{ 396 IOMbufQueue * outQueues = _primaryQueues; 397 UInt32 newState = 0; 398 UInt32 myServiceCount; 399 400 // Switch the input queue. Work on the real queue, while allowing 401 // clients to continue to queue packets to the "shadow" queue. 402 403 _inQueues = _shadowQueues; 404 405 // While dequeue is allowed, and incoming queue has packets. 406 407 UInt32 priority = 0; 408 while ( STATE_IS( kStateRunning | kStateOutputActive ) && 409 priority < _priorities ) 410 { 411 if (IOMbufQueueGetSize(&(outQueues[priority])) > 0) 412 { 413 myServiceCount = _serviceCount; 414 415 QUEUE_UNLOCK; 416 417 output( &(outQueues[priority]), &newState ); 418 419 QUEUE_LOCK; 420 421 // If driver called service() while the queue lock was released, 422 // refuse to honor any stall requests and re-attempt transmission. 423 424 if ( newState ) 425 { 426 if ( myServiceCount != _serviceCount ) 427 newState &= ~kStateOutputStalled; 428 429 STATE_SET( newState ); 430 } 431 432 // Absorb new packets added to the shadow queues. 433 // Must empty all shadow queues since the loop might exit 434 // before servicing all priority levels due to driver stall. 435 436 int newPriority = -1; 437 for (UInt32 i = 0; i < _priorities; i++) 438 { 439 IOMbufQueueEnqueue( &(outQueues[i]), &(_inQueues[i])); 440 441 if ((newPriority < 0) && (i <= priority) && 442 (IOMbufQueueGetSize(&(outQueues[i])) > 0)) 443 { 444 newPriority = i; 445 } 446 } 447 448 // Service higher or equal priority mbufs if they arrived while 449 // the queue lock was dropped. 450 451 if (newPriority >= 0) 452 { 453 priority = newPriority; 454 continue; 455 } 456 } 457 458 priority++; 459 } 460 461 _inQueues = _primaryQueues; 462 463 STATE_CLR( kStateOutputActive ); 464 465 if ( newState & kStateOutputServiceMask ) 466 { 467 scheduleServiceThread( 468 (void *)(uintptr_t) (newState & kStateOutputServiceMask)); 469 } 470 471 if (_waitDequeueDone) 472 { 473 // A stop() request is waiting for the transmit thread to 474 // complete transmission. Wake up the waiting thread. 475 476 _waitDequeueDone = false; 477 thread_wakeup((void *) &_waitDequeueDone); 478 } 479} 480 481//--------------------------------------------------------------------------- 482// Transfer all packets from the given queue to the target. Continue until 483// the queue becomes empty, or if the target throttle the queue. 484 485void IOBasicOutputQueue::output(IOMbufQueue * queue, UInt32 * state) 486{ 487 mbuf_t pkt; 488 UInt32 status; 489 490 do { 491 pkt = IOMbufQueueDequeue(queue); 492 assert(pkt); 493 494 // Handoff each packet to the controller driver. 495 496 status = (_target->*_action)( pkt, 0 ); 497 498 if ( status == ( kIOOutputStatusAccepted | kIOOutputCommandNone ) ) 499 { 500 // Fast-path the typical code path. 501 _stats->outputCount++; 502 } 503 else 504 { 505 // Look at the return status and update statistics counters. 506 507 switch (status & kIOOutputStatusMask) 508 { 509 default: 510 case kIOOutputStatusAccepted: 511 _stats->outputCount++; 512 break; 513 514 case kIOOutputStatusRetry: 515 IOMbufQueuePrepend(queue, pkt); 516 _stats->retryCount++; 517 break; 518 } 519 520 // Handle the requested action. 521 522 switch (status & kIOOutputCommandMask) 523 { 524 case kIOOutputCommandStall: 525 *state = kStateOutputStalled; 526 _stats->stallCount++; 527 break; 528 529 default: 530 break; 531 } 532 } 533 } 534 while ( IOMbufQueueGetSize(queue) && (*state == 0) ); 535} 536 537//--------------------------------------------------------------------------- 538// Start or enable the queue. 539 540bool IOBasicOutputQueue::start() 541{ 542 QUEUE_LOCK; 543 544 STATE_SET( kStateRunning ); 545 STATE_CLR( kStateOutputStalled ); 546 _serviceCount++; 547 548 if ( STATE_IS( kStateRunning ) ) 549 { 550 STATE_SET( kStateOutputActive ); 551 dequeue(); 552 } 553 554 QUEUE_UNLOCK; 555 556 return true; /* always return true */ 557} 558 559//--------------------------------------------------------------------------- 560// Stop or disable the queue. 561 562bool IOBasicOutputQueue::stop() 563{ 564 bool wasRunning; 565 566 QUEUE_LOCK; 567 568 wasRunning = STATE_HAS( kStateRunning ); 569 570 STATE_CLR( kStateRunning ); 571 572 if ( STATE_HAS( kStateOutputActive ) ) 573 { 574 // If dequeue is active, it means that: 575 // 1. A thread is about to call dequeue(). 576 // 2. A thread is in dequeue() and calling the target. 577 // 578 // Wait for the dequeue thread to complete processing. 579 580 _waitDequeueDone = true; 581 582 assert_wait((void *) &_waitDequeueDone, false); 583 } 584 585 QUEUE_UNLOCK; 586 587 thread_block((void (*)(void*, int)) 0); 588 589 return wasRunning; 590} 591 592//--------------------------------------------------------------------------- 593// If the queue becomes stalled, then service() must be called by the target 594// to restart the queue when the target is ready to accept more packets. 595 596bool IOBasicOutputQueue::service(IOOptionBits options) 597{ 598 bool doDequeue = false; 599 bool async = (options & kServiceAsync); 600 UInt32 oldState; 601 602 QUEUE_LOCK; 603 604 oldState = _state; 605 606 // Clear the stall condition. 607 608 STATE_CLR( kStateOutputStalled ); 609 _serviceCount++; 610 611 bool workToDo = false; 612 for(UInt32 i = 0; i < _priorities; i++) 613 { 614 if(IOMbufQueueGetSize(&(_primaryQueues[i])) > 0) 615 { 616 workToDo = true; 617 break; 618 } 619 } 620 621 if ( ( oldState & kStateOutputStalled ) && 622 STATE_IS( kStateRunning ) && 623 workToDo ) 624 { 625 doDequeue = true; 626 STATE_SET( kStateOutputActive ); 627 if (async == false) dequeue(); 628 } 629 630 QUEUE_UNLOCK; 631 632 if ( doDequeue && async ) 633 { 634 scheduleServiceThread(); 635 } 636 637 return doDequeue; 638} 639 640//--------------------------------------------------------------------------- 641// Release all packets held by the queue. 642 643UInt32 IOBasicOutputQueue::flush() 644{ 645 UInt32 flushCount; 646 mbuf_t m; 647 for(UInt32 i = 0; i < _priorities; i++) 648 { 649 QUEUE_LOCK; 650 m = IOMbufQueueDequeueAll( &(_inQueues[i]) ); 651 QUEUE_UNLOCK; 652 flushCount = IOMbufFree(m); 653 OSAddAtomic(flushCount, (SInt32 *) &_stats->dropCount); 654 } 655 return flushCount; 656} 657 658//--------------------------------------------------------------------------- 659// Change the capacity of the queue. 660 661bool IOBasicOutputQueue::setCapacity(UInt32 capacity) 662{ 663 QUEUE_LOCK; 664 for(UInt32 i = 0; i < _priorities; i++) 665 { 666 IOMbufQueueSetCapacity(&(_primaryQueues[i]), capacity); 667 IOMbufQueueSetCapacity(&(_shadowQueues[i]), capacity); 668 } 669 _stats->capacity = capacity * _priorities; 670 QUEUE_UNLOCK; 671 return true; 672} 673 674//--------------------------------------------------------------------------- 675// Returns the current queue capacity. 676 677UInt32 IOBasicOutputQueue::getCapacity() const 678{ 679 return _stats->capacity; 680} 681 682//--------------------------------------------------------------------------- 683// Returns the current queue size. 684 685UInt32 IOBasicOutputQueue::getSize() const 686{ 687 UInt32 total = 0; 688 for(UInt32 i = 0; i < _priorities; i++) 689 { 690 total += IOMbufQueueGetSize(&(_primaryQueues[i])); 691 } 692 return total; 693} 694 695//--------------------------------------------------------------------------- 696// Returns the number of packets dropped by the queue due to over-capacity. 697 698UInt32 IOBasicOutputQueue::getDropCount() 699{ 700 return _stats->dropCount; 701} 702 703//--------------------------------------------------------------------------- 704// Returns the number of packet passed to the target. 705 706UInt32 IOBasicOutputQueue::getOutputCount() 707{ 708 return _stats->outputCount; 709} 710 711//--------------------------------------------------------------------------- 712// Returns the number of times that a kIOOutputStatusRetry status code 713// is received from the target. 714 715UInt32 IOBasicOutputQueue::getRetryCount() 716{ 717 return _stats->retryCount; 718} 719 720//--------------------------------------------------------------------------- 721// Returns the number of times that a kIOOutputCommandStall action code 722// is received from the target. 723 724UInt32 IOBasicOutputQueue::getStallCount() 725{ 726 return _stats->stallCount; 727} 728 729//--------------------------------------------------------------------------- 730// Returns the current state of the queue object. 731 732UInt32 IOBasicOutputQueue::getState() const 733{ 734 return _state; 735} 736 737//--------------------------------------------------------------------------- 738// This method is called by our IONetworkData object when it receives 739// a read or a reset request. We need to be notified to intervene in 740// the request handling. 741 742IOReturn 743IOBasicOutputQueue::handleNetworkDataAccess(IONetworkData * data, 744 UInt32 accessType, 745 void * arg) 746{ 747 IOReturn ret = kIOReturnSuccess; 748 749 assert(data && (arg == kIOOutputQueueSignature)); 750 751 // Check the type of data request. 752 753 switch (accessType) 754 { 755 case kIONetworkDataAccessTypeRead: 756 case kIONetworkDataAccessTypeSerialize: 757 { 758 UInt32 size; 759 QUEUE_LOCK; 760 size = getSize(); // _primaryQueues 761 for(UInt32 i = 0; i < _priorities; i++) 762 { 763 size += IOMbufQueueGetSize(&(_shadowQueues[i])); 764 } 765 QUEUE_UNLOCK; 766 _stats->size = size; 767 break; 768 } 769 770 default: 771 ret = kIOReturnNotWritable; 772 break; 773 } 774 775 return ret; 776} 777 778//--------------------------------------------------------------------------- 779// Return an IONetworkData object containing an IOOutputQueueStats structure. 780 781IONetworkData * IOBasicOutputQueue::getStatisticsData() const 782{ 783 return _statsData; 784} 785 786//=========================================================================== 787// IOGatedOutputQueue 788//=========================================================================== 789 790#undef super 791#define super IOBasicOutputQueue 792OSDefineMetaClassAndStructors( IOGatedOutputQueue, IOBasicOutputQueue ) 793 794//--------------------------------------------------------------------------- 795// Initialize an IOGatedOutputQueue object. 796 797bool IOGatedOutputQueue::init(OSObject * target, 798 IOOutputAction action, 799 IOWorkLoop * workloop, 800 UInt32 capacity, 801 UInt32 priorities) 802{ 803 if (super::init(target, action, capacity, priorities) == false) 804 return false; 805 806 // Verify that the IOWorkLoop provided is valid. 807 808 if (OSDynamicCast(IOWorkLoop, workloop) == 0) 809 return false; 810 811 // Allocate and attach an IOCommandGate object to the workloop. 812 813 _gate = IOCommandGate::commandGate(this); 814 815 if (!_gate || (workloop->addEventSource(_gate) != kIOReturnSuccess)) 816 return false; 817 818 // Allocate and attach an IOInterruptEventSource object to the workloop. 819 820 _interruptSrc = IOInterruptEventSource::interruptEventSource( 821 this, 822 (IOInterruptEventSource::Action) restartDeferredOutput 823 ); 824 825 if ( !_interruptSrc || 826 (workloop->addEventSource(_interruptSrc) != kIOReturnSuccess) ) 827 return false; 828 829 return true; 830} 831 832//--------------------------------------------------------------------------- 833// Factory methods that will construct and initialize an IOGatedOutputQueue 834// object. 835 836IOGatedOutputQueue * 837IOGatedOutputQueue::withTarget(IONetworkController * target, 838 IOWorkLoop * workloop, 839 UInt32 capacity) 840{ 841 return IOGatedOutputQueue::withTarget(target, workloop, capacity, 1 /* priorities */); 842} 843 844IOGatedOutputQueue * 845IOGatedOutputQueue::withTarget(IONetworkController * target, 846 IOWorkLoop * workloop, 847 UInt32 capacity, 848 UInt32 priorities) 849{ 850 IOGatedOutputQueue * queue = new IOGatedOutputQueue; 851 852 if (queue && !queue->init(target, target->getOutputHandler(), workloop, 853 capacity, priorities)) 854 { 855 queue->release(); 856 queue = 0; 857 } 858 return queue; 859} 860 861IOGatedOutputQueue * 862IOGatedOutputQueue::withTarget(OSObject * target, 863 IOOutputAction action, 864 IOWorkLoop * workloop, 865 UInt32 capacity) 866{ 867 return IOGatedOutputQueue::withTarget(target, action, workloop, capacity, 1 /* priorities */); 868} 869 870IOGatedOutputQueue * 871IOGatedOutputQueue::withTarget(OSObject * target, 872 IOOutputAction action, 873 IOWorkLoop * workloop, 874 UInt32 capacity, 875 UInt32 priorities) 876{ 877 IOGatedOutputQueue * queue = new IOGatedOutputQueue; 878 879 if (queue && !queue->init(target, action, workloop, capacity, priorities)) 880 { 881 queue->release(); 882 queue = 0; 883 } 884 return queue; 885} 886 887//--------------------------------------------------------------------------- 888// Free the IOGatedOutputQueue object. 889 890void IOGatedOutputQueue::free() 891{ 892 cancelServiceThread(); 893 894 if (_gate) 895 { 896 IOWorkLoop *wl = _gate->getWorkLoop(); 897 if(wl) wl->removeEventSource(_gate); 898 _gate->release(); 899 _gate = 0; 900 } 901 902 if (_interruptSrc) 903 { 904 IOWorkLoop * wl = _interruptSrc->getWorkLoop(); 905 if (wl) wl->removeEventSource(_interruptSrc); 906 _interruptSrc->release(); 907 _interruptSrc = 0; 908 } 909 910 super::free(); 911} 912 913//--------------------------------------------------------------------------- 914// Called by an IOCommandGate object. 915 916void IOGatedOutputQueue::gatedOutput(OSObject * /* owner */, 917 IOGatedOutputQueue * self, 918 IOMbufQueue * queue, 919 UInt32 * state) 920{ 921 mbuf_t pkt; 922 UInt32 status; 923 924 do { 925 pkt = IOMbufQueueDequeue(queue); 926 assert(pkt); 927 928 // Handoff the packet to the controller driver. 929 930 status = ((self->_target)->*(self->_action))( pkt, 0 ); 931 932 if ( status == ( kIOOutputStatusAccepted | kIOOutputCommandNone ) ) 933 { 934 // Fast-path the typical code path. 935 self->_stats->outputCount++; 936 } 937 else 938 { 939 // Look at the return status and update statistics counters. 940 941 switch (status & kIOOutputStatusMask) 942 { 943 default: 944 case kIOOutputStatusAccepted: 945 self->_stats->outputCount++; 946 break; 947 948 case kIOOutputStatusRetry: 949 IOMbufQueuePrepend(queue, pkt); 950 self->_stats->retryCount++; 951 break; 952 } 953 954 // Handle the requested action. 955 956 switch (status & kIOOutputCommandMask) 957 { 958 case kIOOutputCommandStall: 959 *state = kStateOutputStalled; 960 self->_stats->stallCount++; 961 break; 962 963 default: 964 break; 965 } 966 } 967 } 968 while ( IOMbufQueueGetSize(queue) && (*state == 0) ); 969} 970 971//--------------------------------------------------------------------------- 972// Called by our superclass to output all packets in the packet queue given. 973 974enum { 975 kStateOutputDeferred = 0x100 976}; 977 978void IOGatedOutputQueue::output(IOMbufQueue * queue, UInt32 * state) 979{ 980 if ( _gate->attemptAction((IOCommandGate::Action) 981 &IOGatedOutputQueue::gatedOutput, 982 (void *) this, 983 (void *) queue, 984 (void *) state) == kIOReturnCannotLock ) 985 { 986 *state = kStateOutputDeferred; 987 } 988} 989 990bool IOGatedOutputQueue::scheduleServiceThread(void * param) 991{ 992 if ( ((uintptr_t) param) & kStateOutputDeferred ) 993 { 994 _interruptSrc->interruptOccurred(0, 0, 0); 995 return true; 996 } 997 else 998 { 999 return super::scheduleServiceThread(param); 1000 } 1001} 1002 1003void IOGatedOutputQueue::restartDeferredOutput( 1004 OSObject * owner, 1005 IOInterruptEventSource * sender, 1006 int count) 1007{ 1008 IOGatedOutputQueue * self = (IOGatedOutputQueue *) owner; 1009 self->serviceThread((void *) kStateOutputDeferred); 1010} 1011