]> git.saurik.com Git - apple/xnu.git/blame - iokit/Drivers/network/drvIntel82557/i82557.cpp
xnu-124.13.tar.gz
[apple/xnu.git] / iokit / Drivers / network / drvIntel82557 / i82557.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, 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 * Copyright (c) 1996 NeXT Software, Inc. All rights reserved.
24 *
25 * i82557.cpp
26 *
27 * HISTORY
28 *
29 * 22-Jan-96 Dieter Siegmund (dieter) at NeXT
30 * Created.
31 *
32 * 03-May-96 Dieter Siegmund (dieter) at NeXT
33 * Added a real ISR to improve performance.
34 *
35 * 10-June-96 Dieter Siegmund (dieter) at NeXT
36 * Added support for Splash 3 (10 Base-T only card).
37 *
38 * 18-June-96 Dieter Siegmund (dieter) at NeXT
39 * Keep the transmit queue draining by interrupting every
40 * N / 2 transmits (where N is the size of the hardware queue).
41 *
42 * 15-Dec-97 Joe Liu (jliu) at Apple
43 * Updated PHY programming to be 82558 aware.
44 * Misc changes to conform to new 82558 register flags.
45 * Changed RNR interrupt handler to restart RU instead of a reset.
46 * Interrupt handler now does a thread_call_func() to do most of its work.
47 * Interrupts are disabled until the thread callout finishes its work.
48 * Increased the size of TX/RX rings.
49 * buffer object removed, we use cluster mbufs to back up the receive ring.
50 *
51 * 29-May-98 Joe Liu (jliu) at Apple
52 * Updated _setupPhy method to take advantage of parallel detection whenever
53 * possible in order to detect the proper link speed.
54 *
55 * 17-Aug-98 Joe Liu (jliu) at Apple
56 * Re-enabled the setting of txready_sel PHY (PCS) bit for DP83840.
57 * Simplified interrupt handling, resulting in RCV performance improvements.
58 * Receive packets are sent upstream via a cached function pointer.
59 */
60
61#include "i82557.h"
62
63#define ONE_SECOND_TICKS 1000
64#define LOAD_STATISTICS_INTERVAL (4 * ONE_SECOND_TICKS)
65
66#define super IOEthernetController
67OSDefineMetaClassAndStructors( Intel82557, IOEthernetController )
68
69//---------------------------------------------------------------------------
70// Function: pciConfigInit
71//
72// Update PCI command register to enable the memory-mapped range,
73// and bus-master interface.
74
75bool Intel82557::pciConfigInit(IOPCIDevice * provider)
76{
77 UInt32 reg;
78
79 reg = provider->configRead32( kIOPCIConfigCommand );
80
81 reg |= ( kIOPCICommandBusMaster |
82 kIOPCICommandMemorySpace |
83 kIOPCICommandMemWrInvalidate );
84
85 reg &= ~kIOPCICommandIOSpace; // disable I/O space
86
87 provider->configWrite32( kIOPCIConfigCommand, reg );
88
89 return true;
90}
91
92//---------------------------------------------------------------------------
93// Function: initDriver
94//
95// Create and initialize driver objects before the hardware is
96// enabled.
97//
98// Returns true on sucess, and false if initialization failed.
99
100bool Intel82557::initDriver(IOService * provider)
101{
102 currentMediumType = MEDIUM_TYPE_INVALID;
103
104 // This driver will allocate and use an IOGatedOutputQueue.
105 //
106 transmitQueue = getOutputQueue();
107 if ( transmitQueue == 0 ) return false;
108
109 // Allocate two IOMbufLittleMemoryCursor instances. One for transmit and
110 // the other for receive.
111 //
112 rxMbufCursor = IOMbufLittleMemoryCursor::withSpecification(MAX_BUF_SIZE,1);
113 txMbufCursor = IOMbufLittleMemoryCursor::withSpecification(MAX_BUF_SIZE,
114 TBDS_PER_TCB);
115 if (!rxMbufCursor || !txMbufCursor)
116 return false;
117
118 // Get a handle to our superclass' workloop.
119 //
120 IOWorkLoop * myWorkLoop = (IOWorkLoop *) getWorkLoop();
121 if (!myWorkLoop)
122 return false;
123
124 // Create and register an interrupt event source. The provider will
125 // take care of the low-level interrupt registration stuff.
126 //
127 interruptSrc =
128 IOInterruptEventSource::interruptEventSource(this,
129 (IOInterruptEventAction) &Intel82557::interruptOccurred,
130 provider);
131
132 if (!interruptSrc ||
133 (myWorkLoop->addEventSource(interruptSrc) != kIOReturnSuccess))
134 return false;
135
136 // Register a timer event source. This is used as a watchdog timer.
137 //
138 timerSrc = IOTimerEventSource::timerEventSource( this,
139 (IOTimerEventSource::Action) &Intel82557::timeoutOccurred );
140 if (!timerSrc ||
141 (myWorkLoop->addEventSource(timerSrc) != kIOReturnSuccess))
142 return false;
143
144 // Create a dictionary to hold IONetworkMedium objects.
145 //
146 mediumDict = OSDictionary::withCapacity(5);
147 if (!mediumDict)
148 return false;
149
150 return true;
151}
152
153//---------------------------------------------------------------------------
154// Function: getDefaultSettings
155//
156// Get the default driver settings chosen by the user. The properties
157// are all stored in our property table (an OSDictionary).
158
159bool Intel82557::getDefaultSettings()
160{
161 OSNumber * numObj;
162 OSBoolean * boolObj;
163
164 // Check for PHY address override.
165 //
166 phyAddr = PHY_ADDRESS_DEFAULT;
167 numObj = OSDynamicCast( OSNumber, getProperty("PHY Address") );
168 if ( numObj )
169 {
170 phyAddr = numObj->unsigned32BitValue();
171 }
172
173 // Check for Verbose flag.
174 //
175 verbose = false;
176 boolObj = OSDynamicCast( OSBoolean, getProperty("Verbose") );
177 if ( boolObj && boolObj->isTrue() )
178 {
179 IOLog("%s: verbose mode enabled\n", getName());
180 verbose = true;
181 }
182
183 // Check for Flow-Control enable flag.
184 //
185 flowControl = false;
186 boolObj = OSDynamicCast( OSBoolean, getProperty("Flow Control") );
187 if ( boolObj && boolObj->isTrue() )
188 {
189 IOLog("%s: 802.3x flow control enabled\n", getName());
190 flowControl = true;
191 }
192
193 return true;
194}
195
196//---------------------------------------------------------------------------
197// Function: start <IOService>
198//
199// Hardware was detected and initialized, start the driver.
200
201bool Intel82557::start( IOService * provider )
202{
203 bool ret = false;
204
205 do {
206 // Start our superclass first.
207
208 if ( super::start(provider) == false )
209 break;
210
211 // Cache our provider to an instance variable.
212
213 pciNub = OSDynamicCast(IOPCIDevice, provider);
214 if ( pciNub == 0 ) break;
215
216 // Retain provider, released in free().
217
218 pciNub->retain();
219
220 // Open our provider.
221
222 if ( pciNub->open(this) == false ) break;
223
224 // Initialize the driver's event sources and other support objects.
225
226 if ( initDriver(provider) == false ) break;
227
228 // Get the virtual address mapping of CSR registers located at
229 // Base Address Range 0 (0x10). The size of this range is 4K.
230
231 csrMap = pciNub->mapDeviceMemoryWithRegister( kIOPCIConfigBaseAddress0 );
232 if ( csrMap == 0 ) break;
233
234 CSR_p = (CSR_t *) csrMap->getVirtualAddress();
235
236 // Setup our PCI config space.
237
238 if ( pciConfigInit(pciNub) == false ) break;
239
240 // Create the EEPROM object.
241
242 eeprom = i82557eeprom::withAddress(&CSR_p->eepromControl);
243 if ( eeprom == 0 )
244 {
245 IOLog("%s: couldn't allocate eeprom object", getName());
246 break;
247 }
248
249 // Get default driver settings (stored in property table).
250
251 if ( getDefaultSettings() == false ) break;
252
253 if ( verbose ) eeprom->dumpContents();
254
255 // Execute one-time initialization code.
256
257 if ( coldInit() == false )
258 {
259 IOLog("%s: coldInit failed\n", getName());
260 break;
261 }
262
263 if ( hwInit() == false )
264 {
265 IOLog("%s: hwInit failed\n", getName());
266 break;
267 }
268
269 // Publish our media capabilities.
270
271 _phyPublishMedia();
272 if ( publishMediumDictionary(mediumDict) == false )
273 {
274 IOLog("%s: publishMediumDictionary failed\n", getName());
275 break;
276 }
277
278#if 0
279 // Announce the basic hardware configuration info.
280 IOLog("%s: Memory 0x%lx irq %d\n", getName(),
281 csrMap->getPhysicalAddress(), 0);
282#endif
283
284 ret = true;
285 }
286 while ( false );
287
288 // Close our provider, it will be re-opened on demand when
289 // our enable() is called.
290
291 if ( pciNub ) pciNub->close(this);
292
293 do {
294 if ( ret == false ) break;
295
296 ret = false;
297
298 // Allocate and attach an IOEthernetInterface instance to this driver
299 // object.
300
301 if ( attachInterface((IONetworkInterface **) &netif, false) == false )
302 break;
303
304 // Attach a kernel debugger client. This is not an essential service,
305 // and the return is not checked.
306
307 attachDebuggerClient(&debugger);
308
309 // Start matching for clients of IONetworkInterface.
310
311 netif->registerService();
312
313 ret = true;
314 }
315 while ( false );
316
317 return ret;
318}
319
320//---------------------------------------------------------------------------
321// Function: stop <IOService>
322//
323// Stop all activities and prepare for termination.
324
325void Intel82557::stop(IOService * provider)
326{
327 super::stop(provider);
328}
329
330//---------------------------------------------------------------------------
331// Function: createWorkLoop <IONetworkController>
332//
333// Override IONetworkController::createWorkLoop() method to create a workloop.
334
335bool Intel82557::createWorkLoop()
336{
337 workLoop = IOWorkLoop::workLoop();
338
339 return ( workLoop != 0 );
340}
341
342//---------------------------------------------------------------------------
343// Function: getWorkLoop <IOService>
344//
345// Override IOService::getWorkLoop() method to return our workloop.
346
347IOWorkLoop * Intel82557::getWorkLoop() const
348{
349 return workLoop;
350}
351
352//---------------------------------------------------------------------------
353// Function: configureInterface <IONetworkController>
354//
355// Configure a newly instantiated IONetworkInterface object.
356
357bool Intel82557::configureInterface(IONetworkInterface * netif)
358{
359 IONetworkData * data;
360
361 if ( super::configureInterface(netif) == false )
362 return false;
363
364 // Get the generic network statistics structure.
365
366 data = netif->getParameter(kIONetworkStatsKey);
367 if (!data || !(netStats = (IONetworkStats *) data->getBuffer())) {
368 return false;
369 }
370
371 // Get the Ethernet statistics structure.
372
373 data = netif->getParameter(kIOEthernetStatsKey);
374 if (!data || !(etherStats = (IOEthernetStats *) data->getBuffer())) {
375 return false;
376 }
377
378 return true;
379}
380
381//---------------------------------------------------------------------------
382// Function: free <IOService>
383//
384// Deallocate all resources and destroy the instance.
385
386void Intel82557::free()
387{
388 if (debugger) { debugger->release(); debugger = 0; }
389 if (netif) { netif->release(); netif = 0; }
390 if (interruptSrc) { interruptSrc->release(); interruptSrc = 0; }
391 if (timerSrc) { timerSrc->release(); timerSrc = 0; }
392 if (rxMbufCursor) { rxMbufCursor->release(); rxMbufCursor = 0; }
393 if (txMbufCursor) { txMbufCursor->release(); txMbufCursor = 0; }
394 if (csrMap) { csrMap->release(); csrMap = 0; }
395 if (eeprom) { eeprom->release(); eeprom = 0; }
396 if (mediumDict) { mediumDict->release(); mediumDict = 0; }
397 if ( pciNub ) { pciNub->release(); pciNub = 0; }
398 if ( workLoop ) { workLoop->release(); workLoop = 0; }
399
400 _freeMemPage( &shared );
401 _freeMemPage( &txRing );
402 _freeMemPage( &rxRing );
403
404 super::free(); // pass it to our superclass
405}
406
407//---------------------------------------------------------------------------
408// Function: enableAdapter
409//
410// Enables the adapter & driver to the given level of support.
411
412bool Intel82557::enableAdapter(UInt32 level)
413{
414 bool ret = false;
415
416// IOLog("%s::%s enabling level %ld\n", getName(), __FUNCTION__, level);
417
418 switch (level) {
419 case kActivationLevel1:
420
421 // Open provider.
422 //
423 if ( ( pciNub == 0 ) || ( pciNub->open(this) == false ) )
424 {
425 break;
426 }
427
428 if (!_initRingBuffers())
429 break;
430
431 if (!_startReceive()) {
432 _clearRingBuffers();
433 break;
434 }
435
436 // Set current medium.
437 //
438 if (setMedium(getCurrentMedium()) != kIOReturnSuccess)
439 IOLog("%s: setMedium error\n", getName());
440
441 // Start the watchdog timer.
442 //
443 timerSrc->setTimeoutMS(LOAD_STATISTICS_INTERVAL);
444
445 // Enable interrupt event sources and hardware interrupts.
446 //
447 if (getWorkLoop())
448 getWorkLoop()->enableAllInterrupts();
449 enableAdapterInterrupts();
450
451 // Force PHY to report link status.
452 //
453 _phyReportLinkStatus(true);
454
455 ret = true;
456 break;
457
458 case kActivationLevel2:
459 // Issue a dump statistics command.
460 //
461 _dumpStatistics();
462
463 // Start our IOOutputQueue object.
464 //
465 transmitQueue->setCapacity(TRANSMIT_QUEUE_SIZE);
466 transmitQueue->start();
467
468 ret = true;
469 break;
470 }
471
472 if (!ret)
473 IOLog("%s::%s error in level %ld\n", getName(), __FUNCTION__, level);
474
475 return ret;
476}
477
478//---------------------------------------------------------------------------
479// Function: disableAdapter
480//
481// Disables the adapter & driver to the given level of support.
482
483bool Intel82557::disableAdapter(UInt32 level)
484{
485 bool ret = false;
486
487// IOLog("%s::%s disabling level %ld\n", getName(), __FUNCTION__, level);
488
489 switch (level) {
490 case kActivationLevel1:
491 // Disable interrupt handling and hardware interrupt sources.
492 //
493 disableAdapterInterrupts();
494 if (getWorkLoop())
495 getWorkLoop()->disableAllInterrupts();
496
497 // Stop the timer event source, and initialize the watchdog state.
498 //
499 timerSrc->cancelTimeout();
500 packetsReceived = true; // assume we're getting packets
501 packetsTransmitted = false;
502 txCount = 0;
503
504 // Reset the hardware engine.
505 //
506 ret = hwInit();
507
508 // Clear the descriptor rings after the hardware is idle.
509 //
510 _clearRingBuffers();
511
512 // Report link status: unknown.
513 //
514 setLinkStatus(0, 0);
515
516 // Flush all packets held in the queue and prevent it
517 // from accumulating any additional packets.
518 //
519 transmitQueue->setCapacity(0);
520 transmitQueue->flush();
521
522 // Close provider.
523 //
524 if ( pciNub )
525 {
526 pciNub->close(this);
527 }
528
529 break;
530
531 case kActivationLevel2:
532 // Stop the transmit queue. outputPacket() will not get called
533 // after this.
534 //
535 transmitQueue->stop();
536
537 ret = true;
538 break;
539 }
540
541 if (!ret)
542 IOLog("%s::%s error in level %ld\n", getName(), __FUNCTION__, level);
543
544 return ret;
545}
546
547//---------------------------------------------------------------------------
548// Function: setActivationLevel
549//
550// Sets the adapter's activation level.
551//
552// kActivationLevel0 - Adapter is disabled.
553// kActivationLevel1 - Adapter is brought up just enough to support debugging.
554// kActivationLevel2 - Adapter is completely up.
555
556bool Intel82557::setActivationLevel(UInt32 level)
557{
558 bool ret = false;
559 UInt32 nextLevel;
560
561 // IOLog("---> DESIRED LEVEL : %d\n", level);
562
563 if (currentLevel == level) return true;
564
565 for ( ; currentLevel > level; currentLevel--)
566 {
567 if ( (ret = disableAdapter(currentLevel)) == false )
568 break;
569 }
570
571 for ( nextLevel = currentLevel + 1;
572 currentLevel < level;
573 currentLevel++, nextLevel++ )
574 {
575 if ( (ret = enableAdapter(nextLevel)) == false )
576 break;
577 }
578
579 // IOLog("---> PRESENT LEVEL : %d\n\n", currentLevel);
580
581 return ret;
582}
583
584//---------------------------------------------------------------------------
585// Function: enable <IONetworkController>
586//
587// A request from our interface client to enable the adapter.
588
589IOReturn Intel82557::enable(IONetworkInterface * /*netif*/)
590{
591 if ( enabledForNetif ) return kIOReturnSuccess;
592
593 enabledForNetif = setActivationLevel( kActivationLevel2 );
594
595 return ( enabledForNetif ? kIOReturnSuccess : kIOReturnIOError );
596}
597
598//---------------------------------------------------------------------------
599// Function: disable <IONetworkController>
600//
601// A request from our interface client to disable the adapter.
602
603IOReturn Intel82557::disable(IONetworkInterface * /*netif*/)
604{
605 enabledForNetif = false;
606
607 setActivationLevel( enabledForDebugger ?
608 kActivationLevel1 : kActivationLevel0 );
609
610 return kIOReturnSuccess;
611}
612
613//---------------------------------------------------------------------------
614// Function: enable <IONetworkController>
615//
616// A request from our debugger client to enable the adapter.
617
618IOReturn Intel82557::enable(IOKernelDebugger * /*debugger*/)
619{
620 if ( enabledForDebugger || enabledForNetif )
621 {
622 enabledForDebugger = true;
623 return kIOReturnSuccess;
624 }
625
626 enabledForDebugger = setActivationLevel( kActivationLevel1 );
627
628 return ( enabledForDebugger ? kIOReturnSuccess : kIOReturnIOError );
629}
630
631//---------------------------------------------------------------------------
632// Function: disable <IONetworkController>
633//
634// A request from our debugger client to disable the adapter.
635
636IOReturn Intel82557::disable(IOKernelDebugger * /*debugger*/)
637{
638 enabledForDebugger = false;
639
640 if ( enabledForNetif == false )
641 setActivationLevel( kActivationLevel0 );
642
643 return kIOReturnSuccess;
644}
645
646//---------------------------------------------------------------------------
647// Function: timeoutOccurred
648//
649// Periodic timer that monitors the receiver status, updates error
650// and collision statistics, and update the current link status.
651
652void Intel82557::timeoutOccurred(IOTimerEventSource * /*timer*/)
653{
654 if ( (packetsReceived == false) && (packetsTransmitted == true) )
655 {
656 /*
657 * The B-step of the i82557 requires that an mcsetup command be
658 * issued if the receiver stops receiving. This is a documented
659 * errata.
660 */
661 mcSetup(0, 0, true);
662 }
663 packetsReceived = packetsTransmitted = false;
664
665 _updateStatistics();
666
667 _phyReportLinkStatus();
668
669 timerSrc->setTimeoutMS(LOAD_STATISTICS_INTERVAL);
670}
671
672//---------------------------------------------------------------------------
673// Function: setPromiscuousMode <IOEthernetController>
674
675IOReturn Intel82557::setPromiscuousMode(IOEnetPromiscuousMode mode)
676{
677 bool rv;
678 promiscuousEnabled = (mode == kIOEnetPromiscuousModeOff) ? false : true;
679 reserveDebuggerLock();
680 rv = config();
681 releaseDebuggerLock();
682 return (rv ? kIOReturnSuccess : kIOReturnIOError);
683}
684
685//---------------------------------------------------------------------------
686// Function: setMulticastMode <IOEthernetController>
687
688IOReturn Intel82557::setMulticastMode(IOEnetMulticastMode mode)
689{
690 multicastEnabled = (mode == kIOEnetMulticastModeOff) ? false : true;
691 return kIOReturnSuccess;
692}
693
694//---------------------------------------------------------------------------
695// Function: setMulticastList <IOEthernetController>
696
697IOReturn Intel82557::setMulticastList(IOEthernetAddress * addrs, UInt32 count)
698{
699 IOReturn ret = kIOReturnSuccess;
700
701 if ( mcSetup(addrs, count) == false )
702 {
703 IOLog("%s: set multicast list failed\n", getName());
704 ret = kIOReturnIOError;
705 }
706 return ret;
707}
708
709//---------------------------------------------------------------------------
710// Function: getPacketBufferConstraints <IONetworkController>
711//
712// Return our driver's packet alignment requirements.
713
714void
715Intel82557::getPacketBufferConstraints(IOPacketBufferConstraints * constraints) const
716{
717 constraints->alignStart = kIOPacketBufferAlign2; // even word aligned.
718 constraints->alignLength = kIOPacketBufferAlign1; // no restriction.
719}
720
721//---------------------------------------------------------------------------
722// Function: getHardwareAddress <IOEthernetController>
723//
724// Return the adapter's hardware/Ethernet address.
725
726IOReturn Intel82557::getHardwareAddress(IOEthernetAddress * addrs)
727{
728 bcopy(&myAddress, addrs, sizeof(*addrs));
729 return kIOReturnSuccess;
730}
731
732//---------------------------------------------------------------------------
733// Function: createOutputQueue <IONetworkController>
734//
735// Allocate an IOGatedOutputQueue instance.
736
737IOOutputQueue * Intel82557::createOutputQueue()
738{
739 return IOGatedOutputQueue::withTarget(this, getWorkLoop());
740}
741
742//---------------------------------------------------------------------------
743// Function: setMedium <IONetworkController>
744//
745// Transition the controller/PHY to use a new medium. Note that
746// this function can be called my the driver, or by our client.
747
748IOReturn Intel82557::setMedium(const IONetworkMedium * medium)
749{
750 bool r;
751
752 if ( OSDynamicCast(IONetworkMedium, medium) == 0 )
753 {
754 // Defaults to Auto.
755 medium = _phyGetMediumWithType( MEDIUM_TYPE_AUTO );
756 if ( medium == 0 ) return kIOReturnError;
757 }
758
759#if 0
760 IOLog("%s: setMedium -> %s\n", getName(),
761 medium->getName()->getCStringNoCopy());
762#endif
763
764 // Program PHY to select the desired medium.
765 //
766 r = _phySetMedium( (mediumType_t) medium->getIndex() );
767
768 // Update the current medium property.
769 //
770 if ( r && !setCurrentMedium(medium) )
771 IOLog("%s: setCurrentMedium error\n", getName());
772
773 return ( r ? kIOReturnSuccess : kIOReturnIOError );
774}
775
776//---------------------------------------------------------------------------
777// Function: newVendorString(), newModelString()
778// <IONetworkController>
779//
780// Report human readable hardware information strings.
781
782const OSString * Intel82557::newVendorString() const
783{
784 return OSString::withCString("Intel");
785}
786
787const OSString * Intel82557::newModelString() const
788{
789 const char * model = 0;
790
791 assert( eeprom && eeprom->getContents() );
792
793 switch ( eeprom->getContents()->controllerType )
794 {
795 case I82558_CONTROLLER_TYPE:
796 model = "82558";
797 break;
798 case I82557_CONTROLLER_TYPE:
799 default:
800 model = "82557";
801 break;
802 }
803 return OSString::withCString(model);
804}
805
806//---------------------------------------------------------------------------
807// Kernel debugger entry points.
808//
809// KDP driven polling routines to send and transmit a frame.
810// Remember, no memory allocation! Not even mbufs are safe.
811
812void Intel82557::sendPacket(void * pkt, UInt32 pkt_len)
813{
814 _sendPacket(pkt, pkt_len);
815}
816
817void Intel82557::receivePacket(void * pkt, UInt32 * pkt_len, UInt32 timeout)
818{
819 _receivePacket(pkt, (UInt *) pkt_len, timeout);
820}