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