|
|
1.1 root 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: * i82557Private.cpp
26: *
27: */
28:
29: #include "i82557.h"
30:
31: extern "C" {
32: #include <sys/param.h>
33: #include <sys/mbuf.h>
34: #include <string.h>
35: }
36:
37: //---------------------------------------------------------------------------
38: // Function: IOPhysicalFromVirtual
39: //
40: // Hack, remove ASAP.
41:
42: static inline IOReturn
43: IOPhysicalFromVirtual(vm_address_t vaddr, IOPhysicalAddress * paddr)
44: {
45: *paddr = pmap_extract(kernel_pmap, vaddr);
46: return (*paddr == 0) ? kIOReturnBadArgument : kIOReturnSuccess;
47: }
48:
49: //---------------------------------------------------------------------------
50: // Function: _intrACK
51: //
52: // Purpose:
53: // Acknowledge all of the pending interrupt sources.
54: //
55: // Returns:
56: // Return the interrupt status.
57: //
58: // CSR usage:
59: // Read/Write: SCB status
60:
61: static inline scb_status_t _intrACK(CSR_t * CSR_p)
62: {
63: scb_status_t stat_irq = OSReadLE16(&CSR_p->status) & SCB_STATUS_INT_MASK;
64: if (stat_irq)
65: OSWriteLE16(&CSR_p->status, stat_irq); // ack pending interrupts.
66: return (stat_irq);
67: }
68:
69: //---------------------------------------------------------------------------
70: // Function: _waitSCBCommandClear
71: //
72: // Purpose:
73: // Wait for the SCB Command field to clear. Ensures that we don't
74: // overrun the NIC's command unit.
75: //
76: // Returns:
77: // true if the SCB command field was cleared.
78: // false if the SCB command field was not cleared.
79: //
80: // CSR usage:
81: // Read: SCB command
82:
83: static inline bool
84: _waitSCBCommandClear(CSR_t * CSR_p)
85: {
86: for (int i = 0; i < SPIN_TIMEOUT; i++) {
87: if (!OSReadLE8(&CSR_p->command))
88: return true;
89: IODelay(SPIN_COUNT);
90: }
91: return false; // hardware is not responding.
92: }
93:
94: //---------------------------------------------------------------------------
95: // Function: _waitCUNonActive
96: //
97: // Purpose:
98: // Waits for the Command Unit to become inactive.
99: //
100: // Returns:
101: // true if the CU has become inactive.
102: // false if the CU remains active.
103: //
104: // CSR usage:
105: // Read: SCB status
106:
107: static inline bool
108: _waitCUNonActive(CSR_t * CSR_p)
109: {
110: for (int i = 0; i < SPIN_TIMEOUT; i++) {
111: if (CSR_VALUE(SCB_STATUS_CUS, OSReadLE16(&CSR_p->status)) !=
112: SCB_CUS_ACTIVE)
113: return true;
114: IODelay(SPIN_COUNT);
115: }
116: return false;
117: }
118:
119: //---------------------------------------------------------------------------
120: // Function: _polledCommand:WithAddress
121: //
122: // Purpose:
123: // Issue a polled command to the NIC.
124:
125: bool Intel82557::_polledCommand(cbHeader_t * hdr_p, IOPhysicalAddress paddr)
126: {
127: if (!_waitSCBCommandClear(CSR_p)) {
128: IOLog("%s: _polledCommand:(%s): _waitSCBCommandClear failed\n",
129: CUCommandString(CSR_VALUE(CB_CMD, OSReadLE16(&hdr_p->command))),
130: getName());
131: return false;
132: }
133:
134: if (!_waitCUNonActive(CSR_p)) {
135: IOLog("%s: _polledCommand:(%s): _waitCUNonActive failed\n",
136: CUCommandString(CSR_VALUE(CB_CMD, OSReadLE16(&hdr_p->command))),
137: getName());
138: return false;
139: }
140:
141: // Set the physical address of the command block, and issue a
142: // command unit start.
143: //
144: OSWriteLE32(&CSR_p->pointer, paddr);
145: OSWriteLE8(&CSR_p->command, CSR_FIELD(SCB_COMMAND_CUC, SCB_CUC_START));
146:
147: prevCUCommand = SCB_CUC_START;
148:
149: for (int i = 0; i < SPIN_TIMEOUT; i++) {
150: if (OSReadLE16(&hdr_p->status) & CB_STATUS_C)
151: return true;
152: IODelay(SPIN_COUNT);
153: }
154: return false;
155: }
156:
157: //---------------------------------------------------------------------------
158: // Function: _abortReceive
159: //
160: // Purpose:
161: // Abort the receive unit.
162:
163: bool Intel82557::_abortReceive()
164: {
165: if (!_waitSCBCommandClear(CSR_p)) {
166: IOLog("%s: _abortReceive: _waitSCBCommandClear failed\n", getName());
167: return false;
168: }
169:
170: OSWriteLE8(&CSR_p->command, CSR_FIELD(SCB_COMMAND_RUC, SCB_RUC_ABORT));
171:
172: for (int i = 0; i < SPIN_TIMEOUT; i++) {
173: if (CSR_VALUE(SCB_STATUS_RUS, OSReadLE16(&CSR_p->status)) ==
174: SCB_RUS_IDLE)
175: return true;
176: IODelay(SPIN_COUNT);
177: }
178:
179: IOLog("%s: _abortReceive: timeout\n", getName());
180: return false;
181: }
182:
183: //---------------------------------------------------------------------------
184: // Function: _startReceive
185: //
186: // Purpose:
187: // Start the receive unit
188:
189: bool Intel82557::_startReceive()
190: {
191: if (!_waitSCBCommandClear(CSR_p)) {
192: IOLog("%s: _startReceive: _waitSCBCommandClear failed\n", getName());
193: return false;
194: }
195:
196: // Make sure the initial RFD has a link to its RBD
197: OSWriteLE32(&headRfd->rbdAddr, headRfd->_rbd._paddr);
198:
199: OSWriteLE32(&CSR_p->pointer, headRfd->_paddr);
200: OSWriteLE8(&CSR_p->command, CSR_FIELD(SCB_COMMAND_RUC, SCB_RUC_START));
201:
202: for (int i = 0; i < SPIN_TIMEOUT; i++) {
203: if (CSR_VALUE(SCB_STATUS_RUS, OSReadLE16(&CSR_p->status)) ==
204: SCB_RUS_READY)
205: return true;
206: IODelay(SPIN_COUNT);
207: }
208:
209: IOLog("%s: _startReceive: timeout\n", getName());
210: return false;
211: }
212:
213: //---------------------------------------------------------------------------
214: // Function: _resetChip
215: //
216: // Purpose:
217: // Issue a selective reset then a full reset.
218: // This is done to avoid a PCI bus hang if the 82557 is in the midst of
219: // a PCI bus cycle. The selective reset pauses the transmit and receive
220: // engines.
221: //
222: void Intel82557::_resetChip()
223: {
224: int i = 0;
225:
226: sendPortCommand(portSelectiveReset_e, 0);
227: do {
228: IOSleep(1);
229: } while (OSReadLE32(&CSR_p->port) && ++i < 100);
230:
231: sendPortCommand(portReset_e, 0);
232: IOSleep(1);
233: return;
234: }
235:
236: //---------------------------------------------------------------------------
237: // Function: issueReset
238: //
239: // Purpose:
240: // Shut down the chip, and issue a reset.
241:
242: void Intel82557::issueReset()
243: {
244: IOLog("%s: resetting adapter\n", getName());
245:
246: etherStats->dot3RxExtraEntry.resets++;
247:
248: setAdapterLevel(kAdapterLevel0);
249: if (!setAdapterLevel(currentLevel)) {
250: IOLog("%s: Reset attempt unsuccessful\n", getName());
251: }
252: }
253:
254: //---------------------------------------------------------------------------
255: // Function: updateRFDFromMbuf
256: //
257: // Purpose:
258: // Updated a RFD/RBD in order to attach it to a cluster mbuf.
259: // XXX - assume cluster will never cross page boundary.
260:
261: bool Intel82557::updateRFDFromMbuf(rfd_t * rfd_p, struct mbuf * m)
262: {
263: struct IOPhysicalSegment vector;
264: UInt count;
265:
266: count = rxMbufCursor->getPhysicalSegments(m, &vector, 1);
267: if (!count)
268: return false;
269:
270: // Start modifying RFD
271: //
272: rfd_p->_rbd.buffer = vector.location; // cursor is little-endian
273: // OSWriteLE32(&rfd_p->_rbd.size, CSR_FIELD(RBD_SIZE, vector.length));
274:
275: rfd_p->_rbd._mbuf = m;
276:
277: return true;
278: }
279:
280: //---------------------------------------------------------------------------
281: // Function: _initTcbQ
282: //
283: // Purpose:
284: // Initialize the transmit control block queue. Create a circularly
285: // linked list of tcbs.
286:
287: bool Intel82557::_initTcbQ(bool enable = false)
288: {
289: int i;
290:
291: tcbQ.numFree = tcbQ.numTcbs = NUM_TRANSMIT_FRAMES;
292: tcbQ.activeHead_p = tcbQ.activeTail_p = tcbQ.freeHead_p = tcbList_p;
293:
294: for (i = 0; i < tcbQ.numTcbs; i++) { /* free up buffers */
295: if (tcbList_p[i]._mbuf) {
296: freePacket(tcbList_p[i]._mbuf);
297: tcbList_p[i]._mbuf = 0;
298: }
299: }
300: bzero(tcbList_p, sizeof(tcb_t) * tcbQ.numTcbs);
301:
302: if (!enable)
303: return true;
304:
305: for (i = 0; i < tcbQ.numTcbs; i++) {
306: IOPhysicalAddress paddr;
307:
308: IOReturn result = IOPhysicalFromVirtual((vm_address_t) &tcbList_p[i],
309: &tcbList_p[i]._paddr);
310: if (result != kIOReturnSuccess) {
311: IOLog("i82557(tcbQ): Invalid TCB address\n");
312: return false;
313: }
314:
315: result = IOPhysicalFromVirtual((vm_address_t) &tcbList_p[i]._tbds,
316: &paddr);
317: if (result != kIOReturnSuccess) {
318: IOLog("i82557(tcbQ): Invalid TBD address\n");
319: return false;
320: }
321: OSWriteLE32(&tcbList_p[i].tbdAddr, paddr);
322:
323: if (i == (tcbQ.numTcbs - 1))
324: tcbList_p[i]._next = &tcbList_p[0];
325: else
326: tcbList_p[i]._next = &tcbList_p[i + 1];
327: }
328: for (i = 0; i < tcbQ.numTcbs; i++) /* make physical links */
329: OSWriteLE32(&tcbList_p[i].link, tcbList_p[i]._next->_paddr);
330:
331: return true;
332: }
333:
334: //---------------------------------------------------------------------------
335: // Function: _setupRfd
336:
337: static void _setupRfd(rfd_t * rfdList_p)
338: {
339: for (int i = 0; i < NUM_RECEIVE_FRAMES; i++) {
340: if (i == (NUM_RECEIVE_FRAMES - 1)) {
341: /* mark tails and link the lists circularly */
342: OSSetLE16(&rfdList_p[i].command, RFD_COMMAND_EL);
343: rfdList_p[i]._next = &rfdList_p[0];
344: OSSetLE32(&rfdList_p[i]._rbd.size, RBD_SIZE_EL);
345: rfdList_p[i]._rbd._next = &rfdList_p[0]._rbd;
346: }
347: else {
348: rfdList_p[i]._next = &rfdList_p[i + 1];
349: rfdList_p[i]._rbd._next = &rfdList_p[i + 1]._rbd;
350: }
351:
352: OSWriteLE32(&rfdList_p[i].link, rfdList_p[i]._next->_paddr);
353: OSWriteLE32(&rfdList_p[i].rbdAddr,
354: (i == 0) ? rfdList_p[0]._rbd._paddr : C_NULL);
355:
356: OSWriteLE32(&rfdList_p[i]._rbd.link, rfdList_p[i]._rbd._next->_paddr);
357: OSSetLE32(&rfdList_p[i]._rbd.size, CSR_FIELD(RBD_SIZE, MAX_BUF_SIZE));
358: }
359: }
360:
361: //---------------------------------------------------------------------------
362: // Function: _initRfdList
363: //
364: // Purpose:
365: // Create a circularly linked list of receive frame descriptors, and
366: // populate them with receive buffers allocated from our special pool.
367:
368: bool Intel82557::_initRfdList(bool enable = false)
369: {
370: int i;
371: IOReturn result;
372:
373: /* free allocated packet buffers */
374: for (i = 0; i < NUM_RECEIVE_FRAMES; i++) {
375: if (rfdList_p[i]._rbd._mbuf) {
376: freePacket(rfdList_p[i]._rbd._mbuf);
377: // rfdList_p[i]._rbd._mbuf = 0;
378: }
379: }
380:
381: /* zero out the entire structure, and re-create it */
382: bzero(rfdList_p, sizeof(rfd_t) * NUM_RECEIVE_FRAMES);
383:
384: if (!enable)
385: return true;
386:
387: for (i = 0; i < NUM_RECEIVE_FRAMES; i++) {
388: OSSetLE16(&rfdList_p[i].command, RFD_COMMAND_SF);
389:
390: result = IOPhysicalFromVirtual((vm_address_t) &rfdList_p[i],
391: &rfdList_p[i]._paddr);
392: if (result != kIOReturnSuccess) {
393: IOLog("%s: Invalid RFD address\n", getName());
394: return false;
395: }
396: result = IOPhysicalFromVirtual((vm_address_t) &rfdList_p[i]._rbd,
397: &rfdList_p[i]._rbd._paddr);
398: if (result != kIOReturnSuccess) {
399: IOLog("%s: Invalid RBD address\n", getName());
400: return false;
401: }
402: }
403:
404: _setupRfd(rfdList_p);
405:
406: for (i = 0; i < NUM_RECEIVE_FRAMES; i++) {
407: // Pre-load the receive ring with max size mbuf packets.
408: //
409: struct mbuf * m = allocatePacket(MAX_BUF_SIZE);
410: if (!m)
411: return false;
412:
413: if (updateRFDFromMbuf(&rfdList_p[i], m) == false) {
414: IOLog("%s: updateRFDFromMbuf() error\n", getName());
415: freePacket(m);
416: return false;
417: }
418: }
419:
420: headRfd = rfdList_p;
421: tailRfd = rfdList_p + NUM_RECEIVE_FRAMES - 1;
422:
423: return true;
424: }
425:
426: //---------------------------------------------------------------------------
427: // Function: _resetRfdList
428: //
429: // Purpose:
430: // Reset the RFD list before the receiver engine is restarted after
431: // a resource shortage.
432:
433: bool Intel82557::_resetRfdList()
434: {
435: int i;
436:
437: struct _cache {
438: IOPhysicalAddress rbd_buffer;
439: struct mbuf * rbd_mbuf;
440: IOPhysicalAddress rfd_paddr;
441: IOPhysicalAddress rbd_paddr;
442: } * cache_p = (struct _cache *) KDB_buf_p;
443:
444: if ((sizeof(struct _cache) * NUM_RECEIVE_FRAMES) > ETHERMAXPACKET) {
445: IOLog("%s: no space for cache data\n", getName());
446: return false;
447: }
448:
449: /* cache allocated packet buffers */
450: for (i = 0; i < NUM_RECEIVE_FRAMES; i++) {
451: cache_p[i].rbd_mbuf = rfdList_p[i]._rbd._mbuf;
452: cache_p[i].rbd_buffer = rfdList_p[i]._rbd.buffer;
453: cache_p[i].rfd_paddr = rfdList_p[i]._paddr;
454: cache_p[i].rbd_paddr = rfdList_p[i]._rbd._paddr;
455: }
456:
457: /* zero out the entire structure, and re-create it */
458: bzero(rfdList_p, sizeof(rfd_t) * NUM_RECEIVE_FRAMES);
459:
460: for (i = 0; i < NUM_RECEIVE_FRAMES; i++) {
461: OSSetLE16(&rfdList_p[i].command, RFD_COMMAND_SF);
462: rfdList_p[i]._paddr = cache_p[i].rfd_paddr;
463: rfdList_p[i]._rbd._paddr = cache_p[i].rbd_paddr;
464: }
465:
466: _setupRfd(rfdList_p);
467:
468: for (i = 0; i < NUM_RECEIVE_FRAMES; i++) {
469: rfdList_p[i]._rbd.buffer = cache_p[i].rbd_buffer;
470: rfdList_p[i]._rbd._mbuf = cache_p[i].rbd_mbuf;
471: }
472:
473: headRfd = rfdList_p;
474: tailRfd = rfdList_p + NUM_RECEIVE_FRAMES - 1;
475:
476: return true;
477: }
478:
479: //---------------------------------------------------------------------------
480: // Function: _mdiReadPHY:Register:Data
481: //
482: // Purpose:
483: // Read the specified MDI register and return the results.
484:
485: bool
486: Intel82557::_mdiReadPHY(UInt8 phyAddress, UInt8 regAddress, UInt16 * data_p)
487: {
488: mdi_control_t mdi;
489:
490: mdi = CSR_FIELD(MDI_CONTROL_PHYADDR, phyAddress) |
491: CSR_FIELD(MDI_CONTROL_REGADDR, regAddress) |
492: CSR_FIELD(MDI_CONTROL_OPCODE, MDI_CONTROL_OP_READ);
493:
494: OSWriteLE32(&CSR_p->mdiControl, mdi);
495: IODelay(20);
496:
497: bool ready = false;
498: for (int i = 0; i < SPIN_TIMEOUT; i++) {
499: if (OSReadLE32(&CSR_p->mdiControl) & MDI_CONTROL_READY) {
500: ready = true;
501: break;
502: }
503: IODelay(20);
504: }
505: if (ready == false) {
506: IOLog("%s: _mdiReadPHYRegisterSuccess timeout\n", getName());
507: return false;
508: }
509:
510: *data_p = CSR_VALUE(MDI_CONTROL_DATA, OSReadLE32(&CSR_p->mdiControl));
511: return true;
512: }
513:
514: //---------------------------------------------------------------------------
515: // Function: _mdiWritePHY:Register:Data
516: //
517: // Purpose:
518: // Write the specified MDI register with the given data.
519:
520: bool Intel82557::_mdiWritePHY(UInt8 phyAddress, UInt8 regAddress, UInt16 data)
521: {
522: mdi_control_t mdi;
523:
524: mdi = CSR_FIELD(MDI_CONTROL_PHYADDR, phyAddress) |
525: CSR_FIELD(MDI_CONTROL_REGADDR, regAddress) |
526: CSR_FIELD(MDI_CONTROL_OPCODE, MDI_CONTROL_OP_WRITE) |
527: CSR_FIELD(MDI_CONTROL_DATA, data);
528:
529: OSWriteLE32(&CSR_p->mdiControl, mdi);
530: IODelay(20);
531:
532: bool ready = false;
533: for (int i = 0; i < SPIN_TIMEOUT; i++) {
534: if (OSReadLE32(&CSR_p->mdiControl) & MDI_CONTROL_READY) {
535: ready = true;
536: break;
537: }
538: IODelay(20);
539: }
540: if (ready == false) {
541: IOLog("%s: _mdiWritePHYRegisterData timeout\n", getName());
542: return false;
543: }
544: return true;
545: }
546:
547: //---------------------------------------------------------------------------
548: // Function: nop
549: //
550: // Purpose:
551: // Issue a polled NOP command to the NIC.
552:
553: bool Intel82557::nop()
554: {
555: cbHeader_t * nop_p = &overlay_p->nop;
556:
557: bzero(nop_p, sizeof(*nop_p));
558: OSWriteLE16(&nop_p->command, CSR_FIELD(CB_CMD, CB_CMD_NOP) | CB_EL);
559: OSWriteLE32(&nop_p->link, C_NULL);
560:
561: return _polledCommand(nop_p, overlay_paddr);
562: }
563:
564: //---------------------------------------------------------------------------
565: // Function: config
566: //
567: // Purpose:
568: // Issue a polled CONFIGURE command to the NIC.
569:
570: bool Intel82557::config()
571: {
572: UInt8 * cb_p;
573: cb_configure_t * cfg_p = &overlay_p->configure;
574:
575: /*
576: * Fill the configure command block
577: */
578: bzero(cfg_p, sizeof(*cfg_p));
579:
580: OSWriteLE16(&cfg_p->header.command,
581: CSR_FIELD(CB_CMD, CB_CMD_CONFIGURE) | CB_EL);
582: OSWriteLE32(&cfg_p->header.link, C_NULL);
583:
584: cb_p = cfg_p->byte;
585: cb_p[0] = CSR_FIELD(CB_CB0_BYTE_COUNT, CB_CONFIG_BYTE_COUNT);
586:
587: cb_p[1] = CSR_FIELD(CB_CB1_TX_FIFO_LIMIT, CB_CB1_TX_FIFO_0) |
588: CSR_FIELD(CB_CB1_RX_FIFO_LIMIT, CB_CB1_RX_FIFO_64);
589:
590: cb_p[3] = CB_CB3_MWI_ENABLE; // enable PCI-MWI on 82558 devices
591:
592: cb_p[4] = 0; // disable PCI transfer limits
593: cb_p[5] = 0;
594:
595: cb_p[6] = CB_CB6_NON_DIRECT_DMA | CB_CB6_STD_TCB | CB_CB6_STD_STATS;
596:
597: cb_p[7] = CSR_FIELD(CB_CB7_UNDERRUN_RETRY, CB_CB7_UNDERRUN_RETRY_1) |
598: CB_CB7_DISC_SHORT_FRAMES;
599:
600: if ((eeprom->getContents()->controllerType != I82558_CONTROLLER_TYPE) &&
601: (phyAddr != PHY_ADDRESS_I82503))
602: cb_p[8] = CB_CB8_CSMA_EN;
603:
604: cb_p[10] = CSR_FIELD(CB_CB10_PREAMBLE, CB_CB10_PREAMBLE_7_BYTES) |
605: CB_CB10_NSAI;
606:
607: cb_p[12] = CSR_FIELD(CB_CB12_IFS, CB_CB12_IFS_96_BIT_TIMES);
608:
609: cb_p[13] = CSR_FIELD(CB_CB13_FC_TYPE_LSB, CB_CB13_FC_TYPE_LSB_DEF);
610: cb_p[14] = CSR_FIELD(CB_CB14_FC_TYPE_MSB, CB_CB14_FC_TYPE_MSB_DEF);
611:
612: cb_p[15] = ((cb_p[8] & CB_CB8_CSMA_EN) ? 0 : CB_CB15_CRS_CDT) |
613: (promiscuousEnabled ? CB_CB15_PROMISCUOUS : 0);
614:
615: cb_p[16] = CSR_FIELD(CB_CB16_FC_DELAY_LSB, CB_CB16_FC_DELAY_LSB_DEF);
616: cb_p[17] = CSR_FIELD(CB_CB17_FC_DELAY_MSB, CB_CB17_FC_DELAY_MSB_DEF);
617:
618: cb_p[18] = CB_CB18_PADDING | CB_CB18_STRIPPING;
619:
620: #if 0 // XXX - need to fix this
621: /*
622: * Force full duplex if there is a user override, or we are using Phy 0
623: * and full duplex mode is enabled. The FDX# pin is wired to Phy 1,
624: * which means that the 82557 can't autodetect the setting correctly.
625: */
626: if (forceFullDuplex || (phyAddr == PHY_ADDRESS_0 && fullDuplexMode))
627: cb_p[19] = CB_CB19_FORCE_FDX;
628: #endif
629:
630: cb_p[19] = CB_CB19_AUTO_FDX;
631: if (flowControl) {
632: cb_p[19] |= ( CB_CB19_TX_FC |
633: CB_CB19_RX_FC_RESTOP |
634: CB_CB19_RX_FC_RESTART |
635: CB_CB19_REJECT_FC );
636: }
637:
638: cb_p[20] = CSR_FIELD(CB_CB20_FC_ADDR_LSB, CB_CB20_FC_ADDR_LSB_DEF);
639:
640: IOSync();
641:
642: return _polledCommand((cbHeader_t *) cfg_p, overlay_paddr);
643: }
644:
645: //---------------------------------------------------------------------------
646: // Function: iaSetup
647: //
648: // Purpose:
649: // Issue a polled IndividualAddressSETUP command to the NIC.
650: //
651: bool Intel82557::iaSetup()
652: {
653: cb_iasetup_t * iaSetup_p = &overlay_p->iasetup;
654:
655: /*
656: * Fill the IA-setup command block
657: */
658: bzero(iaSetup_p, sizeof(*iaSetup_p));
659:
660: OSWriteLE16(&iaSetup_p->header.command, CSR_FIELD(CB_CMD, CB_CMD_IASETUP) |
661: CB_EL);
662: OSWriteLE32(&iaSetup_p->header.link, C_NULL);
663: iaSetup_p->addr = myAddress;
664:
665: return _polledCommand((cbHeader_t *) iaSetup_p, overlay_paddr);
666: }
667:
668: //---------------------------------------------------------------------------
669: // Function: mcSetup
670: //
671: // Purpose:
672: // Issue a polled MultiCastSETUP command to the NIC. If 'fromData' is
673: // true, then we ignore the addrs/count arguments and instead use the
674: // multicast address list property in our interface client object.
675:
676: bool Intel82557::mcSetup(enet_addr_t * addrs,
677: UInt count,
678: bool fromData = false)
679: {
680: cb_mcsetup_t * mcSetup_p;
681: bool cmdResult;
682: IOReturn result;
683: IOPhysicalAddress mcSetup_paddr;
684:
685: if (fromData) {
686: // mcSetup() was not called by the setMulticastList() function.
687: // We should get the multicast list stored in the interface
688: // object's property table.
689: //
690: // mcSetup() is always executed by the default workloop thread,
691: // thus we don't have to worry about the address list being
692: // changed while we go through it.
693: //
694: addrs = 0;
695: count = 0;
696:
697: if (netif) {
698: OSData * mcData = OSDynamicCast(OSData,
699: netif->getProperty(kIOMulticastAddresses));
700: if (mcData) {
701: addrs = (enet_addr_t *) mcData->getBytesNoCopy();
702: count = mcData->getLength() / sizeof(enet_addr_t);
703: assert(addrs && count);
704: }
705: }
706: }
707:
708: mcSetup_p = (cb_mcsetup_t *) IOMallocAligned(PAGE_SIZE, PAGE_SIZE);
709: if (!mcSetup_p) {
710: IOLog("%s: mcSetup:IOMallocAligned return NULL\n", getName());
711: return false;
712: }
713:
714: reserveDebuggerLock();
715:
716: do {
717: cmdResult = false;
718:
719: OSWriteLE16(&mcSetup_p->header.status, 0);
720: OSWriteLE16(&mcSetup_p->header.command,
721: CSR_FIELD(CB_CMD, CB_CMD_MCSETUP) | CB_EL);
722: OSWriteLE32(&mcSetup_p->header.link, C_NULL);
723:
724: /* fill in the addresses (count may be zero) */
725: for (UInt i = 0; i < count; i++)
726: mcSetup_p->addrs[i] = addrs[i];
727:
728: /* Set the number of bytes in the MC list, if the count is zero,
729: * it is equivalent to disabling the multicast filtering mechanism.
730: */
731: OSWriteLE16(&mcSetup_p->count, count * sizeof(enet_addr_t));
732:
733: result = IOPhysicalFromVirtual((vm_address_t) mcSetup_p,
734: &mcSetup_paddr);
735: if (result != kIOReturnSuccess) {
736: IOLog("%s: Invalid MC-setup command block address\n", getName());
737: break;
738: }
739:
740: if (!_polledCommand((cbHeader_t *) mcSetup_p, mcSetup_paddr)) {
741: IOLog("%s: MC-setup command failed 0x%x\n", getName(),
742: OSReadLE16(&mcSetup_p->header.status));
743: break;
744: }
745:
746: cmdResult = (OSReadLE16(&mcSetup_p->header.status) & CB_STATUS_OK) ?
747: true : false;
748: } while (0);
749:
750: releaseDebuggerLock();
751:
752: IOFreeAligned(mcSetup_p, PAGE_SIZE);
753:
754: return cmdResult;
755: }
756:
757: //---------------------------------------------------------------------------
758: // Function: _selfTest
759: //
760: // Purpose:
761: // Issue a PORT self test command to the NIC and verify the results.
762:
763: bool Intel82557::_selfTest()
764: {
765: port_selftest_t * test_p = (port_selftest_t *) overlay_p;
766: UInt32 results;
767:
768: OSWriteLE32(&test_p->signature, 0);
769: OSWriteLE32(&test_p->results, ~0);
770: sendPortCommand(portSelfTest_e, overlay_paddr);
771: IOSleep(20);
772: if (OSReadLE32(&test_p->signature) == 0) {
773: IOLog("%s: Self test timed out\n", getName());
774: return false;
775: }
776:
777: results = OSReadLE32(&test_p->results);
778: if (results) { /* report errors from self test */
779: if (results & PORT_SELFTEST_ROM)
780: IOLog("%s: Self test reports invalid ROM contents\n",
781: getName());
782: if (results & PORT_SELFTEST_REGISTER)
783: IOLog("%s: Self test reports internal register failure\n",
784: getName());
785: if (results & PORT_SELFTEST_DIAGNOSE)
786: IOLog("%s: Self test reports serial subsystem failure\n",
787: getName());
788: if (results & PORT_SELFTEST_GENERAL)
789: IOLog("%s: Self test failed\n", getName());
790: return false;
791: }
792: return true;
793: }
794:
795: //---------------------------------------------------------------------------
796: // Function: sendPortCommand
797: //
798: // Purpose:
799: // Issue an 82557 PORT command.
800: //
801: void Intel82557::sendPortCommand(port_command_t command, UInt arg)
802: {
803: OSWriteLE32(&CSR_p->port, (arg & PORT_ADDRESS_MASK) |
804: CSR_FIELD(PORT_FUNCTION, command));
805: return;
806: }
807:
808: //---------------------------------------------------------------------------
809: // Function: enableAdapterInterrupts, disableAdapterInterrupts
810: //
811: // Purpose:
812: // Turn on/off interrupts at the adapter.
813:
814: void Intel82557::enableAdapterInterrupts()
815: {
816: /*
817: * For 82558, mask (disable) the ER and FCP interrupts.
818: */
819: UInt8 interruptByte;
820: interruptByte = SCB_INTERRUPT_ER | SCB_INTERRUPT_FCP;
821: OSWriteLE8(&CSR_p->interrupt, interruptByte);
822: interruptEnabled = true;
823: return;
824: }
825:
826: void Intel82557::disableAdapterInterrupts()
827: {
828: UInt8 interruptByte;
829: interruptByte = SCB_INTERRUPT_M;
830: OSWriteLE8(&CSR_p->interrupt, interruptByte);
831: interruptEnabled = false;
832: return;
833: }
834:
835: //---------------------------------------------------------------------------
836: // Function: _logCounters
837: //
838: // Purpose:
839: // If Verbose is defined as yes, log extra information about errors that
840: // have occurred.
841:
842: static inline void
843: _logCounters(errorCounters_t * errorCounters_p)
844: {
845: if (errorCounters_p->tx_good_frames)
846: IOLog("tx_good_frames %ld\n",
847: OSReadLE32(&errorCounters_p->tx_good_frames));
848: if (errorCounters_p->tx_maxcol_errors)
849: IOLog("tx_maxcol_errors %ld\n",
850: OSReadLE32(&errorCounters_p->tx_maxcol_errors));
851: if (errorCounters_p->tx_late_collision_errors)
852: IOLog("tx_late_collision_errors %ld\n",
853: OSReadLE32(&errorCounters_p->tx_late_collision_errors));
854: if (errorCounters_p->tx_underrun_errors)
855: IOLog("tx_underrun_errors %ld\n",
856: OSReadLE32(&errorCounters_p->tx_underrun_errors));
857: if (errorCounters_p->tx_lost_carrier_sense_errors)
858: IOLog("tx_lost_carrier_sense_errors %ld\n",
859: OSReadLE32(&errorCounters_p->tx_lost_carrier_sense_errors));
860: if (errorCounters_p->tx_deferred)
861: IOLog("tx_deferred %ld\n", OSReadLE32(&errorCounters_p->tx_deferred));
862: if (errorCounters_p->tx_single_collisions)
863: IOLog("tx_single_collisions %ld\n",
864: OSReadLE32(&errorCounters_p->tx_single_collisions));
865: if (errorCounters_p->tx_multiple_collisions)
866: IOLog("tx_multiple_collisions %ld\n",
867: OSReadLE32(&errorCounters_p->tx_multiple_collisions));
868: if (errorCounters_p->tx_total_collisions)
869: IOLog("tx_total_collisions %ld\n",
870: OSReadLE32(&errorCounters_p->tx_total_collisions));
871: if (errorCounters_p->rx_good_frames)
872: IOLog("rx_good_frames %ld\n",
873: OSReadLE32(&errorCounters_p->rx_good_frames));
874: if (errorCounters_p->rx_crc_errors)
875: IOLog("rx_crc_errors %ld\n",
876: OSReadLE32(&errorCounters_p->rx_crc_errors));
877: if (errorCounters_p->rx_alignment_errors)
878: IOLog("rx_alignment_errors %ld\n",
879: OSReadLE32(&errorCounters_p->rx_alignment_errors));
880: if (errorCounters_p->rx_resource_errors)
881: IOLog("rx_resource_errors %ld\n",
882: OSReadLE32(&errorCounters_p->rx_resource_errors));
883: if (errorCounters_p->rx_overrun_errors)
884: IOLog("rx_overrun_errors %ld\n",
885: OSReadLE32(&errorCounters_p->rx_overrun_errors));
886: if (errorCounters_p->rx_collision_detect_errors)
887: IOLog("rx_collision_detect_errors %ld\n",
888: OSReadLE32(&errorCounters_p->rx_collision_detect_errors));
889: if (errorCounters_p->rx_short_frame_errors)
890: IOLog("rx_short_frame_errors %ld\n",
891: OSReadLE32(&errorCounters_p->rx_short_frame_errors));
892: return;
893: }
894:
895: //---------------------------------------------------------------------------
896: // Function: _dumpStatistics
897: //
898: // Purpose:
899: // _dumpStatistics issues a new statistics dump command. Every few seconds,
900: // _updateStatistics is called from timeoutOccurred to check for updated
901: // statistics. If complete, update our counters, and issue a new dump
902: // command.
903:
904: bool Intel82557::_dumpStatistics()
905: {
906: reserveDebuggerLock();
907:
908: if (!_waitSCBCommandClear(CSR_p)) {
909: IOLog("%s: _dumpStatistics: _waitSCBCommandClear failed\n", getName());
910: return false;
911: }
912:
913: OSWriteLE8(&CSR_p->command,
914: CSR_FIELD(SCB_COMMAND_CUC, SCB_CUC_DUMP_RESET_STAT));
915:
916: prevCUCommand = SCB_CUC_DUMP_RESET_STAT;
917:
918: releaseDebuggerLock();
919:
920: return true;
921: }
922:
923: //---------------------------------------------------------------------------
924: // Function: _updateStatistics
925: //
926: // Purpose:
927: // Gather statistics information from the adapter at regular intervals.
928:
929: void Intel82557::_updateStatistics()
930: {
931: if (OSReadLE32(&errorCounters_p->_status) != DUMP_STATUS) {
932: if (verbose)
933: _logCounters(errorCounters_p);
934:
935: // Ethernet transmitter stats.
936: //
937: etherStats->dot3StatsEntry.singleCollisionFrames +=
938: OSReadLE32(&errorCounters_p->tx_single_collisions);
939:
940: etherStats->dot3StatsEntry.multipleCollisionFrames +=
941: OSReadLE32(&errorCounters_p->tx_multiple_collisions);
942:
943: etherStats->dot3StatsEntry.lateCollisions +=
944: OSReadLE32(&errorCounters_p->tx_late_collision_errors);
945:
946: etherStats->dot3StatsEntry.excessiveCollisions +=
947: OSReadLE32(&errorCounters_p->tx_maxcol_errors);
948:
949: etherStats->dot3StatsEntry.deferredTransmissions +=
950: OSReadLE32(&errorCounters_p->tx_deferred);
951:
952: etherStats->dot3StatsEntry.carrierSenseErrors +=
953: OSReadLE32(&errorCounters_p->tx_lost_carrier_sense_errors);
954:
955: etherStats->dot3TxExtraEntry.underruns +=
956: OSReadLE32(&errorCounters_p->tx_underrun_errors);
957:
958: // Ethernet receiver stats.
959: //
960: etherStats->dot3StatsEntry.alignmentErrors +=
961: OSReadLE32(&errorCounters_p->rx_alignment_errors);
962:
963: etherStats->dot3StatsEntry.fcsErrors +=
964: OSReadLE32(&errorCounters_p->rx_crc_errors);
965:
966: etherStats->dot3RxExtraEntry.resourceErrors +=
967: OSReadLE32(&errorCounters_p->rx_resource_errors);
968:
969: etherStats->dot3RxExtraEntry.overruns +=
970: OSReadLE32(&errorCounters_p->rx_overrun_errors);
971:
972: etherStats->dot3RxExtraEntry.collisionErrors +=
973: OSReadLE32(&errorCounters_p->rx_collision_detect_errors);
974:
975: etherStats->dot3RxExtraEntry.frameTooShorts +=
976: OSReadLE32(&errorCounters_p->rx_short_frame_errors);
977:
978: // Generic network stats. For the error counters, we assume
979: // the Ethernet stats will never be cleared. Thus we derive the
980: // error counters by summing the appropriate Ethernet error fields.
981: //
982: netStats->outputErrors =
983: ( etherStats->dot3StatsEntry.lateCollisions
984: + etherStats->dot3StatsEntry.excessiveCollisions
985: + etherStats->dot3StatsEntry.carrierSenseErrors
986: + etherStats->dot3TxExtraEntry.underruns
987: + etherStats->dot3TxExtraEntry.resourceErrors);
988:
989: netStats->inputErrors =
990: ( etherStats->dot3StatsEntry.fcsErrors
991: + etherStats->dot3StatsEntry.alignmentErrors
992: + etherStats->dot3RxExtraEntry.resourceErrors
993: + etherStats->dot3RxExtraEntry.overruns
994: + etherStats->dot3RxExtraEntry.collisionErrors
995: + etherStats->dot3RxExtraEntry.frameTooShorts);
996:
997: netStats->collisions +=
998: OSReadLE32(&errorCounters_p->tx_total_collisions);
999:
1000: OSWriteLE32(&errorCounters_p->_status, DUMP_STATUS);
1001: _dumpStatistics();
1002: }
1003: }
1004:
1005: //---------------------------------------------------------------------------
1006: // Function: _allocateMemPage
1007: //
1008: // Purpose:
1009: // Allocate a page of memory.
1010:
1011: bool Intel82557::_allocateMemPage(pageBlock_t * p)
1012: {
1013: p->memSize = PAGE_SIZE;
1014: p->memPtr = IOMallocAligned(p->memSize, PAGE_SIZE);
1015:
1016: if (!p->memPtr)
1017: return false;
1018:
1019: bzero(p->memPtr, p->memSize);
1020: p->memAllocPtr = p->memPtr; /* initialize for allocation routine */
1021: p->memAvail = p->memSize;
1022:
1023: return true;
1024: }
1025:
1026: //---------------------------------------------------------------------------
1027: // Function: _freeMemPage
1028: //
1029: // Purpose:
1030: // Deallocate a page of memory.
1031: //
1032: void Intel82557::_freeMemPage(pageBlock_t * p)
1033: {
1034: IOFreeAligned(p->memPtr, p->memSize);
1035: }
1036:
1037: //---------------------------------------------------------------------------
1038: // Function: hwInit
1039: //
1040: // Purpose:
1041: // Reset/configure the chip, detect the PHY.
1042:
1043: bool Intel82557::hwInit()
1044: {
1045: disableAdapterInterrupts();
1046: _resetChip();
1047: disableAdapterInterrupts();
1048:
1049: /* disable early RX interrupt */
1050: OSWriteLE8(&CSR_p->earlyRxInterrupt, 0);
1051:
1052: /* load command unit base address */
1053: if (!_waitSCBCommandClear(CSR_p)) {
1054: IOLog("%s: hwInit: CU _waitSCBCommandClear failed\n", getName());
1055: return false;
1056: }
1057: OSWriteLE32(&CSR_p->pointer, 0);
1058: OSWriteLE8(&CSR_p->command, CSR_FIELD(SCB_COMMAND_CUC, SCB_CUC_LOAD_BASE));
1059: prevCUCommand = SCB_CUC_LOAD_BASE;
1060:
1061: /* load receive unit base address */
1062: if (!_waitSCBCommandClear(CSR_p)) {
1063: IOLog("%s: hwInit: RU _waitSCBCommandClear failed\n", getName());
1064: return false;
1065: }
1066: OSWriteLE32(&CSR_p->pointer, 0);
1067: OSWriteLE8(&CSR_p->command, CSR_FIELD(SCB_COMMAND_RUC, SCB_RUC_LOAD_BASE));
1068:
1069: if (!_waitSCBCommandClear(CSR_p)) {
1070: IOLog("%s: hwInit: before LOAD_DUMP_COUNTERS_ADDRESS:"
1071: " _waitSCBCommandClear failed\n", getName());
1072: return false;
1073: }
1074: OSWriteLE32(&errorCounters_p->_status, DUMP_STATUS);
1075: OSWriteLE32(&CSR_p->pointer, errorCounters_paddr);
1076: OSWriteLE8(&CSR_p->command,
1077: CSR_FIELD(SCB_COMMAND_CUC, SCB_CUC_LOAD_DUMP_ADDR));
1078: prevCUCommand = SCB_CUC_LOAD_DUMP_ADDR;
1079:
1080: if (!_waitSCBCommandClear(CSR_p)) {
1081: IOLog("%s: hwInit: before intrACK _waitSCBCommandClear failed\n",
1082: getName());
1083: return false;
1084: }
1085:
1086: /* Setup flow-control threshold */
1087: OSWriteLE8(&CSR_p->flowControlThreshold,
1088: CSR_FIELD(FC_THRESHOLD, FC_THRESHOLD_512));
1089:
1090: _intrACK(CSR_p); /* ack any pending interrupts */
1091:
1092: _phyProbe();
1093:
1094: phyID = _phyGetID();
1095: VPRINT("%s: PHY model id is 0x%08lx\n", getName(), phyID);
1096: phyID &= PHY_MODEL_MASK;
1097:
1098: if (!config())
1099: return false;
1100: IOSleep(500);
1101:
1102: if (!iaSetup())
1103: return false;
1104:
1105: _intrACK(CSR_p); /* ack any pending interrupts */
1106:
1107: return true;
1108: }
1109:
1110: //---------------------------------------------------------------------------
1111: // Function: _memAlloc
1112: //
1113: // Purpose:
1114: // Return the next aligned chunk of memory in our shared memory page.
1115:
1116: void * Intel82557::_memAllocFrom(pageBlock_t * p, UInt allocSize, UInt align)
1117: {
1118: void * allocPtr;
1119: UInt sizeReal;
1120:
1121: if (align == 0)
1122: return 0;
1123:
1124: // Advance allocPtr to next aligned boundary.
1125: allocPtr =
1126: (void *)((UInt)((UInt) p->memAllocPtr + (align - 1)) & (~(align - 1)));
1127:
1128: // Actual size of required storage. We need to take the alignment padding
1129: // into account.
1130: sizeReal = allocSize + ((UInt) allocPtr - (UInt) p->memAllocPtr);
1131:
1132: if (sizeReal > p->memAvail)
1133: return 0;
1134:
1135: p->memAllocPtr = (void *)((UInt) p->memAllocPtr + sizeReal);
1136: p->memAvail = p->memSize - ((UInt) p->memAllocPtr - (UInt) p->memPtr);
1137: return allocPtr;
1138: }
1139:
1140: //---------------------------------------------------------------------------
1141: // Function: coldInit
1142: //
1143: // Purpose:
1144: // One-time initialization code. This is called by start(), before we
1145: // attach any client objects.
1146:
1147: bool Intel82557::coldInit()
1148: {
1149: IOReturn result;
1150: IOPhysicalAddress paddr;
1151:
1152: disableAdapterInterrupts();
1153:
1154: /* allocate and initialize shared memory pointers */
1155: if (!_allocateMemPage(&shared)) {
1156: IOLog("%s: Can't allocate shared memory page\n", getName());
1157: return false;
1158: }
1159: if (!_allocateMemPage(&txRing)) {
1160: IOLog("%s: Can't allocate memory page for TX ring\n", getName());
1161: return false;
1162: }
1163: if (!_allocateMemPage(&rxRing)) {
1164: IOLog("%s: Can't allocate memory page for RX ring\n", getName());
1165: return false;
1166: }
1167:
1168: /* allocate memory for shared data structures
1169: * self test needs to be
1170: * 16 byte aligned
1171: */
1172: overlay_p = (overlay_t *) _memAllocFrom(&shared, sizeof(overlay_t),
1173: PARAGRAPH_ALIGNMENT);
1174: if (!overlay_p)
1175: return false;
1176: result = IOPhysicalFromVirtual((vm_address_t) overlay_p, &overlay_paddr);
1177: if (result != kIOReturnSuccess) {
1178: IOLog("%s: Invalid command block address\n", getName());
1179: return false;
1180: }
1181:
1182: tcbList_p = (tcb_t *) _memAllocFrom(&txRing,
1183: sizeof(tcb_t) * NUM_TRANSMIT_FRAMES,
1184: CACHE_ALIGNMENT);
1185: if (!tcbList_p)
1186: return false;
1187:
1188: KDB_tcb_p = (tcb_t *) _memAllocFrom(&shared,
1189: sizeof(tcb_t),
1190: CACHE_ALIGNMENT);
1191: if (!KDB_tcb_p)
1192: return false;
1193: result = IOPhysicalFromVirtual((vm_address_t) KDB_tcb_p,
1194: &KDB_tcb_p->_paddr);
1195: if (result != kIOReturnSuccess) {
1196: IOLog("%s: Invalid TCB address\n", getName());
1197: return false;
1198: }
1199:
1200: result = IOPhysicalFromVirtual((vm_address_t) &KDB_tcb_p->_tbds, &paddr);
1201: if (result != kIOReturnSuccess) {
1202: IOLog("%s: Invalid TCB->_TBD address\n", getName());
1203: return false;
1204: }
1205: OSWriteLE32(&KDB_tcb_p->tbdAddr, paddr);
1206:
1207: KDB_buf_p = _memAllocFrom(&shared, ETHERMAXPACKET, DWORD_ALIGNMENT);
1208: if (!KDB_buf_p)
1209: return false;
1210: result = IOPhysicalFromVirtual((vm_address_t) KDB_buf_p, &KDB_buf_paddr);
1211: if (result != kIOReturnSuccess) {
1212: IOLog("%s: Invalid address\n", getName());
1213: return false;
1214: }
1215:
1216: errorCounters_p = (errorCounters_t *) _memAllocFrom(&shared,
1217: sizeof(errorCounters_t),
1218: DWORD_ALIGNMENT);
1219: if (!errorCounters_p)
1220: return false;
1221: result = IOPhysicalFromVirtual((vm_address_t) errorCounters_p,
1222: &errorCounters_paddr);
1223: if (result != kIOReturnSuccess) {
1224: IOLog("%s: Invalid errorCounters address\n", getName());
1225: return false;
1226: }
1227:
1228: rfdList_p = (rfd_t *) _memAllocFrom(&rxRing,
1229: sizeof(rfd_t) * NUM_RECEIVE_FRAMES,
1230: CACHE_ALIGNMENT);
1231: if (!rfdList_p)
1232: return false;
1233:
1234: if (!_selfTest())
1235: return false;
1236:
1237: myAddress = eeprom->getContents()->addr;
1238:
1239: return true;
1240: }
1241:
1242: //---------------------------------------------------------------------------
1243: // Function: receiveInterruptOccurred
1244: //
1245: // Purpose:
1246: // Hand up rceived frames.
1247:
1248: bool Intel82557::receiveInterruptOccurred()
1249: {
1250: bool packetsQueued = false;
1251:
1252: while (OSReadLE16(&headRfd->status) & RFD_STATUS_C) {
1253: rbd_count_t rbd_count = OSReadLE32(&headRfd->_rbd.count);
1254:
1255: // rxCount does NOT include the Ethernet CRC (FCS).
1256: //
1257: UInt rxCount = CSR_VALUE(RBD_COUNT, rbd_count);
1258:
1259: #if 0
1260: // When the receive unit runs out of resources, it will
1261: // skip over RFD/RBD, making them as complete, but the RBD will
1262: // have zero bytes and the EOF bit will not be set.
1263: // We just skip over those and allow them to be recycled.
1264: //
1265: // In those cases, the RFD->status word will be 0x8220.
1266:
1267: /* should have exactly 1 rbd per rfd */
1268: if (!(rbd_count & RBD_COUNT_EOF)) {
1269: IOLog("%s: more than 1 rbd, frame size %d\n", getName(), rxCount);
1270:
1271: IOLog("%s: RFD status: %04x\n", getName(),
1272: OSReadLE16(&headRfd->status));
1273:
1274: issueReset();
1275: return;
1276: }
1277: #endif
1278:
1279: if ((!(OSReadLE16(&headRfd->status) & RFD_STATUS_OK)) ||
1280: (rxCount < (ETHERMINPACKET - ETHERCRC)) ||
1281: !enabledForNetif) {
1282: ; /* bad or unwanted packet */
1283: }
1284: else {
1285: struct mbuf * m = headRfd->_rbd._mbuf;
1286: struct mbuf * m_in = 0; // packet to pass up to inputPacket()
1287: bool replaced;
1288:
1289: packetsReceived = true;
1290:
1291: m_in = replaceOrCopyPacket(&m, rxCount, &replaced);
1292: if (!m_in) {
1293: etherStats->dot3RxExtraEntry.resourceErrors++;
1294: goto RX_INTR_ABORT;
1295: }
1296:
1297: if (replaced && (updateRFDFromMbuf(headRfd, m) == false)) {
1298: freePacket(m); // free the new replacement mbuf.
1299: m_in = 0; // pass up nothing.
1300: etherStats->dot3RxExtraEntry.resourceErrors++;
1301: IOLog("%s: updateRFDFromMbuf() error\n", getName());
1302: goto RX_INTR_ABORT;
1303: }
1304:
1305: netif->inputPacket(m_in, rxCount, true);
1306: packetsQueued = true;
1307: netStats->inputPackets++;
1308: }
1309:
1310: RX_INTR_ABORT:
1311: /* clear fields in rfd */
1312: OSWriteLE16(&headRfd->status, 0);
1313: OSWriteLE16(&headRfd->command, (RFD_COMMAND_SF | RFD_COMMAND_EL));
1314: OSWriteLE32(&headRfd->rbdAddr, C_NULL);
1315: OSWriteLE32(&headRfd->misc, 0);
1316:
1317: /* clear fields in rbd */
1318: OSWriteLE32(&headRfd->_rbd.count, 0);
1319: OSWriteLE32(&headRfd->_rbd.size, CSR_FIELD(RBD_SIZE, MAX_BUF_SIZE) |
1320: RBD_SIZE_EL);
1321:
1322: /* adjust tail markers */
1323: OSWriteLE32(&tailRfd->_rbd.size, CSR_FIELD(RBD_SIZE, MAX_BUF_SIZE));
1324: OSWriteLE16(&tailRfd->command, RFD_COMMAND_SF);
1325:
1326: tailRfd = headRfd; // new tail
1327: headRfd = headRfd->_next; // new head
1328: } /* while */
1329:
1330: return packetsQueued;
1331: }
1332:
1333: //---------------------------------------------------------------------------
1334: // Function: transmitInterruptOccurred
1335: //
1336: // Purpose:
1337: // Free up packets associated with any completed TCB's.
1338:
1339: void Intel82557::transmitInterruptOccurred()
1340: {
1341: tcbQ_t * tcbQ_p = &tcbQ;
1342: tcb_t * head;
1343:
1344: head = tcbQ_p->activeHead_p;
1345: while (tcbQ_p->numFree < tcbQ_p->numTcbs &&
1346: (OSReadLE16(&head->status) & TCB_STATUS_C))
1347: {
1348: OSWriteLE16(&head->status, 0);
1349: if (head->_mbuf) {
1350: freePacket(head->_mbuf);
1351: head->_mbuf = 0;
1352: }
1353: head = tcbQ_p->activeHead_p = head->_next;
1354: tcbQ_p->numFree++;
1355: }
1356:
1357: return;
1358: }
1359:
1360: //---------------------------------------------------------------------------
1361: // Function: checkForInterrupt
1362: //
1363: // Purpose:
1364: // A filtering function for the IOFilterInterruptEventSource. We use
1365: // this because otherwise interrupts will cause a hard hang on i386.
1366:
1367: #ifdef USE_FILTER_INTERRUPT_EVENT_SRC
1368: bool
1369: Intel82557::checkForInterrupt(IOFilterInterruptEventSource * src)
1370: {
1371: UInt8 interruptByte;
1372:
1373: // I386 hack! Turn off all hardware interrupt sources.
1374: //
1375: interruptByte = SCB_INTERRUPT_M;
1376: OSWriteLE8(&CSR_p->interrupt, interruptByte);
1377:
1378: return true; // go ahead and call interruptOccurred()
1379: }
1380: #endif
1381:
1382: //---------------------------------------------------------------------------
1383: // Function: interruptOccurred
1384: //
1385: // Purpose:
1386: // Field an interrupt.
1387:
1388: void Intel82557::interruptOccurred(IOInterruptEventSource * src, int /*count*/)
1389: {
1390: scb_status_t status;
1391: bool flushInputQ = false;
1392: bool doService = false;
1393:
1394: reserveDebuggerLock();
1395:
1396: if (interruptEnabled == false) {
1397: _intrACK(CSR_p);
1398: releaseDebuggerLock();
1399: IOLog("%s: unexpected interrupt\n", getName());
1400: return;
1401: }
1402:
1403: /*
1404: * Loop until the interrupt line becomes deasserted.
1405: */
1406: while (1) {
1407: if ((status = _intrACK(CSR_p)) == 0)
1408: break;
1409:
1410: /*
1411: * RX interrupt.
1412: */
1413: if (status & (SCB_STATUS_FR | SCB_STATUS_RNR)) {
1414:
1415: flushInputQ = receiveInterruptOccurred() || flushInputQ;
1416:
1417: etherStats->dot3RxExtraEntry.interrupts++;
1418:
1419: if (status & SCB_STATUS_RNR) {
1420: etherStats->dot3RxExtraEntry.resets++;
1421:
1422: _abortReceive();
1423: _resetRfdList();
1424:
1425: if (!_startReceive()) {
1426: IOLog("%s: Unable to restart receiver\n", getName());
1427: // issueReset(); /* shouldn't need to do this. */
1428: }
1429: }
1430: }
1431:
1432: /*
1433: * TX interrupt.
1434: */
1435: if (status & (SCB_STATUS_CX | SCB_STATUS_CNA)) {
1436: transmitInterruptOccurred();
1437: etherStats->dot3TxExtraEntry.interrupts++;
1438: doService = true;
1439: }
1440: }
1441:
1442: #ifdef USE_FILTER_INTERRUPT_EVENT_SRC
1443: enableAdapterInterrupts(); // I386 hack! - turn interrupts back on
1444: #endif
1445:
1446: releaseDebuggerLock();
1447:
1448: if (enabledForNetif) {
1449: // Flush all packets received and pass them to the network stack.
1450: //
1451: if (flushInputQ)
1452: netif->flushInputQueue();
1453:
1454: // Call service() without holding the debugger lock to prevent a
1455: // deadlock when service() calls our outputPacket() function.
1456: //
1457: if (doService)
1458: transmitQueue->service();
1459: }
1460: }
1461:
1462: //---------------------------------------------------------------------------
1463: // Function: updateTCBForMbuf
1464: //
1465: // Update the TxCB pointed by tcb_p to point to the mbuf chain 'm'.
1466: // Returns the mbuf encoded onto the TxCB.
1467:
1468: struct mbuf *
1469: Intel82557::updateTCBForMbuf(tcb_t * tcb_p, struct mbuf * m)
1470: {
1471: // Set the invariant TCB fields.
1472: //
1473: OSWriteLE16(&tcb_p->status, 0);
1474:
1475: if (++txCount == TRANSMIT_INT_DELAY) {
1476: OSWriteLE16(&tcb_p->command, CSR_FIELD(TCB_COMMAND, CB_CMD_TRANSMIT) |
1477: TCB_COMMAND_S |
1478: TCB_COMMAND_SF |
1479: TCB_COMMAND_I);
1480: txCount = 0;
1481: }
1482: else
1483: OSWriteLE16(&tcb_p->command, CSR_FIELD(TCB_COMMAND, CB_CMD_TRANSMIT) |
1484: TCB_COMMAND_S |
1485: TCB_COMMAND_SF);
1486:
1487: OSWriteLE8(&tcb_p->threshold, TCB_TX_THRESHOLD);
1488: OSWriteLE16(&tcb_p->count, 0); // all data are in the TBD's, none in TxCB
1489:
1490: // Since the format of a TBD closely matches the structure of an
1491: // 'struct IOPhysicalSegment', we shall have the cursor update the TBD list
1492: // directly.
1493: //
1494: UInt segments = txMbufCursor->getPhysicalSegmentsWithCoalesce(m,
1495: (struct IOPhysicalSegment *) &tcb_p->_tbds[0],
1496: TBDS_PER_TCB);
1497:
1498: if (!segments) {
1499: IOLog("%s: getPhysicalSegments error, pkt len = %d\n",
1500: getName(), m->m_pkthdr.len);
1501: return 0;
1502: }
1503:
1504: // Update the TBD array size count.
1505: //
1506: OSWriteLE8(&tcb_p->number, segments);
1507:
1508: return m;
1509: }
1510:
1511: //---------------------------------------------------------------------------
1512: // Function: outputPacket <IONetworkController>
1513: //
1514: // Purpose:
1515: // Transmit the packet handed by our IOOutputQueue.
1516: // TCBs have the suspend bit set, so that the CU goes into the suspend
1517: // state when done. We use the CU_RESUME optimization that allows us to
1518: // issue CU_RESUMES without waiting for SCB command to clear.
1519: //
1520: UInt32 Intel82557::outputPacket(struct mbuf * m)
1521: {
1522: tcb_t * tcb_p;
1523:
1524: if (!enabledForNetif) { // drop the packet.
1525: freePacket(m);
1526: return kIOOQReturnDropped;
1527: }
1528:
1529: reserveDebuggerLock();
1530:
1531: if (tcbQ.numFree == 0) { // retry when more space is available.
1532: releaseDebuggerLock();
1533: return kIOOQReturnStall;
1534: }
1535:
1536: packetsTransmitted = true;
1537: netStats->outputPackets++;
1538:
1539: tcb_p = tcbQ.freeHead_p;
1540:
1541: tcb_p->_mbuf = updateTCBForMbuf(tcb_p, m);
1542: if (tcb_p->_mbuf == 0) {
1543: etherStats->dot3TxExtraEntry.resourceErrors++;
1544: goto fail;
1545: }
1546:
1547: /* update the queue */
1548: tcbQ.numFree--;
1549: tcbQ.freeHead_p = tcbQ.freeHead_p->_next;
1550:
1551: /* The TCB is already setup and the suspend bit set. Now clear the
1552: * suspend bit of the previous TCB.
1553: */
1554: if (tcbQ.activeTail_p != tcb_p)
1555: OSClearLE16(&tcbQ.activeTail_p->command, TCB_COMMAND_S);
1556: tcbQ.activeTail_p = tcb_p;
1557:
1558: /*
1559: * CUC_RESUME is optimized such that it is unnecessary to wait
1560: * for the CU to clear the SCB command word if the previous command
1561: * was a resume and the CU state is not idle.
1562: */
1563: if (CSR_VALUE(SCB_STATUS_CUS, OSReadLE16(&CSR_p->status)) == SCB_CUS_IDLE)
1564: {
1565: if (!_waitSCBCommandClear(CSR_p)) {
1566: IOLog("%s: outputPacket: _waitSCBCommandClear error\n", getName());
1567: etherStats->dot3TxExtraEntry.timeouts++;
1568: goto fail;
1569: }
1570: OSWriteLE32(&CSR_p->pointer, tcb_p->_paddr);
1571: OSWriteLE8(&CSR_p->command, CSR_FIELD(SCB_COMMAND_CUC, SCB_CUC_START));
1572: prevCUCommand = SCB_CUC_START;
1573: }
1574: else {
1575: if (prevCUCommand != SCB_CUC_RESUME) {
1576: if (!_waitSCBCommandClear(CSR_p)) {
1577: IOLog("%s: outputPacket: _waitSCBCommandClear error\n",
1578: getName());
1579: etherStats->dot3TxExtraEntry.timeouts++;
1580: goto fail;
1581: }
1582: }
1583: OSWriteLE8(&CSR_p->command, CSR_FIELD(SCB_COMMAND_CUC,SCB_CUC_RESUME));
1584: prevCUCommand = SCB_CUC_RESUME;
1585: }
1586: releaseDebuggerLock();
1587: return kIOOQReturnSuccess;
1588:
1589: fail:
1590: freePacket(m);
1591: tcb_p->_mbuf = 0;
1592: releaseDebuggerLock();
1593: return kIOOQReturnDropped;
1594: }
1595:
1596: //---------------------------------------------------------------------------
1597: // Function: _receivePacket
1598: //
1599: // Purpose:
1600: // Part of kerneldebugger protocol.
1601: // Returns true if a packet was received successfully.
1602: //
1603: bool Intel82557::_receivePacket(void * pkt, UInt * len, UInt timeout)
1604: {
1605: bool processPacket = true;
1606: bool ret = false;
1607: scb_status_t status;
1608:
1609: timeout *= 1000;
1610:
1611: while ((OSReadLE16(&headRfd->status) & RFD_STATUS_C) == 0) {
1612: if ((int) timeout <= 0) {
1613: processPacket = false;
1614: break;
1615: }
1616: IODelay(50);
1617: timeout -= 50;
1618: }
1619:
1620: if (processPacket) {
1621: if ((OSReadLE16(&headRfd->status) & RFD_STATUS_OK) &&
1622: (OSReadLE32(&headRfd->_rbd.count) & RBD_COUNT_EOF))
1623: {
1624: // Pass up good frames.
1625: //
1626: *len = CSR_VALUE(RBD_COUNT, OSReadLE32(&headRfd->_rbd.count));
1627: *len = MIN(*len, ETHERMAXPACKET);
1628: bcopy(mtod(headRfd->_rbd._mbuf, void *), pkt, *len);
1629: ret = true;
1630: }
1631:
1632: /* the head becomes the new tail */
1633: /* clear fields in rfd */
1634: OSWriteLE16(&headRfd->status, 0);
1635: OSWriteLE16(&headRfd->command, (RFD_COMMAND_SF | RFD_COMMAND_EL));
1636: OSWriteLE32(&headRfd->rbdAddr, C_NULL);
1637: OSWriteLE32(&headRfd->misc, 0);
1638:
1639: /* clear fields in rbd */
1640: OSWriteLE32(&headRfd->_rbd.count, 0);
1641: OSWriteLE32(&headRfd->_rbd.size, CSR_FIELD(RBD_SIZE, MAX_BUF_SIZE) |
1642: RBD_SIZE_EL);
1643:
1644: /* adjust tail markers */
1645: OSWriteLE32(&tailRfd->_rbd.size, CSR_FIELD(RBD_SIZE, MAX_BUF_SIZE));
1646: OSWriteLE16(&tailRfd->command, RFD_COMMAND_SF);
1647:
1648: tailRfd = headRfd; // new tail
1649: headRfd = headRfd->_next; // new head
1650: }
1651:
1652: status = OSReadLE16(&CSR_p->status) & SCB_STATUS_RNR;
1653: if (status) {
1654: OSWriteLE16(&CSR_p->status, status); // ack RNR interrupt
1655:
1656: IOLog("Intel82557::%s restarting receiver\n", __FUNCTION__);
1657:
1658: IOLog("%s::%s RUS:0x%x Index:%d\n", getName(), __FUNCTION__,
1659: CSR_VALUE(SCB_STATUS_RUS, OSReadLE16(&CSR_p->status)),
1660: tailRfd - rfdList_p);
1661:
1662: _abortReceive();
1663:
1664: #if 0 // Display RFD/RBD fields
1665: for (int i = 0; i < NUM_RECEIVE_FRAMES; i++) {
1666: IOLog(" %02d: %04x %04x - %08x %08x\n", i,
1667: OSReadLE16(&rfdList_p[i].command),
1668: OSReadLE16(&rfdList_p[i].status),
1669: OSReadLE32(&rfdList_p[i]._rbd.size),
1670: OSReadLE32(&rfdList_p[i].misc));
1671: }
1672: #endif
1673:
1674: _resetRfdList();
1675: _startReceive();
1676: }
1677:
1678: return ret;
1679: }
1680:
1681: //---------------------------------------------------------------------------
1682: // Function: _sendPacket
1683: //
1684: // Purpose:
1685: // Part of kerneldebugger protocol.
1686: // Returns true if the packet was sent successfully.
1687:
1688: bool Intel82557::_sendPacket(void * pkt, UInt len)
1689: {
1690: tbd_t * tbd_p;
1691:
1692: // Set up the TCB and issue the command
1693: //
1694: OSWriteLE16(&KDB_tcb_p->status, 0);
1695: OSWriteLE32(&KDB_tcb_p->link, C_NULL);
1696: OSWriteLE8(&KDB_tcb_p->threshold, TCB_TX_THRESHOLD);
1697: OSWriteLE16(&KDB_tcb_p->command, CSR_FIELD(TCB_COMMAND, CB_CMD_TRANSMIT) |
1698: TCB_COMMAND_EL |
1699: TCB_COMMAND_SF );
1700: OSWriteLE16(&KDB_tcb_p->count, 0); // all data are in the TBD's.
1701: OSWriteLE8(&KDB_tcb_p->number, 1); // 1 TBD only.
1702:
1703: // Copy the debugger packet to the pre-allocated buffer area.
1704: //
1705: len = MIN(len, ETHERMAXPACKET);
1706: len = MAX(len, ETHERMINPACKET);
1707: bcopy(pkt, KDB_buf_p, len);
1708:
1709: // Update the TBD.
1710: //
1711: tbd_p = &KDB_tcb_p->_tbds[0];
1712: OSWriteLE32(&tbd_p->addr, KDB_buf_paddr);
1713: OSWriteLE32(&tbd_p->size, CSR_FIELD(TBD_SIZE, len));
1714:
1715: // Start up the command unit to send the packet.
1716: //
1717: return _polledCommand((cbHeader_t *) KDB_tcb_p, KDB_tcb_p->_paddr);
1718: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.