BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / vax / if / 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 */
#endif
int 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);
/*
* Reset interface, then requeue rcv buffers.
* Some incoming packets may be lost, but that
* can't be helped.
*/
addr->ec_xcr = EC_UECLR;
#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 = start_read|i;
/*
* Reset and transmit next packet (if any).
*/
es->es_if.if_flags &= ~IFF_OACTIVE;
es->es_mask = ~0;
if (es->es_if.if_snd.ifq_head)
(void) ecstart(&es->es_if);
return;
}
/*
* Do exponential backoff. Compute delay based on low bits
* of the interval timer (1 bit for each transmission attempt,
* but at most 5 bits). Then delay for that number of
* slot times. A slot time is 51.2 microseconds (rounded to 51).
* This does not take into account the time already used to
* process the interrupt.
*/
es->es_mask <<= 1;
delay = mfpr(ICR) & 0x1f &~ es->es_mask;
DELAY(delay * 51);
/*
* Clear the controller's collision flag, thus enabling retransmit.
*/
addr->ec_xcr = EC_CLEAR;
}
/*
* Ethernet interface receiver interrupt.
* If input error just drop packet.
* Otherwise 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.
*/
ecrint(unit)
int unit;
{
struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
while (addr->ec_rcr & EC_RDONE)
ecread(unit);
}
ecread(unit)
int unit;
{
register struct ec_softc *es = &ec_softc[unit];
struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
register struct ether_header *ec;
struct mbuf *m;
int len, off, resid, ecoff, rbuf;
register struct ifqueue *inq;
u_short start_read;
u_char *ecbuf;
es->es_if.if_ipackets++;
rbuf = addr->ec_rcr & EC_RBN;
if (rbuf < ECRLBF || rbuf > ECRHBF)
panic("ecrint");
ecbuf = es->es_buf[rbuf];
ecoff = *(short *)ecbuf;
if (ecoff <= ECRDOFF || ecoff > 2046) {
es->es_if.if_ierrors++;
#ifdef notdef
if (es->es_if.if_ierrors % 100 == 0)
printf("ec%d: += 100 input errors\n", unit);
#endif
goto setup;
}
/*
* Get input data length.
* Get pointer to ethernet header (in input buffer).
* Deal with trailer protocol: if type is trailer type
* get true type from first 16-bit word past data.
* Remember that type was trailer by setting off.
*/
len = ecoff - ECRDOFF - sizeof (struct ether_header);
ec = (struct ether_header *)(ecbuf + ECRDOFF);
ec->ether_type = ntohs((u_short)ec->ether_type);
#define ecdataaddr(ec, off, type) ((type)(((caddr_t)((ec)+1)+(off))))
if (ec->ether_type >= ETHERTYPE_TRAIL &&
ec->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
off = (ec->ether_type - ETHERTYPE_TRAIL) * 512;
if (off >= ETHERMTU)
goto setup; /* sanity */
ec->ether_type = ntohs(*ecdataaddr(ec, off, u_short *));
resid = ntohs(*(ecdataaddr(ec, off+2, u_short *)));
if (off + resid > len)
goto setup; /* sanity */
len = off + resid;
} else
off = 0;
if (len == 0)
goto setup;
/*
* Pull packet off interface. Off is nonzero if packet
* has trailing header; ecget will then force this header
* information to be at the front, but we still have to drop
* the type and length which are at the front of any trailer data.
*/
m = ecget(ecbuf, len, off, &es->es_if);
if (m)
ether_input(&es->es_if, ec, m);
/*
* Reset for next packet.
*/
setup:
#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;
addr->ec_rcr = start_read|EC_RCLR|rbuf;
}
/*
* Routine to copy from mbuf chain to transmit
* buffer in UNIBUS memory.
* If packet size is less than the minimum legal size,
* the buffer is expanded. We probably should zero out the extra
* bytes for security, but that would slow things down.
*/
ecput(ecbuf, m)
u_char *ecbuf;
struct mbuf *m;
{
register struct mbuf *mp;
register int off;
u_char *bp;
for (off = 2048, mp = m; mp; mp = mp->m_next)
off -= mp->m_len;
if (2048 - off < ETHERMIN + sizeof (struct ether_header))
off = 2048 - ETHERMIN - sizeof (struct ether_header);
*(u_short *)ecbuf = off;
bp = (u_char *)(ecbuf + off);
for (mp = m; mp; mp = mp->m_next) {
register unsigned len = mp->m_len;
u_char *mcp;
if (len == 0)
continue;
mcp = mtod(mp, u_char *);
if ((unsigned)bp & 01) {
*bp++ = *mcp++;
len--;
}
if (off = (len >> 1)) {
register u_short *to, *from;
to = (u_short *)bp;
from = (u_short *)mcp;
do
*to++ = *from++;
while (--off > 0);
bp = (u_char *)to,
mcp = (u_char *)from;
}
if (len & 01)
*bp++ = *mcp++;
}
m_freem(m);
}
/*
* Routine to copy from UNIBUS memory into mbufs.
* Similar in spirit to if_rubaget.
*
* Warning: This makes the fairly safe assumption that
* mbufs have even lengths.
*/
struct mbuf *
ecget(ecbuf, totlen, off0, ifp)
u_char *ecbuf;
int totlen, off0;
struct ifnet *ifp;
{
register struct mbuf *m;
struct mbuf *top = 0, **mp = &top;
register int off = off0, len;
u_char *cp = (ecbuf += ECRDOFF + sizeof (struct ether_header));
u_char *packet_end = cp + totlen;
if (off) {
off += 2 * sizeof(u_short);
totlen -= 2 *sizeof(u_short);
cp += off;
}
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == 0)
return (0);
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = totlen;
m->m_len = MHLEN;
while (totlen > 0) {
register int words;
u_char *mcp;
if (top) {
MGET(m, M_DONTWAIT, MT_DATA);
if (m == 0) {
m_freem(top);
return (0);
}
m->m_len = MLEN;
}
len = min(totlen, (packet_end - cp));
if (len >= MINCLSIZE) {
MCLGET(m, M_DONTWAIT);
if (m->m_flags & M_EXT)
m->m_len = len = min(len, MCLBYTES);
else
len = m->m_len;
} else {
/*
* Place initial small packet/header at end of mbuf.
*/
if (len < m->m_len) {
if (top == 0 && len + max_linkhdr <= m->m_len)
m->m_data += max_linkhdr;
m->m_len = len;
} else
len = m->m_len;
}
mcp = mtod(m, u_char *);
if (words = (len >> 1)) {
register u_short *to, *from;
to = (u_short *)mcp;
from = (u_short *)cp;
do
*to++ = *from++;
while (--words > 0);
mcp = (u_char *)to;
cp = (u_char *)from;
}
if (len & 01)
*mcp++ = *cp++;
*mp = m;
mp = &m->m_next;
totlen -= len;
if (cp == packet_end)
cp = ecbuf;
}
return (top);
bad:
m_freem(top);
return (0);
}
/*
* Process an ioctl request.
*/
ecioctl(ifp, cmd, data)
register struct ifnet *ifp;
int cmd;
caddr_t data;
{
register struct ifaddr *ifa = (struct ifaddr *)data;
struct ec_softc *es = &ec_softc[ifp->if_unit];
struct ecdevice *addr;
int s = splimp(), error = 0;
addr = (struct ecdevice *)(ecinfo[ifp->if_unit]->ui_addr);
switch (cmd) {
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
ecinit(ifp->if_unit); /* before arpwhohas */
((struct arpcom *)ifp)->ac_ipaddr =
IA_SIN(ifa)->sin_addr;
arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
break;
#endif
#ifdef NS
case AF_NS:
{
register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
if (ns_nullhost(*ina))
ina->x_host = *(union ns_host *)(es->es_addr);
else {
/*
* The manual says we can't change the address
* while the receiver is armed,
* so reset everything
*/
ifp->if_flags &= ~IFF_RUNNING;
bcopy((caddr_t)ina->x_host.c_host,
(caddr_t)es->es_addr, sizeof(es->es_addr));
}
ecinit(ifp->if_unit); /* does ec_setaddr() */
break;
}
#endif
default:
ecinit(ifp->if_unit);
break;
}
break;
case SIOCSIFFLAGS:
if ((ifp->if_flags & IFF_UP) == 0 &&
ifp->if_flags & IFF_RUNNING) {
addr->ec_xcr = EC_UECLR;
ifp->if_flags &= ~IFF_RUNNING;
} else if (ifp->if_flags & IFF_UP &&
(ifp->if_flags & IFF_RUNNING) == 0)
ecinit(ifp->if_unit);
break;
default:
error = EINVAL;
}
splx(s);
return (error);
}
ec_setaddr(physaddr,unit)
u_char *physaddr;
int unit;
{
struct ec_softc *es = &ec_softc[unit];
struct uba_device *ui = ecinfo[unit];
register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr;
register char nibble;
register int i, j;
/*
* Use the ethernet address supplied
* Note that we do a UECLR here, so the receive buffers
* must be requeued.
*/
#ifdef DEBUG
printf("ec_setaddr: setting address for unit %d = %s",
unit, ether_sprintf(physaddr));
#endif
addr->ec_xcr = EC_UECLR;
addr->ec_rcr = 0;
/* load requested address */
for (i = 0; i < 6; i++) { /* 6 bytes of address */
es->es_addr[i] = physaddr[i];
nibble = physaddr[i] & 0xf; /* lower nibble */
addr->ec_rcr = (nibble << 8);
addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */
addr->ec_rcr = (nibble << 8);
for (j=0; j < 4; j++) {
addr->ec_rcr = 0;
addr->ec_rcr = EC_ASTEP; /* step counter */
addr->ec_rcr = 0;
}
nibble = (physaddr[i] >> 4) & 0xf; /* upper nibble */
addr->ec_rcr = (nibble << 8);
addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */
addr->ec_rcr = (nibble << 8);
for (j=0; j < 4; j++) {
addr->ec_rcr = 0;
addr->ec_rcr = EC_ASTEP; /* step counter */
addr->ec_rcr = 0;
}
}
#ifdef DEBUG
/*
* Read the ethernet address off the board, one nibble at a time.
*/
addr->ec_xcr = EC_UECLR;
addr->ec_rcr = 0; /* read RAM */
cp = es->es_addr;
#undef NEXTBIT
#define NEXTBIT addr->ec_rcr = EC_ASTEP; addr->ec_rcr = 0
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_setaddr: RAM address for unit %d = %s",
unit, ether_sprintf(physaddr));
#endif
}
#endif