📄 if_il.c
字号:
#ifndef lintstatic char *sccsid = "@(#)if_il.c 4.1 (ULTRIX) 7/2/90";#endif lint/************************************************************************ * * * Copyright (c) 1985 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * Modification History * * * * 1-Apr-88 -- lea 43.5bsd fixes and decnet hooks. * * * 13-Jun-86 -- jaw fix to uba reset and drivers. XXX? * * 18-mar-86 -- jaw br/cvec changed to NOT use registers. * * Larry Cohen - 09/16/85 * * Add 43bsd alpha tape changes for subnet routing * * * ************************************************************************//* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * * @(#)if_il.c 7.2 (Berkeley) 8/7/86 */#include "il.h"#ifdef NIL > 0 || defined(BINARY)#include "../data/if_il_data.c"extern struct protosw *iftype_to_proto(), *iffamily_to_proto();int ilprobe(), ilattach(), ilrint(), ilcint();u_short ilstd[] = { 0 };struct uba_driver ildriver = { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };#define ILUNIT(x) minor(x)int ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch();int ildebug = 0;/* * Interlan Ethernet Communications Controller interface */ilprobe(reg) caddr_t reg;{ register struct ildevice *addr = (struct ildevice *)reg; register i;#ifdef lint i = 0; ilrint(i); ilcint(i); ilwatch(i);#endif addr->il_csr = ILC_OFFLINE|IL_CIE; DELAY(100000); i = addr->il_csr; /* clear CDONE */ if (cvec > 0 && cvec != 0x200) cvec -= 4; return (1);}/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. A STATUS command is done to get the ethernet * address and other interesting data. */ilattach(ui) struct uba_device *ui;{ register struct il_softc *is = &il_softc[ui->ui_unit]; register struct ifnet *ifp = &is->is_if; register struct ildevice *addr = (struct ildevice *)ui->ui_addr; ifp->if_unit = ui->ui_unit; ifp->if_name = "il"; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST; /* * Reset the board and map the statistics * buffer onto the Unibus. */ addr->il_csr = ILC_RESET; (void)ilwait(ui, "reset"); is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats, sizeof (struct il_stats), 0); addr->il_bar = is->is_ubaddr & 0xffff; addr->il_bcr = sizeof (struct il_stats); addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT; (void)ilwait(ui, "status"); ubarelse(ui->ui_ubanum, &is->is_ubaddr); if (ildebug) printf("il%d: module=%s firmware=%s\n", ui->ui_unit, is->is_stats.ils_module, is->is_stats.ils_firmware); bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, sizeof (is->is_addr)); printf("il%d: hardware address %s\n", ui->ui_unit, ether_sprintf(is->is_addr)); ifp->if_init = ilinit; ifp->if_output = iloutput; ifp->if_ioctl = ilioctl; ifp->if_reset = ilreset; is->is_ifuba.ifu_flags = UBA_CANTWAIT;#ifdef notdef is->is_ifuba.ifu_flags |= UBA_NEEDBDP;#endif if_attach(ifp);}ilwait(ui, op) struct uba_device *ui; char *op;{ register struct ildevice *addr = (struct ildevice *)ui->ui_addr; while ((addr->il_csr&IL_CDONE) == 0) ; if (addr->il_csr&IL_STATUS) { printf("il%d: %s failed, csr=%b\n", ui->ui_unit, op, addr->il_csr, IL_BITS); return (-1); } return (0);}/* * Reset of interface after UNIBUS reset. * If interface is on specified uba, reset its state. */ilreset(unit, uban) int unit, uban;{ register struct uba_device *ui; if (unit >= nNIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) return; printf(" il%d", unit); il_softc[unit].is_if.if_flags &= ~IFF_RUNNING; il_softc[unit].is_flags &= ~ILF_RUNNING; ilinit(unit);}/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */ilinit(unit) int unit;{ register struct il_softc *is = &il_softc[unit]; register struct uba_device *ui = ilinfo[unit]; register struct ildevice *addr; register struct ifnet *ifp = &is->is_if; int s; /* not yet, if address still unknown */ if (ifp->if_addrlist == (struct ifaddr *)0) return; if (is->is_flags & ILF_RUNNING) return; if ((ifp->if_flags & IFF_RUNNING) == 0) { if (if_ubainit(&is->is_ifuba, ui->ui_ubanum, sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) { printf("il%d: can't initialize\n", unit); is->is_if.if_flags &= ~IFF_UP; return; } is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats, sizeof (struct il_stats), 0); } ifp->if_watchdog = ilwatch; is->is_scaninterval = ILWATCHINTERVAL; ifp->if_timer = is->is_scaninterval; addr = (struct ildevice *)ui->ui_addr; /* * Turn off source address insertion (it's faster this way), * and set board online. Former doesn't work if board is * already online (happens on ubareset), so we put it offline * first. */ s = splimp(); addr->il_csr = ILC_RESET; if (ilwait(ui, "hardware diag")) { is->is_if.if_flags &= ~IFF_UP; splx(s); return; } addr->il_csr = ILC_CISA; while ((addr->il_csr & IL_CDONE) == 0) ; /* * If we must reprogram this board's physical ethernet * address (as for secondary XNS interfaces), we do so * before putting it on line, and starting receive requests. * If you try this on an older 1010 board, it will total * wedge the board. */ if (is->is_flags & ILF_SETADDR) { bcopy((caddr_t)is->is_addr, (caddr_t)&is->is_stats, sizeof is->is_addr); addr->il_bar = is->is_ubaddr & 0xffff; addr->il_bcr = sizeof is->is_addr; addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_LDPA; if (ilwait(ui, "setaddr")) return; addr->il_bar = is->is_ubaddr & 0xffff; addr->il_bcr = sizeof (struct il_stats); addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT; if (ilwait(ui, "verifying setaddr")) return; if (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, sizeof (is->is_addr)) != 0) { printf("il%d: setaddr didn't work\n", ui->ui_unit); return; } } /* * Set board online. * Hang receive buffer and start any pending * writes by faking a transmit complete. * Receive bcr is not a multiple of 8 so buffer * chaining can't happen. */ addr->il_csr = ILC_ONLINE; while ((addr->il_csr & IL_CDONE) == 0) ; addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; while ((addr->il_csr & IL_CDONE) == 0) ; is->is_flags = ILF_OACTIVE; is->is_if.if_flags |= IFF_RUNNING; is->is_flags |= ILF_RUNNING; is->is_lastcmd = 0; ilcint(unit); splx(s);}/* * Start output on interface. * Get another datagram to send off of the interface queue, * and map it to the interface before starting the output. */ilstart(dev) dev_t dev;{ int unit = ILUNIT(dev), len; struct uba_device *ui = ilinfo[unit]; register struct il_softc *is = &il_softc[unit]; register struct ildevice *addr; struct mbuf *m; short csr; IF_DEQUEUE(&is->is_if.if_snd, m); addr = (struct ildevice *)ui->ui_addr; if (m == 0) { if ((is->is_flags & ILF_STATPENDING) == 0) return; addr->il_bar = is->is_ubaddr & 0xffff; addr->il_bcr = sizeof (struct il_stats); csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE; is->is_flags &= ~ILF_STATPENDING; goto startcmd; } len = if_wubaput(&is->is_ifuba, m); /* * Ensure minimum packet length. * This makes the safe assumtion that there are no virtual holes * after the data. * For security, it might be wise to zero out the added bytes, * but we're mainly interested in speed at the moment. */ if (len - sizeof(struct ether_header) < ETHERMIN) len = ETHERMIN + sizeof(struct ether_header); if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp, is->is_ifuba.ifu_uban); addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff; addr->il_bcr = len; csr = ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE;startcmd: is->is_lastcmd = csr & IL_CMD; addr->il_csr = csr; is->is_flags |= ILF_OACTIVE;}/* * Command done interrupt. */ilcint(unit) int unit;{ register struct il_softc *is = &il_softc[unit]; struct uba_device *ui = ilinfo[unit]; register struct ildevice *addr = (struct ildevice *)ui->ui_addr; short csr; if ((is->is_flags & ILF_OACTIVE) == 0) { printf("il%d: stray xmit interrupt, csr=%b\n", unit, addr->il_csr, IL_BITS); return; } csr = addr->il_csr; /* * Hang receive buffer if it couldn't * be done earlier (in ilrint). */ if (is->is_flags & ILF_RCVPENDING) { int s; addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; s = splhigh(); while ((addr->il_csr & IL_CDONE) == 0) ; splx(s); is->is_flags &= ~ILF_RCVPENDING; } is->is_flags &= ~ILF_OACTIVE; csr &= IL_STATUS; switch (is->is_lastcmd) { case ILC_XMIT: is->is_if.if_opackets++; if (csr > ILERR_RETRIES) is->is_if.if_oerrors++; break; case ILC_STAT: if (csr == ILERR_SUCCESS) iltotal(is); break; } if (is->is_ifuba.ifu_xtofree) { m_freem(is->is_ifuba.ifu_xtofree); is->is_ifuba.ifu_xtofree = 0; } ilstart(unit);}/* * Ethernet interface receiver interrupt. * If input error just drop packet. * Otherwise purge input buffered data path and examine * packet to determine type. If can't determine length * from type, then have to drop packet. Othewise decapsulate * packet based on type and pass to type specific higher-level * input routine. */ilrint(unit) int unit;{ register struct il_softc *is = &il_softc[unit]; struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -