1 /* if_en.c 4.16 81/12/02 */ 2 3 #include "en.h" 4 5 /* 6 * Xerox prototype (3 Mb) Ethernet interface driver. 7 */ 8 9 #include "../h/param.h" 10 #include "../h/systm.h" 11 #include "../h/mbuf.h" 12 #include "../h/pte.h" 13 #include "../h/buf.h" 14 #include "../h/protosw.h" 15 #include "../h/socket.h" 16 #include "../h/ubareg.h" 17 #include "../h/ubavar.h" 18 #include "../h/enreg.h" 19 #include "../h/cpu.h" 20 #include "../h/mtpr.h" 21 #include "../h/vmmac.h" 22 #include "../net/in.h" 23 #include "../net/in_systm.h" 24 #include "../net/if.h" 25 #include "../net/if_en.h" 26 #include "../net/if_uba.h" 27 #include "../net/ip.h" 28 #include "../net/ip_var.h" 29 30 #define ENMTU 1024 31 32 int enprobe(), enattach(), enrint(), enxint(), encollide(); 33 struct uba_device *eninfo[NEN]; 34 u_short enstd[] = { 0 }; 35 struct uba_driver endriver = 36 { enprobe, 0, enattach, 0, enstd, "es", eninfo }; 37 #define ENUNIT(x) minor(x) 38 39 int eninit(),enoutput(),enreset(); 40 41 /* 42 * Ethernet software status per interface. 43 * 44 * Each interface is referenced by a network interface structure, 45 * es_if, which the routing code uses to locate the interface. 46 * This structure contains the output queue for the interface, its address, ... 47 * We also have, for each interface, a UBA interface structure, which 48 * contains information about the UNIBUS resources held by the interface: 49 * map registers, buffered data paths, etc. Information is cached in this 50 * structure for use by the if_uba.c routines in running the interface 51 * efficiently. 52 */ 53 struct en_softc { 54 struct ifnet es_if; /* network-visible interface */ 55 struct ifuba es_ifuba; /* UNIBUS resources */ 56 short es_delay; /* current output delay */ 57 short es_mask; /* mask for current output delay */ 58 u_char es_lastx; /* host last transmitted to */ 59 short es_oactive; /* is output active? */ 60 short es_olen; /* length of last output */ 61 } en_softc[NEN]; 62 63 /* 64 * Do output DMA to determine interface presence and 65 * interrupt vector. DMA is too short to disturb other hosts. 66 */ 67 enprobe(reg) 68 caddr_t reg; 69 { 70 register int br, cvec; 71 register struct endevice *addr = (struct endevice *)reg; 72 73 COUNT(ENPROBE); 74 #ifdef lint 75 br = 0; cvec = br; br = cvec; 76 enrint(0); enxint(0); encollide(0); 77 #endif 78 addr->en_istat = 0; 79 addr->en_owc = -1; 80 addr->en_oba = 0; 81 addr->en_ostat = EN_IEN|EN_GO; 82 DELAY(100000); 83 addr->en_ostat = 0; 84 return (1); 85 } 86 87 /* 88 * Interface exists: make available by filling in network interface 89 * record. System will initialize the interface when it is ready 90 * to accept packets. 91 */ 92 enattach(ui) 93 struct uba_device *ui; 94 { 95 register struct en_softc *es = &en_softc[ui->ui_unit]; 96 COUNT(ENATTACH); 97 98 es->es_if.if_unit = ui->ui_unit; 99 es->es_if.if_mtu = ENMTU; 100 es->es_if.if_net = ui->ui_flags; 101 es->es_if.if_host[0] = 102 ~(((struct endevice *)eninfo[ui->ui_unit])->en_addr) & 0xff; 103 es->es_if.if_addr = 104 if_makeaddr(es->es_if.if_net, es->es_if.if_host[0]); 105 es->es_if.if_output = enoutput; 106 es->es_if.if_init = eninit; 107 es->es_if.if_ubareset = enreset; 108 if_attach(&es->es_if); 109 } 110 111 /* 112 * Reset of interface after UNIBUS reset. 113 * If interface is on specified uba, reset its state. 114 */ 115 enreset(unit, uban) 116 int unit, uban; 117 { 118 register struct uba_device *ui; 119 COUNT(ENRESET); 120 121 if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0) { 122 printf("es%d: not alive\n", unit); 123 return; 124 } 125 if (ui->ui_ubanum != uban) 126 return; 127 eninit(unit); 128 } 129 130 /* 131 * Initialization of interface; clear recorded pending 132 * operations, and reinitialize UNIBUS usage. 133 */ 134 eninit(unit) 135 int unit; 136 { 137 register struct uba_device *ui; 138 register struct endevice *addr; 139 register struct en_softc *es; 140 int s; 141 142 es = &en_softc[unit]; 143 ui = eninfo[unit]; 144 if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, 145 sizeof (struct en_header), (int)btop(ENMTU)) == 0) { 146 printf("es%d: can't initialize\n", unit); 147 return; 148 } 149 addr = (struct endevice *)ui->ui_addr; 150 addr->en_istat = addr->en_ostat = 0; 151 152 /* 153 * Hang pending read, start any writes. 154 */ 155 s = splimp(); 156 enstart(unit); 157 enxint(unit); 158 splx(s); 159 } 160 161 int enlastdel = 25; 162 163 /* 164 * Start or restart output on interface. 165 * If interface is already active, then this is a retransmit 166 * after a collision, and just restuff registers and delay. 167 * If interface is not already active, get another datagram 168 * to send off of the interface queue, and map it to the interface 169 * before starting the output. 170 */ 171 enstart(dev) 172 dev_t dev; 173 { 174 int unit; 175 struct uba_device *ui; 176 register struct endevice *addr; 177 register struct en_softc *es; 178 struct mbuf *m; 179 int dest; 180 COUNT(ENSTART); 181 182 unit = ENUNIT(dev); 183 ui = eninfo[unit]; 184 es = &en_softc[unit]; 185 if (es->es_oactive) 186 goto restart; 187 188 /* 189 * Not already active: dequeue another request 190 * and map it to the UNIBUS. If no more requests, 191 * just return. 192 */ 193 IF_DEQUEUE(&es->es_if.if_snd, m); 194 if (m == 0) { 195 es->es_oactive = 0; 196 return; 197 } 198 es->es_olen = if_wubaput(&es->es_ifuba, m); 199 200 /* 201 * Ethernet cannot take back-to-back packets (no 202 * buffering in interface. To avoid overrunning 203 * receiver, enforce a small delay (about 1ms) in interface 204 * on successive packets sent to same host. 205 */ 206 dest = mtod(m, struct en_header *)->en_dhost; 207 if (es->es_lastx && es->es_lastx == dest) 208 es->es_delay = enlastdel; 209 else 210 es->es_lastx = dest; 211 212 restart: 213 /* 214 * Have request mapped to UNIBUS for transmission. 215 * Purge any stale data from this BDP, and start the otput. 216 */ 217 UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); 218 addr = (struct endevice *)ui->ui_addr; 219 addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; 220 addr->en_odelay = es->es_delay; 221 addr->en_owc = -((es->es_olen + 1) >> 1); 222 addr->en_ostat = EN_IEN|EN_GO; 223 es->es_oactive = 1; 224 } 225 226 /* 227 * Ethernet interface transmitter interrupt. 228 * Start another output if more data to send. 229 */ 230 enxint(unit) 231 int unit; 232 { 233 register struct endevice *addr; 234 register struct uba_device *ui; 235 register struct en_softc *es; 236 COUNT(ENXINT); 237 238 ui = eninfo[unit]; 239 es = &en_softc[unit]; 240 if (es->es_oactive == 0) 241 return; 242 addr = (struct endevice *)ui->ui_addr; 243 es = &en_softc[unit]; 244 es->es_oactive = 0; 245 es->es_delay = 0; 246 es->es_mask = ~0; 247 if (addr->en_ostat&EN_OERROR) 248 printf("es%d: output error\n", unit); 249 if (es->es_if.if_snd.ifq_head == 0) { 250 es->es_lastx = 0; 251 return; 252 } 253 enstart(unit); 254 } 255 256 /* 257 * Collision on ethernet interface. Do exponential 258 * backoff, and retransmit. If have backed off all 259 * the way printing warning diagnostic, and drop packet. 260 */ 261 encollide(unit) 262 int unit; 263 { 264 register struct en_softc *es; 265 COUNT(ENCOLLIDE); 266 267 es = &en_softc[unit]; 268 es->es_if.if_collisions++; 269 if (es->es_oactive == 0) 270 return; 271 if (es->es_mask == 0) { 272 printf("es%d: send error\n", unit); 273 enxint(unit); 274 } else { 275 es->es_mask <<= 1; 276 es->es_delay = mfpr(ICR) &~ es->es_mask; 277 enstart(unit); 278 } 279 } 280 281 /* 282 * Ethernet interface receiver interrupt. 283 * If input error just drop packet. 284 * Otherwise purge input buffered data path and examine 285 * packet to determine type. If can't determine length 286 * from type, then have to drop packet. Othewise decapsulate 287 * packet based on type and pass to type specific higher-level 288 * input routine. 289 */ 290 enrint(unit) 291 int unit; 292 { 293 struct endevice *addr; 294 register struct en_softc *es; 295 struct en_header *en; 296 struct mbuf *m; 297 struct ifqueue *inq; 298 register int len; 299 int off; 300 COUNT(ENRINT); 301 302 es = &en_softc[unit]; 303 addr = (struct endevice *)eninfo[unit]->ui_addr; 304 305 /* 306 * Purge BDP; drop error packets. 307 */ 308 UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp); 309 if (addr->en_istat&EN_IERROR) { 310 es->es_if.if_ierrors++; 311 printf("es%d: input error\n", unit); 312 goto setup; 313 } 314 315 /* 316 * Get pointer to ethernet header (in input buffer). 317 * Deal with trailer protocol: if type is PUP trailer 318 * get true type from first 16-bit word past data. 319 * Remember that type was trailer by setting off. 320 */ 321 en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr); 322 #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 323 if (en->en_type >= ENPUP_TRAIL && 324 en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) { 325 off = (en->en_type - ENPUP_TRAIL) * 512; 326 en->en_type = *endataaddr(en, off, u_short *); 327 off += 2; 328 } else 329 off = 0; 330 331 /* 332 * Attempt to infer packet length from type; 333 * can't deal with packet if can't infer length. 334 */ 335 switch (en->en_type) { 336 337 #ifdef INET 338 case ENPUP_IPTYPE: 339 len = endataaddr(en, off, struct ip *)->ip_len; 340 setipintr(); 341 inq = &ipintrq; 342 break; 343 #endif 344 345 default: 346 printf("en%d: unknow pkt type 0x%x\n", en->en_type); 347 goto setup; 348 } 349 if (len == 0) 350 goto setup; 351 352 /* 353 * Pull packet off interface. Off is nonzero if packet 354 * has trailing header; if_rubaget will then force this header 355 * information to be at the front, but we still have to drop 356 * the two-byte type which is at the front of the trailer data 357 * (which we ``consumed'' above). 358 */ 359 m = if_rubaget(&es->es_ifuba, len, off); 360 if (off) { 361 m->m_off += 2; 362 m->m_len -= 2; 363 } 364 IF_ENQUEUE(inq, m); 365 366 setup: 367 /* 368 * Reset for next packet. 369 */ 370 addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 371 addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1; 372 addr->en_istat = EN_IEN|EN_GO; 373 } 374 375 /* 376 * Ethernet output routine. 377 * Encapsulate a packet of type family for the local net. 378 * Use trailer local net encapsulation if enough data in first 379 * packet leaves a multiple of 512 bytes of data in remainder. 380 */ 381 enoutput(ifp, m0, pf) 382 struct ifnet *ifp; 383 struct mbuf *m0; 384 int pf; 385 { 386 int type, dest; 387 register struct mbuf *m = m0; 388 register struct en_header *en; 389 int s; 390 391 switch (pf) { 392 393 #ifdef INET 394 case PF_INET: { 395 register struct ip *ip = mtod(m0, struct ip *); 396 int off; 397 398 dest = ip->ip_dst.s_addr >> 24; 399 off = ip->ip_len - m->m_len; 400 if (off && off % 512 == 0 && m->m_off >= MMINOFF + 2) { 401 type = ENPUP_TRAIL + (off>>9); 402 m->m_off -= 2; 403 m->m_len += 2; 404 *mtod(m, u_short *) = ENPUP_IPTYPE; 405 goto gottrailertype; 406 } 407 type = ENPUP_IPTYPE; 408 off = 0; 409 goto gottype; 410 } 411 #endif 412 413 default: 414 printf("en%d: can't encapsulate pf%d\n", ifp->if_unit, pf); 415 m_freem(m0); 416 return (0); 417 } 418 419 /* 420 * Packet to be sent as trailer: move first packet 421 * (control information) to end of chain. 422 */ 423 gottrailertype: 424 while (m->m_next) 425 m = m->m_next; 426 m->m_next = m0; 427 m = m0->m_next; 428 m0->m_next = 0; 429 430 /* 431 * Add local net header. If no space in first mbuf, 432 * allocate another. 433 */ 434 gottype: 435 m0 = m; 436 if (MMINOFF + sizeof (struct en_header) > m->m_off) { 437 m = m_get(0); 438 if (m == 0) { 439 m_freem(m0); 440 return (0); 441 } 442 m->m_next = m0; 443 m->m_off = MMINOFF; 444 m->m_len = sizeof (struct en_header); 445 } else { 446 m = m0; 447 m->m_off -= sizeof (struct en_header); 448 m->m_len += sizeof (struct en_header); 449 } 450 en = mtod(m, struct en_header *); 451 en->en_shost = ifp->if_host[0]; 452 en->en_dhost = dest; 453 en->en_type = type; 454 455 /* 456 * Queue message on interface, and start output if interface 457 * not yet active. 458 */ 459 s = splimp(); 460 IF_ENQUEUE(&ifp->if_snd, m); 461 splx(s); 462 if (en_softc[ifp->if_unit].es_oactive == 0) 463 enstart(ifp->if_unit); 464 return (1); 465 } 466