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