|
|
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.