]>
Commit | Line | Data |
---|---|---|
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 | |
67 | OSDefineMetaClassAndStructors( 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 | ||
75 | bool 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 | ||
100 | bool 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 | ||
159 | bool 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 | ||
201 | bool 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 | ||
325 | void 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 | ||
335 | bool 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 | ||
347 | IOWorkLoop * Intel82557::getWorkLoop() const | |
348 | { | |
349 | return workLoop; | |
350 | } | |
351 | ||
352 | //--------------------------------------------------------------------------- | |
353 | // Function: configureInterface <IONetworkController> | |
354 | // | |
355 | // Configure a newly instantiated IONetworkInterface object. | |
356 | ||
357 | bool 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 | ||
386 | void 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 | ||
412 | bool 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 | ||
483 | bool 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 | ||
556 | bool 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 | ||
589 | IOReturn 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 | ||
603 | IOReturn 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 | ||
618 | IOReturn 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 | ||
636 | IOReturn 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 | ||
652 | void 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 | ||
675 | IOReturn 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 | ||
688 | IOReturn Intel82557::setMulticastMode(IOEnetMulticastMode mode) | |
689 | { | |
690 | multicastEnabled = (mode == kIOEnetMulticastModeOff) ? false : true; | |
691 | return kIOReturnSuccess; | |
692 | } | |
693 | ||
694 | //--------------------------------------------------------------------------- | |
695 | // Function: setMulticastList <IOEthernetController> | |
696 | ||
697 | IOReturn 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 | ||
714 | void | |
715 | Intel82557::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 | ||
726 | IOReturn 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 | ||
737 | IOOutputQueue * 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 | ||
748 | IOReturn 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 | ||
782 | const OSString * Intel82557::newVendorString() const | |
783 | { | |
784 | return OSString::withCString("Intel"); | |
785 | } | |
786 | ||
787 | const 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 | ||
812 | void Intel82557::sendPacket(void * pkt, UInt32 pkt_len) | |
813 | { | |
814 | _sendPacket(pkt, pkt_len); | |
815 | } | |
816 | ||
817 | void Intel82557::receivePacket(void * pkt, UInt32 * pkt_len, UInt32 timeout) | |
818 | { | |
819 | _receivePacket(pkt, (UInt *) pkt_len, timeout); | |
820 | } |