1/* $NetBSD: if_ie.c,v 1.12 2008/01/12 09:54:32 tsutsui 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 56int ie_debug = 0; 57 58void ie_stop(struct netif *); 59void ie_end(struct netif *); 60void ie_error(struct netif *, char *, volatile struct iereg *); 61int ie_get(struct iodesc *, void *, size_t, saseconds_t); 62void ie_init(struct iodesc *, void *); 63int ie_match(struct netif *, void *); 64int ie_poll(struct iodesc *, void *, int); 65int ie_probe(struct netif *, void *); 66int ie_put(struct iodesc *, void *, size_t); 67void ie_reset(struct netif *, u_char *); 68void ieack(volatile struct iereg *, struct iemem *); 69 70struct netif_stats ie_stats; 71 72struct netif_dif ie0_dif = { 73 0, /* unit */ 74 1, /* nsel */ 75 &ie_stats, 76 0, 77 0, 78}; 79 80struct 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 92struct ie_configuration { 93 u_int phys_addr; 94 int used; 95} ie_config[] = { 96 { INTEL_REG_ADDR, 0 } 97}; 98 99int nie_config = __arraycount(ie_config); 100 101struct { 102 struct iereg *sc_reg; /* IE registers */ 103 struct iemem *sc_mem; /* RAM */ 104} ie_softc; 105 106int 107ie_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 130int 131ie_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 143void 144ie_error(struct netif *nif, char *str, volatile struct iereg *ier) 145{ 146 147 panic("ie%d: unknown error", nif->nif_unit); 148} 149 150void 151ieack(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 161void 162ie_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 289int 290ie_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 if (status & IE_FD_OK) { 307 length = iem->im_rbd[slot].ie_rbd_actual & 0x3fff; 308 if (length > len) 309 length = len; 310 memcpy(pkt, (void *)&iem->im_rxbuf[slot * IE_RBUF_SIZE], 311 length); 312 313 iem->im_rfd[slot].ie_fd_status = 0; 314 iem->im_rfd[slot].ie_fd_last |= IE_FD_LAST; 315 iem->im_rfd[(slot+NRXBUF-1)%NRXBUF].ie_fd_last &= 316 ~IE_FD_LAST; 317 iem->im_rbd[slot].ie_rbd_actual = 0; 318 iem->im_rbd[slot].ie_rbd_length |= IE_RBD_LAST; 319 iem->im_rbd[(slot+NRXBUF-1)%NRXBUF].ie_rbd_length &= 320 ~IE_RBD_LAST; 321#if 0 322 printf("S%d\n", slot); 323#endif 324 } else { 325 printf("shit\n"); 326 } 327 slot++; 328 /* should move descriptor onto end of queue... */ 329 } 330 if ((iem->im_scb.ie_status & IE_RU_READY) == 0) { 331 printf("RR\n"); 332 333 for (slot = 0; slot < NRXBUF; slot++) { 334 iem->im_rbd[slot].ie_rbd_length &= ~IE_RBD_LAST; 335 iem->im_rfd[slot].ie_fd_last &= ~IE_FD_LAST; 336 } 337 iem->im_rbd[NRXBUF-1].ie_rbd_length |= IE_RBD_LAST; 338 iem->im_rfd[NRXBUF-1].ie_fd_last |= IE_FD_LAST; 339 340 iem->im_rfd[0].ie_fd_buf_desc = (int)&iem->im_rbd[0] - (int)iem; 341 342 iem->im_scb.ie_command = IE_RU_START; 343 iem->im_scb.ie_command_list = 0; 344 iem->im_scb.ie_recv_list = (int)&iem->im_rfd[0] - (int)iem; 345 ier->ie_attention = 1; /* chan attention! */ 346 while (iem->im_scb.ie_command) 347 ; 348 slot = 0; 349 } 350 slot = slot % NRXBUF; 351 return length; 352} 353 354int 355ie_put(struct iodesc *desc, void *pkt, size_t len) 356{ 357 volatile struct iereg *ier = ie_softc.sc_reg; 358 struct iemem *iem = ie_softc.sc_mem; 359 u_char *p = pkt; 360 u_int a; 361 int xx = 0; 362 363 /* send transmit command */ 364 365 while (iem->im_scb.ie_command) 366 ; 367 368 /* copy data */ 369 memcpy((void *)&iem->im_txbuf[xx], p, len); 370 371 len = MAX(len, ETHER_MIN_LEN); 372 373 /* build transmit descriptor */ 374 iem->im_xd[xx].ie_xmit_flags = len | IE_XMIT_LAST; 375 iem->im_xd[xx].ie_xmit_next = 0xffff; 376 a = (int) &iem->im_txbuf[xx]; 377 iem->im_xd[xx].ie_xmit_buf_low = a & 0xffff; 378 iem->im_xd[xx].ie_xmit_buf_high = a >> 16; 379 380 /* transmit command */ 381 iem->im_xc[xx].com.ie_cmd_status = 0; 382 iem->im_xc[xx].com.ie_cmd_cmd = IE_CMD_XMIT | IE_CMD_LAST; 383 iem->im_xc[xx].com.ie_cmd_link = 0xffff; 384 iem->im_xc[xx].ie_xmit_desc = (int)&iem->im_xd[xx] - (int)iem; 385 iem->im_xc[xx].ie_xmit_length = len; 386 memcpy((void *)&iem->im_xc[xx].ie_xmit_addr, p, 387 sizeof iem->im_xc[xx].ie_xmit_addr); 388 389 iem->im_scb.ie_command = IE_CU_START; 390 iem->im_scb.ie_command_list = (int)&iem->im_xc[xx] - (int)iem; 391 392 ier->ie_attention = 1; /* chan attention! */ 393 394 if (ie_debug) { 395 printf("ie%d: send %d to %x:%x:%x:%x:%x:%x\n", 396 ((struct netif *)desc->io_netif)->nif_unit, len, 397 p[0], p[1], p[2], p[3], p[4], p[5]); 398 } 399 return len; 400} 401 402int 403ie_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout) 404{ 405 satime_t t; 406 int cc; 407 408 t = getsecs(); 409 cc = 0; 410 while (((getsecs() - t) < timeout) && !cc) { 411 cc = ie_poll(desc, pkt, len); 412 } 413 return cc; 414} 415/* 416 * init ie device. return 0 on failure, 1 if ok. 417 */ 418void 419ie_init(struct iodesc *desc, void *machdep_hint) 420{ 421 struct netif *nif = desc->io_netif; 422 423 if (ie_debug) 424 printf("ie%d: ie_init called\n", nif->nif_unit); 425 machdep_common_ether(desc->myea); 426 memset(&ie_softc, 0, sizeof(ie_softc)); 427 ie_softc.sc_reg = 428 (struct iereg *)ie_config[nif->nif_unit].phys_addr; 429 ie_softc.sc_mem = (struct iemem *)0x3e0000; 430 ie_reset(desc->io_netif, desc->myea); 431 printf("device: %s%d attached to %s\n", nif->nif_driver->netif_bname, 432 nif->nif_unit, ether_sprintf(desc->myea)); 433} 434 435void 436ie_stop(struct netif *nif) 437{ 438 volatile struct iereg *ier = ie_softc.sc_reg; 439 struct iemem *iem = ie_softc.sc_mem; 440 int timo = 10000; 441 volatile int t; 442 u_int a; 443 444 iem->im_iscp.iscp_busy = 1; 445 /* reset chip */ 446 a = IE_PORT_RESET; 447 ier->ie_porthigh = a & 0xffff; 448 t = 0; 449 t = 1; 450 ier->ie_portlow = a >> 16; 451 for (t = timo; t--;) 452 ; 453 454 /* reset chip again */ 455 a = IE_PORT_RESET; 456 ier->ie_porthigh = a & 0xffff; 457 t = 0; 458 t = 1; 459 ier->ie_portlow = a >> 16; 460 for (t = timo; t--;) 461 ; 462 463#if 0 464 printf("status %x busy %x\n", iem->im_scb.ie_status, 465 iem->im_iscp.iscp_busy); 466#endif 467} 468 469void 470ie_end(struct netif *nif) 471{ 472 473 if (ie_debug) 474 printf("ie%d: ie_end called\n", nif->nif_unit); 475 476 ie_stop(nif); 477 478#if 0 479 *(u_char *)0xfff42002 = 0; 480#endif 481} 482