📄 if_ie.c
字号:
bzero(es->es_rfdtab, (IENRBUF * sizeof (struct ierfd))); bzero(es->es_rbdtab, (IENRBUF * sizeof (struct ierbd))); /* * Walk through the rfd ring and rbd table initializing each. */ for (i = 0; i < IENRBUF; i++) { rfd = &es->es_rfdtab[i]; rbd = &es->es_rbdtab[i]; rbuf = es->es_rbufs[i]; rfd->ierfd_next = to_ieoff(es, (caddr_t) nextrfd(es, rfd)); rfd->ierfd_rbd = to_ieoff(es, (caddr_t) rbd); rbd->ierbd_next = -1; /* not used since el is 1 */ rbd->ierbd_el = 1; rbd->ierbd_buf = to_ieaddr(es, rbuf); rbd->ierbd_sizehi = IERBUFSIZ >> 8; rbd->ierbd_sizelo = IERBUFSIZ & 0xFF; } rfd = &es->es_rfdtab[IENRBUF-1]; rfd->ierfd_next = to_ieoff(es, (caddr_t) &es->es_rfdtab[0]); rfd->ierfd_el = 1; /* * Set the head rfd pointer. */ es->es_rfdhd = &es->es_rfdtab[0];}/* * Initialize and start the Receive Unit */intierustart(es) register struct ie_softc *es;{ register struct iescb *scb = &es->es_scb; int timebomb = TIMEBOMB; if (scb->ie_rus == IERUS_READY) { return OK; } while (scb->ie_cmd != 0) /* XXX */ if (timebomb-- <= 0) return TIMEOUT; /* * Start the RU. */ scb->ie_rfa = to_ieoff(es, (caddr_t) es->es_rfdhd); scb->ie_cmd = IECMD_RU_START; ieca(es); return OK;}ieca(es) register struct ie_softc *es;{ switch (es->es_type) { case IE_OB: es->es_obie->obie_ca = 1; es->es_obie->obie_ca = 0; break; case IE_MB: { register struct mie_device *mie; mie = (struct mie_device *)ie_getval(&es->es_mie); mie->mie_ca = 1; mie->mie_ca = 0; } break; case IE_TE: es->es_tie->tie_ca = 1; es->es_tie->tie_ca = 0; break; default: break; }}intiesimple(es, cb) register struct ie_softc *es; register struct iecb *cb;{ register struct iescb *scb = &es->es_scb; register timebomb = TIMEBOMB;#if defined(sun4) /* * Sunray must use IO Cache. Flush the outgoing ethernet line. * This insures that the buffers we are about to add to the queue * are not already in the I/O cache. * * XXX -- not positive that this is necessary. */ if ((id.id_machine == IDM_SUN4_SUNRAY) && (es->es_type == IE_OB)){ ioc_flush(IOC_ETHER_OUT); }#endif /* sun4 */ *(short *)cb = 0; /* clear status bits */ cb->iec_el = 1; cb->iec_next = 0; /* start CU */ while (scb->ie_cmd != 0) /* XXX */ if (timebomb-- <= 0) return TIMEOUT; scb->ie_cbl = to_ieoff(es, (caddr_t)cb); scb->ie_cmd = IECMD_CU_START; if (scb->ie_cx) scb->ie_cmd |= IECMD_ACK_CX; if (scb->ie_cnr) scb->ie_cmd |= IECMD_ACK_CNR; ieca(es); while (!cb->iec_done) /* XXX */ if (timebomb-- <= 0) return TIMEOUT; while (scb->ie_cmd != 0) /* XXX */ if (timebomb-- <= 0) return TIMEOUT; if (scb->ie_cx) scb->ie_cmd |= IECMD_ACK_CX; if (scb->ie_cnr) scb->ie_cmd |= IECMD_ACK_CNR; ieca(es); return OK;} /* * Transmit a packet. * Always copy the packet for the sake of Multibus * boards and Sun3's. This is not a performance critical situation */iexmit(es, buf, count) register struct ie_softc *es; char *buf; int count;{ register struct ietbd *tbd = &es->es_tbd; register struct ietfd *td = &es->es_tfd; bzero((caddr_t)tbd, sizeof *tbd); tbd->ietbd_eof = 1; tbd->ietbd_cntlo = count & 0xFF; tbd->ietbd_cnthi = count >> 8; bcopy(buf, es->es_xbuf, count); if (es->es_type == IE_MB){ /* this is a macro */ put_ieaddr((es->es_xbuf - (caddr_t)es), &(tbd->ietbd_buf)); }else tbd->ietbd_buf = to_ieaddr(es, es->es_xbuf); td->ietfd_tbd = to_ieoff(es, (caddr_t)tbd); td->ietfd_cmd = IE_TRANSMIT; if (iesimple(es, (struct iecb *)td)) { printf("ie: xmit hang\n"); return -1; } stats.collis += td->ietfd_ncoll; if (td->ietfd_ok) { stats.opackets++; stats.defer += td->ietfd_defer; return (0); } if (td->ietfd_xcoll || td->ietfd_nocarr || td->ietfd_nocts) printf("ie: Ethernet cable problem\n"); if (td->ietfd_underrun) stats.urunerrs++; return (-1);}intiepoll(es, buf) register struct ie_softc *es; char *buf;{ register struct ierfd *rfd; register struct ierbd *rbd; register char *rbuf; register struct iescb *scb = &es->es_scb; int i; int len; int timebomb = TIMEBOMB; /* * Cheat. Depend on the fact that rfd-->rbd-->rbuf use same indices. */ rfd = es->es_rfdhd; i = (int) (rfd - es->es_rfdtab); rbd = &es->es_rbdtab[i]; rbuf = es->es_rbufs[i]; /* update cumulative statistics */ stats.crcerrs = from_ieint(scb->ie_crcerrs); stats.alnerrs = from_ieint(scb->ie_alnerrs); stats.rscerrs = from_ieint(scb->ie_rscerrs); stats.orunerrs = from_ieint(scb->ie_ovrnerrs); if (!rfd->ierfd_done) return (0); /* no packet yet */ /* * We got a packet. */ stats.ipackets++; if (rbd->ierbd_eof) { /* good packet */#ifdef sun4 /* * For sunray IO Cache, flush the incoming ethernet * line. This insures that the buffer we are about to * look at is not still in the I/O cache. */#if defined(IOC_RBUF) if ((id.id_machine == IDM_SUN4_SUNRAY) && (es->es_type == IE_OB)) { ioc_flush(IOC_ETHER_IN); }#endif IOC_RBUF#endif sun4 len = (rbd->ierbd_cnthi << 8) + rbd->ierbd_cntlo; bcopy(rbuf, buf, len); } /* * Reinitialize rfd and increment rfd ring head pointer. */ rbd->ierbd_sizehi = IERBUFSIZ >> 8; rbd->ierbd_sizelo = IERBUFSIZ & 0xFF; rfd->ierfd_el = 1; prevrfd(es, es->es_rfdhd)->ierfd_el = 0; es->es_rfdhd = nextrfd(es, es->es_rfdhd); /* * Acknowledge frame reception and prod the chip for more. */ while (scb->ie_cmd != 0) /* XXX */ if (timebomb-- <= 0) return TIMEOUT; if (scb->ie_fr) scb->ie_cmd |= IECMD_ACK_FR; if (scb->ie_rnr) scb->ie_cmd |= IECMD_ACK_RNR; ieca(es); ierustart(es); return (len);}/* * Convert a CPU virtual address into an Ethernet virtual address. * * For Multibus, we assume it's in the Ethernet's memory space, and we * just subtract off the start of the memory space (==es). For Model 50, * the Ethernet chip has full access to supervisor virtual memory. * For Carrera, the chip can access the top 16MB of virtual memory, * but we never give it addresses outside that range, so the high * order bits can be ignored. */ieaddr_tto_ieaddr(es, cp) struct ie_softc *es; caddr_t cp;{ union { int n; char c[4]; } a, b;#ifdef sun3#ifdef DEBUG if ((es->es_type != IE_TE) && (cp < (char *)0x0F000000 || cp >= (char *)0x10000000)) { /* printf("Bad ptr to_ieaddr(%x)\n", cp); */ ; asm(" .word 0xFFFF") ; ; }#endif DEBUG#endif sun3 switch (es->es_type) { case IE_MB: case IE_TE: a.n = cp - (caddr_t)es; break; case IE_OB: a.n = (int)cp; break; default: break; } b.c[0] = a.c[3]; b.c[1] = a.c[2]; b.c[2] = a.c[1]; b.c[3] = 0; return (b.n);}/* * Convert a CPU virtual address into a 16-bit offset for the Ethernet * chip. * * This is the same for Onboard and Multibus, since the offset is based * on the absolute address supplied in the initial system configuration * block -- which we customize for Multibus or Onboard. */ieoff_tto_ieoff(es, addr) register struct ie_softc *es; caddr_t addr;{ union { short s; char c[2]; } a, b; a.s = (short)(addr - (caddr_t)es); b.c[0] = a.c[1]; b.c[1] = a.c[0]; return (b.s);}ieint_tfrom_ieint(n) short n;{ union { short s; char c[2]; } a, b; a.s = n; b.c[0] = a.c[1]; b.c[1] = a.c[0]; return (b.s);}/* * Set default configuration parameters * As spec'd by Intel, except acloc == 1 for header in data */iedefaultconf(ic) register struct ieconf *ic;{ bzero((caddr_t)ic, sizeof (struct ieconf)); ic->ieconf_cb.iec_cmd = IE_CONFIG; ic->ieconf_bytes = 12; ic->ieconf_fifolim = 8; ic->ieconf_pream = 2; /* 8 byte preamble */ ic->ieconf_alen = 6; ic->ieconf_acloc = 1; ic->ieconf_space = 96; ic->ieconf_slttmh = 512 >> 8; ic->ieconf_minfrm = 64; ic->ieconf_retry = 15;}/* * Close down intel ethernet device. * On the Model 50, we reset the chip and take it off the wire, since * it is sharing main memory with us (occasionally reading and writing), * and most programs don't know how to deal with that -- they just assume * that main memory is theirs to play with. */ieclose(sip) struct saioreq *sip;{ register struct ie_softc *es = (struct ie_softc *) sip->si_devdata; if (es->es_type == IE_OB) { *es->es_obie = obie_reset; }}iestats(){ printf("ie: ipackets %d opackets %d collis %d defer %d crcerrs %d alnerrs %d rscerrs %d orunerrs %d urunerrs %d\n", stats.ipackets, stats.opackets, stats.collis, stats.defer, stats.crcerrs, stats.alnerrs, stats.rscerrs, stats.orunerrs, stats.urunerrs);}/* * used to store controller address so we only have to pass around * a pointer to ie_softc */ie_putval(val, where){ register u_short *cp; union { u_int n; u_short s[2]; } a; a.n = (u_int)val; cp = (u_short *)(where); cp[0] = a.s[0]; cp[1] = a.s[1];}ie_getval(where){ register u_short *cp; union { u_int n; u_short s[2]; } a; register int x; cp = (u_short *)(where); a.s[0] = cp[0]; a.s[1] = cp[1]; x = a.n; return (x);}#if defined(sun4)/* * map sunray static RAM to IOC_IEDESCR_ADDR. * set the tags and zero out the descriptor RAM. */sunray_ioc_init(){ register u_long *p; register u_long tag; /* * map in tags and initialize them * we use the flush virtual address temporarily * since we normally don't touch the tags or data * once the i/o cache is initialized */ setpgmap((addr_t)IOC_FLUSH_ADDR, PG_V | PG_KW | PGT_OBIO | btop(OBIO_IOCDATA_ADDR)); /* zero both data and tag */ for (p = (u_long *)IOC_FLUSH_ADDR; (u_long)p != IOC_FLUSH_ADDR+0x2000; p++) *p = 0; /* * Initialize the ram and tags we are going to use * to hold the ethernet decriptors. */ setpgmap((addr_t)IOC_IEDESCR_ADDR, PG_V | PG_KW | PGT_OBIO | btop(OBIO_DESCR_DATA_ADDR)); /* zero descriptor data */ for ( p = (u_long *)IOC_IEDESCR_ADDR; (u_long)p < IOC_IEDESCR_ADDR + 0x1000; p++ ) *p = 0; /* * Initialize descriptor tags, * Bit 0 is the modified bit, bit 1 is the valid bit. * Bits 2-4 aren't used and the rest are virtual address bits. */ for ( p = (u_long *)(IOC_IEDESCR_ADDR+0x1000), tag = IOC_IEDESCR_ADDR+3; (u_long)p < IOC_IEDESCR_ADDR + PAGESIZE; ) { *p = tag; p++; if ((p != (u_long *)(IOC_IEDESCR_ADDR+0x1000)) && (((u_long)p%32) == 0)) tag += IOC_LINESIZE; } /* map in flush page for i/o cache */ setpgmap((addr_t)IOC_FLUSH_ADDR, PG_V | PG_KW | PGT_OBIO | btop(OBIO_IOCFLUSH_ADDR)); /* XXX - for debugging only, remove later */ setpgmap((addr_t)IOC_DATA_ADDR, PG_V | PG_KW | PGT_OBIO | btop(OBIO_IOCDATA_ADDR)); /* turn on the i/o cache */ sys_enable(ENA_IOCACHE);}#define SUNRAY_IE_DMA (1<<23 | 1<<15) /* 0x00808000 *//* * On a Sunray, if the 82586 issues a VA with both these * bits set, and the pg_ioc bit is set in the pte, then * the access will go to the on board descriptor RAM, not * the IO Cached buffer in main memory. * Since rbufs and xbuf don't fit in descriptor RAM * and they must be IO Cached on Sunray, * we must put them in memory address where both * these bits are not simultaneously set. */char *alloc_sunray_page(){ char *addr; int max;#if defined(IOC_RBUF) register u_int *p; struct pte pte; p = (u_int *)&pte;#endif IOC_RBUF#define MAX_WASTE 4 /* 4 consecutive pages have VA[15] set */ for(max = 0; max <= MAX_WASTE; ++max) { addr = resalloc(RES_DMAMEM, PAGESIZE); if(((u_int)addr & SUNRAY_IE_DMA) != SUNRAY_IE_DMA) break; /* address ok */ } if(max > MAX_WASTE) panic("ie: can't allocate legal sunray ethernet buffer.");#if defined(IOC_RBUF) *p = getpgmap(addr); pte.pg_ioc = 1; setpgmap(addr, *p);#endif IOC_RBUF return(addr);}#ifdef DEBUG/* * alloc_sanity() * * Sanity check addresses of xbuf and rbufs * to make sure that 586 can reach them, * and in the case of Sunray, that the VA's are legal */alloc_sanity(es)register struct ie_softc *es;{ u_int death = 0; int i; if(id.id_machine == IDM_SUN4_SUNRAY) { /* Sanity check Sunray addresses */ if(((u_int)es->es_xbuf & SUNRAY_IE_DMA) == SUNRAY_IE_DMA) { printf("alloc_sanity: xbuf = 0x%x\n", es->es_xbuf); death++; } for (i = 0; i < IENRBUF ; ++i) { if(((u_int)es->es_rbufs[i] & SUNRAY_IE_DMA) == SUNRAY_IE_DMA) { printf("alloc_sanity: es_rbufs[%d]=0x%x\n", i, es->es_rbufs[i]); death++; } } if(death) panic("alloc_sanity: illegal Sunray 85286 buffers"); } /* sanity check that the 82586 can actually reach the buffers */ if(((u_int)(es->es_xbuf) & IEDMABASE) != IEDMABASE) { printf("alloc_sanity: es_xbuf=0x%x\n", es->es_xbuf); death++; } for (i = 0; i < IENRBUF ; ++i) { if(((u_int)(es->es_rbufs[i]) & IEDMABASE) != IEDMABASE) { printf("alloc_sanity: rbufs[%d]=0x%x\n", i, es->es_rbufs[i]); death++; } } if(death) panic("alloc_sanity: buffers can't be addressed by 82586.");}#endif DEBUG/* * ieallocbufs() * Allocates xbuf and rbufs, and initializes * es->es_xbuf and es->es_rbufs[] appropriately. * * Knows about Sunray IO Cache requirements. * * no return value. */voidieallocbufs(es)register struct ie_softc *es;{ int rbuf; char *addr; if(es->es_xbuf) /* been here already */ { return; } /* Receive Buffers */#define RBUFPERPAGE (PAGESIZE / IERBUFSIZ) for (rbuf = 0; rbuf < IENRBUF; rbuf += RBUFPERPAGE) { int i; if(id.id_machine == IDM_SUN4_SUNRAY) addr = alloc_sunray_page(); else addr = resalloc(RES_DMAMEM, PAGESIZE); for(i = 0; (i < RBUFPERPAGE) && ((rbuf + i) < IENRBUF); ++i) { es->es_rbufs[rbuf + i] = addr + (i * IERBUFSIZ); if(verbosemode) printf(" ieallocbufs() es_rbufs[%d]=0x%x\n", rbuf + i, es->es_rbufs[rbuf + i]); } } /* Transmit Buffer */ if(id.id_machine == IDM_SUN4_SUNRAY) {#if !defined(IOC_RBUF) register u_int *p; struct pte pte; p = (u_int *)&pte;#endif !IOC_RBUF es->es_xbuf = alloc_sunray_page();#if !defined(IOC_RBUF) *p = getpgmap(es->es_xbuf); pte.pg_ioc = 1; setpgmap(es->es_xbuf, *p);#endif !IOC_RBUF } else es->es_xbuf = resalloc(RES_DMAMEM, PAGESIZE);#if defined(DEBUG) alloc_sanity(es);#endif DEBUG}#endif sun4#endif !sun4c /* top of file */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -