|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1998-1999 by Apple Computer, Inc., All rights reserved.
27: *
28: * Hardware independent (relatively) code for the BMac Ethernet Controller
29: *
30: * HISTORY
31: *
32: * dd-mmm-yy
33: * Created.
34: *
35: */
36:
37: #import "BMacEnetPrivate.h"
38:
39: @implementation BMacEnet
40:
41: /*
42: * Public Factory Methods
43: */
44:
45: + (BOOL)probe:(IOTreeDevice *)devDesc
46: {
47: BMacEnet *BMacEnetInstance;
48:
49: BMacEnetInstance = [self alloc];
50: return [BMacEnetInstance initFromDeviceDescription:devDesc] != nil;
51: }
52:
53: /*
54: * Public Instance Methods
55: */
56:
57: /*-------------------------------------------------------------------------
58: *
59: *
60: *
61: *-------------------------------------------------------------------------*/
62:
63: - initFromDeviceDescription:(IOTreeDevice *)devDesc
64: {
65: IOTreeDevice *devDescHeathrow;
66: IORange *ioRangeBMac;
67: IORange *ioRangeHeathrow;
68:
69: if ([super initFromDeviceDescription:devDesc] == nil)
70: {
71: IOLog( "Ethernet(BMac): [super initFromDeviceDescription] failed\n");
72: return nil;
73: }
74:
75: if ( [devDesc numMemoryRanges] < 3 )
76: {
77: IOLog( "Ethernet(BMac): Incorrect deviceDescription - 1\n\r");
78: return nil;
79: }
80:
81: ioRangeBMac = [devDesc memoryRangeList];
82:
83: ioBaseEnet = (IOPPCAddress) ioRangeBMac[0].start;
84: ioBaseEnetTxDMA = (IOPPCAddress) ioRangeBMac[1].start;
85: ioBaseEnetRxDMA = (IOPPCAddress) ioRangeBMac[2].start;
86:
87: devDescHeathrow = [[devDesc parent] deviceDescription];
88:
89: if ( [devDescHeathrow numMemoryRanges] < 1 )
90: {
91: IOLog( "Ethernet(BMac): Incorrect deviceDescription - 2\n\r");
92: return nil;
93: }
94:
95: ioRangeHeathrow = [devDescHeathrow memoryRangeList];
96:
97: ioBaseHeathrow = (IOPPCAddress) ioRangeHeathrow[0].start;
98:
99: sromAddressBits = 6;
100: enetAddressOffset = 20;
101: phyId = -1;
102: phyMIIDelay = MII_DEFAULT_DELAY;
103:
104: if ( ![self resetAndEnable:NO] )
105: {
106: [self free];
107: return nil;
108: }
109:
110: [self _getStationAddress:&myAddress];
111:
112: if ([self _allocateMemory] == NO)
113: {
114: [self free];
115: return nil;
116: }
117:
118: if ( ![self resetAndEnable:YES] )
119: {
120: [self free];
121: return nil;
122: }
123:
124: isPromiscuous = NO;
125: multicastEnabled = NO;
126:
127: networkInterface = [super attachToNetworkWithAddress:myAddress];
128:
129: [networkInterface getIONetworkIfnet]->if_eflags |= IFEF_DVR_REENTRY_OK;
130:
131: return self;
132: }
133:
134: /*-------------------------------------------------------------------------
135: *
136: *
137: *
138: *-------------------------------------------------------------------------*/
139:
140: - free
141: {
142: int i;
143:
144: [self clearTimeout];
145:
146: [self _resetChip];
147:
148: if (networkInterface)
149: [networkInterface free];
150:
151: for (i = 0; i < rxMaxCommand; i++)
152: if (rxNetbuf[i]) nb_free(rxNetbuf[i]);
153:
154: for (i = 0; i < txMaxCommand; i++)
155: if (txNetbuf[i]) nb_free(txNetbuf[i]);
156:
157: return [super free];
158: }
159:
160: /*-------------------------------------------------------------------------
161: *
162: *
163: *
164: *-------------------------------------------------------------------------*/
165:
166: - (void)interruptOccurredAt:(int)irqNum
167: {
168:
169: [self reserveDebuggerLock];
170:
171: switch ( irqNum )
172: {
173: /*
174: * On the transmit side, we use the chipset interrupt. Using the transmit
175: * DMA interrupt (or having multiple transmit DMA entries) would allows us to
176: * send the next frame to the chipset prior the transmit fifo going empty.
177: * However, this aggrevates a BMac chipset bug where the next frame going out
178: * gets corrupted (first two bytes lost) if the chipset had to retry the previous
179: * frame.
180: */
181: case kIRQEnetDev:
182: case kIRQEnetTxDMA:
183: txWDInterrupts++;
184: KERNEL_DEBUG(DBG_BMAC_TXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
185: [self _transmitInterruptOccurred];
186: [self serviceTransmitQueue];
187: KERNEL_DEBUG(DBG_BMAC_TXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 );
188: break;
189: case kIRQEnetRxDMA:
190: KERNEL_DEBUG(DBG_BMAC_RXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
191: [self _receiveInterruptOccurred];
192: KERNEL_DEBUG(DBG_BMAC_RXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 );
193: break;
194: }
195:
196: [self enableAllInterrupts];
197:
198: [self releaseDebuggerLock];
199: }
200:
201: /*-------------------------------------------------------------------------
202: *
203: *
204: *
205: *-------------------------------------------------------------------------*/
206:
207: - (void) serviceTransmitQueue
208: {
209: netbuf_t packet;
210: u_int32_t i;
211:
212: while ( 1 )
213: {
214: if ( ![transmitQueue count] )
215: {
216: break;
217: }
218:
219: i = txCommandTail + 1;
220: if ( i >= txMaxCommand ) i = 0;
221: if ( i == txCommandHead )
222: {
223: break;
224: }
225: packet = [transmitQueue dequeue];
226: [self _transmitPacket:packet];
227: }
228:
229: }
230:
231: /*-------------------------------------------------------------------------
232: *
233: *
234: *
235: *-------------------------------------------------------------------------*/
236:
237: - (void)transmit:(netbuf_t)pkt
238: {
239: u_int32_t i;
240: u_int32_t n;
241:
242: KERNEL_DEBUG(DBG_BMAC_TXQUEUE | DBG_FUNC_NONE, (int) pkt, (int) nb_size(pkt), 0, 0, 0 );
243:
244: /*
245: * Hold the debugger lock so the debugger can't interrupt us
246: */
247: [self reserveDebuggerLock];
248:
249: do
250: {
251: /*
252: * Preliminary sanity checks
253: */
254: if (!pkt)
255: {
256: IOLog("EtherNet(BMac): transmit received NULL netbuf\n");
257: continue;
258: }
259: if ( ![self isRunning] )
260: {
261: nb_free(pkt);
262: continue;
263: }
264:
265: #if 0
266: /*
267: * Remove any completed packets from the Tx ring
268: */
269: if ( chipId >= kCHIPID_PaddingtonXmitStreaming )
270: {
271: [self _transmitInterruptOccurred];
272: }
273: #endif
274:
275: /*
276: * Refill the Tx ring from the Transmit waiting list
277: */
278: [self serviceTransmitQueue];
279:
280: /*
281: * If the Transmit waiting list is not empty or the Tx ring is
282: * full, add the new packet to the waiting list.
283: */
284: n = [transmitQueue count];
285: if ( n > 0 )
286: {
287: if ( n >= [transmitQueue maxCount] )
288: {
289: IOLog("Ethernet(BMac): Transmit queue overflow\n");
290: }
291:
292: [transmitQueue enqueue:pkt];
293: continue;
294: }
295: i = txCommandTail + 1;
296: if ( i >= txMaxCommand ) i = 0;
297: if ( i == txCommandHead )
298: {
299: [transmitQueue enqueue:pkt];
300: continue;
301: }
302:
303: /*
304: * If there is space on the Tx ring, add the packet directly to the
305: * ring
306: */
307: [self _transmitPacket:pkt];
308: }
309: while( 0 );
310:
311: [self releaseDebuggerLock];
312: }
313:
314: /*-------------------------------------------------------------------------
315: *
316: *
317: *
318: *-------------------------------------------------------------------------*/
319:
320: - (int) transmitQueueSize
321: {
322: return (TRANSMIT_QUEUE_SIZE);
323: }
324:
325: - (int) transmitQueueCount
326: {
327: return ([transmitQueue count]);
328: }
329: /*-------------------------------------------------------------------------
330: *
331: *
332: *
333: *-------------------------------------------------------------------------*/
334:
335: - (BOOL)resetAndEnable:(BOOL)enable
336: {
337: resetAndEnabled = NO;
338: [self clearTimeout];
339: [self disableAllInterrupts];
340: [self _resetChip];
341:
342: if (enable)
343: {
344: if (![self _initRxRing] || ![self _initTxRing])
345: {
346: return NO;
347: }
348:
349: if ( phyId != 0xff )
350: {
351: [self miiInitializePHY:phyId];
352: }
353:
354: if ([self _initChip] == NO)
355: {
356: [self setRunning:NO];
357: return NO;
358: }
359:
360: [self _startChip];
361:
362: [self setRelativeTimeout: WATCHDOG_TIMER_MS];
363:
364: [self enableAllInterrupts];
365: [self _enableAdapterInterrupts];
366:
367: resetAndEnabled = YES;
368:
369: [self _sendDummyPacket];
370: }
371:
372: [self setRunning:enable];
373:
374: return YES;
375: }
376:
377: /*-------------------------------------------------------------------------
378: *
379: *
380: *
381: *-------------------------------------------------------------------------*/
382:
383: - (void)timeoutOccurred
384: {
385: u_int32_t dmaStatus;
386: u_int16_t phyStatus;
387: u_int16_t linkStatus;
388: u_int16_t phyStatusChange;
389: BOOL fullDuplex = NO;
390:
391: if ( ![self isRunning] )
392: {
393: return;
394: }
395:
396: [self reserveDebuggerLock];
397:
398: /*
399: * Check for DMA shutdown on receive channel
400: */
401: dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetRxDMA );
402: if ( !(dmaStatus & kdbdmaActive) )
403: {
404: IOLog( "Ethernet(BMac): Checking for timeout - RxHead = %d RxTail = %d\n\r", rxCommandHead, rxCommandTail);
405: #if 0
406: IOLog( "Ethernet(BMac): Rx Commands = %08x(p) Rx DMA Ptr = %08x(p)\n\r", rxDMACommandsPhys, IOGetDBDMACommandPtr(ioBaseEnetRxDMA) );
407: [self _dumpDesc:(void *)rxDMACommands Size:rxMaxCommand * sizeof(enet_dma_cmd_t)];
408: #endif
409: [self _receiveInterruptOccurred];
410: }
411:
412: /*
413: * If there are pending entries on the Tx ring
414: */
415: if ( txCommandHead != txCommandTail )
416: {
417: /*
418: * If we did not service the Tx ring during the last timeout interval,
419: * then force servicing of the Tx ring
420: */
421: if ( txWDInterrupts == 0 )
422: {
423: if ( txWDCount++ > 0 )
424: {
425: if ( [self _transmitInterruptOccurred] == NO )
426: {
427: IOLog( "Ethernet(BMac): Checking for timeout - TxHead = %d TxTail = %d\n\r", txCommandHead, txCommandTail);
428: [self _restartTransmitter];
429: }
430: }
431: }
432: else
433: {
434: txWDInterrupts = 0;
435: txWDCount = 0;
436: }
437: }
438: else
439: {
440: txWDInterrupts = 0;
441: txWDCount = 0;
442: }
443:
444: if ( phyId != 0xff )
445: {
446: if ( [self miiReadWord:&phyStatus reg:MII_STATUS phy:phyId] == YES )
447: {
448: phyStatusChange = (phyStatusPrev ^ phyStatus) & (MII_STATUS_LINK_STATUS | MII_STATUS_NEGOTIATION_COMPLETE);
449: if ( phyStatusChange )
450: {
451: if ( (phyStatus & MII_STATUS_LINK_STATUS) && (phyStatus & MII_STATUS_NEGOTIATION_COMPLETE ) )
452: {
453: if ( (phyType & MII_ST10040_MASK) == MII_ST10040_ID )
454: {
455: [self miiReadWord:&linkStatus reg:MII_ST10040_CHIPST phy:phyId];
456:
457: fullDuplex = (linkStatus & MII_ST10040_CHIPST_DUPLEX) ? YES : NO;
458:
459: IOLog( "Ethernet(BMac): Link is up at %sMb - %s Duplex\n\r",
460: (linkStatus & MII_ST10040_CHIPST_SPEED) ? "100" : "10",
461: (fullDuplex) ? "Full" : "Half" );
462: }
463: else if ( (phyType & MII_DP83843_MASK) == MII_DP83843_ID )
464: {
465: [self miiReadWord:&linkStatus reg:MII_DP83843_PHYSTS phy:phyId];
466:
467: fullDuplex = (linkStatus & MII_DP83843_PHYSTS_DUPLEX) ? YES : NO;
468:
469: IOLog( "Ethernet(BMac): Link is up at %sMb - %s Duplex\n\r",
470: (linkStatus & MII_DP83843_PHYSTS_SPEED10) ? "10" : "100",
471: (fullDuplex) ? "Full" : "Half" );
472: }
473: else
474: {
475: fullDuplex = NO ;
476: IOLog( "Ethernet(BMac): Link is up\n\r" );
477: }
478:
479: if ( fullDuplex != isFullDuplex )
480: {
481: [self _setDuplexMode: fullDuplex];
482: }
483: }
484: else
485: {
486: IOLog( "Ethernet(BMac): Link is down.\n\r" );
487: }
488: phyStatusPrev = phyStatus;
489: }
490: }
491: }
492:
493: /*
494: * Restart the watchdog timer
495: */
496: [self setRelativeTimeout: WATCHDOG_TIMER_MS];
497:
498: [self releaseDebuggerLock];
499:
500: }
501:
502: /*-------------------------------------------------------------------------
503: *
504: *
505: *
506: *-------------------------------------------------------------------------*/
507:
508: - (BOOL)enablePromiscuousMode
509: {
510: u_int16_t rxCFGVal;
511:
512: isPromiscuous = YES;
513:
514: [self reserveDebuggerLock];
515:
516: /*
517: * Turn off the receiver and wait for the chipset to acknowledge
518: */
519: rxCFGVal = ReadBigMacRegister(ioBaseEnet, kRXCFG);
520: WriteBigMacRegister(ioBaseEnet, kRXCFG, rxCFGVal & ~kRxMACEnable );
521: while( ReadBigMacRegister(ioBaseEnet, kRXCFG) & kRxMACEnable )
522: ;
523:
524: /*
525: * Set promiscuous mode and restore receiver state
526: */
527: rxCFGVal |= kRxPromiscEnable;
528: WriteBigMacRegister( ioBaseEnet, kRXCFG, rxCFGVal );
529:
530: [self releaseDebuggerLock];
531:
532: return YES;
533: }
534:
535: - (void)disablePromiscuousMode
536: {
537: u_int16_t rxCFGVal;
538:
539: isPromiscuous = NO;
540:
541: [self reserveDebuggerLock];
542:
543: /*
544: * Turn off the receiver and wait for the chipset to acknowledge
545: */
546: rxCFGVal = ReadBigMacRegister(ioBaseEnet, kRXCFG);
547: WriteBigMacRegister(ioBaseEnet, kRXCFG, rxCFGVal & ~kRxMACEnable );
548: while( ReadBigMacRegister(ioBaseEnet, kRXCFG) & kRxMACEnable )
549: ;
550:
551: /*
552: * Reset promiscuous mode and restore receiver state
553: */
554: rxCFGVal &= ~kRxPromiscEnable;
555: WriteBigMacRegister( ioBaseEnet, kRXCFG, rxCFGVal );
556:
557: [self releaseDebuggerLock];
558: }
559:
560: - (BOOL)enableMulticastMode
561: {
562: multicastEnabled = YES;
563: return YES;
564: }
565:
566: - (void)disableMulticastMode
567: {
568: multicastEnabled = NO;
569: }
570:
571: - (void)addMulticastAddress:(enet_addr_t *)addr
572: {
573: multicastEnabled = YES;
574: [self reserveDebuggerLock];
575: [self _addToHashTableMask:addr->ea_byte];
576: [self _updateBMacHashTableMask];
577: [self releaseDebuggerLock];
578: }
579:
580: - (void)removeMulticastAddress:(enet_addr_t *)addr
581: {
582: [self reserveDebuggerLock];
583: [self _removeFromHashTableMask:addr->ea_byte];
584: [self _updateBMacHashTableMask];
585: [self releaseDebuggerLock];
586: }
587:
588: /*
589: * Kernel Debugger Support
590: */
591: - (void)sendPacket:(void *)pkt length:(unsigned int)pkt_len
592: {
593: [self _sendPacket:(void *)pkt length:(unsigned int)pkt_len];
594: }
595:
596: - (void)receivePacket:(void *)pkt length:(unsigned int *)pkt_len timeout:(unsigned int)timeout
597: {
598: [self _receivePacket:(void *)pkt length:(unsigned int *)pkt_len timeout:(unsigned int)timeout];
599: }
600:
601: /*
602: * Power management methods.
603: */
604: - (IOReturn)getPowerState:(PMPowerState *)state_p
605: {
606: return IO_R_UNSUPPORTED;
607: }
608:
609: - (IOReturn)setPowerState:(PMPowerState)state
610: {
611: if (state == PM_OFF) {
612: resetAndEnabled = NO;
613: [self _resetChip];
614: return IO_R_SUCCESS;
615: }
616: return IO_R_UNSUPPORTED;
617: }
618:
619: - (IOReturn)getPowerManagement:(PMPowerManagementState *)state_p
620: {
621: return IO_R_UNSUPPORTED;
622: }
623:
624: - (IOReturn)setPowerManagement:(PMPowerManagementState)state
625: {
626: return IO_R_UNSUPPORTED;
627: }
628:
629: - (void)reserveDebuggerLock
630: {
631: if ( debuggerLockCount++ == 0 )
632: {
633: [super reserveDebuggerLock];
634: }
635: }
636:
637: - (void)releaseDebuggerLock
638: {
639: if ( --debuggerLockCount == 0 )
640: {
641: [super releaseDebuggerLock];
642: }
643: }
644:
645:
646: @end
647:
648:
649:
650:
651:
652:
653:
654:
655:
656:
657:
658:
659:
660:
661:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.