📄 if_ec.c
字号:
/* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if_ec.c 7.8 (Berkeley) 12/16/90 */#include "ec.h"#if NEC > 0/* * 3Com Ethernet Controller interface */#include "../include/pte.h"#include "sys/param.h"#include "sys/systm.h"#include "sys/mbuf.h"#include "sys/buf.h"#include "sys/protosw.h"#include "sys/socket.h"#include "sys/syslog.h"#include "sys/vmmac.h"#include "sys/ioctl.h"#include "sys/errno.h"#include "net/if.h"#include "net/netisr.h"#include "net/route.h"#ifdef INET#include "netinet/in.h"#include "netinet/in_systm.h"#include "netinet/in_var.h"#include "netinet/ip.h"#include "netinet/if_ether.h"#endif#ifdef NS#include "netns/ns.h"#include "netns/ns_if.h"#endif#include "../include/cpu.h"#include "../include/mtpr.h"#include "if_ecreg.h"#include "if_uba.h"#include "../uba/ubareg.h"#include "../uba/ubavar.h"#if CLSIZE == 2#define ECBUFSIZE 32 /* on-board memory, clusters */#endifint ecubamem(), ecprobe(), ecattach(), ecrint(), ecxint(), eccollide();struct uba_device *ecinfo[NEC];u_short ecstd[] = { 0 };struct uba_driver ecdriver = { ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo, 0, 0, 0, 0, ecubamem };int ecinit(),ecioctl(),ecstart(),ecreset(),ether_output();struct mbuf *ecget();extern struct ifnet loif;/* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * es_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... * We also have, for each interface, a UBA interface structure, which * contains information about the UNIBUS resources held by the interface: * map registers, buffered data paths, etc. Information is cached in this * structure for use by the if_uba.c routines in running the interface * efficiently. */struct ec_softc { struct arpcom es_ac; /* common Ethernet structures */#define es_if es_ac.ac_if /* network-visible interface */#define es_addr es_ac.ac_enaddr /* hardware Ethernet address */ struct ifuba es_ifuba; /* UNIBUS resources */ short es_mask; /* mask for current output delay */ u_char *es_buf[16]; /* virtual addresses of buffers */} ec_softc[NEC];/* * Configure on-board memory for an interface. * Called from autoconfig and after a uba reset. * The address of the memory on the uba is supplied in the device flags. */ecubamem(ui, uban) register struct uba_device *ui;{ register caddr_t ecbuf = (caddr_t) &umem[uban][ui->ui_flags]; register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; /* * Make sure csr is there (we run before ecprobe). */ if (badaddr((caddr_t)addr, 2)) return (-1);#if VAX780 if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) { uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr; return (-1); }#endif /* * Make sure memory is turned on */ addr->ec_rcr = EC_AROM; /* * Tell the system that the board has memory here, so it won't * attempt to allocate the addresses later. */ if (ubamem(uban, ui->ui_flags, ECBUFSIZE*CLSIZE, 1) == 0) { printf("ec%d: cannot reserve uba addresses\n", ui->ui_unit); addr->ec_rcr = EC_MDISAB; /* disable memory */ return (-1); } /* * Check for existence of buffers on Unibus. */ if (badaddr((caddr_t)ecbuf, 2)) {bad: printf("ec%d: buffer mem not found\n", ui->ui_unit); (void) ubamem(uban, ui->ui_flags, ECBUFSIZE*2, 0); addr->ec_rcr = EC_MDISAB; /* disable memory */ return (-1); }#if VAX780 if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) { uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr; goto bad; }#endif if (ui->ui_alive == 0) /* Only printf from autoconfig */ printf("ec%d: mem %x-%x\n", ui->ui_unit, ui->ui_flags, ui->ui_flags + ECBUFSIZE*CLBYTES - 1); ui->ui_type = 1; /* Memory on, allocated */ return (0);}/* * Do output DMA to determine interface presence and * interrupt vector. DMA is too short to disturb other hosts. */ecprobe(reg, ui) caddr_t reg; struct uba_device *ui;{ register int br, cvec; /* r11, r10 value-result */ register struct ecdevice *addr = (struct ecdevice *)reg; register caddr_t ecbuf = (caddr_t) &umem[ui->ui_ubanum][ui->ui_flags];#ifdef lint br = 0; cvec = br; br = cvec; ecrint(0); ecxint(0); eccollide(0);#endif /* * Check that buffer memory was found and enabled. */ if (ui->ui_type == 0) return(0); /* * Make a one byte packet in what should be buffer #0. * Submit it for sending. This should cause an xmit interrupt. * The xmit interrupt vector is 8 bytes after the receive vector, * so adjust for this before returning. */ *(u_short *)ecbuf = (u_short) 03777; ecbuf[03777] = '\0'; addr->ec_xcr = EC_XINTEN|EC_XWBN; DELAY(100000); addr->ec_xcr = EC_XCLR; if (cvec > 0 && cvec != 0x200) { if (cvec & 04) { /* collision interrupt */ cvec -= 04; br += 1; /* rcv is collision + 1 */ } else { /* xmit interrupt */ cvec -= 010; br += 2; /* rcv is xmit + 2 */ } } return (1);}/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */ecattach(ui) struct uba_device *ui;{ struct ec_softc *es = &ec_softc[ui->ui_unit]; register struct ifnet *ifp = &es->es_if; register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; int i, j; u_char *cp; ifp->if_unit = ui->ui_unit; ifp->if_name = "ec"; ifp->if_mtu = ETHERMTU; /* * Read the ethernet address off the board, one nibble at a time. */ addr->ec_xcr = EC_UECLR; /* zero address pointer */ addr->ec_rcr = EC_AROM; cp = es->es_addr;#define NEXTBIT addr->ec_rcr = EC_AROM|EC_ASTEP; addr->ec_rcr = EC_AROM for (i=0; i < sizeof (es->es_addr); i++) { *cp = 0; for (j=0; j<=4; j+=4) { *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; } cp++; } printf("ec%d: hardware address %s\n", ui->ui_unit, ether_sprintf(es->es_addr)); ifp->if_init = ecinit; ifp->if_ioctl = ecioctl; ifp->if_output = ether_output; ifp->if_start = ecstart; ifp->if_reset = ecreset; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; for (i=0; i<16; i++) es->es_buf[i] = (u_char *)&umem[ui->ui_ubanum][ui->ui_flags + 2048*i]; if_attach(ifp);}/* * Reset of interface after UNIBUS reset. * If interface is on specified uba, reset its state. */ecreset(unit, uban) int unit, uban;{ register struct uba_device *ui; if (unit >= NEC || (ui = ecinfo[unit]) == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) return; printf(" ec%d", unit); ec_softc[unit].es_if.if_flags &= ~IFF_RUNNING; ecinit(unit);}/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */ecinit(unit) int unit;{ struct ec_softc *es = &ec_softc[unit]; struct ecdevice *addr; register struct ifnet *ifp = &es->es_if; int i, s; /* not yet, if address still unknown */ if (ifp->if_addrlist == (struct ifaddr *)0) return; /* * Hang receive buffers and start any pending writes. * Writing into the rcr also makes sure the memory * is turned on. */ if ((ifp->if_flags & IFF_RUNNING) == 0) { u_short start_read; addr = (struct ecdevice *)ecinfo[unit]->ui_addr; s = splimp(); /* * write our ethernet address into the address recognition ROM * so we can always use the same EC_READ bits (referencing ROM), * in case we change the address sometime. * Note that this is safe here as the receiver is NOT armed. */ ec_setaddr(es->es_addr, unit); /* * Arm the receiver#ifdef MULTI if (es->es_if.if_flags & IFF_PROMISC) start_read = EC_PROMISC; else if (es->es_if.if_flags & IFF_MULTI) start_read = EC_MULTI; else#endif MULTI start_read = EC_READ; */ for (i = ECRHBF; i >= ECRLBF; i--) addr->ec_rcr = EC_READ | i; es->es_if.if_flags &= ~IFF_OACTIVE; es->es_mask = ~0; es->es_if.if_flags |= IFF_RUNNING; if (es->es_if.if_snd.ifq_head) (void) ecstart(&es->es_if); splx(s); }}/* * Start output on interface. Get another datagram to send * off of the interface queue, and copy it to the interface * before starting the output. */ecstart(ifp)struct ifnet *ifp;{ int unit = ifp->if_unit; register struct ec_softc *es = &ec_softc[unit]; struct ecdevice *addr; struct mbuf *m; if ((es->es_if.if_flags & IFF_RUNNING) == 0) return (0); IF_DEQUEUE(&es->es_if.if_snd, m); if (m == 0) return (0); ecput(es->es_buf[ECTBF], m); addr = (struct ecdevice *)ecinfo[unit]->ui_addr; addr->ec_xcr = EC_WRITE|ECTBF; es->es_if.if_flags |= IFF_OACTIVE; return (0);}/* * Ethernet interface transmitter interrupt. * Start another output if more data to send. */ecxint(unit) int unit;{ register struct ec_softc *es = &ec_softc[unit]; register struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; if ((es->es_if.if_flags & IFF_OACTIVE) == 0) return; if ((addr->ec_xcr&EC_XDONE) == 0 || (addr->ec_xcr&EC_XBN) != ECTBF) { printf("ec%d: stray xmit interrupt, xcr=%b\n", unit, addr->ec_xcr, EC_XBITS); es->es_if.if_flags &= ~IFF_OACTIVE; addr->ec_xcr = EC_XCLR; return; } es->es_if.if_opackets++; es->es_if.if_flags &= ~IFF_OACTIVE; es->es_mask = ~0; addr->ec_xcr = EC_XCLR; if (es->es_if.if_snd.ifq_head) (void) ecstart(&es->es_if);}/* * Collision on ethernet interface. Do exponential * backoff, and retransmit. If have backed off all * the way print warning diagnostic, and drop packet. */eccollide(unit) int unit;{ register struct ec_softc *es = &ec_softc[unit]; register struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; register i; int delay; es->es_if.if_collisions++; if ((es->es_if.if_flags & IFF_OACTIVE) == 0) return; /* * Es_mask is a 16 bit number with n low zero bits, with * n the number of backoffs. When es_mask is 0 we have * backed off 16 times, and give up. */ if (es->es_mask == 0) { u_short start_read; es->es_if.if_oerrors++; log(LOG_ERR, "ec%d: send error\n", unit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -