1 /* $NetBSD: if_ie.c,v 1.11 2005/12/24 22:45:35 perry 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 __P((struct netif *)); 59 void ie_end __P((struct netif *)); 60 void ie_error __P((struct netif *, char *, volatile struct iereg *)); 61 int ie_get __P((struct iodesc *, void *, size_t, time_t)); 62 void ie_init __P((struct iodesc *, void *)); 63 int ie_match __P((struct netif *, void *)); 64 int ie_poll __P((struct iodesc *, void *, int)); 65 int ie_probe __P((struct netif *, void *)); 66 int ie_put __P((struct iodesc *, void *, size_t)); 67 void ie_reset __P((struct netif *, u_char *)); 68 void ieack __P((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 = sizeof(ie_config) / (sizeof(ie_config[0])); 100 101 struct { 102 struct iereg *sc_reg; /* IE registers */ 103 struct iemem *sc_mem; /* RAM */ 104 } ie_softc; 105 106 int 107 ie_match(nif, machdep_hint) 108 struct netif *nif; 109 void *machdep_hint; 110 { 111 char *name; 112 int i, val = 0; 113 114 if (bugargs.cputyp == CPU_147) 115 return (0); 116 name = machdep_hint; 117 if (name && !memcmp(ie_driver.netif_bname, name, 2)) 118 val += 10; 119 for (i = 0; i < nie_config; i++) { 120 if (ie_config[i].used) 121 continue; 122 if (ie_debug) 123 printf("ie%d: ie_match --> %d\n", i, val + 1); 124 ie_config[i].used++; 125 return (val + 1); 126 } 127 if (ie_debug) 128 printf("ie%d: ie_match --> 0\n", i); 129 return (0); 130 } 131 132 int 133 ie_probe(nif, machdep_hint) 134 struct netif *nif; 135 void *machdep_hint; 136 { 137 138 /* the set unit is the current unit */ 139 if (ie_debug) 140 printf("ie%d: ie_probe called\n", nif->nif_unit); 141 142 if (bugargs.cputyp != CPU_147) 143 return (0); 144 return (1); 145 } 146 147 void 148 ie_error(nif, str, ier) 149 struct netif *nif; 150 char *str; 151 volatile struct iereg *ier; 152 { 153 panic("ie%d: unknown error", nif->nif_unit); 154 } 155 156 void 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, 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 memset(iem, 0, 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 memcpy((void *)&iem->im_ic.ie_address, myea, 258 sizeof iem->im_ic.ie_address); 259 260 ier->ie_attention = 1; /* chan attention! */ 261 for (t = timo * 10; t--;) 262 ; 263 264 ieack(ier, iem); 265 266 /* setup buffers */ 267 268 for (i = 0; i < NRXBUF; i++) { 269 iem->im_rfd[i].ie_fd_next = (int) &iem->im_rfd[(i+1) % NRXBUF] - 270 (int) iem; 271 iem->im_rbd[i].ie_rbd_next = (int) &iem->im_rbd[(i+1) % NRXBUF] - 272 (int) iem; 273 a = (int) &iem->im_rxbuf[i * IE_RBUF_SIZE]; 274 iem->im_rbd[i].ie_rbd_buffer_low = a & 0xffff; 275 iem->im_rbd[i].ie_rbd_buffer_high = a >> 16; 276 iem->im_rbd[i].ie_rbd_length = IE_RBUF_SIZE; 277 } 278 iem->im_rfd[NRXBUF-1].ie_fd_last |= IE_FD_LAST; 279 iem->im_rbd[NRXBUF-1].ie_rbd_length |= IE_RBD_LAST; 280 iem->im_rfd[0].ie_fd_buf_desc = (int) &iem->im_rbd[0] - (int) iem; 281 282 /*printf("rfd[0] %x rbd[0] %x buf[0] %x\n", &iem->im_rfd, &iem->im_rbd, 283 &iem->im_rxbuf);*/ 284 285 /* send receiver start command */ 286 iem->im_scb.ie_command = IE_RU_START; 287 iem->im_scb.ie_command_list = 0; 288 iem->im_scb.ie_recv_list = (int) &iem->im_rfd[0] - (int) iem; 289 ier->ie_attention = 1; /* chan attention! */ 290 while (iem->im_scb.ie_command) 291 ; 292 293 ieack(ier, iem); 294 } 295 296 int 297 ie_poll(desc, pkt, len) 298 struct iodesc *desc; 299 void *pkt; 300 int len; 301 { 302 volatile struct iereg *ier = ie_softc.sc_reg; 303 struct iemem *iem = ie_softc.sc_mem; 304 static int slot; 305 int length = 0; 306 u_short status; 307 308 __asm(".word 0xf518\n"); 309 status = iem->im_rfd[slot].ie_fd_status; 310 if (status & IE_FD_BUSY) 311 return (0); 312 313 /* printf("slot %d: %x\n", slot, status); */ 314 if ((status & (IE_FD_COMPLETE | IE_FD_OK)) == (IE_FD_COMPLETE | IE_FD_OK)) { 315 if (status & IE_FD_OK) { 316 length = iem->im_rbd[slot].ie_rbd_actual & 0x3fff; 317 if (length > len) 318 length = len; 319 memcpy(pkt, (void *)&iem->im_rxbuf[slot * IE_RBUF_SIZE], 320 length); 321 322 iem->im_rfd[slot].ie_fd_status = 0; 323 iem->im_rfd[slot].ie_fd_last |= IE_FD_LAST; 324 iem->im_rfd[(slot+NRXBUF-1)%NRXBUF].ie_fd_last &= 325 ~IE_FD_LAST; 326 iem->im_rbd[slot].ie_rbd_actual = 0; 327 iem->im_rbd[slot].ie_rbd_length |= IE_RBD_LAST; 328 iem->im_rbd[(slot+NRXBUF-1)%NRXBUF].ie_rbd_length &= 329 ~IE_RBD_LAST; 330 /*printf("S%d\n", slot);*/ 331 332 } else { 333 printf("shit\n"); 334 } 335 slot++; 336 /* should move descriptor onto end of queue... */ 337 } 338 if ((iem->im_scb.ie_status & IE_RU_READY) == 0) { 339 printf("RR\n"); 340 341 for (slot = 0; slot < NRXBUF; slot++) { 342 iem->im_rbd[slot].ie_rbd_length &= ~IE_RBD_LAST; 343 iem->im_rfd[slot].ie_fd_last &= ~IE_FD_LAST; 344 } 345 iem->im_rbd[NRXBUF-1].ie_rbd_length |= IE_RBD_LAST; 346 iem->im_rfd[NRXBUF-1].ie_fd_last |= IE_FD_LAST; 347 348 iem->im_rfd[0].ie_fd_buf_desc = (int)&iem->im_rbd[0] - (int)iem; 349 350 iem->im_scb.ie_command = IE_RU_START; 351 iem->im_scb.ie_command_list = 0; 352 iem->im_scb.ie_recv_list = (int)&iem->im_rfd[0] - (int)iem; 353 ier->ie_attention = 1; /* chan attention! */ 354 while (iem->im_scb.ie_command) 355 ; 356 slot = 0; 357 } 358 slot = slot % NRXBUF; 359 return (length); 360 } 361 362 int 363 ie_put(desc, pkt, len) 364 struct iodesc *desc; 365 void *pkt; 366 size_t len; 367 { 368 volatile struct iereg *ier = ie_softc.sc_reg; 369 struct iemem *iem = ie_softc.sc_mem; 370 u_char *p = pkt; 371 u_int a; 372 int xx = 0; 373 374 /* send transmit command */ 375 376 while (iem->im_scb.ie_command) 377 ; 378 379 /* copy data */ 380 memcpy((void *)&iem->im_txbuf[xx], p, len); 381 382 len = MAX(len, ETHER_MIN_LEN); 383 384 /* build transmit descriptor */ 385 iem->im_xd[xx].ie_xmit_flags = len | IE_XMIT_LAST; 386 iem->im_xd[xx].ie_xmit_next = 0xffff; 387 a = (int) &iem->im_txbuf[xx]; 388 iem->im_xd[xx].ie_xmit_buf_low = a & 0xffff; 389 iem->im_xd[xx].ie_xmit_buf_high = a >> 16; 390 391 /* transmit command */ 392 iem->im_xc[xx].com.ie_cmd_status = 0; 393 iem->im_xc[xx].com.ie_cmd_cmd = IE_CMD_XMIT | IE_CMD_LAST; 394 iem->im_xc[xx].com.ie_cmd_link = 0xffff; 395 iem->im_xc[xx].ie_xmit_desc = (int) &iem->im_xd[xx] - (int) iem; 396 iem->im_xc[xx].ie_xmit_length = len; 397 memcpy((void *)&iem->im_xc[xx].ie_xmit_addr, p, 398 sizeof iem->im_xc[xx].ie_xmit_addr); 399 400 iem->im_scb.ie_command = IE_CU_START; 401 iem->im_scb.ie_command_list = (int) &iem->im_xc[xx] - (int) iem; 402 403 ier->ie_attention = 1; /* chan attention! */ 404 405 if (ie_debug) { 406 printf("ie%d: send %d to %x:%x:%x:%x:%x:%x\n", 407 ((struct netif *)desc->io_netif)->nif_unit, len, 408 p[0], p[1], p[2], p[3], p[4], p[5]); 409 } 410 return (len); 411 } 412 413 int 414 ie_get(desc, pkt, len, timeout) 415 struct iodesc *desc; 416 void *pkt; 417 size_t len; 418 time_t timeout; 419 { 420 time_t t; 421 int cc; 422 423 t = getsecs(); 424 cc = 0; 425 while (((getsecs() - t) < timeout) && !cc) { 426 cc = ie_poll(desc, pkt, len); 427 } 428 return (cc); 429 } 430 /* 431 * init ie device. return 0 on failure, 1 if ok. 432 */ 433 void 434 ie_init(desc, machdep_hint) 435 struct iodesc *desc; 436 void *machdep_hint; 437 { 438 struct netif *nif = desc->io_netif; 439 440 if (ie_debug) 441 printf("ie%d: ie_init called\n", nif->nif_unit); 442 machdep_common_ether(desc->myea); 443 memset(&ie_softc, 0, sizeof(ie_softc)); 444 ie_softc.sc_reg = 445 (struct iereg *) ie_config[nif->nif_unit].phys_addr; 446 ie_softc.sc_mem = (struct iemem *) 0x3e0000; 447 ie_reset(desc->io_netif, desc->myea); 448 printf("device: %s%d attached to %s\n", nif->nif_driver->netif_bname, 449 nif->nif_unit, ether_sprintf(desc->myea)); 450 } 451 452 void 453 ie_stop(nif) 454 struct netif *nif; 455 { 456 volatile struct iereg *ier = ie_softc.sc_reg; 457 struct iemem *iem = ie_softc.sc_mem; 458 int timo = 10000; 459 volatile int t; 460 u_int a; 461 462 iem->im_iscp.iscp_busy = 1; 463 /* reset chip */ 464 a = IE_PORT_RESET; 465 ier->ie_porthigh = a & 0xffff; 466 t = 0; 467 t = 1; 468 ier->ie_portlow = a >> 16; 469 for (t = timo; t--;) 470 ; 471 472 /* reset chip again */ 473 a = IE_PORT_RESET; 474 ier->ie_porthigh = a & 0xffff; 475 t = 0; 476 t = 1; 477 ier->ie_portlow = a >> 16; 478 for (t = timo; t--;) 479 ; 480 481 /*printf("status %x busy %x\n", iem->im_scb.ie_status, 482 iem->im_iscp.iscp_busy);*/ 483 } 484 485 void 486 ie_end(nif) 487 struct netif *nif; 488 { 489 if (ie_debug) 490 printf("ie%d: ie_end called\n", nif->nif_unit); 491 492 ie_stop(nif); 493 494 /* *(u_char *) 0xfff42002 = 0; */ 495 } 496