1 | /* |
---|
2 | * Driver for Xilinx plb temac v3.00a |
---|
3 | * |
---|
4 | * Author: Keith Robertson <kjrobert@alumni.uwaterloo.ca> |
---|
5 | * Copyright (c) 2007 Linn Products Ltd, Scotland. |
---|
6 | * |
---|
7 | * The license and distribution terms for this file may be |
---|
8 | * found in the file LICENSE in this distribution or at |
---|
9 | * http://www.rtems.com/license/LICENSE. |
---|
10 | * |
---|
11 | */ |
---|
12 | #define PPC_HAS_CLASSIC_EXCEPTIONS FALSE |
---|
13 | |
---|
14 | #ifndef __INSIDE_RTEMS_BSD_TCPIP_STACK__ |
---|
15 | #define __INSIDE_RTEMS_BSD_TCPIP_STACK__ |
---|
16 | #endif |
---|
17 | |
---|
18 | #ifndef __BSD_VISIBLE |
---|
19 | #define __BSD_VISIBLE |
---|
20 | #endif |
---|
21 | |
---|
22 | #include <rtems.h> |
---|
23 | #include <rtems/bspIo.h> |
---|
24 | #include <rtems/rtems_bsdnet.h> |
---|
25 | |
---|
26 | #include <sys/param.h> |
---|
27 | #include <sys/mbuf.h> |
---|
28 | |
---|
29 | #include <sys/socket.h> |
---|
30 | #include <sys/sockio.h> |
---|
31 | #include <net/if.h> |
---|
32 | #include <netinet/in.h> |
---|
33 | #include <netinet/if_ether.h> |
---|
34 | |
---|
35 | #include <stdio.h> |
---|
36 | #include <stdarg.h> |
---|
37 | #include <errno.h> |
---|
38 | #include <string.h> |
---|
39 | #include <assert.h> |
---|
40 | |
---|
41 | #include <xiltemac.h> |
---|
42 | #include <rtems/irq.h> |
---|
43 | |
---|
44 | /* Reading/Writing memory mapped i/o */ |
---|
45 | #define IN32(aPtr) ((uint32_t)( *((volatile uint32_t *)(aPtr))) ) |
---|
46 | #define OUT32(aPtr, aValue) (*((volatile uint32_t *)(aPtr)) = (uint32_t)aValue) |
---|
47 | #define NUM_XILTEMAC_UNITS 2 |
---|
48 | |
---|
49 | /* Why isn't this defined in stdio.h like it's supposed to be? */ |
---|
50 | extern int snprintf(char*, size_t, const char*, ...); |
---|
51 | |
---|
52 | extern rtems_isr xilTemacIsr( void *handle ); |
---|
53 | extern void xilTemacIsrOn(const rtems_irq_connect_data *); |
---|
54 | extern void xilTemacIsrOff(const rtems_irq_connect_data *); |
---|
55 | extern int xilTemacIsrIsOn(const rtems_irq_connect_data *); |
---|
56 | |
---|
57 | void xilTemacInit( void *voidptr ); |
---|
58 | void xilTemacReset(struct ifnet *ifp); |
---|
59 | void xilTemacStop(struct ifnet *ifp); |
---|
60 | void xilTemacSend(struct ifnet *ifp); |
---|
61 | void xilTemacStart(struct ifnet *ifp); |
---|
62 | void xilTemacSetMacAddress(struct ifnet *ifp, unsigned char* aAddr); |
---|
63 | void xilTemacPrintStats(struct ifnet *ifp); |
---|
64 | |
---|
65 | void xilTemacRxThread( void *ignore ); |
---|
66 | void xilTemacTxThread( void *ignore ); |
---|
67 | |
---|
68 | static struct XilTemac gXilTemac[ NUM_XILTEMAC_UNITS ]; |
---|
69 | |
---|
70 | static rtems_id gXilRxThread = 0; |
---|
71 | static rtems_id gXilTxThread = 0; |
---|
72 | |
---|
73 | /* |
---|
74 | ** Events, one per unit. The event is sent to the rx task from the isr |
---|
75 | ** or from the stack to the tx task whenever a unit needs service. The |
---|
76 | ** rx/tx tasks identify the requesting unit(s) by their particular |
---|
77 | ** events so only requesting units are serviced. |
---|
78 | */ |
---|
79 | |
---|
80 | static rtems_event_set gUnitSignals[ NUM_XILTEMAC_UNITS ]= { RTEMS_EVENT_1, |
---|
81 | RTEMS_EVENT_2 }; |
---|
82 | |
---|
83 | uint32_t xilTemacTxFifoVacancyBytes(uint32_t aBaseAddr) |
---|
84 | { |
---|
85 | uint32_t ipisr = IN32(aBaseAddr + XTE_IPISR_OFFSET); |
---|
86 | uint32_t bytes = 0; |
---|
87 | if(ipisr & XTE_IPXR_XMIT_LFIFO_FULL_MASK) { |
---|
88 | /* If there's no room in the transmit length fifo, then any room in the |
---|
89 | * data fifo is irrelevant, return 0 */ |
---|
90 | } else { |
---|
91 | bytes = IN32(aBaseAddr + XTE_PFIFO_TX_VACANCY_OFFSET); |
---|
92 | bytes &= XTE_PFIFO_COUNT_MASK; |
---|
93 | bytes *= 8; |
---|
94 | } |
---|
95 | return bytes; |
---|
96 | } |
---|
97 | |
---|
98 | void xilTemacFifoRead64(uint32_t aBaseAddr, uint32_t* aBuf, uint32_t aBytes) |
---|
99 | { |
---|
100 | uint32_t numqwords = aBytes / 8; |
---|
101 | uint32_t xtrabytes = aBytes % 8; |
---|
102 | uint32_t i; |
---|
103 | |
---|
104 | for(i = 0; i < numqwords; i++) |
---|
105 | { |
---|
106 | aBuf[ (i*2) ] = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET); |
---|
107 | aBuf[ (i*2)+1 ] = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET + 4); |
---|
108 | } |
---|
109 | |
---|
110 | /* If there was a non qword sized read */ |
---|
111 | if( xtrabytes != 0 ) |
---|
112 | { |
---|
113 | uint32_t lastdwordMS = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET); |
---|
114 | uint32_t lastdwordLS = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET + 4); |
---|
115 | uint8_t* finalbytes = (uint8_t *)&aBuf[ (numqwords*2) ]; |
---|
116 | uint8_t* ptr8; |
---|
117 | int32_t offset = 0; |
---|
118 | |
---|
119 | ptr8 = (uint8_t *)&lastdwordMS; |
---|
120 | if( xtrabytes >= 4 ) |
---|
121 | { |
---|
122 | finalbytes[ offset++ ] = ptr8[0]; |
---|
123 | finalbytes[ offset++ ] = ptr8[1]; |
---|
124 | finalbytes[ offset++ ] = ptr8[2]; |
---|
125 | finalbytes[ offset++ ] = ptr8[3]; |
---|
126 | |
---|
127 | xtrabytes -= 4; |
---|
128 | ptr8 = (uint8_t *)&lastdwordLS; |
---|
129 | } |
---|
130 | |
---|
131 | if( xtrabytes == 1 ) |
---|
132 | { |
---|
133 | finalbytes[ offset++ ] = ptr8[0]; |
---|
134 | } |
---|
135 | else if ( xtrabytes == 2 ) |
---|
136 | { |
---|
137 | finalbytes[ offset++ ] = ptr8[0]; |
---|
138 | finalbytes[ offset++ ] = ptr8[1]; |
---|
139 | } |
---|
140 | else if ( xtrabytes == 3 ) |
---|
141 | { |
---|
142 | finalbytes[ offset++ ] = ptr8[0]; |
---|
143 | finalbytes[ offset++ ] = ptr8[1]; |
---|
144 | finalbytes[ offset++ ] = ptr8[2]; |
---|
145 | } |
---|
146 | } |
---|
147 | } |
---|
148 | |
---|
149 | void xilTemacFifoWrite64(uint32_t aBaseAddr, uint32_t* aBuf, uint32_t aBytes) |
---|
150 | { |
---|
151 | uint32_t numqwords = aBytes / 8; |
---|
152 | uint32_t xtrabytes = aBytes % 8; |
---|
153 | uint32_t i; |
---|
154 | |
---|
155 | for(i = 0; i < numqwords; i++ ) { |
---|
156 | OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET , aBuf[ (i*2) ]); |
---|
157 | OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET + 4, aBuf[ (i*2)+1 ]); |
---|
158 | } |
---|
159 | |
---|
160 | /* If there was a non word sized write */ |
---|
161 | if( xtrabytes != 0 ) { |
---|
162 | uint32_t lastdwordMS = 0; |
---|
163 | uint32_t lastdwordLS = 0; |
---|
164 | uint8_t* finalbytes = (uint8_t *)&aBuf[ (numqwords*2) ]; |
---|
165 | uint8_t* ptr8; |
---|
166 | int32_t offset = 0; |
---|
167 | |
---|
168 | ptr8 = (uint8_t *)&lastdwordMS; |
---|
169 | |
---|
170 | if( xtrabytes >= 4 ) { |
---|
171 | ptr8[0] = finalbytes[ offset++ ]; |
---|
172 | ptr8[1] = finalbytes[ offset++ ]; |
---|
173 | ptr8[2] = finalbytes[ offset++ ]; |
---|
174 | ptr8[3] = finalbytes[ offset++ ]; |
---|
175 | |
---|
176 | xtrabytes -= 4; |
---|
177 | |
---|
178 | ptr8 = (uint8_t *)&lastdwordLS; |
---|
179 | } |
---|
180 | |
---|
181 | if( xtrabytes == 1 ) { |
---|
182 | ptr8[0] = finalbytes[ offset++ ]; |
---|
183 | } |
---|
184 | else if ( xtrabytes == 2 ) { |
---|
185 | ptr8[0] = finalbytes[ offset++ ]; |
---|
186 | ptr8[1] = finalbytes[ offset++ ]; |
---|
187 | } |
---|
188 | else if ( xtrabytes == 3 ) { |
---|
189 | ptr8[0] = finalbytes[ offset++ ]; |
---|
190 | ptr8[1] = finalbytes[ offset++ ]; |
---|
191 | ptr8[2] = finalbytes[ offset++ ]; |
---|
192 | } |
---|
193 | |
---|
194 | OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET, lastdwordMS); |
---|
195 | OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET + 4, lastdwordLS); |
---|
196 | } |
---|
197 | } |
---|
198 | |
---|
199 | void xilTemacStop(struct ifnet *ifp) |
---|
200 | { |
---|
201 | struct XilTemac* xilTemac = ifp->if_softc; |
---|
202 | uint32_t base = xilTemac->iAddr; |
---|
203 | |
---|
204 | /* Disable ipif interrupts */ |
---|
205 | OUT32(base + XTE_DGIE_OFFSET, 0); |
---|
206 | |
---|
207 | /* Disable the receiver */ |
---|
208 | uint32_t rxc1 = IN32(base + XTE_ERXC1_OFFSET); |
---|
209 | rxc1 &= ~XTE_ERXC1_RXEN_MASK; |
---|
210 | OUT32(base + XTE_ERXC1_OFFSET, rxc1); |
---|
211 | |
---|
212 | /* If receiver was receiving a packet when we disabled it, it will be |
---|
213 | * rejected, clear appropriate status bit */ |
---|
214 | uint32_t ipisr = IN32(base + XTE_IPISR_OFFSET); |
---|
215 | if( ipisr & XTE_IPXR_RECV_REJECT_MASK ) { |
---|
216 | OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_RECV_REJECT_MASK); |
---|
217 | } |
---|
218 | |
---|
219 | #if PPC_HAS_CLASSIC_EXCEPTIONS |
---|
220 | if( xilTemac->iOldHandler ) |
---|
221 | { |
---|
222 | opb_intc_set_vector( xilTemac->iOldHandler, xilTemac->iIsrVector, NULL ); |
---|
223 | xilTemac->iOldHandler = 0; |
---|
224 | } |
---|
225 | #else |
---|
226 | if( xilTemac->iOldHandler.name != 0) |
---|
227 | { |
---|
228 | BSP_install_rtems_irq_handler (&xilTemac->iOldHandler); |
---|
229 | } |
---|
230 | #endif |
---|
231 | |
---|
232 | ifp->if_flags &= ~IFF_RUNNING; |
---|
233 | } |
---|
234 | |
---|
235 | void xilTemacStart(struct ifnet *ifp) |
---|
236 | { |
---|
237 | if( (ifp->if_flags & IFF_RUNNING) == 0 ) |
---|
238 | { |
---|
239 | struct XilTemac* xilTemac = ifp->if_softc; |
---|
240 | uint32_t base = xilTemac->iAddr; |
---|
241 | |
---|
242 | /* Reset plb temac */ |
---|
243 | OUT32(base + XTE_DSR_OFFSET, XTE_DSR_RESET_MASK); |
---|
244 | /* Don't have usleep on rtems 4.6 |
---|
245 | usleep(1); |
---|
246 | */ |
---|
247 | /* @ fastest ppc clock of 500 MHz = 2ns clk */ |
---|
248 | uint32_t i = 0; |
---|
249 | for( i = 0; i < 1 * 500; i++) { |
---|
250 | } |
---|
251 | |
---|
252 | /* Reset hard temac */ |
---|
253 | OUT32(base + XTE_CR_OFFSET, XTE_CR_HTRST_MASK); |
---|
254 | /* Don't have usleep on rtems 4.6 |
---|
255 | usleep(4); |
---|
256 | */ |
---|
257 | for( i = 0; i < 4 * 500; i++) { |
---|
258 | } |
---|
259 | |
---|
260 | /* Disable the receiver -- no need to disable xmit as we control that ;) */ |
---|
261 | uint32_t rxc1 = IN32(base + XTE_ERXC1_OFFSET); |
---|
262 | rxc1 &= ~XTE_ERXC1_RXEN_MASK; |
---|
263 | OUT32(base + XTE_ERXC1_OFFSET, rxc1); |
---|
264 | |
---|
265 | /* If receiver was receiving a packet when we disabled it, it will be |
---|
266 | * rejected, clear appropriate status bit */ |
---|
267 | uint32_t ipisr = IN32(base + XTE_IPISR_OFFSET); |
---|
268 | if( ipisr & XTE_IPXR_RECV_REJECT_MASK ) { |
---|
269 | OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_RECV_REJECT_MASK); |
---|
270 | } |
---|
271 | |
---|
272 | /* Setup IPIF interrupt enables */ |
---|
273 | uint32_t dier = XTE_DXR_CORE_MASK | XTE_DXR_DPTO_MASK | XTE_DXR_TERR_MASK; |
---|
274 | dier |= XTE_DXR_RECV_FIFO_MASK | XTE_DXR_SEND_FIFO_MASK; |
---|
275 | OUT32(base + XTE_DIER_OFFSET, dier); |
---|
276 | |
---|
277 | /* Set the mac address */ |
---|
278 | xilTemacSetMacAddress( ifp, xilTemac->iArpcom.ac_enaddr); |
---|
279 | |
---|
280 | /* Set the link speed */ |
---|
281 | uint32_t emcfg = IN32(base + XTE_ECFG_OFFSET); |
---|
282 | printk("xiltemacStart, default linkspeed: %08x\n", emcfg); |
---|
283 | emcfg = (emcfg & ~XTE_ECFG_LINKSPD_MASK) | XTE_ECFG_LINKSPD_100; |
---|
284 | OUT32(base + XTE_ECFG_OFFSET, emcfg); |
---|
285 | |
---|
286 | /* Set phy divisor and enable mdio. For a plb bus freq of 150MHz (the |
---|
287 | maximum as of Virtex4 Fx), a divisor of 29 gives a mdio clk freq of |
---|
288 | 2.5MHz (see Xilinx docs for equation), the maximum in the phy standard. |
---|
289 | For slower plb frequencies, slower mkdio clks will result. They may not |
---|
290 | be optimal, but they should work. */ |
---|
291 | uint32_t divisor = 29; |
---|
292 | OUT32(base + XTE_EMC_OFFSET, divisor | XTE_EMC_MDIO_MASK); |
---|
293 | |
---|
294 | #if PPC_HAS_CLASSIC_EXCEPTIONS /* old connect code */ |
---|
295 | /* Connect isr vector */ |
---|
296 | rtems_status_code sc; |
---|
297 | extern rtems_isr xilTemacIsr( rtems_vector_number aVector ); |
---|
298 | sc = opb_intc_set_vector( xilTemacIsr, xilTemac->iIsrVector, &xilTemac->iOldHandler ); |
---|
299 | if( sc != RTEMS_SUCCESSFUL ) |
---|
300 | { |
---|
301 | xilTemac->iOldHandler = 0; |
---|
302 | printk("%s: Could not set interrupt vector for interface '%s' opb_intc_set_vector ret: %d\n", DRIVER_PREFIX, xilTemac->iUnitName, sc ); |
---|
303 | assert(0); |
---|
304 | } |
---|
305 | #else |
---|
306 | { |
---|
307 | rtems_irq_connect_data IrqConnData; |
---|
308 | |
---|
309 | /* |
---|
310 | *get old irq handler |
---|
311 | */ |
---|
312 | xilTemac->iOldHandler.name = xilTemac->iIsrVector; |
---|
313 | if (!BSP_get_current_rtems_irq_handler (&xilTemac->iOldHandler)) { |
---|
314 | xilTemac->iOldHandler.name = 0; |
---|
315 | printk("%s: Unable to detect previous Irq handler\n",DRIVER_PREFIX); |
---|
316 | rtems_fatal_error_occurred(1); |
---|
317 | } |
---|
318 | |
---|
319 | IrqConnData.on = xilTemacIsrOn; |
---|
320 | IrqConnData.off = xilTemacIsrOff; |
---|
321 | IrqConnData.isOn = xilTemacIsrIsOn; |
---|
322 | IrqConnData.name = xilTemac->iIsrVector; |
---|
323 | IrqConnData.hdl = xilTemacIsr; |
---|
324 | IrqConnData.handle = xilTemac; |
---|
325 | |
---|
326 | if (!BSP_install_rtems_irq_handler (&IrqConnData)) { |
---|
327 | printk("%s: Unable to connect Irq handler\n",DRIVER_PREFIX); |
---|
328 | rtems_fatal_error_occurred(1); |
---|
329 | } |
---|
330 | } |
---|
331 | #endif |
---|
332 | /* Enable promiscuous mode -- The temac only supports full duplex, which |
---|
333 | means we're plugged into a switch. Thus promiscuous mode simply means |
---|
334 | we get all multicast addresses*/ |
---|
335 | OUT32(base + XTE_EAFM_OFFSET, XTE_EAFM_EPPRM_MASK); |
---|
336 | |
---|
337 | /* Setup and enable receiver */ |
---|
338 | rxc1 = XTE_ERXC1_RXFCS_MASK | XTE_ERXC1_RXEN_MASK | XTE_ERXC1_RXVLAN_MASK; |
---|
339 | OUT32(base + XTE_ERXC1_OFFSET, rxc1); |
---|
340 | |
---|
341 | /* Setup and enable transmitter */ |
---|
342 | uint32_t txc = XTE_ETXC_TXEN_MASK | XTE_ETXC_TXVLAN_MASK; |
---|
343 | OUT32(base + XTE_ETXC_OFFSET, txc); |
---|
344 | |
---|
345 | /* Enable interrupts for temac */ |
---|
346 | uint32_t ipier = IN32(base + XTE_IPIER_OFFSET); |
---|
347 | ipier |= (XTE_IPXR_XMIT_ERROR_MASK); |
---|
348 | ipier |= (XTE_IPXR_RECV_ERROR_MASK | XTE_IPXR_RECV_DONE_MASK); |
---|
349 | ipier |= (XTE_IPXR_AUTO_NEG_MASK); |
---|
350 | OUT32(base + XTE_IPIER_OFFSET, ipier); |
---|
351 | |
---|
352 | printk("%s: xiltemacStart, ipier: %08x\n",DRIVER_PREFIX, ipier); |
---|
353 | |
---|
354 | /* Enable device global interrutps */ |
---|
355 | OUT32(base + XTE_DGIE_OFFSET, XTE_DGIE_ENABLE_MASK); |
---|
356 | ifp->if_flags |= IFF_RUNNING; |
---|
357 | } |
---|
358 | } |
---|
359 | |
---|
360 | void xilTemacInit( void *voidptr ) |
---|
361 | { |
---|
362 | } |
---|
363 | |
---|
364 | void xilTemacReset(struct ifnet *ifp) |
---|
365 | { |
---|
366 | xilTemacStop( ifp ); |
---|
367 | xilTemacStart( ifp ); |
---|
368 | } |
---|
369 | |
---|
370 | void xilTemacSetMacAddress(struct ifnet *ifp, unsigned char* aAddr) |
---|
371 | { |
---|
372 | struct XilTemac* xilTemac = ifp->if_softc; |
---|
373 | uint32_t base = xilTemac->iAddr; |
---|
374 | |
---|
375 | /* You can't change the mac address while the card is in operation */ |
---|
376 | if( (ifp->if_flags & IFF_RUNNING) != 0 ) { |
---|
377 | printk("%s: attempted to change MAC while up, interface '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName ); |
---|
378 | assert(0); |
---|
379 | } |
---|
380 | uint32_t mac; |
---|
381 | mac = aAddr[0] & 0x000000FF; |
---|
382 | mac |= aAddr[1] << 8; |
---|
383 | mac |= aAddr[2] << 16; |
---|
384 | mac |= aAddr[3] << 24; |
---|
385 | OUT32(base + XTE_EUAW0_OFFSET, mac); |
---|
386 | |
---|
387 | mac = IN32(base + XTE_EUAW1_OFFSET); |
---|
388 | mac &= ~XTE_EUAW1_MASK; |
---|
389 | mac |= aAddr[4] & 0x000000FF; |
---|
390 | mac |= aAddr[5] << 8; |
---|
391 | OUT32(base + XTE_EUAW1_OFFSET, mac); |
---|
392 | } |
---|
393 | |
---|
394 | void xilTemacPrintStats( struct ifnet *ifp ) |
---|
395 | { |
---|
396 | struct XilTemac* xilTemac = ifp->if_softc; |
---|
397 | |
---|
398 | printf("\n"); |
---|
399 | printf("%s: Statistics for interface '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName ); |
---|
400 | |
---|
401 | printf("%s: Ipif Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iInterrupts); |
---|
402 | printf("%s: Rx Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxInterrupts); |
---|
403 | printf("%s: Rx Rejected Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedInterrupts); |
---|
404 | printf("%s: Rx Rej Invalid Frame: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedInvalidFrame); |
---|
405 | printf("%s: Rx Rej Data Fifo Full: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedDataFifoFull); |
---|
406 | printf("%s:Rx Rej Length Fifo Full: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedLengthFifoFull); |
---|
407 | printf("%s: Rx Stray Events: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxStrayEvents); |
---|
408 | printf("%s: Rx Max Drained: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxMaxDrained); |
---|
409 | printf("%s: Tx Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iTxInterrupts); |
---|
410 | printf("%s: Tx Max Drained: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iTxMaxDrained); |
---|
411 | |
---|
412 | printf("\n"); |
---|
413 | } |
---|
414 | |
---|
415 | void xilTemacIsrSingle(struct XilTemac* xilTemac) |
---|
416 | { |
---|
417 | uint32_t base = xilTemac->iAddr; |
---|
418 | uint32_t disr = IN32( base + XTE_DISR_OFFSET ); |
---|
419 | struct ifnet* ifp = xilTemac->iIfp; |
---|
420 | |
---|
421 | if( disr && (ifp->if_flags & IFF_RUNNING) == 0 ) { |
---|
422 | /* some interrupt status bits are asserted but card is down */ |
---|
423 | printk("%s: Fatal error, disr 0 or this emac not running\n", DRIVER_PREFIX); |
---|
424 | /*assert(0);*/ |
---|
425 | } else { |
---|
426 | /* Handle all error conditions first */ |
---|
427 | if( disr & (XTE_DXR_DPTO_MASK | XTE_DXR_TERR_MASK | |
---|
428 | XTE_DXR_RECV_FIFO_MASK | XTE_DXR_SEND_FIFO_MASK) ) { |
---|
429 | printk("%s: Fatal Bus error, disr: %08x\n", DRIVER_PREFIX, disr); |
---|
430 | /*assert(0);*/ |
---|
431 | } |
---|
432 | if( disr & XTE_DXR_CORE_MASK ) { |
---|
433 | /* Normal case, temac interrupt */ |
---|
434 | uint32_t ipisr = IN32(base + XTE_IPISR_OFFSET); |
---|
435 | uint32_t ipier = IN32(base + XTE_IPIER_OFFSET); |
---|
436 | uint32_t newipier = ipier; |
---|
437 | uint32_t pending = ipisr & ipier; |
---|
438 | xilTemac->iStats.iInterrupts++; |
---|
439 | |
---|
440 | /* Check for all fatal errors, even if that error is not enabled in ipier */ |
---|
441 | if(ipisr & XTE_IPXR_FIFO_FATAL_ERROR_MASK) { |
---|
442 | printk("%s: Fatal Fifo Error ipisr: %08x\n", DRIVER_PREFIX, ipisr); |
---|
443 | /*assert(0);*/ |
---|
444 | } |
---|
445 | |
---|
446 | if(pending & XTE_IPXR_RECV_DONE_MASK) { |
---|
447 | /* We've received a packet |
---|
448 | - inc stats |
---|
449 | - disable rx interrupt |
---|
450 | - signal rx thread to empty out fifo |
---|
451 | (rx thread must renable interrupt) |
---|
452 | */ |
---|
453 | xilTemac->iStats.iRxInterrupts++; |
---|
454 | |
---|
455 | newipier &= ~XTE_IPXR_RECV_DONE_MASK; |
---|
456 | |
---|
457 | rtems_event_send(gXilRxThread, xilTemac->iIoEvent); |
---|
458 | } |
---|
459 | if(pending & XTE_IPXR_XMIT_DONE_MASK) { |
---|
460 | /* We've transmitted a packet. This interrupt is only ever enabled in |
---|
461 | the ipier if the tx thread didn't have enough space in the data fifo |
---|
462 | or the tplr fifo. If that's the case, we: |
---|
463 | - inc stats |
---|
464 | - disable tx interrupt |
---|
465 | - signal tx thread that a transmit has completed and thus there is now |
---|
466 | room to send again. |
---|
467 | */ |
---|
468 | xilTemac->iStats.iTxInterrupts++; |
---|
469 | |
---|
470 | newipier &= ~XTE_IPXR_XMIT_DONE_MASK; |
---|
471 | |
---|
472 | rtems_event_send(gXilTxThread, xilTemac->iIoEvent); |
---|
473 | } |
---|
474 | if(pending & XTE_IPXR_RECV_DROPPED_MASK) { |
---|
475 | /* A packet was dropped (because it was invalid, or receiving it |
---|
476 | have overflowed one of the rx fifo's). |
---|
477 | - Increment stats. |
---|
478 | - Clear interrupt condition. |
---|
479 | */ |
---|
480 | uint32_t toggle = 0; |
---|
481 | if(pending & XTE_IPXR_RECV_REJECT_MASK) { |
---|
482 | xilTemac->iStats.iRxRejectedInvalidFrame++; |
---|
483 | toggle |= XTE_IPXR_RECV_REJECT_MASK; |
---|
484 | } |
---|
485 | if(pending & XTE_IPXR_RECV_PFIFO_ABORT_MASK) { |
---|
486 | xilTemac->iStats.iRxRejectedDataFifoFull++; |
---|
487 | toggle |= XTE_IPXR_RECV_PFIFO_ABORT_MASK; |
---|
488 | } |
---|
489 | if(pending & XTE_IPXR_RECV_LFIFO_ABORT_MASK) { |
---|
490 | xilTemac->iStats.iRxRejectedLengthFifoFull++; |
---|
491 | toggle |= XTE_IPXR_RECV_LFIFO_ABORT_MASK; |
---|
492 | } |
---|
493 | xilTemac->iStats.iRxRejectedInterrupts++; |
---|
494 | OUT32(base + XTE_IPISR_OFFSET, toggle); |
---|
495 | } |
---|
496 | if(pending & XTE_IPXR_AUTO_NEG_MASK) { |
---|
497 | printk("%s: Autonegotiation finished\n", DRIVER_PREFIX); |
---|
498 | OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_AUTO_NEG_MASK); |
---|
499 | } |
---|
500 | if(newipier != ipier) { |
---|
501 | OUT32(base + XTE_IPIER_OFFSET, newipier); |
---|
502 | } |
---|
503 | } |
---|
504 | } |
---|
505 | } |
---|
506 | |
---|
507 | #if PPC_HAS_CLASSIC_EXCEPTIONS |
---|
508 | rtems_isr xilTemacIsr( rtems_vector_number aVector ) |
---|
509 | { |
---|
510 | struct XilTemac* xilTemac; |
---|
511 | int i; |
---|
512 | |
---|
513 | for( i=0; i< NUM_XILTEMAC_UNITS; i++ ) { |
---|
514 | xilTemac = &gXilTemac[i]; |
---|
515 | |
---|
516 | if( xilTemac->iIsPresent ) { |
---|
517 | xilTemacIsrSingle(xilTemac); |
---|
518 | } |
---|
519 | } |
---|
520 | } |
---|
521 | #else |
---|
522 | rtems_isr xilTemacIsr(void *handle ) |
---|
523 | { |
---|
524 | struct XilTemac* xilTemac = (struct XilTemac*)handle; |
---|
525 | |
---|
526 | xilTemacIsrSingle(xilTemac); |
---|
527 | } |
---|
528 | |
---|
529 | void xilTemacIsrOn(const rtems_irq_connect_data *unused) |
---|
530 | { |
---|
531 | } |
---|
532 | |
---|
533 | void xilTemacIsrOff(const rtems_irq_connect_data *unused) |
---|
534 | { |
---|
535 | } |
---|
536 | |
---|
537 | int xilTemacIsrIsOn(const rtems_irq_connect_data *unused) |
---|
538 | { |
---|
539 | return 1; |
---|
540 | } |
---|
541 | #endif |
---|
542 | |
---|
543 | |
---|
544 | int32_t xilTemacSetMulticastFilter(struct ifnet *ifp) |
---|
545 | { |
---|
546 | return 0; |
---|
547 | } |
---|
548 | |
---|
549 | int xilTemacIoctl(struct ifnet* ifp, ioctl_command_t aCommand, caddr_t aData) |
---|
550 | { |
---|
551 | struct XilTemac* xilTemac = ifp->if_softc; |
---|
552 | int32_t error = 0; |
---|
553 | |
---|
554 | switch(aCommand) { |
---|
555 | case SIOCGIFADDR: |
---|
556 | case SIOCSIFADDR: |
---|
557 | ether_ioctl(ifp, aCommand, aData); |
---|
558 | break; |
---|
559 | |
---|
560 | case SIOCSIFFLAGS: |
---|
561 | switch(ifp->if_flags & (IFF_UP | IFF_RUNNING)) |
---|
562 | { |
---|
563 | case IFF_RUNNING: |
---|
564 | xilTemacStop(ifp); |
---|
565 | break; |
---|
566 | |
---|
567 | case IFF_UP: |
---|
568 | xilTemacStart(ifp); |
---|
569 | break; |
---|
570 | |
---|
571 | case IFF_UP | IFF_RUNNING: |
---|
572 | xilTemacReset(ifp); |
---|
573 | break; |
---|
574 | |
---|
575 | default: |
---|
576 | break; |
---|
577 | } |
---|
578 | break; |
---|
579 | |
---|
580 | case SIOCADDMULTI: |
---|
581 | case SIOCDELMULTI: { |
---|
582 | struct ifreq* ifr = (struct ifreq*) aData; |
---|
583 | error = ((aCommand == SIOCADDMULTI) ? |
---|
584 | ( ether_addmulti(ifr, &(xilTemac->iArpcom)) ) : |
---|
585 | ( ether_delmulti(ifr, &(xilTemac->iArpcom))) |
---|
586 | ); |
---|
587 | /* ENETRESET indicates that driver should update its multicast filters */ |
---|
588 | if(error == ENETRESET) |
---|
589 | { |
---|
590 | error = xilTemacSetMulticastFilter( ifp ); |
---|
591 | } |
---|
592 | break; |
---|
593 | } |
---|
594 | |
---|
595 | case SIO_RTEMS_SHOW_STATS: |
---|
596 | xilTemacPrintStats( ifp ); |
---|
597 | break; |
---|
598 | |
---|
599 | default: |
---|
600 | error = EINVAL; |
---|
601 | break; |
---|
602 | } |
---|
603 | return error; |
---|
604 | } |
---|
605 | |
---|
606 | void xilTemacSend(struct ifnet* ifp) |
---|
607 | { |
---|
608 | struct XilTemac* xilTemac = ifp->if_softc; |
---|
609 | |
---|
610 | /* wake up tx thread w/ outbound interface's signal */ |
---|
611 | rtems_event_send( gXilTxThread, xilTemac->iIoEvent ); |
---|
612 | |
---|
613 | ifp->if_flags |= IFF_OACTIVE; |
---|
614 | } |
---|
615 | |
---|
616 | /* align the tx buffer to 32 bytes just for kicks, should make it more |
---|
617 | * cache friendly */ |
---|
618 | static unsigned char gTxBuf[2048] __attribute__ ((aligned (32))); |
---|
619 | |
---|
620 | void xilTemacSendPacket(struct ifnet *ifp, struct mbuf* aMbuf) |
---|
621 | { |
---|
622 | struct XilTemac *xilTemac = ifp->if_softc; |
---|
623 | struct mbuf *n = aMbuf; |
---|
624 | uint32_t len = 0; |
---|
625 | |
---|
626 | #ifdef DEBUG |
---|
627 | printk("SendPacket\n"); |
---|
628 | printk("TXD: 0x%08x\n", (int32_t) n->m_data); |
---|
629 | #endif |
---|
630 | |
---|
631 | /* assemble the packet into the tx buffer */ |
---|
632 | for(;;) { |
---|
633 | #ifdef DEBUG |
---|
634 | uint32_t i = 0; |
---|
635 | printk("MBUF: 0x%08x : ", (int32_t) n->m_data); |
---|
636 | for (i=0;i<n->m_len;i+=2) { |
---|
637 | printk("%02x%02x ", mtod(n, unsigned char*)[i], mtod(n, unsigned char*)[i+1]); |
---|
638 | } |
---|
639 | printk("\n"); |
---|
640 | #endif |
---|
641 | |
---|
642 | if( n->m_len > 0 ) { |
---|
643 | memcpy( &gTxBuf[ len ], (char *)n->m_data, n->m_len); |
---|
644 | len += n->m_len; |
---|
645 | } |
---|
646 | if( (n = n->m_next) == 0) { |
---|
647 | break; |
---|
648 | } |
---|
649 | } |
---|
650 | |
---|
651 | xilTemacFifoWrite64( xilTemac->iAddr, (uint32_t*)gTxBuf, len ); |
---|
652 | /* Set the Transmit Packet Length Register which registers the packet |
---|
653 | * length, enqueues the packet and signals the xmit unit to start |
---|
654 | * sending. */ |
---|
655 | OUT32(xilTemac->iAddr + XTE_TPLR_OFFSET, len); |
---|
656 | |
---|
657 | #ifdef DEBUG |
---|
658 | printk("%s: txpkt, len %d\n", DRIVER_PREFIX, len ); |
---|
659 | memset(gTxBuf, 0, len); |
---|
660 | #endif |
---|
661 | } |
---|
662 | |
---|
663 | void xilTemacTxThreadSingle(struct ifnet* ifp) |
---|
664 | { |
---|
665 | struct XilTemac* xilTemac = ifp->if_softc; |
---|
666 | struct mbuf* m; |
---|
667 | uint32_t base = xilTemac->iAddr; |
---|
668 | |
---|
669 | #ifdef DEBUG |
---|
670 | printk("%s: tx send packet, interface '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName ); |
---|
671 | #endif |
---|
672 | |
---|
673 | /* Send packets till mbuf queue empty or tx fifo full */ |
---|
674 | for(;;) { |
---|
675 | uint32_t i = 0; |
---|
676 | |
---|
677 | /* 1) clear out any statuses from previously sent tx frames */ |
---|
678 | while( IN32(base + XTE_IPISR_OFFSET) & XTE_IPXR_XMIT_DONE_MASK ) { |
---|
679 | IN32(base + XTE_TSR_OFFSET); |
---|
680 | OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_XMIT_DONE_MASK); |
---|
681 | i++; |
---|
682 | } |
---|
683 | if( i > xilTemac->iStats.iTxMaxDrained ) { |
---|
684 | xilTemac->iStats.iTxMaxDrained = i; |
---|
685 | } |
---|
686 | |
---|
687 | /* 2) Check if enough space in tx data fifo _and_ tx tplr for an entire |
---|
688 | ethernet frame */ |
---|
689 | if( xilTemacTxFifoVacancyBytes( xilTemac->iAddr ) <= ifp->if_mtu ) { |
---|
690 | /* 2a) If not, enable transmit done interrupt and break out of loop to |
---|
691 | wait for space */ |
---|
692 | uint32_t ipier = IN32(base + XTE_IPIER_OFFSET); |
---|
693 | ipier |= (XTE_IPXR_XMIT_DONE_MASK); |
---|
694 | OUT32(base + XTE_IPIER_OFFSET, ipier); |
---|
695 | break; |
---|
696 | } |
---|
697 | |
---|
698 | /* 3) Contuine to dequeue mbuf chains till none left */ |
---|
699 | IF_DEQUEUE( &(ifp->if_snd), m); |
---|
700 | if( !m ) { |
---|
701 | break; |
---|
702 | } |
---|
703 | |
---|
704 | /* 4) Send dequeued mbuf chain */ |
---|
705 | xilTemacSendPacket( ifp, m ); |
---|
706 | |
---|
707 | /* 5) Free mbuf chain */ |
---|
708 | m_freem( m ); |
---|
709 | } |
---|
710 | ifp->if_flags &= ~IFF_OACTIVE; |
---|
711 | } |
---|
712 | |
---|
713 | void xilTemacTxThread( void *ignore ) |
---|
714 | { |
---|
715 | struct XilTemac *xilTemac; |
---|
716 | struct ifnet *ifp; |
---|
717 | |
---|
718 | rtems_event_set events; |
---|
719 | int i; |
---|
720 | |
---|
721 | for(;;) { |
---|
722 | /* Wait for: |
---|
723 | - notification from stack of packet to send OR |
---|
724 | - notification from interrupt handler that there is space available to |
---|
725 | send already queued packets |
---|
726 | */ |
---|
727 | rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS, |
---|
728 | RTEMS_EVENT_ANY | RTEMS_WAIT, |
---|
729 | RTEMS_NO_TIMEOUT, |
---|
730 | &events ); |
---|
731 | |
---|
732 | for(i=0; i< NUM_XILTEMAC_UNITS; i++) { |
---|
733 | xilTemac = &gXilTemac[i]; |
---|
734 | |
---|
735 | if( xilTemac->iIsPresent ) { |
---|
736 | ifp = xilTemac->iIfp; |
---|
737 | |
---|
738 | if( (ifp->if_flags & IFF_RUNNING) ) { |
---|
739 | |
---|
740 | if( events & xilTemac->iIoEvent ) { |
---|
741 | xilTemacTxThreadSingle(ifp); |
---|
742 | } |
---|
743 | |
---|
744 | } else { |
---|
745 | printk("%s: xilTemacTxThread: event received for device: %s, but device not active\n", |
---|
746 | DRIVER_PREFIX, xilTemac->iUnitName); |
---|
747 | assert(0); |
---|
748 | } |
---|
749 | } |
---|
750 | } |
---|
751 | } |
---|
752 | } |
---|
753 | |
---|
754 | void xilTemacRxThreadSingle(struct ifnet* ifp) |
---|
755 | { |
---|
756 | struct XilTemac* xilTemac = ifp->if_softc; |
---|
757 | |
---|
758 | uint32_t npkts = 0; |
---|
759 | #ifdef DEBUG |
---|
760 | printk("%s: rxthread, packet rx on interface %s\n", DRIVER_PREFIX, xilTemac->iUnitName ); |
---|
761 | #endif |
---|
762 | |
---|
763 | uint32_t base = xilTemac->iAddr; |
---|
764 | |
---|
765 | /* While RECV_DONE_MASK in ipisr stays set */ |
---|
766 | while( IN32(base + XTE_IPISR_OFFSET) & XTE_IPXR_RECV_DONE_MASK ) { |
---|
767 | |
---|
768 | /* 1) Read the length of the packet */ |
---|
769 | uint32_t bytes = IN32(base + XTE_RPLR_OFFSET); |
---|
770 | |
---|
771 | /* 2) Read the Read Status Register (which contains no information). When |
---|
772 | * all of these in the fifo have been read, then XTE_IPXR_RECV_DONE_MASK |
---|
773 | * will stay turned off, after it's written to */ |
---|
774 | IN32(base + XTE_RSR_OFFSET); |
---|
775 | npkts++; |
---|
776 | |
---|
777 | struct mbuf* m; |
---|
778 | struct ether_header* eh; |
---|
779 | |
---|
780 | /* 3) Get some memory from the ip stack to store the packet in */ |
---|
781 | MGETHDR(m, M_WAIT, MT_DATA); |
---|
782 | MCLGET(m, M_WAIT); |
---|
783 | |
---|
784 | m->m_pkthdr.rcvif = ifp; |
---|
785 | |
---|
786 | /* 4) Copy the packet into the ip stack's memory */ |
---|
787 | xilTemacFifoRead64( base, mtod(m, uint32_t*), bytes); |
---|
788 | |
---|
789 | m->m_len = bytes - sizeof(struct ether_header); |
---|
790 | m->m_pkthdr.len = bytes - sizeof(struct ether_header); |
---|
791 | |
---|
792 | eh = mtod(m, struct ether_header*); |
---|
793 | |
---|
794 | m->m_data += sizeof(struct ether_header); |
---|
795 | |
---|
796 | /* 5) Tell the ip stack about the received packet */ |
---|
797 | ether_input(ifp, eh, m); |
---|
798 | |
---|
799 | /* 6) Try and turn off XTE_IPXR_RECV_DONE bit in the ipisr. If there's |
---|
800 | * still more packets (ie RSR ! empty), then it will stay asserted. If |
---|
801 | * there's no more packets, this will turn it off. |
---|
802 | */ |
---|
803 | OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_RECV_DONE_MASK); |
---|
804 | } |
---|
805 | |
---|
806 | /* End) All Rx packets serviced, renable rx interrupt */ |
---|
807 | uint32_t ipier = IN32(base + XTE_IPIER_OFFSET); |
---|
808 | ipier |= XTE_IPXR_RECV_DONE_MASK; |
---|
809 | OUT32(base + XTE_IPIER_OFFSET, ipier); |
---|
810 | |
---|
811 | #ifdef DEBUG |
---|
812 | printk("%s: rxthread, retrieved %d packets\n", DRIVER_PREFIX, npkts ); |
---|
813 | #endif |
---|
814 | if(npkts > xilTemac->iStats.iRxMaxDrained) { |
---|
815 | xilTemac->iStats.iRxMaxDrained = npkts; |
---|
816 | } |
---|
817 | /* ??) Very very occasionally, under extremely high stress, I get a situation |
---|
818 | * where we process no packets. That is, the rx thread was evented, but |
---|
819 | * there was no packet available. I'm not sure how this happens. Ideally, |
---|
820 | * it shouldn't ocurr, and I suspect a minor bug in the driver. However, for |
---|
821 | * me it's happenning 3 times in several hunderd million interrupts. Nothing |
---|
822 | * bad happens, as long as we don't read from the rx fifo's if nothing is |
---|
823 | * there. It is just not as efficient as possible (rx thread being evented |
---|
824 | * pointlessly) and a bit disconcerting about how it's ocurring. |
---|
825 | * The best way to reproduce this is to have two clients run: |
---|
826 | * $ ping <host> -f -s 65507 |
---|
827 | * This flood pings the device from two clients with the maximum size ping |
---|
828 | * packet. It absolutely hammers the device under test. Eventually, (if |
---|
829 | * you leave it running overnight for instance), you'll get a couple of these |
---|
830 | * stray rx events. */ |
---|
831 | if(npkts == 0) { |
---|
832 | /*printk("%s: RxThreadSingle: fatal error: event received, but no packets available\n", DRIVER_PREFIX); |
---|
833 | assert(0); */ |
---|
834 | xilTemac->iStats.iRxStrayEvents++; |
---|
835 | } |
---|
836 | } |
---|
837 | |
---|
838 | void xilTemacRxThread( void *ignore ) |
---|
839 | { |
---|
840 | struct XilTemac* xilTemac; |
---|
841 | struct ifnet* ifp; |
---|
842 | int i; |
---|
843 | rtems_event_set events; |
---|
844 | |
---|
845 | #ifdef DEBUG |
---|
846 | printk("%s: xilTemacRxThread running\n", DRIVER_PREFIX ); |
---|
847 | #endif |
---|
848 | |
---|
849 | for(;;) { |
---|
850 | rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS, |
---|
851 | RTEMS_WAIT | RTEMS_EVENT_ANY, |
---|
852 | RTEMS_NO_TIMEOUT, |
---|
853 | &events); |
---|
854 | |
---|
855 | #ifdef DEBUG |
---|
856 | printk("%s: rxthread, wakeup\n", DRIVER_PREFIX ); |
---|
857 | #endif |
---|
858 | |
---|
859 | for(i=0; i< NUM_XILTEMAC_UNITS; i++) { |
---|
860 | xilTemac = &gXilTemac[i]; |
---|
861 | |
---|
862 | if( xilTemac->iIsPresent ) { |
---|
863 | ifp = xilTemac->iIfp; |
---|
864 | |
---|
865 | if( (ifp->if_flags & IFF_RUNNING) != 0 ) { |
---|
866 | if( events & xilTemac->iIoEvent ) { |
---|
867 | xilTemacRxThreadSingle(ifp); |
---|
868 | } |
---|
869 | } |
---|
870 | else { |
---|
871 | printk("%s: rxthread, interface %s present but not running\n", DRIVER_PREFIX, xilTemac->iUnitName ); |
---|
872 | assert(0); |
---|
873 | } |
---|
874 | } |
---|
875 | } |
---|
876 | } |
---|
877 | } |
---|
878 | |
---|
879 | int32_t xilTemac_driver_attach(struct rtems_bsdnet_ifconfig* aBsdConfig, int aDummy) |
---|
880 | { |
---|
881 | struct ifnet* ifp; |
---|
882 | int32_t mtu; |
---|
883 | int32_t unit; |
---|
884 | char* unitName; |
---|
885 | struct XilTemac* xilTemac; |
---|
886 | |
---|
887 | unit = rtems_bsdnet_parse_driver_name(aBsdConfig, &unitName); |
---|
888 | if(unit < 0 ) |
---|
889 | { |
---|
890 | printk("%s: Interface Unit number < 0\n", DRIVER_PREFIX ); |
---|
891 | return 0; |
---|
892 | } |
---|
893 | |
---|
894 | if( aBsdConfig->bpar == 0 ) |
---|
895 | { |
---|
896 | printk("%s: Did not specify base address for device '%s'", DRIVER_PREFIX, unitName ); |
---|
897 | return 0; |
---|
898 | } |
---|
899 | |
---|
900 | if( aBsdConfig->hardware_address == NULL ) |
---|
901 | { |
---|
902 | printk("%s: No MAC address given for interface '%s'\n", DRIVER_PREFIX, unitName ); |
---|
903 | return 0; |
---|
904 | } |
---|
905 | |
---|
906 | xilTemac = &gXilTemac[ unit ]; |
---|
907 | memset(xilTemac, 0, sizeof(struct XilTemac)); |
---|
908 | |
---|
909 | xilTemac->iIsPresent = 1; |
---|
910 | |
---|
911 | snprintf( xilTemac->iUnitName, MAX_UNIT_BYTES, "%s%" PRId32, unitName, unit ); |
---|
912 | |
---|
913 | xilTemac->iIfp = &(xilTemac->iArpcom.ac_if); |
---|
914 | ifp = &(xilTemac->iArpcom.ac_if); |
---|
915 | xilTemac->iAddr = aBsdConfig->bpar; |
---|
916 | xilTemac->iIoEvent = gUnitSignals[ unit ]; |
---|
917 | xilTemac->iIsrVector = aBsdConfig->irno; |
---|
918 | |
---|
919 | memcpy( xilTemac->iArpcom.ac_enaddr, aBsdConfig->hardware_address, ETHER_ADDR_LEN); |
---|
920 | |
---|
921 | if( aBsdConfig->mtu ) |
---|
922 | { |
---|
923 | mtu = aBsdConfig->mtu; |
---|
924 | } |
---|
925 | else |
---|
926 | { |
---|
927 | mtu = ETHERMTU; |
---|
928 | } |
---|
929 | |
---|
930 | ifp->if_softc = xilTemac; |
---|
931 | ifp->if_unit = unit; |
---|
932 | ifp->if_name = unitName; |
---|
933 | ifp->if_mtu = mtu; |
---|
934 | ifp->if_init = xilTemacInit; |
---|
935 | ifp->if_ioctl = xilTemacIoctl; |
---|
936 | ifp->if_start = xilTemacSend; |
---|
937 | ifp->if_output = ether_output; |
---|
938 | |
---|
939 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; |
---|
940 | |
---|
941 | if(ifp->if_snd.ifq_maxlen == 0) |
---|
942 | { |
---|
943 | ifp->if_snd.ifq_maxlen = ifqmaxlen; |
---|
944 | } |
---|
945 | |
---|
946 | if_attach(ifp); |
---|
947 | ether_ifattach(ifp); |
---|
948 | |
---|
949 | /* create shared rx & tx threads */ |
---|
950 | if( (gXilRxThread == 0) && (gXilTxThread == 0) ) |
---|
951 | { |
---|
952 | printk("%s: Creating shared RX/TX threads\n", DRIVER_PREFIX ); |
---|
953 | gXilRxThread = rtems_bsdnet_newproc("xerx", 4096, xilTemacRxThread, NULL ); |
---|
954 | gXilTxThread = rtems_bsdnet_newproc("xetx", 4096, xilTemacTxThread, NULL ); |
---|
955 | } |
---|
956 | |
---|
957 | printk("%s: Initializing driver for '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName ); |
---|
958 | |
---|
959 | printk("%s: base address 0x%08X, intnum 0x%02X, \n", |
---|
960 | DRIVER_PREFIX, |
---|
961 | aBsdConfig->bpar, |
---|
962 | aBsdConfig->irno ); |
---|
963 | |
---|
964 | return 1; |
---|
965 | } |
---|
966 | |
---|