1 /* $NetBSD: en.c,v 1.16 2009/03/18 17:06:46 cegger Exp $ */
3 * Copyright (c) 1996 Rolf Grossmann
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Rolf Grossmann.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <netinet/in.h>
35 #include <netinet/in_systm.h>
36 #include <next68k/dev/enreg.h>
37 #include <next68k/next68k/nextrom.h>
46 #include <lib/libkern/libkern.h>
49 #define MON(type, off) (*(type *)((u_int) (mg) + off))
51 #define PRINTF(x) printf x;
53 #define DPRINTF(x) printf x;
58 #define EN_TIMEOUT 2000000
61 int en_match(struct netif
*, void *);
62 int en_probe(struct netif
*, void *);
63 void en_init(struct iodesc
*, void *);
64 int en_get(struct iodesc
*, void *, size_t, saseconds_t
);
65 int en_put(struct iodesc
*, void *, size_t);
66 void en_end(struct netif
*);
68 static int en_wait_for_intr(int);
70 struct netif_stats en_stats
;
72 struct netif_dif en_ifs
[] = {
73 /* dif_unit dif_nsel dif_stats dif_private */
74 { 0, 1, &en_stats
, NULL
, },
77 struct netif_driver en_driver
= {
79 en_match
, en_probe
, en_init
, en_get
, en_put
, en_end
,
80 en_ifs
, sizeof(en_ifs
) / sizeof(en_ifs
[0])
85 /* ### int netdev_sock;
86 static int open_count; */
88 char dma_buffer1
[MAX_DMASIZE
+DMA_ENDALIGNMENT
],
89 dma_buffer2
[MAX_DMASIZE
+DMA_ENDALIGNMENT
],
95 en_match(struct netif
*nif
, void *machdep_hint
)
97 /* we always match, because every NeXT has an ethernet interface
98 * and we've checked the unit numbers before we even started this
100 * ### now that open is generic, we should check the params!
106 en_probe(struct netif
*nif
, void *machdep_hint
)
108 /* we also always probe ok, see en_match. */
113 en_init(struct iodesc
*desc
, void *machdep_hint
)
115 volatile struct en_regs
*er
;
116 volatile u_int
*bmap_chip
;
119 DPRINTF(("en_init\n"));
121 er
= (struct en_regs
*)P_ENET
;
122 bmap_chip
= (u_int
*)P_BMAP
;
124 dma_buffers
[0] = DMA_ALIGN(char *, dma_buffer1
);
125 dma_buffers
[1] = DMA_ALIGN(char *, dma_buffer2
);
127 er
->reset
= EN_RST_RESET
;
134 er
->txmode
= 0 | EN_TMD_COLLSHIFT
;
136 er
->txmode
= EN_TMD_LB_DISABLE
;
138 /* setup for bnc/tp */
140 DPRINTF (("en_media: %s\n",
141 (bmap_chip
[13] & 0x20000000) ? "BNC" : "TP"));
142 if (!(bmap_chip
[13] & 0x20000000)) {
143 bmap_chip
[12] |= 0x90000000;
144 bmap_chip
[13] |= (0x80000000|0x10000000); /* TP */
149 /* er->txmode |= EN_TMD_COLLSHIFT; */
151 /* er->txmode &= ~EN_TMD_LB_DISABLE; /\* ZZZ *\/ */
157 er
->rxmode
= EN_RMD_TEST
| EN_RMD_RECV_NORMAL
;
159 er
->rxmode
= EN_RMD_RECV_NORMAL
;
161 er
->addr
[i
] = desc
->myea
[i
] = MON(char *,MG_clientetheraddr
)[i
];
163 DPRINTF(("ethernet addr (%x:%x:%x:%x:%x:%x)\n",
164 desc
->myea
[0],desc
->myea
[1],desc
->myea
[2],
165 desc
->myea
[3],desc
->myea
[4],desc
->myea
[5]));
172 /* ### remove this when things work! */
173 #define XCHR(x) hexdigits[(x) & 0xf]
175 dump_pkt(unsigned char *pkt
, size_t len
)
180 for(i
=0; i
<len
; i
++) {
181 printf("%c%c ", XCHR(pkt
[i
]>>4), XCHR(pkt
[i
]));
182 if ((i
+1) % 16 == 0) {
185 printf("%c", pkt
[i
-15+j
]>=32 && pkt
[i
-15+j
]<127?pkt
[i
-15+j
]:'.');
186 printf("%c\n%c%c%c%c: ", '"', XCHR((i
+1)>>12),
187 XCHR((i
+1)>>8), XCHR((i
+1)>>4), XCHR(i
+1));
195 en_put(struct iodesc
*desc
, void *pkt
, size_t len
)
197 volatile struct en_regs
*er
;
198 volatile struct dma_dev
*txdma
;
202 DPRINTF(("en_put: %d bytes at 0x%lx\n", len
, (unsigned long)pkt
));
207 er
= (struct en_regs
*)P_ENET
;
208 txdma
= (struct dma_dev
*)P_ENETX_CSR
;
210 DPRINTF(("en_put: txdma->dd_csr = %x\n",txdma
->dd_csr
));
218 while ((er
->txstat
& EN_TXS_READY
) == 0)
219 printf("en: tx not ready\n");
222 for (retries
= 0; retries
< EN_RETRIES
; retries
++) {
224 memcpy(dma_buffers
[0], pkt
, len
);
225 txdma
->dd_csr
= (turbo
? DMACSR_INITBUFTURBO
: DMACSR_INITBUF
) |
226 DMACSR_RESET
| DMACSR_WRITE
;
228 txdma
->dd_next
/* _initbuf */ = dma_buffers
[0];
229 txdma
->dd_start
= (turbo
? dma_buffers
[0] : 0);
230 txdma
->dd_limit
= ENDMA_ENDALIGN(char *, dma_buffers
[0]+len
);
232 txdma
->dd_csr
= DMACSR_SETENABLE
;
237 if (en_wait_for_intr(ENETX_DMA_INTR
)) {
238 printf("en_put: timed out\n");
243 state
= txdma
->dd_csr
&
244 (DMACSR_BUSEXC
| DMACSR_COMPLETE
245 | DMACSR_SUPDATE
| DMACSR_ENABLE
);
248 DPRINTF(("en_put: DMA state = 0x%x.\n", state
));
250 if (state
& (DMACSR_COMPLETE
|DMACSR_BUSEXC
))
251 txdma
->dd_csr
= DMACSR_RESET
| DMACSR_CLRCOMPLETE
;
258 DPRINTF(("en_put: done txstat=%x.\n", txs
));
261 #define EN_TXS_ERROR (EN_TXS_SHORTED | EN_TXS_UNDERFLOW | EN_TXS_PARERR)
262 if ((state
& DMACSR_COMPLETE
) == 0 ||
263 (txs
& EN_TXS_ERROR
) != 0) {
267 if ((txs
& EN_TXS_COLLERR
) == 0)
268 return len
; /* success */
271 errno
= EIO
; /* too many retries */
276 en_get(struct iodesc
*desc
, void *pkt
, size_t len
, saseconds_t timeout
)
278 volatile struct en_regs
*er
;
279 volatile struct dma_dev
*rxdma
;
280 volatile struct dma_dev
*txdma
;
285 rxdma
= (struct dma_dev
*)P_ENETR_CSR
;
286 txdma
= (struct dma_dev
*)P_ENETX_CSR
;
287 er
= (struct en_regs
*)P_ENET
;
289 DPRINTF(("en_get: rxdma->dd_csr = %x\n",rxdma
->dd_csr
));
293 /* this is mouse's code now ... still doesn't work :( */
294 /* The previous comment is now a lie, this does work
295 * Darrin B Jewell <jewell@mit.edu> Sat Jan 24 21:44:56 1998
299 rxdma
->dd_csr
= (turbo
? DMACSR_INITBUFTURBO
: DMACSR_INITBUF
) |
300 DMACSR_READ
| DMACSR_RESET
;
303 rxdma
->dd_saved_next
= 0;
304 rxdma
->dd_saved_limit
= 0;
305 rxdma
->dd_saved_start
= 0;
306 rxdma
->dd_saved_stop
= 0;
308 rxdma
->dd_saved_next
= dma_buffers
[0];
311 rxdma
->dd_next
= dma_buffers
[0];
312 rxdma
->dd_limit
= DMA_ENDALIGN(char *, dma_buffers
[0]+MAX_DMASIZE
);
315 /* !!! not a typo: txdma */
316 txdma
->dd_stop
= dma_buffers
[0];
321 rxdma
->dd_csr
= DMACSR_SETENABLE
| DMACSR_READ
;
323 er
->rxmode
= EN_RMD_TEST
| EN_RMD_RECV_NORMAL
;
325 er
->rxmode
= EN_RMD_RECV_NORMAL
;
328 DPRINTF(("en_get: blocking on rcv DMA\n"));
332 if (en_wait_for_intr(ENETR_DMA_INTR
)) /* ### use timeout? */
335 state
= rxdma
->dd_csr
&
336 (DMACSR_BUSEXC
| DMACSR_COMPLETE
337 | DMACSR_SUPDATE
| DMACSR_ENABLE
);
338 DPRINTF(("en_get: DMA state = 0x%x.\n", state
));
339 if ((state
& DMACSR_ENABLE
) == 0) {
340 rxdma
->dd_csr
= DMACSR_RESET
| DMACSR_CLRCOMPLETE
;
344 if (state
& DMACSR_COMPLETE
) {
345 PRINTF(("en_get: ending DMA sequence\n"));
346 rxdma
->dd_csr
= DMACSR_CLRCOMPLETE
;
352 if ((state
& DMACSR_COMPLETE
) == 0 ||
353 (rxs
& EN_RX_OK
) == 0) {
355 return -1; /* receive failed */
359 gotpkt
= rxdma
->dd_saved_next
;
360 rlen
= rxdma
->dd_next
- rxdma
->dd_saved_next
;
362 gotpkt
= rxdma
->dd_saved_next
;
363 rlen
= rxdma
->dd_next
- rxdma
->dd_saved_next
;
366 if (gotpkt
!= dma_buffers
[0]) {
367 printf("Unexpected received packet location\n");
368 printf("DEBUG: rxstat=%x.\n", rxs
);
369 printf("DEBUG: gotpkt = 0x%lx, rlen = %d, len = %d\n",(u_long
)gotpkt
,rlen
,len
);
370 printf("DEBUG: rxdma->dd_csr = 0x%lx\n",(u_long
)rxdma
->dd_csr
);
371 printf("DEBUG: rxdma->dd_saved_next = 0x%lx\n",(u_long
)rxdma
->dd_saved_next
);
372 printf("DEBUG: rxdma->dd_saved_limit = 0x%lx\n",(u_long
)rxdma
->dd_saved_limit
);
373 printf("DEBUG: rxdma->dd_saved_start = 0x%lx\n",(u_long
)rxdma
->dd_saved_start
);
374 printf("DEBUG: rxdma->dd_saved_stop = 0x%lx\n",(u_long
)rxdma
->dd_saved_stop
);
375 printf("DEBUG: rxdma->dd_next = 0x%lx\n",(u_long
)rxdma
->dd_next
);
376 printf("DEBUG: rxdma->dd_limit = 0x%lx\n",(u_long
)rxdma
->dd_limit
);
377 printf("DEBUG: rxdma->dd_start = 0x%lx\n",(u_long
)rxdma
->dd_start
);
378 printf("DEBUG: rxdma->dd_stop = 0x%lx\n",(u_long
)rxdma
->dd_stop
);
379 printf("DEBUG: rxdma->dd_next_initbuf = 0x%lx\n",(u_long
)rxdma
->dd_next_initbuf
);
383 dump_pkt(gotpkt
, rlen
< 255 ? rlen
: 128);
386 DPRINTF(("en_get: done rxstat=%x.\n", rxs
));
389 DPRINTF(("en_get: buffer too small. want %d, got %d\n",
394 memcpy(pkt
, gotpkt
, rlen
);
397 printf("DEBUG: gotpkt = 0x%lx, pkt = 0x%lx, rlen = %d\n",
398 (u_long
)gotpkt
,(u_long
)pkt
,rlen
);
399 dump_pkt(gotpkt
, rlen
< 255 ? rlen
: 128);
400 dump_pkt(pkt
, rlen
< 255 ? rlen
: 128);
408 en_end(struct netif
*a
)
410 DPRINTF(("en_end: WARNING not doing anything\n"));
415 #define MKPANIC(ret,name,args) \
416 ret name args { panic(#name ## ": not implemented.\n"); }
418 MKPANIC(void, en_end
, (struct netif
*a
));
420 /* device functions */
423 enopen(struct open_file
*f
, char count
, char lun
, char part
)
427 DPRINTF(("open: en(%d,%d,%d)\n", count
, lun
, part
));
429 if (count
!= 0 || lun
!= 0 || part
!= 0)
430 return EUNIT
; /* there can be exactly one ethernet */
432 if (open_count
== 0) {
433 /* Find network interface. */
434 if ((netdev_sock
= netif_open(NULL
)) < 0)
436 if ((error
= mountroot(netdev_sock
)) != 0) {
438 netif_close(netdev_sock
);
443 f
->f_devdata
= NULL
; /* ### nfs_root_node ?! */
448 enclose(struct open_file
*f
)
451 if (--open_count
== 0)
452 netif_close(netdev_sock
);
458 enstrategy(void *devdata
, int rw
, daddr_t dblk
,
459 size_t size
, void *buf
, size_t *rsize
)
461 return ENXIO
; /* wrong access method */
464 /* private function */
469 /* Mount the root directory from a boot server */
471 struct in_addr in
= {
476 res
= arpwhohas(socktodesc(sock
), in
);
477 panic("arpwhohas returned %s", res
);
479 /* 1. use bootp. This does most of the work for us. */
482 if (myip
.s_addr
== 0 || rootip
.s_addr
== 0 || rootpath
[0] == '\0')
485 printf("Using IP address: %s\n", inet_ntoa(myip
));
486 printf("root addr=%s path=%s\n", inet_ntoa(rootip
), rootpath
);
489 if (nfs_mount(sock
, rootip
, rootpath
) < 0)
497 en_wait_for_intr(int flag
)
499 volatile int *intrstat
= MON(volatile int *, MG_intrstat
);
503 for (count
= 0; count
< EN_TIMEOUT
; count
++)
504 if (*intrstat
& flag
)