1 /* 2 * Copyright (c) 1982, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)if_apx.c 8.1 (Berkeley) 06/11/93 8 */ 9 10 /* 11 * Driver for SGS-THOMSON MK5025 based Link level controller. 12 * The chip will do LAPB in hardware, although this driver only 13 * attempts to use it for HDLC framing. 14 * 15 * Driver written by Keith Sklower, based on lance AMD7990 16 * driver by Van Jacobsen, and information graciously supplied 17 * by the ADAX corporation of Berkeley, CA. 18 */ 19 20 #include "apx.h" 21 #if NAPX > 0 22 23 #include <sys/param.h> 24 #include <sys/mbuf.h> 25 #include <sys/socket.h> 26 #include <sys/ioctl.h> 27 #include <sys/errno.h> 28 #include <sys/syslog.h> 29 30 #include <net/if.h> 31 #include <net/netisr.h> 32 #include <net/if_types.h> 33 #ifdef CCITT 34 #include <netccitt/x25.h> 35 int x25_rtrequest(), x25_ifoutput(); 36 #endif 37 38 #include <i386/isa/if_apxreg.h> 39 40 int apxprobe(), apxattach(), apxstart(), apx_uprim(), apx_meminit(); 41 int apxinit(), apxoutput(), apxioctl(), apxreset(), apxdebug = 0; 42 void apx_ifattach(), apxtest(), apxinput(), apxintr(), apxtint(), apxrint(); 43 44 struct apx_softc { 45 struct ifnet apx_if; 46 caddr_t apx_device; /* e.g. isa_device, vme_device, etc. */ 47 struct apc_reg *apx_reg; /* control regs for both subunits */ 48 struct apc_mem *apx_hmem; /* Host addr for shared memory */ 49 struct apc_mem *apx_dmem; /* Device (chip) addr for shared mem */ 50 struct sgcp *apx_sgcp; /* IO control port for this subunit */ 51 int apx_flags; /* Flags specific to this driver */ 52 #define APXF_CHIPHERE 0x01 /* mk5025 present */ 53 int apx_rxnum; /* Last receiver dx we looked at */ 54 int apx_txnum; /* Last tranmistter dx we stomped on */ 55 int apx_txcnt; /* Number of packets queued for tx*/ 56 u_int apx_msize; 57 struct sgae apx_csr23; /* 24 bit init addr, as seen by chip */ 58 u_short apx_csr4; /* byte gender, set in mach dep code */ 59 struct apc_modes apx_modes; /* Parameters, as amended by ioctls */ 60 } apx_softc[2 * NAPX]; 61 62 struct apxstat { 63 int rxnull; /* no rx bufs ready this interrupt */ 64 int rxnrdy; /* expected rx buf not ready */ 65 int rx2big; /* expected rx buf not ready */ 66 int txnull; 67 int pint; /* new primitive available interrupt */ 68 int rint; /* receive interrupts */ 69 int tint; /* transmit interrupts */ 70 int anyint; /* note all interrupts */ 71 int queued; /* got through apxinput */ 72 int nxpctd; /* received while if was down */ 73 int rstfld; /* reset didn't work */ 74 } apxstat; 75 76 /* default operating paramters for devices */ 77 struct apc_modes apx_default_modes = { 78 { 1, /* apm_sgob.lsaddr; */ 79 3, /* apm_sgob.rsaddr; */ 80 -SGMTU, /* apm_sgob.n1; */ 81 ((-10)<<8), /* apm_sgob.n2_scale; */ 82 -1250, /* apm_sgob.t1; */ 83 -10000, /* apm_sgob.t3; */ 84 -80, /* apm_sgob.tp; */ 85 }, 86 2, /* apm_txwin; */ 87 1, /* apm_apxmode: RS_232 connector and modem clock; */ 88 0, /* apm_apxaltmode: enable dtr, disable X.21 connector; */ 89 IFT_X25, /* apm_iftype; */ 90 }; 91 92 /* Begin bus & endian dependence */ 93 94 #include <i386/isa/isa_device.h> 95 96 struct isa_driver apxdriver = { 97 apxprobe, apxattach, "apx", 98 }; 99 100 #define SG_RCSR(apx, csrnum) \ 101 (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \ 102 inw(&(apx->apx_sgcp->sgcp_rdp))) 103 104 #define SG_WCSR(apx, csrnum, data) \ 105 (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \ 106 outw(&(apx->apx_sgcp->sgcp_rdp), data)) 107 108 #define APX_RCSR(apx, csrname) inb(&(apx->apx_reg->csrname)) 109 #define APX_WCSR(apx, csrname, data) outb(&(apx->apx_reg->csrname), data) 110 111 #define TIMO 10000 /* used in apx_uprim */ 112 113 apxprobe(id) 114 register struct isa_device *id; 115 { 116 int moffset = 0, nchips = 2, unit = id->id_unit << 1, subunit; 117 struct apc_reg *reg = (struct apc_reg *)id->id_iobase; 118 register struct apx_softc *apx = apx_softc + unit; 119 120 /* 121 * Probing for the second MK5025 on all ISA/EISA adax boards 122 * manufactured prior to July 1992 (and some time following) 123 * will hang the bus and the system. Thus, it is essential 124 * not to probe for the second mk5025 if it is known not to be there. 125 * As the current config scheme for 386BSD does not have a flags 126 * field, we adopt the convention of using the low order bit of 127 * the memsize to warn us that we have a single chip board. 128 */ 129 if (id->id_msize & 1) 130 nchips = 1; 131 for (subunit = 0; subunit < nchips; subunit++) { 132 apx->apx_msize = id->id_msize >> 1; 133 apx->apx_hmem = (struct apc_mem *) (id->id_maddr + moffset); 134 apx->apx_dmem = (struct apc_mem *) moffset; 135 apx->apx_device = (caddr_t) id; 136 apx->apx_reg = reg; 137 apx->apx_sgcp = reg->axr_sgcp + subunit; 138 apx->apx_csr4 = 0x0210; /* no byte swapping for PC-AT */ 139 apx->apx_modes = apx_default_modes; 140 apx->apx_if.if_unit = unit++; 141 moffset = apx->apx_msize; 142 apxtest(apx++); 143 } 144 return 1; 145 } 146 147 apxattach(id) 148 struct isa_device *id; 149 { 150 register struct apx_softc *apx = apx_softc + (id->id_unit << 1); 151 152 apx_ifattach(&((apx++)->apx_if)); 153 apx_ifattach(&(apx->apx_if)); 154 return 0; 155 } 156 /* End bus & endian dependence */ 157 158 /* 159 * Interface exists: make available by filling in network interface 160 * record. System will initialize the interface when it is ready 161 * to accept packets. 162 */ 163 void 164 apx_ifattach(ifp) 165 register struct ifnet *ifp; 166 { 167 /* 168 * Initialize ifnet structure 169 */ 170 ifp->if_name = "apc"; 171 ifp->if_mtu = SGMTU; 172 ifp->if_init = apxinit; 173 ifp->if_output = apxoutput; 174 ifp->if_start = apxstart; 175 ifp->if_ioctl = apxioctl; 176 ifp->if_reset = apxreset; 177 ifp->if_type = apx_default_modes.apm_iftype; 178 ifp->if_hdrlen = 5; 179 ifp->if_addrlen = 8; 180 if_attach(ifp); 181 } 182 /* 183 * Initialization of interface 184 */ 185 apxinit(unit) 186 int unit; 187 { 188 struct ifnet *ifp = &apx_softc[unit].apx_if; 189 int s = splimp(); 190 191 ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 192 if (apxreset(unit) && (ifp->if_flags & IFF_UP)) { 193 ifp->if_flags |= IFF_RUNNING; 194 (void)apxstart(ifp); 195 } 196 splx(s); 197 return 0; 198 } 199 200 apxctr(apx) 201 register struct apx_softc *apx; 202 { 203 APX_WCSR(apx, axr_ccr, 0xB0); /* select ctr 2, write lsb+msb, mode 0 */ 204 APX_WCSR(apx, axr_cnt2, 0x1); 205 APX_WCSR(apx, axr_cnt2, 0x0); 206 DELAY(50); 207 APX_WCSR(apx, axr_ccr, 0xE8); /* latch status, ctr 2; */ 208 return (APX_RCSR(apx, axr_cnt2)); 209 } 210 211 void 212 apxtest(apx) 213 register struct apx_softc *apx; 214 { 215 int i = 0; 216 217 if ((apx->apx_if.if_unit & 1) == 0 && (i = apxctr(apx)) == 0) 218 apxerror(apx, "no response from timer chip", 0); 219 if (SG_RCSR(apx, 1) & 0x8000) 220 SG_WCSR(apx, 1, 0x8040); 221 SG_WCSR(apx, 4, apx->apx_csr4); 222 SG_WCSR(apx, 5, 0x08); /* Set DTR mode in SGS thompson chip */ 223 if (((i = SG_RCSR(apx, 5)) & 0xff08) != 0x08) 224 apxerror(apx, "no mk5025, csr5 high bits are", i); 225 else 226 apx->apx_flags |= APXF_CHIPHERE; 227 (void) apx_uprim(apx, SG_STOP, "stop after probing"); 228 } 229 230 apxreset(unit) 231 int unit; 232 { 233 register struct apx_softc *apx = &apx_softc[unit ^ 1]; 234 u_char apm_apxmode = 0, apm_apxaltmode = 0; 235 #define MODE(m) (m |= apx->apx_modes.m << ((apx->apx_if.if_unit & 1) ? 1 : 0)) 236 237 MODE(apm_apxmode); 238 MODE(apm_apxaltmode); 239 apx = apx_softc + unit; 240 MODE(apm_apxmode); 241 MODE(apm_apxaltmode); 242 APX_WCSR(apx, axr_mode, apm_apxmode); 243 APX_WCSR(apx, axr_altmode, apm_apxaltmode); 244 (void) apxctr(apx); 245 (void) apx_uprim(apx, SG_STOP, "stop to reset"); 246 if ((apx->apx_if.if_flags & IFF_UP) == 0) 247 return 0; 248 apx_meminit(apx->apx_hmem, apx); 249 SG_WCSR(apx, 4, apx->apx_csr4); 250 SG_WCSR(apx, 2, apx->apx_csr23.f_hi); 251 SG_WCSR(apx, 3, apx->apx_csr23.lo); 252 if (apx_uprim(apx, SG_INIT, "init request") || 253 apx_uprim(apx, SG_STAT, "status request") || 254 apx_uprim(apx, SG_TRANS, "transparent mode")) 255 return 0; 256 SG_WCSR(apx, 0, SG_INEA); 257 return 1; 258 } 259 260 apx_uprim(apx, request, ident) 261 register struct apx_softc *apx; 262 char *ident; 263 { 264 register int timo = 0; 265 int reply; 266 267 if ((apx->apx_flags & APXF_CHIPHERE) == 0) 268 return 1; /* maybe even should panic . . . */ 269 if ((reply = SG_RCSR(apx, 1)) & 0x8040) 270 SG_WCSR(apx, 1, 0x8040); /* Magic! */ 271 if (request == SG_STOP && (SG_RCSR(apx, 0) & SG_STOPPED)) 272 return 0; 273 SG_WCSR(apx, 1, request | SG_UAV); 274 do { 275 reply = SG_RCSR(apx, 1); 276 if (timo++ >= TIMO || (reply & 0x8000)) { 277 apxerror(apx, ident, reply); 278 return 1; 279 } 280 } while (reply & SG_UAV); 281 return 0; 282 } 283 284 apx_meminit(apc, apx) 285 register struct apc_mem *apc; 286 struct apx_softc *apx; 287 { 288 register struct apc_mem *apcbase = apx->apx_dmem; 289 register int i; 290 #define LOWADDR(e) (((u_long)&(apcbase->e)) & 0xffff) 291 #define HIADDR(e) ((((u_long)&(apcbase->e)) >> 16) & 0xff) 292 #define SET_SGAE(d, f, a) {(d).lo = LOWADDR(a); (d).f_hi = (f) | HIADDR(a);} 293 #define SET_SGDX(d, f, a, b) \ 294 {SET_SGAE((d).sgdx_ae, f, a); (d).sgdx_mcnt = (d).sgdx_bcnt = (b);} 295 296 apx->apx_txnum = apx->apx_rxnum = apx->apx_txcnt = 0; 297 bzero((caddr_t)apc, ((caddr_t)(&apc->apc_rxmd[0])) - (caddr_t)apc); 298 apc->apc_mode = 0x0108; /* 2 flag spacing, leave addr & ctl, do CRC16 */ 299 apc->apc_sgop = apx->apx_modes.apm_sgop; 300 SET_SGAE(apx->apx_csr23, SG_UIE | SG_PROM, apc_mode); 301 SET_SGAE(apc->apc_rxdd, SG_RLEN, apc_rxmd[0]); 302 i = SG_TLEN | ((apx->apx_modes.apm_txwin)<< 8); 303 SET_SGAE(apc->apc_txdd, i, apc_txmd[0]); 304 SET_SGAE(apc->apc_stdd, 0, apc_sgsb); 305 SET_SGDX(apc->apc_rxtid, SG_OWN, apc_rxidbuf[0], -SGMTU); 306 SET_SGDX(apc->apc_txtid, 0, apc_txidbuf[0], 0); 307 for (i = 0; i < SGRBUF; i++) 308 SET_SGDX(apc->apc_rxmd[i], SG_OWN, apc_rbuf[i][0], -SGMTU) 309 for (i = 0; i < SGTBUF; i++) 310 SET_SGDX(apc->apc_txmd[i], 0, apc_tbuf[i][0], 0) 311 } 312 313 /* 314 * Start output on interface. Get another datagram to send 315 * off of the interface queue, and copy it to the interface 316 * before starting the output. 317 */ 318 apxstart(ifp) 319 struct ifnet *ifp; 320 { 321 register struct apx_softc *apx = &apx_softc[ifp->if_unit]; 322 register struct sgdx *dx; 323 struct apc_mem *apc = apx->apx_hmem; 324 struct mbuf *m; 325 int len; 326 327 if ((ifp->if_flags & IFF_RUNNING) == 0) 328 return (0); 329 do { 330 dx = apc->apc_txmd + apx->apx_txnum; 331 if (dx->sgdx_flags & SG_OWN) 332 return (0); 333 IF_DEQUEUE(&ifp->if_snd, m); 334 if (m == 0) 335 return (0); 336 len = min(m->m_pkthdr.len, SGMTU); 337 m_copydata(m, 0, len, apc->apc_tbuf[apx->apx_txnum]); 338 m_freem(m); 339 dx->sgdx_mcnt = -len; 340 dx->sgdx_flags = (SG_OWN|SG_TUI|SG_SLF|SG_ELF) | 341 (0xff & dx->sgdx_flags); 342 SG_WCSR(apx, 0, SG_INEA | SG_TDMD); 343 DELAY(20); 344 if (++apx->apx_txnum >= SGTBUF) 345 apx->apx_txnum = 0; 346 } while (++apx->apx_txcnt < SGTBUF); 347 apx->apx_txcnt = SGTBUF; /* in case txcnt > SGTBUF by mistake */ 348 ifp->if_flags |= IFF_OACTIVE; 349 return (0); 350 } 351 352 void 353 apxintr() 354 { 355 register struct apx_softc *apx; 356 int reply; 357 358 apxstat.anyint++; 359 for (apx = apx_softc + NAPX + NAPX; --apx >= apx_softc;) { 360 if (apx->apx_flags & APXF_CHIPHERE) 361 /* Try to turn off interrupt cause */ 362 while ((reply = SG_RCSR(apx, 0)) & 0xff) { 363 SG_WCSR(apx, 0, SG_INEA | 0xfe); 364 if (reply & (SG_MERR|SG_TUR|SG_ROR)) { 365 apxerror(apx, "mem, rx, or tx error", reply); 366 apxinit(apx->apx_if.if_unit); 367 break; 368 } 369 if (reply & SG_RINT) 370 apxrint(apx); 371 if (reply & SG_TINT) 372 apxtint(apx); 373 if (reply & SG_PINT) 374 apxstat.pint++; 375 } 376 } 377 } 378 379 void 380 apxtint(apx) 381 register struct apx_softc *apx; 382 { 383 register struct apc_mem *apc = apx->apx_hmem; 384 int i, loopcount = 0; 385 386 apxstat.tint++; 387 do { 388 if ((i = apx->apx_txnum - apx->apx_txcnt) < 0) 389 i += SGTBUF; 390 if (apc->apc_txmd[i].sgdx_flags & SG_OWN) { 391 if (loopcount) 392 break; 393 apxstat.txnull++; 394 return; 395 } 396 loopcount++; 397 apx->apx_if.if_flags &= ~IFF_OACTIVE; 398 } while (--apx->apx_txcnt > 0); 399 apxstart(&apx->apx_if); 400 } 401 402 void 403 apxrint(apx) 404 register struct apx_softc *apx; 405 { 406 register struct apc_mem *apc = apx->apx_hmem; 407 register struct sgdx *dx = apc->apc_rxmd + apx->apx_rxnum; 408 int i = 0; 409 #define SGNEXTRXMD \ 410 dx = ++apx->apx_rxnum == SGRBUF ? &apc->apc_rxmd[apx->apx_rxnum = 0] : dx + 1; 411 412 apxstat.rint++; 413 /* 414 * Out of sync with hardware, should never happen? 415 */ 416 while (dx->sgdx_flags & SG_OWN) { 417 apxstat.rxnrdy++; 418 if (++i == SGRBUF) { 419 apxstat.rxnull++; 420 return; 421 } 422 SGNEXTRXMD; 423 } 424 /* 425 * Process all buffers with valid data 426 */ 427 while ((dx->sgdx_flags & SG_OWN) == 0) { 428 if ((dx->sgdx_flags & (SG_SLF|SG_ELF)) != (SG_SLF|SG_ELF)) { 429 /* 430 * Find the end of the packet so we synch up. 431 * We throw the data away. 432 */ 433 apxerror(apx, "chained buffer", dx->sgdx_flags); 434 do { 435 apxstat.rx2big++; 436 dx->sgdx_bcnt = 0; 437 dx->sgdx_flags = SG_OWN | (0xff&dx->sgdx_flags); 438 SGNEXTRXMD; 439 } while (!(dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF))); 440 /* 441 * If search terminated without successful completion 442 * we reset the hardware (conservative). 443 */ 444 if ((dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)) != 445 SG_ELF) { 446 apxreset(apx->apx_if.if_unit); 447 return; 448 } 449 } else 450 apxinput(&apx->apx_if, apc->apc_rbuf[apx->apx_rxnum], 451 -dx->sgdx_mcnt); 452 dx->sgdx_bcnt = 0; 453 dx->sgdx_flags = SG_OWN | (0xff & dx->sgdx_flags); 454 SGNEXTRXMD; 455 } 456 } 457 458 void 459 apxinput(ifp, buffer, len) 460 register struct ifnet *ifp; 461 caddr_t buffer; 462 { 463 extern struct ifqueue hdintrq, ipintrq; 464 register struct ifqueue *inq; 465 register u_char *cp = (u_char *)buffer; 466 struct mbuf *m, *m_devget(); 467 int isr; 468 469 ifp->if_ipackets++; 470 if ((ifp->if_flags & IFF_UP) == 0) { 471 apxstat.nxpctd++; 472 return; 473 } 474 if (cp[0] == 0xff && cp[1] == 0x3) { 475 /* This is a UI HDLC Packet, so we'll assume PPP 476 protocol. for now, IP only. */ 477 buffer += 4; 478 len -= 4; 479 inq = &ipintrq; 480 isr = NETISR_IP; 481 } else { 482 #ifdef CCITT 483 inq = &hdintrq; 484 isr = NETISR_CCITT; 485 } 486 if (len <= 0) { 487 #endif 488 return; 489 } 490 m = m_devget(buffer, len, 0, ifp, (void (*)())0); 491 if (m == 0) 492 return; 493 if(IF_QFULL(inq)) { 494 IF_DROP(inq); 495 m_freem(m); 496 } else { 497 apxstat.queued++; 498 IF_ENQUEUE(inq, m); 499 schednetisr(isr); 500 } 501 } 502 503 /* 504 * Process an ioctl request. 505 */ 506 apxioctl(ifp, cmd, data) 507 register struct ifnet *ifp; 508 int cmd; 509 caddr_t data; 510 { 511 register struct ifaddr *ifa = (struct ifaddr *)data; 512 int s = splimp(), error = 0; 513 struct apx_softc *apx = &apx_softc[ifp->if_unit]; 514 515 switch (cmd) { 516 517 case SIOCSIFADDR: 518 #ifdef CCITT 519 ifa->ifa_rtrequest = x25_rtrequest; 520 break; 521 522 case SIOCSIFCONF_X25: 523 ifp->if_output = x25_ifoutput; 524 ifp->if_flags |= IFF_UP; 525 error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr); 526 if (error == 0) 527 apxinit(ifp->if_unit); 528 #endif 529 break; 530 531 case SIOCSIFFLAGS: 532 if (((ifp->if_flags & IFF_UP) == 0 && 533 (ifp->if_flags & IFF_RUNNING)) || 534 (ifp->if_flags & IFF_UP) && 535 (ifp->if_flags & IFF_RUNNING) == 0) 536 apxinit(ifp->if_unit); 537 break; 538 539 case SIOCSIFMODE: 540 if ((ifp->if_flags & IFF_UP) == 0) 541 apx->apx_modes = *(struct apc_modes *)data; 542 else 543 default: 544 error = EINVAL; 545 546 } 547 splx(s); 548 return (error); 549 } 550 551 apxerror(apx, msg, data) 552 register struct apx_softc *apx; 553 char *msg; 554 { 555 log(LOG_WARNING, "apc%d: %s, stat=0x%x\n", 556 apx->apx_if.if_unit, msg, data); 557 } 558 559 /* 560 * For debugging loopback activity. 561 */ 562 apxoutput(ifp, m, dst, rt) 563 register struct ifnet *ifp; 564 register struct mbuf *m; 565 struct sockaddr *dst; 566 struct rtentry *rt; 567 { 568 int s = splimp(), error = 0; 569 static char pppheader[4] = { -1, 3, 0, 0x21 }; 570 /* 571 * Queue message on interface, and start output if interface 572 * not yet active. 573 */ 574 ifp->if_opackets++; 575 M_PREPEND(m, sizeof pppheader, M_DONTWAIT); 576 if (m == 0) { 577 splx(s); 578 return ENOBUFS; 579 } 580 bcopy(pppheader, mtod(m, caddr_t), sizeof pppheader); 581 if (IF_QFULL(&ifp->if_snd)) { 582 IF_DROP(&ifp->if_snd); 583 m_freem(m); 584 error = ENOBUFS; 585 } else { 586 IF_ENQUEUE(&ifp->if_snd, m); 587 if ((ifp->if_flags & IFF_OACTIVE) == 0) 588 (*ifp->if_start)(ifp); 589 } 590 splx(s); 591 return (error); 592 } 593 #endif /* NAPX */ 594