]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
de355530 A |
6 | * The contents of this file constitute Original Code as defined in and |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
1c79356b | 11 | * |
de355530 A |
12 | * This Original Code and all software distributed under the License are |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1c79356b A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
de355530 A |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
1c79356b A |
19 | * |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 1997 Apple Computer, Inc. | |
24 | * | |
25 | * ethernet driver for mace on-board ethernet | |
26 | * | |
27 | * HISTORY | |
28 | * | |
29 | * Dieter Siegmund (dieter@next.com) Thu Feb 27 18:25:33 PST 1997 | |
30 | * - ripped off code from MK/LINUX, turned it into a polled-mode | |
31 | * driver for the PCI (8500) class machines | |
32 | * | |
33 | * Dieter Siegmund (dieter@next.com) Fri Mar 21 12:41:29 PST 1997 | |
34 | * - reworked to support a BSD-style interface, and to support kdb polled | |
35 | * interface and interrupt-driven interface concurrently | |
36 | * | |
37 | * Justin Walker (justin@apple.com) Tue May 20 10:29:29 PDT 1997 | |
38 | * - Added multicast support | |
39 | * | |
40 | * Dieter Siegmund (dieter@next.com) Thu May 29 15:02:29 PDT 1997 | |
41 | * - fixed problem with sending arp packets for ip address 0.0.0.0 | |
42 | * - use kdp_register_send_receive() instead of defining | |
43 | * en_send_pkt/en_recv_pkt routines to avoid name space | |
44 | * collisions with IOEthernetDebugger and allow these routines to be | |
45 | * overridden by a driverkit-style driver | |
46 | * | |
47 | * Dieter Siegmund (dieter@apple.com) Tue Jun 24 18:29:15 PDT 1997 | |
48 | * - don't let the adapter auto-strip 802.3 receive frames, it messes | |
49 | * up the frame size logic | |
50 | * | |
51 | * Dieter Siegmund (dieter@apple.com) Tue Aug 5 16:24:52 PDT 1997 | |
52 | * - handle multicast address deletion correctly | |
53 | */ | |
54 | #ifdef MACE_DEBUG | |
55 | /* | |
56 | * Caveat: MACE_DEBUG delimits some code that is getting kind of | |
57 | * stale. Before blindly turning on MACE_DEBUG for your | |
58 | * testing, take a look at the code enabled by it to check | |
59 | * that it is reasonably sane. | |
60 | */ | |
61 | #endif | |
62 | ||
63 | #include <machdep/ppc/dbdma.h> | |
64 | #include <kern/kdp_en_debugger.h> | |
65 | ||
66 | #define RECEIVE_INT DBDMA_INT_ALWAYS | |
67 | ||
68 | #include <sys/types.h> | |
69 | #include <sys/systm.h> | |
70 | #include <sys/param.h> | |
71 | #include <sys/errno.h> | |
72 | #include <sys/socket.h> | |
73 | #include <net/if.h> | |
74 | #include <net/etherdefs.h> | |
75 | #include <netinet/if_ether.h> | |
76 | #include <sys/sockio.h> | |
77 | #include <netinet/in_var.h> | |
78 | #include <netinet/in.h> | |
79 | #include <sys/mbuf.h> | |
80 | #include <mach/mach_types.h> | |
81 | #include <ppc/powermac.h> | |
82 | #include <ppc/interrupts.h> | |
83 | #include <ppc/proc_reg.h> | |
84 | #include <libkern/libkern.h> | |
85 | #include <kern/thread_call.h> | |
86 | #include "if_en.h" | |
87 | #include "mace.h" | |
88 | ||
89 | extern int kdp_flag; | |
90 | ||
91 | #if NBPFILTER > 0 | |
92 | #include <net/bpf.h> | |
93 | #endif | |
94 | ||
95 | static void polled_send_pkt(char * data, int len); | |
96 | static void polled_receive_pkt(char *data, int *len, int timeout_ms); | |
97 | void mace_dbdma_rx_intr(int unit, void *, void *); | |
98 | void mace_dbdma_tx_intr(int, void *, void *); | |
99 | void mace_pci_intr(int, void *); | |
100 | void mace_service_queue(struct ifnet * ifp); | |
101 | ||
102 | #ifdef MACE_DEBUG | |
103 | static int mace_watchdog(); | |
104 | #endif | |
105 | ||
106 | static __inline__ vm_offset_t | |
107 | KVTOPHYS(vm_offset_t v) | |
108 | { | |
109 | return (v); | |
110 | } | |
111 | ||
112 | typedef int (*funcptr)(char *, int, void *); | |
113 | ||
114 | #ifdef MACE_DEBUG | |
115 | static int | |
116 | macAddrsEqual(unsigned char * one, unsigned char * two) | |
117 | { | |
118 | int i; | |
119 | ||
120 | for (i = 0; i < NUM_EN_ADDR_BYTES; i++) | |
121 | if (*one++ != *two++) | |
122 | return 0; | |
123 | return 1; | |
124 | } | |
125 | #endif | |
126 | ||
127 | static __inline__ int | |
128 | isprint(unsigned char c) | |
129 | { | |
130 | return (c >= 0x20 && c <= 0x7e); | |
131 | } | |
132 | ||
133 | static void | |
134 | printEtherHeader(enet_addr_t * dh, enet_addr_t * sh, u_short etype) | |
135 | { | |
136 | u_char * dhost = dh->ether_addr_octet; | |
137 | u_char * shost = sh->ether_addr_octet; | |
138 | ||
139 | printf("Dst: %x:%x:%x:%x:%x:%x Src: %x:%x:%x:%x:%x:%x Type: 0x%x\n", | |
140 | dhost[0], dhost[1], dhost[2], dhost[3], dhost[4], dhost[5], | |
141 | shost[0], shost[1], shost[2], shost[3], shost[4], shost[5], | |
142 | etype); | |
143 | } | |
144 | ||
145 | static void | |
146 | printData(u_char * data_p, int n_bytes) | |
147 | { | |
148 | #define CHARS_PER_LINE 16 | |
149 | char line_buf[CHARS_PER_LINE + 1]; | |
150 | int line_pos; | |
151 | int offset; | |
152 | ||
153 | for (line_pos = 0, offset = 0; offset < n_bytes; offset++, data_p++) { | |
154 | if (line_pos == 0) { | |
155 | printf("%04d ", offset); | |
156 | } | |
157 | ||
158 | line_buf[line_pos] = isprint(*data_p) ? *data_p : '.'; | |
159 | printf(" %02x", *data_p); | |
160 | line_pos++; | |
161 | if (line_pos == CHARS_PER_LINE) { | |
162 | line_buf[CHARS_PER_LINE] = '\0'; | |
163 | printf(" %s\n", line_buf); | |
164 | line_pos = 0; | |
165 | } | |
166 | } | |
167 | if (line_pos) { /* need to finish up the line */ | |
168 | for (; line_pos < CHARS_PER_LINE; line_pos++) { | |
169 | printf(" "); | |
170 | line_buf[line_pos] = ' '; | |
171 | } | |
172 | line_buf[CHARS_PER_LINE] = '\0'; | |
173 | printf(" %s\n", line_buf); | |
174 | } | |
175 | } | |
176 | ||
177 | static void | |
178 | printEtherPacket(enet_addr_t * dhost, enet_addr_t * shost, u_short type, | |
179 | u_char * data_p, int n_bytes) | |
180 | { | |
181 | printEtherHeader(dhost, shost, type); | |
182 | printData(data_p, n_bytes); | |
183 | } | |
184 | ||
185 | void | |
186 | printContiguousEtherPacket(u_char * data_p, int n_bytes) | |
187 | { | |
188 | printEtherPacket((enet_addr_t *)data_p, | |
189 | (enet_addr_t *)(data_p + NUM_EN_ADDR_BYTES), | |
190 | *((u_short *)(data_p + (NUM_EN_ADDR_BYTES * 2))), | |
191 | data_p, n_bytes); | |
192 | } | |
193 | ||
194 | mace_t mace; | |
195 | ||
196 | #define MACE_DMA_AREA_SIZE (ETHER_RX_NUM_DBDMA_BUFS * ETHERNET_BUF_SIZE + PG_SIZE) | |
197 | static unsigned long mace_rx_dma_area[(MACE_DMA_AREA_SIZE + sizeof(long))/sizeof(long)]; | |
198 | ||
199 | static unsigned long mace_tx_dma_area[(ETHERNET_BUF_SIZE + PG_SIZE + sizeof(long))/sizeof(long)]; | |
200 | ||
201 | /* | |
202 | * mace_get_hwid | |
203 | * | |
204 | * This function computes the Ethernet Hardware address | |
205 | * from PROM. (Its best not to ask how this is done.) | |
206 | */ | |
207 | ||
208 | unsigned char | |
209 | mace_swapbits(unsigned char bits) | |
210 | { | |
211 | unsigned char mask = 0x1, i, newbits = 0; | |
212 | ||
213 | for (i = 0x80; i; mask <<= 1, i >>=1) { | |
214 | if (bits & mask) | |
215 | newbits |= i; | |
216 | } | |
217 | ||
218 | return newbits; | |
219 | } | |
220 | ||
221 | void | |
222 | mace_get_hwid(unsigned char *hwid_addr, mace_t * m) | |
223 | { | |
224 | int i; | |
225 | ||
226 | for (i = 0; i < NUM_EN_ADDR_BYTES; i++, hwid_addr += 16) { | |
227 | m->macaddr[i] = mace_swapbits(*hwid_addr); | |
228 | } | |
229 | } | |
230 | ||
231 | /* | |
232 | * mace_reset | |
233 | * | |
234 | * Reset the board.. | |
235 | */ | |
236 | ||
237 | void | |
238 | mace_reset() | |
239 | { | |
240 | dbdma_reset(DBDMA_ETHERNET_RV); | |
241 | dbdma_reset(DBDMA_ETHERNET_TX); | |
242 | } | |
243 | ||
244 | ||
245 | /* | |
246 | * mace_geteh: | |
247 | * | |
248 | * This function gets the ethernet address (array of 6 unsigned | |
249 | * bytes) from the MACE board registers. | |
250 | * | |
251 | */ | |
252 | ||
253 | void | |
254 | mace_geteh(char *ep) | |
255 | { | |
256 | int i; | |
257 | unsigned char ep_temp; | |
258 | ||
259 | mace.ereg->iac = IAC_PHYADDR; eieio(); | |
260 | ||
261 | for (i = 0; i < ETHER_ADD_SIZE; i++) { | |
262 | ep_temp = mace.ereg->padr; eieio(); | |
263 | *ep++ = ep_temp; | |
264 | } | |
265 | } | |
266 | ||
267 | /* | |
268 | * mace_seteh: | |
269 | * | |
270 | * This function sets the ethernet address (array of 6 unsigned | |
271 | * bytes) on the MACE board. | |
272 | */ | |
273 | ||
274 | static void | |
275 | mace_seteh(char *ep) | |
276 | { | |
277 | int i; | |
278 | unsigned char status; | |
279 | ||
280 | if (mace.chip_id != MACE_REVISION_A2) { | |
281 | mace.ereg->iac = IAC_ADDRCHG|IAC_PHYADDR; eieio(); | |
282 | ||
283 | while ((status = mace.ereg->iac)) { | |
284 | if ((status & IAC_ADDRCHG) == 0) { | |
285 | eieio(); | |
286 | break; | |
287 | } | |
288 | eieio(); | |
289 | } | |
290 | } | |
291 | else { | |
292 | /* start to load the address.. */ | |
293 | mace.ereg->iac = IAC_PHYADDR; eieio(); | |
294 | } | |
295 | ||
296 | for (i = 0; i < NUM_EN_ADDR_BYTES; i++) { | |
297 | mace.ereg->padr = *(ep+i); eieio(); | |
298 | } | |
299 | return; | |
300 | } | |
301 | ||
302 | /* | |
303 | * mace_setup_dbdma | |
304 | * | |
305 | * Setup various dbdma pointers. | |
306 | */ | |
307 | ||
308 | void | |
309 | mace_setup_dbdma() | |
310 | { | |
311 | mace_t * m = &mace; | |
312 | int i; | |
313 | dbdma_command_t * d; | |
314 | vm_offset_t address; | |
315 | dbdma_regmap_t * regmap; | |
316 | ||
317 | #define ALIGN_MASK 0xfffffffcUL | |
318 | if (m->rv_dma_area == 0) { | |
319 | m->rv_dma_area = (unsigned char *) | |
320 | ((((unsigned long)mace_rx_dma_area) + 3) & ALIGN_MASK); | |
321 | m->rv_dma = dbdma_alloc(ETHER_RX_NUM_DBDMA_BUFS + 2); | |
322 | m->tx_dma = dbdma_alloc(TX_NUM_DBDMA); | |
323 | m->tx_dma_area = (unsigned char *) | |
324 | ((((unsigned long)mace_tx_dma_area) + 3) & ALIGN_MASK); | |
325 | } | |
326 | ||
327 | /* set up a ring of buffers */ | |
328 | d = m->rv_dma; | |
329 | for (i = 0; i < ETHER_RX_NUM_DBDMA_BUFS; i++, d++) { | |
330 | address = (vm_offset_t) KVTOPHYS((vm_offset_t)&m->rv_dma_area[i*ETHERNET_BUF_SIZE]); | |
331 | DBDMA_BUILD(d, DBDMA_CMD_IN_LAST, 0, ETHERNET_BUF_SIZE, | |
332 | address, RECEIVE_INT, | |
333 | DBDMA_WAIT_NEVER, | |
334 | DBDMA_BRANCH_NEVER); | |
335 | } | |
336 | ||
337 | /* stop when we hit the end of the list */ | |
338 | DBDMA_BUILD(d, DBDMA_CMD_STOP, 0, 0, 0, RECEIVE_INT, | |
339 | DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); | |
340 | d++; | |
341 | ||
342 | /* branch to command at "address" ie. element 0 of the "array" */ | |
343 | DBDMA_BUILD(d, DBDMA_CMD_NOP, 0, 0, 0, DBDMA_INT_NEVER, | |
344 | DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); | |
345 | address = (vm_offset_t) KVTOPHYS((vm_offset_t)m->rv_dma); | |
346 | dbdma_st4_endian(&d->d_cmddep, address); | |
347 | ||
348 | m->rv_head = 0; | |
349 | m->rv_tail = ETHER_RX_NUM_DBDMA_BUFS; /* always contains DBDMA_CMD_STOP */ | |
350 | ||
351 | /* stop/init/restart dma channel */ | |
352 | dbdma_reset(DBDMA_ETHERNET_RV); | |
353 | dbdma_reset(DBDMA_ETHERNET_TX); | |
354 | ||
355 | /* Set the wait value.. */ | |
356 | regmap = DBDMA_REGMAP(DBDMA_ETHERNET_RV); | |
357 | dbdma_st4_endian(®map->d_wait, DBDMA_SET_CNTRL(0x00)); | |
358 | ||
359 | /* Set the tx wait value */ | |
360 | regmap = DBDMA_REGMAP(DBDMA_ETHERNET_TX); | |
361 | dbdma_st4_endian(®map->d_wait, DBDMA_SET_CNTRL(0x20)); | |
362 | ||
363 | flush_cache_v((vm_offset_t)m->rv_dma, | |
364 | sizeof(dbdma_command_t) * (ETHER_RX_NUM_DBDMA_BUFS + 2)); | |
365 | /* start receiving */ | |
366 | dbdma_start(DBDMA_ETHERNET_RV, m->rv_dma); | |
367 | } | |
368 | ||
369 | #ifdef MACE_DEBUG | |
370 | static unsigned char testBuffer[PG_SIZE * 4]; | |
371 | static unsigned char testMsg[] = "mace ethernet interface test"; | |
372 | ||
373 | static void | |
374 | send_test_packet() | |
375 | { | |
376 | unsigned char * tp; | |
377 | ||
378 | bzero(testBuffer, sizeof(testBuffer)); | |
379 | ||
380 | tp = testBuffer; | |
381 | ||
382 | /* send self-addressed packet */ | |
383 | bcopy(&mace.macaddr[0], tp, NUM_EN_ADDR_BYTES); | |
384 | tp += NUM_EN_ADDR_BYTES; | |
385 | bcopy(&mace.macaddr[0], tp, NUM_EN_ADDR_BYTES); | |
386 | tp += NUM_EN_ADDR_BYTES; | |
387 | *tp++ = 0; | |
388 | *tp++ = 0; | |
389 | bcopy(testMsg, tp, sizeof(testMsg)); | |
390 | polled_send_pkt(testBuffer, 80); | |
391 | return; | |
392 | } | |
393 | #endif | |
394 | ||
395 | /* | |
396 | * Function: init_mace | |
397 | * | |
398 | * Purpose: | |
399 | * Called early on, initializes the adapter and readies it for | |
400 | * kdb kernel debugging. | |
401 | */ | |
402 | void | |
403 | init_mace() | |
404 | { | |
405 | unsigned char status; | |
406 | mace_t * m = &mace; | |
407 | struct mace_board * ereg; | |
408 | int mpc = 0; | |
409 | ||
410 | /* | |
411 | * Only use in-kernel driver for early debugging (bootargs: kdp=1 or kdp=3) | |
412 | */ | |
413 | if ( (kdp_flag & 1) == 0 ) | |
414 | { | |
415 | return; | |
416 | } | |
417 | ||
418 | bzero(&mace, sizeof(mace)); | |
419 | ||
420 | /* get the ethernet registers' mapped address */ | |
421 | ereg = m->ereg | |
422 | = (struct mace_board *) POWERMAC_IO(PCI_ETHERNET_BASE_PHYS); | |
423 | mace_get_hwid((unsigned char *)POWERMAC_IO(PCI_ETHERNET_ADDR_PHYS), m); | |
424 | ||
425 | /* Reset the board & AMIC.. */ | |
426 | mace_reset(); | |
427 | ||
428 | /* grab the MACE chip rev */ | |
429 | m->chip_id = (ereg->chipid2 << 8 | ereg->chipid1); | |
430 | ||
431 | /* don't auto-strip for 802.3 */ | |
432 | m->ereg->rcvfc &= ~(RCVFC_ASTRPRCV); | |
433 | ||
434 | /* set the ethernet address */ | |
435 | mace_seteh(mace.macaddr); | |
436 | { | |
437 | unsigned char macaddr[NUM_EN_ADDR_BYTES]; | |
438 | mace_geteh(macaddr); | |
439 | printf("mace ethernet [%02x:%02x:%02x:%02x:%02x:%02x]\n", | |
440 | macaddr[0], macaddr[1], macaddr[2], | |
441 | macaddr[3], macaddr[4], macaddr[5]); | |
442 | } | |
443 | ||
444 | /* Now clear the Multicast filter */ | |
445 | if (m->chip_id != MACE_REVISION_A2) { | |
446 | ereg->iac = IAC_ADDRCHG|IAC_LOGADDR; eieio(); | |
447 | ||
448 | while ((status = ereg->iac)) { | |
449 | if ((status & IAC_ADDRCHG) == 0) | |
450 | break; | |
451 | eieio(); | |
452 | } | |
453 | eieio(); | |
454 | } | |
455 | else { | |
456 | ereg->iac = IAC_LOGADDR; eieio(); | |
457 | } | |
458 | { | |
459 | int i; | |
460 | ||
461 | for (i=0; i < 8; i++) | |
462 | { ereg->ladrf = 0; | |
463 | eieio(); | |
464 | } | |
465 | } | |
466 | ||
467 | /* register interrupt routines */ | |
468 | mace_setup_dbdma(); | |
469 | ||
470 | /* Start the chip... */ | |
471 | m->ereg->maccc = MACCC_ENXMT|MACCC_ENRCV; eieio(); | |
472 | { | |
473 | volatile char ch = mace.ereg->ir; eieio(); | |
474 | } | |
475 | ||
476 | delay(500); /* paranoia */ | |
477 | mace.ereg->imr = 0xfe; eieio(); | |
478 | ||
479 | /* register our debugger routines */ | |
480 | kdp_register_send_receive((kdp_send_t)polled_send_pkt, | |
481 | (kdp_receive_t)polled_receive_pkt); | |
482 | ||
483 | #if 0 | |
484 | printf("Testing 1 2 3\n"); | |
485 | send_test_packet(); | |
486 | printf("Testing 1 2 3\n"); | |
487 | send_test_packet(); | |
488 | printf("Testing 1 2 3\n"); | |
489 | send_test_packet(); | |
490 | do { | |
491 | static unsigned char buf[ETHERNET_BUF_SIZE]; | |
492 | int len; | |
493 | int nmpc = mace.ereg->mpc; eieio(); | |
494 | ||
495 | if (nmpc > mpc) { | |
496 | mpc = nmpc; | |
497 | printf("mpc %d\n", mpc); | |
498 | } | |
499 | polled_receive_pkt(buf, &len, 100); | |
500 | if (len > 0) { | |
501 | printf("rx %d\n", len); | |
502 | printContiguousEtherPacket(buf, len); | |
503 | } | |
504 | } while(1); | |
505 | #endif | |
506 | ||
507 | return; | |
508 | } | |
509 | ||
510 | #ifdef MACE_DEBUG | |
511 | static void | |
512 | txstatus(char * msg) | |
513 | { | |
514 | volatile dbdma_regmap_t * dmap = DBDMA_REGMAP(DBDMA_ETHERNET_TX); | |
515 | volatile unsigned long status; | |
516 | volatile unsigned long intr; | |
517 | volatile unsigned long branch; | |
518 | volatile unsigned long wait; | |
519 | ||
520 | status = dbdma_ld4_endian(&dmap->d_status); eieio(); | |
521 | intr = dbdma_ld4_endian(&dmap->d_intselect); eieio(); | |
522 | branch = dbdma_ld4_endian(&dmap->d_branch); eieio(); | |
523 | wait = dbdma_ld4_endian(&dmap->d_wait); eieio(); | |
524 | printf("(%s s=0x%x i=0x%x b=0x%x w=0x%x)", msg, status, intr, branch, | |
525 | wait); | |
526 | return; | |
527 | } | |
528 | #endif | |
529 | ||
530 | static void | |
531 | tx_dbdma(char * data, int len) | |
532 | { | |
533 | unsigned long count; | |
534 | dbdma_command_t * d; | |
535 | unsigned long page; | |
536 | ||
537 | d = mace.tx_dma; | |
538 | page = ((unsigned long) data) & PG_MASK; | |
539 | if ((page + len) <= PG_SIZE) { /* one piece dma */ | |
540 | DBDMA_BUILD(d, DBDMA_CMD_OUT_LAST, DBDMA_KEY_STREAM0, | |
541 | len, | |
542 | (vm_offset_t) KVTOPHYS((vm_offset_t) data), | |
543 | DBDMA_INT_NEVER, | |
544 | DBDMA_WAIT_IF_FALSE, DBDMA_BRANCH_NEVER); | |
545 | } | |
546 | else { /* two piece dma */ | |
547 | count = PG_SIZE - page; | |
548 | DBDMA_BUILD(d, DBDMA_CMD_OUT_MORE, DBDMA_KEY_STREAM0, | |
549 | count, | |
550 | (vm_offset_t)KVTOPHYS((vm_offset_t) data), | |
551 | DBDMA_INT_NEVER, | |
552 | DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); | |
553 | d++; | |
554 | DBDMA_BUILD(d, DBDMA_CMD_OUT_LAST, DBDMA_KEY_STREAM0, | |
555 | len - count, (vm_offset_t) | |
556 | KVTOPHYS((vm_offset_t)((unsigned char *)data + count)), | |
557 | DBDMA_INT_NEVER, | |
558 | DBDMA_WAIT_IF_FALSE, DBDMA_BRANCH_NEVER); | |
559 | } | |
560 | d++; | |
561 | DBDMA_BUILD(d, DBDMA_CMD_LOAD_QUAD, DBDMA_KEY_SYSTEM, | |
562 | 1, KVTOPHYS((vm_offset_t) &mace.ereg->xmtfs),DBDMA_INT_NEVER, | |
563 | DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); | |
564 | d++; | |
565 | DBDMA_BUILD(d, DBDMA_CMD_LOAD_QUAD, DBDMA_KEY_SYSTEM, | |
566 | 1, KVTOPHYS((vm_offset_t) &mace.ereg->ir), DBDMA_INT_ALWAYS, | |
567 | DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); | |
568 | d++; | |
569 | DBDMA_BUILD(d, DBDMA_CMD_STOP, 0, 0, 0, 0, 0, 0); | |
570 | flush_cache_v((vm_offset_t)mace.tx_dma, sizeof(dbdma_command_t) * TX_NUM_DBDMA); | |
571 | dbdma_start(DBDMA_ETHERNET_TX, mace.tx_dma); | |
572 | return; | |
573 | ||
574 | } | |
575 | ||
576 | static void | |
577 | waitForDBDMADone(char * msg) | |
578 | { | |
579 | { | |
580 | /* wait for tx dma completion */ | |
581 | volatile dbdma_regmap_t * dmap = DBDMA_REGMAP(DBDMA_ETHERNET_TX); | |
582 | int i; | |
583 | volatile unsigned long val; | |
584 | ||
585 | i = 0; | |
586 | do { | |
587 | val = dbdma_ld4_endian(&dmap->d_status); eieio(); | |
588 | delay(50); | |
589 | i++; | |
590 | } while ((i < 100000) && (val & DBDMA_CNTRL_ACTIVE)); | |
591 | if (i == 100000) | |
592 | printf("mace(%s): tx_dbdma poll timed out 0x%x", msg, val); | |
593 | } | |
594 | } | |
595 | ||
596 | void | |
597 | mace_service_queue(struct ifnet * ifp) | |
598 | { | |
599 | unsigned char * buf_p; | |
600 | struct mbuf * m; | |
601 | struct mbuf * mp; | |
602 | int len; | |
603 | ||
604 | if (mace.tx_busy) { /* transmit in progress? */ | |
605 | return; | |
606 | } | |
607 | ||
608 | IF_DEQUEUE(&(ifp->if_snd), m); | |
609 | if (m == 0) { | |
610 | return; | |
611 | } | |
612 | ||
613 | len = m->m_pkthdr.len; | |
614 | ||
615 | if (len > ETHERMAXPACKET) { | |
616 | printf("mace_start: packet too big (%d), dropping\n", len); | |
617 | m_freem(m); | |
618 | return; | |
619 | ||
620 | } | |
621 | buf_p = mace.tx_dma_area; | |
622 | if (m->m_nextpkt) { | |
623 | printf("mace: sending more than one mbuf\n"); | |
624 | } | |
625 | for (mp = m; mp; mp = mp->m_next) { | |
626 | if (mp->m_len == 0) | |
627 | continue; | |
628 | bcopy(mtod(mp, caddr_t), buf_p, min(mp->m_len, len)); | |
629 | len -= mp->m_len; | |
630 | buf_p += mp->m_len; | |
631 | } | |
632 | m_freem(m); | |
633 | ||
634 | #if NBPFILTER > 0 | |
635 | if (ifp->if_bpf) | |
636 | BPF_TAP(ifp->if_bpf, mace.tx_dma_area, m->m_pkthdr.len); | |
637 | #endif | |
638 | ||
639 | #if 0 | |
640 | printf("tx packet %d\n", m->m_pkthdr.len); | |
641 | printContiguousEtherPacket(mace.tx_dma_area, m->m_pkthdr.len); | |
642 | #endif | |
643 | ||
644 | /* fill in the dbdma records and kick off the dma */ | |
645 | tx_dbdma(mace.tx_dma_area, m->m_pkthdr.len); | |
646 | mace.tx_busy = 1; | |
647 | return; | |
648 | } | |
649 | ||
650 | #ifdef MACE_DEBUG | |
651 | static int | |
652 | mace_watchdog() | |
653 | { | |
654 | struct ifnet * ifp = &mace.en_arpcom.ac_if; | |
655 | int s; | |
656 | ||
657 | mace.txwatchdog++; | |
658 | s = splnet(); | |
659 | if (mace.rxintr == 0) { | |
660 | printf("rx is hung up\n"); | |
661 | rx_intr(); | |
662 | } | |
663 | mace.rxintr = 0; | |
664 | #if 0 | |
665 | if (mace.txintr == 0 && ifp->if_snd.ifq_head) { | |
666 | if (mace.tx_busy) | |
667 | dbdma_stop(DBDMA_ETHERNET_TX); | |
668 | mace.tx_busy = 0; | |
669 | mace_service_queue(ifp); | |
670 | } | |
671 | mace.txintr = 0; | |
672 | #endif | |
673 | timeout(mace_watchdog, 0, 10*hz); /* just in case we drop an interrupt */ | |
674 | return (0); | |
675 | } | |
676 | #endif /* MACE_DEBUG */ | |
677 | ||
678 | static int | |
679 | mace_start(struct ifnet * ifp) | |
680 | { | |
681 | // int i = mace.tx_busy; | |
682 | ||
683 | // printf("mace_start %s\n", mace.tx_busy ? "(txBusy)" : ""); | |
684 | mace_service_queue(ifp); | |
685 | ||
686 | // if (mace.tx_busy && !i) | |
687 | // printf("(txStarted)\n"); | |
688 | return 0; | |
689 | } | |
690 | ||
691 | int | |
692 | mace_recv_pkt(funcptr pktfunc, void * p) | |
693 | { | |
694 | vm_offset_t address; | |
695 | struct mace_board * board; | |
696 | long bytes; | |
697 | int done = 0; | |
698 | int doContinue = 0; | |
699 | mace_t * m; | |
700 | unsigned long resid; | |
701 | unsigned short status; | |
702 | int tail; | |
703 | ||
704 | m = &mace; | |
705 | board = m->ereg; | |
706 | ||
707 | /* remember where the tail was */ | |
708 | tail = m->rv_tail; | |
709 | for (done = 0; (done == 0) && (m->rv_head != tail);) { | |
710 | dbdma_command_t * dmaHead; | |
711 | ||
712 | dmaHead = &m->rv_dma[m->rv_head]; | |
713 | resid = dbdma_ld4_endian(&dmaHead->d_status_resid); | |
714 | status = (resid >> 16); | |
715 | bytes = resid & 0xffff; | |
716 | bytes = ETHERNET_BUF_SIZE - bytes - 8; /* strip off FCS/CRC */ | |
717 | ||
718 | if ((status & DBDMA_ETHERNET_EOP) == 0) { | |
719 | /* no packets are ready yet */ | |
720 | break; | |
721 | } | |
722 | doContinue = 1; | |
723 | /* if the packet is good, pass it up */ | |
724 | if (bytes >= (ETHER_MIN_PACKET - 4)) { | |
725 | char * dmaPacket; | |
726 | dmaPacket = &m->rv_dma_area[m->rv_head * ETHERNET_BUF_SIZE]; | |
727 | done = (*pktfunc)(dmaPacket, bytes, p); | |
728 | } | |
729 | /* mark the head as the new tail in the dma channel command list */ | |
730 | DBDMA_BUILD(dmaHead, DBDMA_CMD_STOP, 0, 0, 0, RECEIVE_INT, | |
731 | DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); | |
732 | flush_cache_v((vm_offset_t)dmaHead, sizeof(*dmaHead)); | |
733 | eieio(); | |
734 | ||
735 | /* make the tail an available dma'able entry */ | |
736 | { | |
737 | dbdma_command_t * dmaTail; | |
738 | dmaTail = &m->rv_dma[m->rv_tail]; | |
739 | address = KVTOPHYS((vm_offset_t) | |
740 | &m->rv_dma_area[m->rv_tail*ETHERNET_BUF_SIZE]); | |
741 | // this command is live so write it carefully | |
742 | DBDMA_ST4_ENDIAN(&dmaTail->d_address, address); | |
743 | dmaTail->d_status_resid = 0; | |
744 | dmaTail->d_cmddep = 0; | |
745 | eieio(); | |
746 | DBDMA_ST4_ENDIAN(&dmaTail->d_cmd_count, | |
747 | ((DBDMA_CMD_IN_LAST) << 28) | ((0) << 24) | | |
748 | ((RECEIVE_INT) << 20) | | |
749 | ((DBDMA_BRANCH_NEVER) << 18) | ((DBDMA_WAIT_NEVER) << 16) | | |
750 | (ETHERNET_BUF_SIZE)); | |
751 | eieio(); | |
752 | flush_cache_v((vm_offset_t)dmaTail, sizeof(*dmaTail)); | |
753 | } | |
754 | /* head becomes the tail */ | |
755 | m->rv_tail = m->rv_head; | |
756 | ||
757 | /* advance the head */ | |
758 | m->rv_head++; | |
759 | if (m->rv_head == (ETHER_RX_NUM_DBDMA_BUFS + 1)) | |
760 | m->rv_head = 0; | |
761 | } | |
762 | if (doContinue) { | |
763 | sync(); | |
764 | dbdma_continue(DBDMA_ETHERNET_RV); | |
765 | } | |
766 | return (done); | |
767 | } | |
768 | ||
769 | /* kdb handle buffer routines */ | |
770 | struct kdbCopy { | |
771 | int * len; | |
772 | char * data; | |
773 | }; | |
774 | ||
775 | static int | |
776 | kdb_copy(char * pktBuf, int len, void * p) | |
777 | { | |
778 | struct kdbCopy * cp = (struct kdbCopy *)p; | |
779 | ||
780 | bcopy(pktBuf, cp->data, len); | |
781 | *cp->len = len; | |
782 | return (1); /* signal that we're done */ | |
783 | } | |
784 | ||
785 | /* kdb debugger routines */ | |
786 | static void | |
787 | polled_send_pkt(char * data, int len) | |
788 | { | |
789 | waitForDBDMADone("mace: polled_send_pkt start"); | |
790 | tx_dbdma(data, len); | |
791 | waitForDBDMADone("mace: polled_send_pkt end"); | |
792 | return; | |
793 | } | |
794 | ||
795 | static void | |
796 | polled_receive_pkt(char *data, int *len, int timeout_ms) | |
797 | { | |
798 | struct kdbCopy cp; | |
799 | ||
800 | cp.len = len; | |
801 | cp.data = data; | |
802 | ||
803 | timeout_ms *= 1000; | |
804 | *len = 0; | |
805 | while (mace_recv_pkt(kdb_copy, (void *)&cp) == 0) { | |
806 | if (timeout_ms <= 0) | |
807 | break; | |
808 | delay(50); | |
809 | timeout_ms -= 50; | |
810 | } | |
811 | return; | |
812 | } | |
813 | ||
814 | /* Bump to force ethernet data to be 4-byte aligned | |
815 | * (since the ethernet header is 14 bytes, and the 802.3 header is | |
816 | * 22 = 14+8 bytes). This assumes that m_data is word-aligned | |
817 | * (which it is). | |
818 | */ | |
819 | #define ETHER_DATA_ALIGN 2 | |
820 | ||
821 | /* | |
822 | * Function: rxpkt | |
823 | * | |
824 | * Purpose: | |
825 | * Called from within mace_recv_pkt to deal with a packet of data. | |
826 | * rxpkt() allocates an mbuf(+cluser) and passes it up to the stacks. | |
827 | * Returns: | |
828 | * 0 if the packet was copied to an mbuf, 1 otherwise | |
829 | */ | |
830 | static int | |
831 | rxpkt(char * data, int len, void * p) | |
832 | { | |
833 | struct ether_header * eh_p = (struct ether_header *)data; | |
834 | struct ifnet * ifp = &mace.en_arpcom.ac_if; | |
835 | struct mbuf * m; | |
836 | ||
837 | int interesting; | |
838 | ||
839 | mace.rxintr++; | |
840 | ||
841 | /* mcast, bcast -- we're interested in either */ | |
842 | interesting = eh_p->ether_dhost[0] & 1; | |
843 | ||
844 | #if NBPFILTER > 0 | |
845 | /* | |
846 | * Check if there's a bpf filter listening on this interface. | |
847 | * If so, hand off the raw packet to bpf_tap(). | |
848 | */ | |
849 | if (ifp->if_bpf) { | |
850 | BPF_TAP(ifp->if_bpf, data, len); | |
851 | ||
852 | /* | |
853 | * Keep the packet if it's a broadcast or has our | |
854 | * physical ethernet address (or if we support | |
855 | * multicast and it's one). | |
856 | */ | |
857 | if ((interesting == 0) && bcmp(eh_p->ether_dhost, mace.macaddr, | |
858 | sizeof(eh_p->ether_dhost)) != 0) { | |
859 | return (1); | |
860 | } | |
861 | } | |
862 | #endif | |
863 | ||
864 | /* | |
865 | * We "know" a full-sized packet fits in one cluster. Set up the | |
866 | * packet header, and if the length is sufficient, attempt to allocate | |
867 | * a cluster. If that fails, fall back to the old way (m_devget()). | |
868 | * Here, we take the simple approach of cluster vs. single mbuf. | |
869 | */ | |
870 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
871 | if (m == 0) { | |
872 | #ifdef MACE_DEBUG | |
873 | printf("mget failed\n"); | |
874 | #endif | |
875 | return (1); | |
876 | } | |
877 | ||
878 | if (len > (MHLEN - ETHER_DATA_ALIGN)) | |
879 | { MCLGET(m, M_DONTWAIT); | |
880 | if (m->m_flags&M_EXT) /* MCLGET succeeded */ | |
881 | { m->m_data += ETHER_DATA_ALIGN; | |
882 | bcopy(data, mtod(m, caddr_t), (unsigned)len); | |
883 | } else | |
884 | { | |
885 | #ifdef MACE_DEBUG | |
886 | printf("no clusters\n"); | |
887 | #endif | |
888 | m_free(m); | |
889 | m = (struct mbuf *)m_devget(data, len, 0, ifp, 0); | |
890 | if (m == 0) | |
891 | return (1); | |
892 | } | |
893 | } else | |
894 | { m->m_data += ETHER_DATA_ALIGN; | |
895 | bcopy(data, mtod(m, caddr_t), (unsigned)len); | |
896 | } | |
897 | ||
898 | /* | |
899 | * Current code up the line assumes that the media header's been | |
900 | * stripped, but we'd like to preserve it, just in case someone | |
901 | * wants to peek. | |
902 | */ | |
903 | m->m_pkthdr.len = len; | |
904 | m->m_len = len; | |
905 | m->m_pkthdr.rcvif = ifp; | |
906 | m->m_data += sizeof(*eh_p); | |
907 | m->m_len -= sizeof (*eh_p); | |
908 | m->m_pkthdr.len -= sizeof(*eh_p); | |
909 | ether_input(ifp, eh_p, m); | |
910 | ||
911 | return (0); | |
912 | } | |
913 | ||
914 | ||
915 | static void | |
916 | rx_intr() | |
917 | { | |
918 | mace_recv_pkt(rxpkt, 0); | |
919 | } | |
920 | ||
921 | void | |
922 | mace_dbdma_rx_intr(int unit, void *ignored, void * arp) | |
923 | { | |
924 | if (!mace.ready) | |
925 | return; | |
926 | ||
927 | thread_call_func((thread_call_func_t)rx_intr, 0, TRUE); | |
928 | } | |
929 | ||
930 | ||
931 | int | |
932 | mace_ioctl(struct ifnet * ifp,u_long cmd, caddr_t data) | |
933 | { | |
934 | struct arpcom * ar; | |
935 | unsigned error = 0; | |
936 | struct ifaddr * ifa = (struct ifaddr *)data; | |
937 | struct ifreq * ifr = (struct ifreq *)data; | |
938 | struct sockaddr_in * sin; | |
939 | ||
940 | sin = (struct sockaddr_in *)(&((struct ifreq *)data)->ifr_addr); | |
941 | ar = (struct arpcom *)ifp; | |
942 | ||
943 | switch (cmd) { | |
944 | case SIOCAUTOADDR: | |
945 | error = in_bootp(ifp, sin, &mace.en_arpcom.ac_enaddr); | |
946 | break; | |
947 | ||
948 | case SIOCSIFADDR: | |
949 | #if NeXT | |
950 | ifp->if_flags |= (IFF_UP | IFF_RUNNING); | |
951 | #else | |
952 | ifp->if_flags |= IFF_UP; | |
953 | #endif | |
954 | switch (ifa->ifa_addr->sa_family) { | |
955 | case AF_INET: | |
956 | /* | |
957 | * See if another station has *our* IP address. | |
958 | * i.e.: There is an address conflict! If a | |
959 | * conflict exists, a message is sent to the | |
960 | * console. | |
961 | */ | |
962 | if (IA_SIN(ifa)->sin_addr.s_addr != 0) { /* don't bother for 0.0.0.0 */ | |
963 | ar->ac_ipaddr = IA_SIN(ifa)->sin_addr; | |
964 | arpwhohas(ar, &IA_SIN(ifa)->sin_addr); | |
965 | } | |
966 | break; | |
967 | default: | |
968 | break; | |
969 | } | |
970 | break; | |
971 | ||
972 | case SIOCSIFFLAGS: | |
973 | /* | |
974 | * If interface is marked down and it is running, then stop it | |
975 | */ | |
976 | if ((ifp->if_flags & IFF_UP) == 0 && | |
977 | (ifp->if_flags & IFF_RUNNING) != 0) { | |
978 | /* | |
979 | * If interface is marked down and it is running, then | |
980 | * stop it. | |
981 | */ | |
982 | ifp->if_flags &= ~IFF_RUNNING; | |
983 | } else if ((ifp->if_flags & IFF_UP) != 0 && | |
984 | (ifp->if_flags & IFF_RUNNING) == 0) { | |
985 | /* | |
986 | * If interface is marked up and it is stopped, then | |
987 | * start it. | |
988 | */ | |
989 | ifp->if_flags |= IFF_RUNNING; | |
990 | } | |
991 | ||
992 | /* | |
993 | * If the state of the promiscuous bit changes, the | |
994 | * interface must be reset to effect the change. | |
995 | */ | |
996 | if (((ifp->if_flags ^ mace.promisc) & IFF_PROMISC) && | |
997 | (ifp->if_flags & IFF_RUNNING)) { | |
998 | mace.promisc = ifp->if_flags & IFF_PROMISC; | |
999 | mace_sync_promisc(ifp); | |
1000 | } | |
1001 | ||
1002 | break; | |
1003 | ||
1004 | case SIOCADDMULTI: | |
1005 | if ((error = ether_addmulti(ifr, ar)) == ENETRESET) | |
1006 | { if ((error = mace_addmulti(ifr, ar)) != 0) | |
1007 | { error = 0; | |
1008 | mace_sync_mcast(ifp); | |
1009 | } | |
1010 | } | |
1011 | break; | |
1012 | ||
1013 | case SIOCDELMULTI: | |
1014 | { | |
1015 | struct ether_addr enaddr[2]; /* [0] - addrlo, [1] - addrhi */ | |
1016 | ||
1017 | if ((error = ether_delmulti(ifr, ar, enaddr)) == ENETRESET) { | |
1018 | if ((error = mace_delmulti(ifr, ar, enaddr)) != 0) { | |
1019 | error = 0; | |
1020 | mace_sync_mcast(ifp); | |
1021 | } | |
1022 | } | |
1023 | } | |
1024 | break; | |
1025 | ||
1026 | default: | |
1027 | error = EINVAL; | |
1028 | break; | |
1029 | } | |
1030 | return (error); | |
1031 | } | |
1032 | ||
1033 | void | |
1034 | mace_init() | |
1035 | { | |
1036 | struct ifnet * ifp = &mace.en_arpcom.ac_if; | |
1037 | ||
1038 | /* | |
1039 | * Only use in-kernel driver for early debugging (bootargs: kdp=1|3) | |
1040 | */ | |
1041 | if ( (kdp_flag & 1) == 0 ) | |
1042 | { | |
1043 | return; | |
1044 | } | |
1045 | ||
1046 | mace.tx_busy = 0; | |
1047 | mace.txintr = 0; | |
1048 | mace.promisc = 0; | |
1049 | ||
1050 | bzero((caddr_t)ifp, sizeof(struct ifnet)); | |
1051 | bcopy(&mace.macaddr, &mace.en_arpcom.ac_enaddr, NUM_EN_ADDR_BYTES); | |
1052 | ||
1053 | ifp->if_name = "en"; | |
1054 | ifp->if_unit = 0; | |
1055 | ifp->if_private = 0; | |
1056 | ifp->if_ioctl = mace_ioctl; | |
1057 | ifp->if_start = mace_start; | |
1058 | ifp->if_flags = | |
1059 | IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; | |
1060 | #if NBPFILTER > 0 | |
1061 | bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); | |
1062 | #endif | |
1063 | if_attach(ifp); | |
1064 | ether_ifattach(ifp); | |
1065 | ||
1066 | mace.rxintr = 0; | |
1067 | ||
1068 | /* wire in the interrupt routines */ | |
1069 | pmac_register_int(PMAC_DMA_ETHERNET_RX, SPLNET, | |
1070 | mace_dbdma_rx_intr, 0); | |
1071 | pmac_register_int(PMAC_DMA_ETHERNET_TX, SPLNET, | |
1072 | mace_dbdma_tx_intr, 0); | |
1073 | ||
1074 | // pmac_register_int(PMAC_DEV_ETHERNET, SPLNET, mace_pci_intr); | |
1075 | mace.ready = 1; | |
1076 | #ifdef MACE_DEBUG | |
1077 | timeout(mace_watchdog, 0, 10*hz); /* just in case we drop an interrupt */ | |
1078 | #endif | |
1079 | return; | |
1080 | } | |
1081 | ||
1082 | /* | |
1083 | * mace_pci_intr | |
1084 | * | |
1085 | * Service MACE interrupt | |
1086 | */ | |
1087 | ||
1088 | void | |
1089 | mace_pci_intr(int device, void *ssp) | |
1090 | { | |
1091 | unsigned char ir, retry, frame, packet, length; | |
1092 | ||
1093 | ir = mace.ereg->ir; eieio(); /* Clear Interrupt */ | |
1094 | packet = mace.ereg->mpc; eieio(); | |
1095 | length = mace.ereg->rntpc; eieio(); | |
1096 | ||
1097 | printf("(txI)"); | |
1098 | ||
1099 | if (ir & IR_XMTINT) { | |
1100 | retry = mace.ereg->xmtrc; eieio(); /* Grab transmit retry count */ | |
1101 | frame = mace.ereg->xmtfs; eieio(); | |
1102 | // if (mace.ready) | |
1103 | // mace_dbdma_tx_intr(device, ssp); | |
1104 | } | |
1105 | return; | |
1106 | } | |
1107 | ||
1108 | static void | |
1109 | tx_intr() | |
1110 | { | |
1111 | mace.txintr++; | |
1112 | mace.tx_busy = 0; | |
1113 | mace_service_queue(&mace.en_arpcom.ac_if); | |
1114 | } | |
1115 | ||
1116 | /* | |
1117 | * mace_dbdma_tx_intr | |
1118 | * | |
1119 | * DBDMA interrupt routine | |
1120 | */ | |
1121 | void | |
1122 | mace_dbdma_tx_intr(int unit, void *ignored, void * arg) | |
1123 | { | |
1124 | if (!mace.ready) | |
1125 | return; | |
1126 | ||
1127 | thread_call_func((thread_call_func_t)tx_intr, 0, TRUE); | |
1128 | return; | |
1129 | } |