1 /*        $NetBSD: if_ie.c,v 1.14 2025/05/04 14:26:27 andvar Exp $    */
2 
3 /*
4  * Copyright (c) 1995 Theo de Raadt
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 
32 #include <netinet/in.h>
33 #include <netinet/in_systm.h>
34 
35 #include <net/if.h>
36 #include <net/if_ether.h>
37 
38 #include <lib/libkern/libkern.h>
39 #include <lib/libsa/stand.h>
40 #include <lib/libsa/net.h>
41 
42 #define NTXBUF      1
43 #define NRXBUF      16
44 #define IE_RBUF_SIZE          ETHER_MAX_LEN
45 
46 #include <machine/prom.h>
47 
48 #include "libsa.h"
49 #include "netif.h"
50 #include "config.h"
51 #include "dev_net.h"
52 
53 #include "i82586.h"
54 #include "if_iereg.h"
55 
56 int     ie_debug = 0;
57 
58 void ie_stop(struct netif *);
59 void ie_end(struct netif *);
60 void ie_error(struct netif *, char *, volatile struct iereg *);
61 int ie_get(struct iodesc *, void *, size_t, saseconds_t);
62 void ie_init(struct iodesc *, void *);
63 int ie_match(struct netif *, void *);
64 int ie_poll(struct iodesc *, void *, int);
65 int ie_probe(struct netif *, void *);
66 int ie_put(struct iodesc *, void *, size_t);
67 void ie_reset(struct netif *, u_char *);
68 void ieack(volatile struct iereg *, struct iemem *);
69 
70 struct netif_stats ie_stats;
71 
72 struct netif_dif ie0_dif = {
73           0,                            /* unit */
74           1,                            /* nsel */
75           &ie_stats,
76           0,
77           0,
78 };
79 
80 struct netif_driver ie_driver = {
81           "ie",                         /* netif_bname */
82           ie_match,           /* match */
83           ie_probe,           /* probe */
84           ie_init,            /* init */
85           ie_get,                       /* get */
86           ie_put,                       /* put */
87           ie_end,                       /* end */
88           &ie0_dif,           /* netif_ifs */
89           1,                            /* netif_nifs */
90 };
91 
92 struct ie_configuration {
93           u_int   phys_addr;
94           int     used;
95 } ie_config[] = {
96           { INTEL_REG_ADDR, 0 }
97 };
98 
99 int     nie_config = __arraycount(ie_config);
100 
101 struct {
102           struct iereg *sc_reg;         /* IE registers */
103           struct iemem *sc_mem;         /* RAM */
104 }       ie_softc;
105 
106 int
ie_match(struct netif * nif,void * machdep_hint)107 ie_match(struct netif *nif, void *machdep_hint)
108 {
109           char   *name;
110           int     i, val = 0;
111 
112           if (bugargs.cputyp == CPU_147)
113                     return 0;
114           name = machdep_hint;
115           if (name && !memcmp(ie_driver.netif_bname, name, 2))
116                     val += 10;
117           for (i = 0; i < nie_config; i++) {
118                     if (ie_config[i].used)
119                               continue;
120                     if (ie_debug)
121                               printf("ie%d: ie_match --> %d\n", i, val + 1);
122                     ie_config[i].used++;
123                     return (val + 1);
124           }
125           if (ie_debug)
126                     printf("ie%d: ie_match --> 0\n", i);
127           return 0;
128 }
129 
130 int
ie_probe(struct netif * nif,void * machdep_hint)131 ie_probe(struct netif *nif, void *machdep_hint)
132 {
133 
134           /* the set unit is the current unit */
135           if (ie_debug)
136                     printf("ie%d: ie_probe called\n", nif->nif_unit);
137 
138           if (bugargs.cputyp != CPU_147)
139                     return 0;
140           return 1;
141 }
142 
143 void
ie_error(struct netif * nif,char * str,volatile struct iereg * ier)144 ie_error(struct netif *nif, char *str, volatile struct iereg *ier)
145 {
146 
147           panic("ie%d: unknown error", nif->nif_unit);
148 }
149 
150 void
ieack(volatile struct iereg * ier,struct iemem * iem)151 ieack(volatile struct iereg *ier, struct iemem *iem)
152 {
153 
154           /* ack the `interrupt' */
155           iem->im_scb.ie_command = iem->im_scb.ie_status & IE_ST_WHENCE;
156           ier->ie_attention = 1;        /* chan attention! */
157           while (iem->im_scb.ie_command)
158                     ;
159 }
160 
161 void
ie_reset(struct netif * nif,u_char * myea)162 ie_reset(struct netif *nif, u_char *myea)
163 {
164           volatile struct iereg *ier = ie_softc.sc_reg;
165           struct iemem *iem = ie_softc.sc_mem;
166           int     timo = 10000, i;
167           volatile int t;
168           u_int   a;
169 
170           if (ie_debug)
171                     printf("ie%d: ie_reset called\n", nif->nif_unit);
172 
173           /*printf("ier %x iem %x\n", ier, iem);*/
174 
175           *(u_char *)0xfff4202a = 0x40;
176 
177           memset(iem, 0, sizeof(*iem));
178           iem->im_scp.scp_sysbus = 0;
179           iem->im_scp.scp_iscp_low = (int)&iem->im_iscp & 0xffff;
180           iem->im_scp.scp_iscp_high = (int)&iem->im_iscp >> 16;
181 
182           iem->im_iscp.iscp_scboffset = (int)&iem->im_scb - (int) iem;
183           iem->im_iscp.iscp_busy = 1;
184           iem->im_iscp.iscp_base_low = (int)iem & 0xffff;
185           iem->im_iscp.iscp_base_high = (int)iem >> 16;
186 
187           /*
188            * completely and utterly unlike what i expected, the
189            * "write" order is:
190            * 1st:   d15-d0 -> high address
191            * 2nd:   d31-d16 -> low address
192            */
193 
194           /* reset chip */
195           a = IE_PORT_RESET;
196           ier->ie_porthigh = a & 0xffff;
197           t = 0;
198           t = 1;
199           ier->ie_portlow = a >> 16;
200           for (t = timo; t--;)
201                     ;
202 
203           /* set new SCP pointer */
204           a = (int) &iem->im_scp | IE_PORT_NEWSCP;
205           ier->ie_porthigh = a & 0xffff;
206           t = 0;
207           t = 1;
208           ier->ie_portlow = a >> 16;
209           for (t = timo; t--;)
210                     ;
211 
212           ier->ie_attention = 1;        /* chan attention! */
213           for (t = timo * 10; t--;)
214                     ;
215 
216           /* send CONFIGURE command */
217           iem->im_scb.ie_command = IE_CU_START;
218           iem->im_scb.ie_command_list = (int) &iem->im_cc - (int) iem;
219           iem->im_cc.com.ie_cmd_status = 0;
220           iem->im_cc.com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
221           iem->im_cc.com.ie_cmd_link = 0xffff;
222           iem->im_cc.ie_config_count = 0x0c;
223           iem->im_cc.ie_fifo = 8;
224           iem->im_cc.ie_save_bad = 0x40;
225           iem->im_cc.ie_addr_len = 0x2e;
226           iem->im_cc.ie_priority = 0;
227           iem->im_cc.ie_ifs = 0x60;
228           iem->im_cc.ie_slot_low = 0;
229           iem->im_cc.ie_slot_high = 0xf2;
230           iem->im_cc.ie_promisc = 0;
231           iem->im_cc.ie_crs_cdt = 0;
232           iem->im_cc.ie_min_len = 64;
233           iem->im_cc.ie_junk = 0xff;
234 
235           ier->ie_attention = 1;        /* chan attention! */
236           for (t = timo * 10; t--;)
237                     ;
238 
239           ieack(ier, iem);
240 
241           /*printf("ic %x\n", &iem->im_ic);*/
242           /* send IASETUP command */
243           iem->im_scb.ie_command = IE_CU_START;
244           iem->im_scb.ie_command_list = (int)&iem->im_ic - (int)iem;
245           iem->im_ic.com.ie_cmd_status = 0;
246           iem->im_ic.com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
247           iem->im_ic.com.ie_cmd_link = 0xffff;
248           memcpy((void *)&iem->im_ic.ie_address, myea,
249               sizeof(iem->im_ic.ie_address));
250 
251           ier->ie_attention = 1;        /* chan attention! */
252           for (t = timo * 10; t--;)
253                     ;
254 
255           ieack(ier, iem);
256 
257           /* setup buffers */
258 
259           for (i = 0; i < NRXBUF; i++) {
260                     iem->im_rfd[i].ie_fd_next = (int)&iem->im_rfd[(i+1) % NRXBUF] -
261                         (int)iem;
262                     iem->im_rbd[i].ie_rbd_next = (int)&iem->im_rbd[(i+1) % NRXBUF] -
263                         (int)iem;
264                     a = (int)&iem->im_rxbuf[i * IE_RBUF_SIZE];
265                     iem->im_rbd[i].ie_rbd_buffer_low = a & 0xffff;
266                     iem->im_rbd[i].ie_rbd_buffer_high = a >> 16;
267                     iem->im_rbd[i].ie_rbd_length = IE_RBUF_SIZE;
268           }
269           iem->im_rfd[NRXBUF - 1].ie_fd_last |= IE_FD_LAST;
270           iem->im_rbd[NRXBUF - 1].ie_rbd_length |= IE_RBD_LAST;
271           iem->im_rfd[0].ie_fd_buf_desc = (int)&iem->im_rbd[0] - (int)iem;
272 
273 #if 0
274           printf("rfd[0] %x rbd[0] %x buf[0] %x\n", &iem->im_rfd, &iem->im_rbd,
275               &iem->im_rxbuf);
276 #endif
277 
278           /* send receiver start command */
279           iem->im_scb.ie_command = IE_RU_START;
280           iem->im_scb.ie_command_list = 0;
281           iem->im_scb.ie_recv_list = (int) &iem->im_rfd[0] - (int) iem;
282           ier->ie_attention = 1;        /* chan attention! */
283           while (iem->im_scb.ie_command)
284                     ;
285 
286           ieack(ier, iem);
287 }
288 
289 int
ie_poll(struct iodesc * desc,void * pkt,int len)290 ie_poll(struct iodesc *desc, void *pkt, int len)
291 {
292           volatile struct iereg *ier = ie_softc.sc_reg;
293           struct iemem *iem = ie_softc.sc_mem;
294           static int slot;
295           int length = 0;
296           u_short status;
297 
298           __asm(".word        0xf518\n");
299           status = iem->im_rfd[slot].ie_fd_status;
300           if (status & IE_FD_BUSY)
301                     return 0;
302 
303           /* printf("slot %d: %x\n", slot, status); */
304           if ((status & (IE_FD_COMPLETE | IE_FD_OK)) ==
305               (IE_FD_COMPLETE | IE_FD_OK)) {
306                     length = iem->im_rbd[slot].ie_rbd_actual & 0x3fff;
307                     if (length > len)
308                               length = len;
309                     memcpy(pkt, (void *)&iem->im_rxbuf[slot * IE_RBUF_SIZE],
310                         length);
311 
312                     iem->im_rfd[slot].ie_fd_status = 0;
313                     iem->im_rfd[slot].ie_fd_last |= IE_FD_LAST;
314                     iem->im_rfd[(slot+NRXBUF-1)%NRXBUF].ie_fd_last &=
315                         ~IE_FD_LAST;
316                     iem->im_rbd[slot].ie_rbd_actual = 0;
317                     iem->im_rbd[slot].ie_rbd_length |= IE_RBD_LAST;
318                     iem->im_rbd[(slot+NRXBUF-1)%NRXBUF].ie_rbd_length &=
319                         ~IE_RBD_LAST;
320 #if 0
321                     printf("S%d\n", slot);
322 #endif
323                     slot++;
324                     /* should move descriptor onto end of queue... */
325           }
326           if ((iem->im_scb.ie_status & IE_RU_READY) == 0) {
327                     printf("RR\n");
328 
329                     for (slot = 0; slot < NRXBUF; slot++) {
330                               iem->im_rbd[slot].ie_rbd_length &= ~IE_RBD_LAST;
331                               iem->im_rfd[slot].ie_fd_last &= ~IE_FD_LAST;
332                     }
333                     iem->im_rbd[NRXBUF-1].ie_rbd_length |= IE_RBD_LAST;
334                     iem->im_rfd[NRXBUF-1].ie_fd_last |= IE_FD_LAST;
335 
336                     iem->im_rfd[0].ie_fd_buf_desc = (int)&iem->im_rbd[0] - (int)iem;
337 
338                     iem->im_scb.ie_command = IE_RU_START;
339                     iem->im_scb.ie_command_list = 0;
340                     iem->im_scb.ie_recv_list = (int)&iem->im_rfd[0] - (int)iem;
341                     ier->ie_attention = 1;        /* chan attention! */
342                     while (iem->im_scb.ie_command)
343                               ;
344                     slot = 0;
345           }
346           slot = slot % NRXBUF;
347           return length;
348 }
349 
350 int
ie_put(struct iodesc * desc,void * pkt,size_t len)351 ie_put(struct iodesc *desc, void *pkt, size_t len)
352 {
353           volatile struct iereg *ier = ie_softc.sc_reg;
354           struct iemem *iem = ie_softc.sc_mem;
355           u_char *p = pkt;
356           u_int a;
357           int xx = 0;
358 
359           /* send transmit command */
360 
361           while (iem->im_scb.ie_command)
362                     ;
363 
364           /* copy data */
365           memcpy((void *)&iem->im_txbuf[xx], p, len);
366 
367           len = MAX(len, ETHER_MIN_LEN);
368 
369           /* build transmit descriptor */
370           iem->im_xd[xx].ie_xmit_flags = len | IE_XMIT_LAST;
371           iem->im_xd[xx].ie_xmit_next = 0xffff;
372           a = (int) &iem->im_txbuf[xx];
373           iem->im_xd[xx].ie_xmit_buf_low = a & 0xffff;
374           iem->im_xd[xx].ie_xmit_buf_high = a >> 16;
375 
376           /* transmit command */
377           iem->im_xc[xx].com.ie_cmd_status = 0;
378           iem->im_xc[xx].com.ie_cmd_cmd = IE_CMD_XMIT | IE_CMD_LAST;
379           iem->im_xc[xx].com.ie_cmd_link = 0xffff;
380           iem->im_xc[xx].ie_xmit_desc = (int)&iem->im_xd[xx] - (int)iem;
381           iem->im_xc[xx].ie_xmit_length = len;
382           memcpy((void *)&iem->im_xc[xx].ie_xmit_addr, p,
383               sizeof iem->im_xc[xx].ie_xmit_addr);
384 
385           iem->im_scb.ie_command = IE_CU_START;
386           iem->im_scb.ie_command_list = (int)&iem->im_xc[xx] - (int)iem;
387 
388           ier->ie_attention = 1;        /* chan attention! */
389 
390           if (ie_debug) {
391                     printf("ie%d: send %d to %x:%x:%x:%x:%x:%x\n",
392                         ((struct netif *)desc->io_netif)->nif_unit, len,
393                         p[0], p[1], p[2], p[3], p[4], p[5]);
394           }
395           return len;
396 }
397 
398 int
ie_get(struct iodesc * desc,void * pkt,size_t len,saseconds_t timeout)399 ie_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
400 {
401           satime_t  t;
402           int     cc;
403 
404           t = getsecs();
405           cc = 0;
406           while (((getsecs() - t) < timeout) && !cc) {
407                     cc = ie_poll(desc, pkt, len);
408           }
409           return cc;
410 }
411 /*
412  * init ie device.   return 0 on failure, 1 if ok.
413  */
414 void
ie_init(struct iodesc * desc,void * machdep_hint)415 ie_init(struct iodesc *desc, void *machdep_hint)
416 {
417           struct netif *nif = desc->io_netif;
418 
419           if (ie_debug)
420                     printf("ie%d: ie_init called\n", nif->nif_unit);
421           machdep_common_ether(desc->myea);
422           memset(&ie_softc, 0, sizeof(ie_softc));
423           ie_softc.sc_reg =
424               (struct iereg *)ie_config[nif->nif_unit].phys_addr;
425           ie_softc.sc_mem = (struct iemem *)0x3e0000;
426           ie_reset(desc->io_netif, desc->myea);
427           printf("device: %s%d attached to %s\n", nif->nif_driver->netif_bname,
428               nif->nif_unit, ether_sprintf(desc->myea));
429 }
430 
431 void
ie_stop(struct netif * nif)432 ie_stop(struct netif *nif)
433 {
434           volatile struct iereg *ier = ie_softc.sc_reg;
435           struct iemem *iem = ie_softc.sc_mem;
436           int timo = 10000;
437           volatile int t;
438           u_int a;
439 
440           iem->im_iscp.iscp_busy = 1;
441           /* reset chip */
442           a = IE_PORT_RESET;
443           ier->ie_porthigh = a & 0xffff;
444           t = 0;
445           t = 1;
446           ier->ie_portlow = a >> 16;
447           for (t = timo; t--;)
448                     ;
449 
450           /* reset chip again */
451           a = IE_PORT_RESET;
452           ier->ie_porthigh = a & 0xffff;
453           t = 0;
454           t = 1;
455           ier->ie_portlow = a >> 16;
456           for (t = timo; t--;)
457                     ;
458 
459 #if 0
460           printf("status %x busy %x\n", iem->im_scb.ie_status,
461               iem->im_iscp.iscp_busy);
462 #endif
463 }
464 
465 void
ie_end(struct netif * nif)466 ie_end(struct netif *nif)
467 {
468 
469           if (ie_debug)
470                     printf("ie%d: ie_end called\n", nif->nif_unit);
471 
472           ie_stop(nif);
473 
474 #if 0
475           *(u_char *)0xfff42002 = 0;
476 #endif
477 }
478