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