|
|
1.1 ! root 1: {\rtf0\ansi{\fonttbl\f0\fmodern Ohlfs;\f1\fmodern Courier;} ! 2: \paperw13040 ! 3: \paperh10200 ! 4: \margl120 ! 5: \margr120 ! 6: {\colortbl\red0\green0\blue0;} ! 7: \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\f0\b0\i0\ul0\fs24 enet Pseudocode\ ! 8: \ ! 9: ! 10: \f1\b\fs28 /* \ ! 11: * instance variables\ ! 12: */ ! 13: \f0\b0\fs24 \ ! 14: \{\ ! 15: enetBuf_t * ! 16: \fc0 TxBufList; // Free buffers. Maybe one global \ ! 17: // list?\ ! 18: enetBuf_t *RxBufList;\ ! 19: id txBufLock; // NXSpinLock; protects TxBufList\ ! 20: id rxBufLock;\ ! 21: id rpcLock; // NXSleepLock; I/O thread and netOutput\ ! 22: // must grab this to do kernel RPCs\ ! 23: int numTxBufsQd; // # of TX DMA buffers enqueued\ ! 24: int numRxBufsQd;\ ! 25: port_t IOPort; // I/O thread gets all of its work \ ! 26: // thru here\ ! 27: int jamRetryCount; ! 28: \ ! 29: \}\ ! 30: \ ! 31: ! 32: \f1\b\fs28 /* \ ! 33: * Exported Methods \ ! 34: */ ! 35: \f0\b0\fs24 \ ! 36: ! 37: \ ! 38: + probe:(dev_num_t)devNumber deviceMaster:(port_t)deviceMaster\ ! 39: \{\ ! 40: alloc an instance of self;\ ! 41: return [newInst enetInit:devNumber deviceMaster:deviceMaster];\ ! 42: \}\ ! 43: \ ! 44: /*\ ! 45: * I think this is only called once...\ ! 46: */\ ! 47: - (int)netInit\ ! 48: \{\ ! 49: init instance variables;\ ! 50: init hardware to a good state;\ ! 51: for(some initial # of free enetBufs) \{\ ! 52: kalloc or vm_allocate a page;\ ! 53: break up page into enetBuf's;\ ! 54: for each enetBuf_t \{\ ! 55: init it;\ ! 56: enqueue on Rx or TXBufList;\ ! 57: numFreeBufs++;\ ! 58: \}\ ! 59: \}\ ! 60: [self enqueueRxBufs];\ ! 61: \}\ ! 62: \ ! 63: - (int)netOutput : (netbuf_t)buf\ ! 64: addrs : (void *)addrs\ ! 65: \{\ ! 66: /*\ ! 67: * Assuming that this is NOT called at interrupt level...\ ! 68: */\ ! 69: [rpcLock lock];\ ! 70: dma_enqueue(data = nb_map(netbuf), \ ! 71: dma_id = netbuf, \ ! 72: length = nb_size(netbuf));\ ! 73: if(!running) \{\ ! 74: [self dmaStart];\ ! 75: arrange for NetJamTimer() callout in 10 seconds;\ ! 76: \}\ ! 77: [rpcLock unlock];\ ! 78: \}\ ! 79: \ ! 80: - (netbuf_t)netGetBuf\ ! 81: \{\ ! 82: if no bufs in TxBufList \{\ ! 83: return NULL;\ ! 84: \}\ ! 85: return(nb_alloc_wrapper(&enetBuf->dmaData,\ ! 86: size of DMA Data,\ ! 87: &enetBufFree(),\ ! 88: &enetBuf));\ ! 89: \}\ ! 90: \ ! 91: - (int)netControl : (const char *)command\ ! 92: data : (void *)data\ ! 93: \{\ ! 94: /* crufty crap */\ ! 95: \}\ ! 96: \ ! 97: ! 98: \f1\b\fs28 /* \ ! 99: * Private Methods\ ! 100: */ ! 101: \f0\b0\fs24 \ ! 102: - (void)enqueueRxBufs\ ! 103: \{\ ! 104: /*\ ! 105: * Enqueue all free bufs in RxBufList on hardware DMA queue\ ! 106: */\ ! 107: [rpcLock lock];\ ! 108: do \{\ ! 109: get an enetBuf from RxBufList;\ ! 110: netbuf = nb_alloc_wrapper(&enetBuf->dmaData,\ ! 111: size of DMA Data,\ ! 112: &enetBufFree(),\ ! 113: &enetBuf);\ ! 114: dma_enqueue(data = &enetBuf.dmaData,\ ! 115: dma_id = netbuf, \ ! 116: length = sizeof DMA data);\ ! 117: rxDmaQCount++;\ ! 118: \ ! 119: \} while RxBufList not empty;\ ! 120: [rpcLock unlock]; \ ! 121: \}\ ! 122: \ ! 123: - enetInit:(dev_num_t)devNumber deviceMaster:(port_t)deviceMaster\ ! 124: \{\ ! 125: get ethernet address from monitor or somewhere;\ ! 126: if_attach(a zillion args);\ ! 127: return self;\ ! 128: \}\ ! 129: \ ! 130: - enetInt\ ! 131: \{\ ! 132: if device interrupt \{\ ! 133: log this bogality;\ ! 134: \}\ ! 135: ! 136: \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0 if chan[rcv] interrupt \{\ ! 137: [self enetRxInt];\ ! 138: \}\ ! 139: if chan[xmit] interrupt \{\ ! 140: [self enetTxInt];\ ! 141: \}\ ! 142: ! 143: \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\fc0 \}\ ! 144: \ ! 145: /*\ ! 146: * Note should not be any device errors, only channel errors.\ ! 147: */\ ! 148: ! 149: \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0 - enetRxInt\ ! 150: \{\ ! 151: if any DMA errors (errorInterrupt, busError) \{\ ! 152: dmaAort;\ ! 153: log it and clear it;\ ! 154: \}\ ! 155: if overrun \{\ ! 156: log it and clear it;\ ! 157: \}\ ! 158: do \{\ ! 159: [rpcLock lock];\ ! 160: chan_dma_dequeue(completed only, enable interrupts \ ! 161: if no more);\ ! 162: [rpcLock unlock];\ ! 163: if(dma_id == NULL)\ ! 164: break - done;\ ! 165: if(any errors in chan_status) \{\ ! 166: /* drop it on the floor */\ ! 167: nb_free((netbuf_t)dma_id);\ ! 168: \}\ ! 169: else \{\ ! 170: filter out unwanted multicast packets;\ ! 171: if_handle_input((netbuf_t)dma_id);\ ! 172: \}\ ! 173: \} for all completed descriptors;\ ! 174: [self enqueueRxBufs];\ ! 175: \}\ ! 176: \ ! 177: - enetTxInt\ ! 178: \{\ ! 179: abort = 0;\ ! 180: \ ! 181: untimeout(NetJamTimer callout);\ ! 182: if any DMA errors (errorInterrupt, busError) \{\ ! 183: log it and clear it;\ ! 184: dmaDisable;\ ! 185: abort++;\ ! 186: \}\ ! 187: if late collision or underrun \{\ ! 188: log it and clear it;\ ! 189: abort++;\ ! 190: \}\ ! 191: if No heart beat or >15 retries error \{\ ! 192: abort++;\ ! 193: [self enJam];\ ! 194: \}\ ! 195: do \{\ ! 196: [rpcLock lock];\ ! 197: if(abort) \{\ ! 198: ! 199: \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\fc0 chan_dma_dequeue(ALL descriptors, enable ints);\ ! 200: \}\ ! 201: else \{ ! 202: \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0 \ ! 203: chan_dma_dequeue( ! 204: \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\fc0 completed only, enable ! 205: \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0 ! 206: \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\fc0 interrupts ! 207: \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0 \ ! 208: ! 209: \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\fc0 if no more ! 210: \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0 );\ ! 211: \}\ ! 212: [rpcLock unlock];\ ! 213: if(dma_id == NULL)\ ! 214: break - done;\ ! 215: nb_free((netbuf_t)dma_id);\ ! 216: ! 217: \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\fc0 \} for all completed descriptors; ! 218: \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0 \ ! 219: \}\ ! 220: ! 221: \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\fc0 \ ! 222: - (jam_t)enJam\ ! 223: \{\ ! 224: \ ! 225: if (++jamRetryCount < max) \ ! 226: return JAM_GOOD;\ ! 227: \ ! 228: remember current I/F mode (TPE or thin);\ ! 229: select TPE;\ ! 230: wait some h/w delay for Link Integrity to settle down;\ ! 231: if link integrity good \{\ ! 232: return JAM_GOOD;\ ! 233: \}\ ! 234: else if (mode was TPE on entry) \{\ ! 235: select Thin wire;\ ! 236: return JAM_GOOD;\ ! 237: \}\ ! 238: \ ! 239: /* \ ! 240: * Net down.\ ! 241: */\ ! 242: dequeue and free all frames;\ ! 243: set net_down flag; set timeout to clear it in 10 seconds;\ ! 244: if_down();\ ! 245: return JAM_BAD;\ ! 246: \}\ ! 247: \ ! 248: - (enetBuf_t)enetBufGet(which queue)\ ! 249: \{\ ! 250: safely get an enetBuf from appropriate queue;\ ! 251: \}\ ! 252: \ ! 253: - (void)enetBufPut\ ! 254: \{\ ! 255: safely put an enetBuf on its free queue;\ ! 256: \}\ ! 257: \ ! 258: ! 259: \f1\b\fs28 /*\ ! 260: * Threads and Functions\ ! 261: */ ! 262: \f0\b0\fs24 \ ! 263: \ ! 264: /*\ ! 265: * enetThread() does the following:\ ! 266: * -- handles all interrupts (normally DMA; others are errors)\ ! 267: * -- Dispatches received packets; keeps RX DMA queue as full as possible\ ! 268: * -- detects Net Jammed conditions, reconfigures I/F (TPE or Thin).\ ! 269: */\ ! 270: enetThread(id enetObj)\ ! 271: \{\ ! 272: msg_receive(IOPort);\ ! 273: switch msg_id \{\ ! 274: case INT_MSG_DEVICE:\ ! 275: case INT_MSG_DMA:\ ! 276: [enetObj enetInt];\ ! 277: case ENET_JAMMED_MSG_ID:\ ! 278: [enetObj enJam];\ ! 279: \}\ ! 280: \}\ ! 281: \ ! 282: /*\ ! 283: * Called out from nb_free(), as freefunc(freefunc_arg).\ ! 284: */\ ! 285: enetBufFree(enetBuf_t *enetBuf) \{\ ! 286: enqueue this on enetBufList;\ ! 287: \}\ ! 288: \ ! 289: /*\ ! 290: * Called out via IOTimeout(); we arrange for one of these to happen 10\ ! 291: * seconds after we start a DMA out. This handles the "net jammed so bad that\ ! 292: * we don't even see collisions" error, caused by continuous carrier sense.\ ! 293: */\ ! 294: ! 295: \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0 NetJamTimer ! 296: \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\fc0 ( ! 297: \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0 port_t enetIOPort ! 298: \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\fc0 ) ! 299: \pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\fc0 \{\ ! 300: send ENET_JAMMED_MSG message to the I/O thread;\ ! 301: \}\ ! 302: ! 303: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.