* Copyright (c) 1992 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Ralph Campbell and Rick Macklem.
* %sccs.include.redist.c%
* @(#)if_le.c 7.12 (Berkeley) %G%
* This driver will generate and accept trailer encapsulated packets even
* though it buys us nothing. The motivation was to avoid incompatibilities
* with VAXen, SUNs, and others that handle and benefit from them.
* This reasoning is dubious.
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/if_ether.h>
#if defined (CCITT) && defined (LLC)
#include <sys/socketvar.h>
#include <netccitt/x25.h>
extern llc_ctlinput(), cons_rtrequest();
#include <machine/machConst.h>
#include <pmax/pmax/pmaxtype.h>
#include <pmax/pmax/kn01.h>
#include <pmax/pmax/kmin.h>
#include <pmax/pmax/asic.h>
#include <pmax/dev/device.h>
#include <pmax/dev/if_lereg.h>
struct driver ledriver
= {
"le", leprobe
, 0, 0, leintr
,
int ledebug
= 1; /* console error messages */
* Ethernet software status per interface.
* Each interface is referenced by a network interface structure,
* le_if, which the routing code uses to locate the interface.
* This structure contains the output queue for the interface, its address, ...
struct arpcom sc_ac
; /* common Ethernet structures */
#define sc_if sc_ac.ac_if /* network-visible interface */
#define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */
volatile struct lereg1
*sc_r1
; /* LANCE registers */
volatile void *sc_r2
; /* dual-port RAM */
int sc_ler2pad
; /* Do ring descriptors require short pads? */
void (*sc_copytobuf
)(); /* Copy to buffer */
void (*sc_copyfrombuf
)(); /* Copy from buffer */
void (*sc_zerobuf
)(); /* and Zero bytes in buffer */
int sc_rmd
; /* predicted next rmd to process */
int sc_tmd
; /* last tmd processed */
int sc_tmdnext
; /* next tmd to transmit with */
/* access LANCE registers */
static void lewritereg();
#define LERDWR(cntl, src, dst) { (dst) = (src); DELAY(10); }
#define LEWREG(src, dst) lewritereg(&(dst), (src))
#define CPU_TO_CHIP_ADDR(cpu) \
((unsigned)(&(((struct lereg2 *)0)->cpu)))
#define LE_OFFSET_RAM 0x0
#define LE_OFFSET_LANCE 0x100000
#define LE_OFFSET_ROM 0x1c0000
void copytobuf_contig(), copyfrombuf_contig(), bzerobuf_contig();
void copytobuf_gap2(), copyfrombuf_gap2(), bzerobuf_gap2();
void copytobuf_gap16(), copyfrombuf_gap16(), bzerobuf_gap16();
extern int pmax_boardtype
;
* Test to see if device is present.
* Return true if found and initialized ok.
* If interface exists, make available by filling in network interface
* record. System will initialize the interface when it is ready
volatile struct lereg1
*ler1
;
struct le_softc
*le
= &le_softc
[dp
->pmax_unit
];
struct ifnet
*ifp
= &le
->sc_if
;
extern int leinit(), lereset(), leioctl(), lestart(), ether_output();
switch (pmax_boardtype
) {
le
->sc_r1
= ler1
= (volatile struct lereg1
*)dp
->pmax_addr
;
le
->sc_r2
= (volatile void *)MACH_PHYS_TO_UNCACHED(0x19000000);
cp
= (u_char
*)(MACH_PHYS_TO_UNCACHED(KN01_SYS_CLOCK
) + 1);
le
->sc_copytobuf
= copytobuf_gap2
;
le
->sc_copyfrombuf
= copyfrombuf_gap2
;
le
->sc_zerobuf
= bzerobuf_gap2
;
if (dp
->pmax_unit
== 0) {
volatile u_int
*ssr
, *ldp
;
le
->sc_r1
= ler1
= (volatile struct lereg1
*)
ASIC_SYS_LANCE(asic_base
);
cp
= (u_char
*)ASIC_SYS_ETHER_ADDRESS(asic_base
);
le
->sc_r2
= (volatile void *)
MACH_PHYS_TO_UNCACHED(le_iomem
);
le
->sc_copytobuf
= copytobuf_gap16
;
le
->sc_copyfrombuf
= copyfrombuf_gap16
;
le
->sc_zerobuf
= bzerobuf_gap16
;
* And enable Lance dma through the asic.
ssr
= (volatile u_int
*)ASIC_REG_CSR(asic_base
);
ASIC_REG_LANCE_DMAPTR(asic_base
);
*ldp
= (le_iomem
<< 3); /* phys addr << 3 */
*ssr
|= ASIC_CSR_DMAEN_LANCE
;
* Units other than 0 are turbochannel option boards and fall
le
->sc_r1
= ler1
= (volatile struct lereg1
*)
(dp
->pmax_addr
+ LE_OFFSET_LANCE
);
le
->sc_r2
= (volatile void *)(dp
->pmax_addr
+ LE_OFFSET_RAM
);
cp
= (u_char
*)(dp
->pmax_addr
+ LE_OFFSET_ROM
+ 2);
le
->sc_copytobuf
= copytobuf_contig
;
le
->sc_copyfrombuf
= copyfrombuf_contig
;
le
->sc_zerobuf
= bzerobuf_contig
;
printf("Unknown CPU board type %d\n", pmax_boardtype
);
* Get the ethernet address out of rom
for (i
= 0; i
< sizeof(le
->sc_addr
); i
++) {
/* make sure the chip is stopped */
LEWREG(LE_CSR0
, ler1
->ler1_rap
);
LEWREG(LE_STOP
, ler1
->ler1_rdp
);
ifp
->if_unit
= dp
->pmax_unit
;
ifp
->if_output
= ether_output
;
ifp
->if_flags
= IFF_BROADCAST
| IFF_SIMPLEX
| IFF_MULTICAST
;
ifp
->if_flags
= IFF_BROADCAST
| IFF_SIMPLEX
;
bpfattach(&ifp
->if_bpf
, ifp
, DLT_EN10MB
, sizeof(struct ether_header
));
printf("le%d at nexus0 csr 0x%x priority %d ethernet address %s\n",
dp
->pmax_unit
, dp
->pmax_addr
, dp
->pmax_pri
,
ether_sprintf(le
->sc_addr
));
* Setup the logical address filter
register struct le_softc
*le
;
register volatile struct lereg2
*ler2
= le
->sc_r2
;
register struct ifnet
*ifp
= &le
->sc_if
;
register struct ether_multi
*enm
;
struct ether_multistep step
;
* Set up multicast address filter by passing all multicast
* addresses through a crc generator, and then using the high
* order 6 bits as a index into the 64 bit logical address
* filter. The high order two bits select the word, while the
* rest of the bits select the bit within the word.
ifp
->if_flags
&= ~IFF_ALLMULTI
;
ETHER_FIRST_MULTI(step
, &le
->sc_ac
, enm
);
if (bcmp((caddr_t
)&enm
->enm_addrlo
,
(caddr_t
)&enm
->enm_addrhi
, sizeof(enm
->enm_addrlo
)) == 0) {
* We must listen to a range of multicast
* addresses. For now, just accept all
* multicasts, rather than trying to set only
* those filter bits needed to match the range.
* (At this time, the only use of address
* ranges is for IP multicast routing, for
* which the range is big enough to require all
ifp
->if_flags
|= IFF_ALLMULTI
;
cp
= (unsigned char *)&enm
->enm_addrlo
;
for (i
= 0; i
< 8; i
++) {
if ((c
& 0x01) ^ (crc
& 0x01)) {
/* Just want the 6 most significant bits. */
/* Turn on the corresponding bit in the filter. */
LER2_ladrf0(ler2
, 1 << (crc
& 0x1f));
LER2_ladrf1(ler2
, 1 << (crc
& 0x1f));
LER2_ladrf2(ler2
, 1 << (crc
& 0x1f));
LER2_ladrf3(ler2
, 1 << (crc
& 0x1f));
ETHER_NEXT_MULTI(step
, enm
);
register volatile void *rp
;
for (i
= 0; i
< LERBUF
; i
++) {
rp
= LER2_RMDADDR(le
->sc_r2
, i
);
LER2_rmd0(rp
, CPU_TO_CHIP_ADDR(ler2_rbuf
[i
][0]));
for (i
= 0; i
< LETBUF
; i
++) {
rp
= LER2_TMDADDR(le
->sc_r2
, i
);
LER2_tmd0(rp
, CPU_TO_CHIP_ADDR(ler2_tbuf
[i
][0]));
register struct le_softc
*le
= &le_softc
[unit
];
register volatile struct lereg1
*ler1
= le
->sc_r1
;
register volatile void *ler2
= le
->sc_r2
;
register int timo
= 100000;
LEWREG(LE_CSR0
, ler1
->ler1_rap
);
LEWREG(LE_STOP
, ler1
->ler1_rdp
);
* Setup for transmit/receive
if (le
->sc_if
.if_flags
& IFF_PROMISC
)
/* set the promiscuous bit */
LER2_mode(ler2
, LE_MODE
| 0x8000);
LER2_mode(ler2
, LE_MODE
);
LER2_padr0(ler2
, (le
->sc_addr
[1] << 8) | le
->sc_addr
[0]);
LER2_padr1(ler2
, (le
->sc_addr
[3] << 8) | le
->sc_addr
[2]);
LER2_padr2(ler2
, (le
->sc_addr
[5] << 8) | le
->sc_addr
[4]);
/* Setup the logical address filter */
LER2_rlen(ler2
, LE_RLEN
);
LER2_rdra(ler2
, CPU_TO_CHIP_ADDR(ler2_rmd
[0]));
LER2_tlen(ler2
, LE_TLEN
);
LER2_tdra(ler2
, CPU_TO_CHIP_ADDR(ler2_tmd
[0]));
LEWREG(LE_CSR1
, ler1
->ler1_rap
);
LEWREG(CPU_TO_CHIP_ADDR(ler2_mode
), ler1
->ler1_rdp
);
LEWREG(LE_CSR2
, ler1
->ler1_rap
);
LEWREG(0, ler1
->ler1_rdp
);
LEWREG(LE_CSR3
, ler1
->ler1_rap
);
LEWREG(0, ler1
->ler1_rdp
);
LEWREG(LE_CSR0
, ler1
->ler1_rap
);
LERDWR(ler0
, LE_INIT
, ler1
->ler1_rdp
);
printf("le%d: init timeout, stat = 0x%x\n",
} while ((stat
& LE_IDON
) == 0);
LERDWR(ler0
, LE_IDON
, ler1
->ler1_rdp
);
LERDWR(ler0
, LE_STRT
| LE_INEA
, ler1
->ler1_rdp
);
le
->sc_if
.if_flags
&= ~IFF_OACTIVE
;
* Initialization of interface
register struct ifnet
*ifp
= &le_softc
[unit
].sc_if
;
register struct ifaddr
*ifa
;
/* not yet, if address still unknown */
for (ifa
= ifp
->if_addrlist
;; ifa
= ifa
->ifa_next
)
else if (ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
!= AF_LINK
)
if ((ifp
->if_flags
& IFF_RUNNING
) == 0) {
ifp
->if_flags
|= IFF_RUNNING
;
tmd = LER2_TMDADDR(le->sc_r2, bix)
* Start output on interface. Get another datagram to send
* off of the interface queue, and copy it to the interface
* before starting the output.
register struct le_softc
*le
= &le_softc
[ifp
->if_unit
];
register int bix
= le
->sc_tmdnext
;
register volatile void *tmd
= LER2_TMDADDR(le
->sc_r2
, bix
);
if ((le
->sc_if
.if_flags
& IFF_RUNNING
) == 0)
while (bix
!= le
->sc_tmd
) {
if (LER2V_tmd1(tmd
) & LE_OWN
)
IF_DEQUEUE(&le
->sc_if
.if_snd
, m
);
* If bpf is listening on this interface, let it
* see the packet before we commit it to the wire.
bpf_mtap(ifp
->if_bpf
, m
);
len
= leput(le
, LER2_TBUFADDR(le
->sc_r2
, bix
), m
);
LER2_tmd1(tmd
, LE_OWN
| LE_STP
| LE_ENP
);
le
->sc_if
.if_flags
|= IFF_OACTIVE
;
LERDWR(ler0
, LE_TDMD
| LE_INEA
, le
->sc_r1
->ler1_rdp
);
* Process interrupts from the 7990 chip.
register struct le_softc
*le
;
register volatile struct lereg1
*ler1
;
printf("le%d: spurrious interrupt\n", unit
);
LERDWR(ler0
, LE_BABL
|LE_CERR
|LE_MISS
|LE_INEA
, ler1
->ler1_rdp
);
if ((stat
& LE_RXON
) == 0) {
if ((stat
& LE_TXON
) == 0) {
/* interrupt is cleared in lerint */
LERDWR(ler0
, LE_TINT
|LE_INEA
, ler1
->ler1_rdp
);
* Ethernet interface transmitter interrupt.
* Start another output if more data to send.
register struct le_softc
*le
= &le_softc
[unit
];
register int bix
= le
->sc_tmd
;
register volatile void *tmd
;
if ((le
->sc_if
.if_flags
& IFF_OACTIVE
) == 0) {
while (bix
!= le
->sc_tmdnext
&& (LER2V_tmd1(tmd
) & LE_OWN
) == 0) {
if ((LER2V_tmd1(tmd
) & LE_ERR
) || (LER2V_tmd3(tmd
) & LE_TBUFF
)) {
if (LER2V_tmd3(tmd
) & (LE_TBUFF
|LE_UFLO
)) {
else if (LER2V_tmd3(tmd
) & LE_LCOL
)
le
->sc_if
.if_collisions
++;
else if (LER2V_tmd3(tmd
) & LE_RTRY
)
le
->sc_if
.if_collisions
+= 16;
else if (LER2V_tmd1(tmd
) & LE_ONE
)
le
->sc_if
.if_collisions
++;
else if (LER2V_tmd1(tmd
) & LE_MORE
)
/* what is the real number? */
le
->sc_if
.if_collisions
+= 2;
if (bix
== le
->sc_tmdnext
)
le
->sc_if
.if_flags
&= ~IFF_OACTIVE
;
(void) lestart(&le
->sc_if
);
rmd = LER2_RMDADDR(le->sc_r2, bix)
* Ethernet interface receiver interrupt.
* If input error just drop packet.
* Decapsulate packet based on type and pass to type specific
* higher-level input routine.
register struct le_softc
*le
= &le_softc
[unit
];
register int bix
= le
->sc_rmd
;
register volatile void *rmd
= LER2_RMDADDR(le
->sc_r2
, bix
);
* Out of sync with hardware, should never happen?
if (LER2V_rmd1(rmd
) & LE_OWN
) {
LERDWR(le
->sc_r0
, LE_RINT
|LE_INEA
, le
->sc_r1
->ler1_rdp
);
* Process all buffers with valid data
while ((LER2V_rmd1(rmd
) & LE_OWN
) == 0) {
int len
= LER2V_rmd3(rmd
);
/* Clear interrupt to avoid race condition */
LERDWR(le
->sc_r0
, LE_RINT
|LE_INEA
, le
->sc_r1
->ler1_rdp
);
if (LER2V_rmd1(rmd
) & LE_ERR
) {
lererror(unit
, "bad packet");
} else if ((LER2V_rmd1(rmd
) & (LE_STP
|LE_ENP
)) != (LE_STP
|LE_ENP
)) {
* Find the end of the packet so we can see how long
* it was. We still throw it away.
LERDWR(le
->sc_r0
, LE_RINT
|LE_INEA
,
} while (!(LER2V_rmd1(rmd
) & (LE_OWN
|LE_ERR
|LE_STP
|LE_ENP
)));
lererror(unit
, "chained buffer");
* If search terminated without successful completion
* we reset the hardware (conservative).
if ((LER2V_rmd1(rmd
) & (LE_OWN
|LE_ERR
|LE_STP
|LE_ENP
)) !=
leread(unit
, LER2_RBUFADDR(le
->sc_r2
, bix
), len
);
MachEmptyWriteBuffer(); /* Paranoia */
* Look at the packet in network buffer memory so we can be smart about how
* we copy the data into mbufs.
* This needs work since we can't just read network buffer memory like
register struct le_softc
*le
= &le_softc
[unit
];
u_short sbuf
[2], eth_type
;
extern struct mbuf
*leget();
(*le
->sc_copyfrombuf
)(buf
, 0, (char *)&et
, sizeof (et
));
eth_type
= ntohs(et
.ether_type
);
/* adjust input length to account for header and CRC */
len
= len
- sizeof(struct ether_header
) - 4;
if (eth_type
>= ETHERTYPE_TRAIL
&&
eth_type
< ETHERTYPE_TRAIL
+ETHERTYPE_NTRAILER
) {
off
= (eth_type
- ETHERTYPE_TRAIL
) * 512;
(*le
->sc_copyfrombuf
)(buf
, sizeof (et
) + off
, (char *)sbuf
,
eth_type
= ntohs(sbuf
[0]);
"le%d: ierror(runt packet): from %s: len=%d\n",
unit
, ether_sprintf(et
.ether_shost
), len
);
if (bcmp((caddr_t
)etherbroadcastaddr
,
(caddr_t
)et
.ether_dhost
, sizeof(etherbroadcastaddr
)) == 0)
if (et
.ether_dhost
[0] & 1)
* Pull packet off interface. Off is nonzero if packet
* has trailing header; leget 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
= leget(le
, buf
, len
, off
, &le
->sc_if
);
* Check if there's a bpf filter listening on this interface.
* If so, hand off the raw packet to enet.
bpf_mtap(le
->sc_if
.if_bpf
, m
);
* Keep the packet if it's a broadcast or has our
* physical ethernet address (or if we support
* multicast and it's one).
(flags
& (M_BCAST
| M_MCAST
)) == 0 &&
(flags
& M_BCAST
) == 0 &&
bcmp(et
.ether_dhost
, le
->sc_addr
,
sizeof(et
.ether_dhost
)) != 0) {
et
.ether_type
= eth_type
;
ether_input(&le
->sc_if
, &et
, m
);
* Routine to copy from mbuf chain to transmit buffer in
register volatile void *lebuf
;
register struct mbuf
*mp
;
register int len
, tlen
= 0;
for (mp
= m
; mp
; mp
= mp
->m_next
) {
(*le
->sc_copytobuf
)(mtod(mp
, char *), lebuf
, boff
, len
);
(*le
->sc_zerobuf
)(lebuf
, boff
, LEMINSIZE
- tlen
);
* Routine to copy from network buffer memory into mbufs.
leget(le
, lebuf
, totlen
, off
, ifp
)
struct mbuf
*top
= 0, **mp
= &top
;
register int len
, resid
, boff
;
/* NOTE: sizeof(struct ether_header) should be even */
boff
= sizeof(struct ether_header
);
/* NOTE: off should be even */
boff
+= off
+ 2 * sizeof(u_short
);
totlen
-= 2 * sizeof(u_short
);
MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
m
->m_pkthdr
.len
= totlen
;
MGET(m
, M_DONTWAIT
, MT_DATA
);
m
->m_len
= min(resid
, MCLBYTES
);
else if (resid
< m
->m_len
) {
* Place initial small packet/header at end of mbuf.
if (top
== 0 && resid
+ max_linkhdr
<= m
->m_len
)
m
->m_data
+= max_linkhdr
;
(*le
->sc_copyfrombuf
)(lebuf
, boff
, mtod(m
, char *), len
);
boff
= sizeof (struct ether_header
);
* Process an ioctl request.
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
= (struct ifaddr
*)data
;
struct le_softc
*le
= &le_softc
[ifp
->if_unit
];
volatile struct lereg1
*ler1
= le
->sc_r1
;
switch (ifa
->ifa_addr
->sa_family
) {
leinit(ifp
->if_unit
); /* before arpwhohas */
((struct arpcom
*)ifp
)->ac_ipaddr
=
arpwhohas((struct arpcom
*)ifp
, &IA_SIN(ifa
)->sin_addr
);
register struct ns_addr
*ina
= &(IA_SNS(ifa
)->sns_addr
);
ina
->x_host
= *(union ns_host
*)(le
->sc_addr
);
* The manual says we can't change the address
* while the receiver is armed,
ifp
->if_flags
&= ~IFF_RUNNING
;
LEWREG(LE_STOP
, ler1
->ler1_rdp
);
bcopy((caddr_t
)ina
->x_host
.c_host
,
(caddr_t
)le
->sc_addr
, sizeof(le
->sc_addr
));
leinit(ifp
->if_unit
); /* does le_setaddr() */
#if defined (CCITT) && defined (LLC)
ifa
->ifa_rtrequest
= cons_rtrequest
;
error
= x25_llcglue(PRC_IFUP
, ifa
->ifa_addr
);
#endif /* CCITT && LLC */
if ((ifp
->if_flags
& IFF_UP
) == 0 &&
ifp
->if_flags
& IFF_RUNNING
) {
LEWREG(LE_STOP
, ler1
->ler1_rdp
);
ifp
->if_flags
&= ~IFF_RUNNING
;
} else if (ifp
->if_flags
& IFF_UP
&&
(ifp
->if_flags
& IFF_RUNNING
) == 0)
* If the state of the promiscuous bit changes, the interface
* must be reset to effect the change.
if (((ifp
->if_flags
^ le
->sc_iflags
) & IFF_PROMISC
) &&
(ifp
->if_flags
& IFF_RUNNING
)) {
le
->sc_iflags
= ifp
->if_flags
;
/* Update our multicast list */
error
= (cmd
== SIOCADDMULTI
) ?
ether_addmulti((struct ifreq
*)data
, &le
->sc_ac
) :
ether_delmulti((struct ifreq
*)data
, &le
->sc_ac
);
if (error
== ENETRESET
) {
* Multicast list has changed; set the hardware
* Not all transceivers implement heartbeat
* so we only log CERR once.
if ((stat
& LE_CERR
) && le_softc
[unit
].sc_cerr
)
"le%d: error: stat=%b\n", unit
,
"\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT");
register struct le_softc
*le
= &le_softc
[unit
];
register volatile void *rmd
;
rmd
= LER2_RMDADDR(le
->sc_r2
, le
->sc_rmd
);
(*le
->sc_copyfrombuf
)(LER2_RBUFADDR(le
->sc_r2
, le
->sc_rmd
),
"le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
len
> 11 ? ether_sprintf(eaddr
) : "unknown",
"\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP");
register struct le_softc
*le
= &le_softc
[unit
];
register volatile void *tmd
;
tmd
= LER2_TMDADDR(le
->sc_r2
, 0);
(*le
->sc_copyfrombuf
)(LER2_TBUFADDR(le
->sc_r2
, 0), 0, eaddr
, 6);
"le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n",
len
> 5 ? ether_sprintf(eaddr
) : "unknown",
"\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP",
"\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
* Write a lance register port, reading it back to ensure success. This seems
* to be necessary during initialization, since the chip appears to be a bit
register volatile u_short
*regptr
;
printf("le: Reg did not settle (to x%x): x%x\n",
* Routines for accessing the transmit and receive buffers. Unfortunately,
* CPU addressing of these buffers is done in one of 3 ways:
* - contiguous (for the 3max and turbochannel option card)
* - gap2, which means shorts (2 bytes) interspersed with short (2 byte)
* - gap16, which means 16bytes interspersed with 16byte spaces
* for buffers which must begin on a 32byte boundary (for 3min and maxine)
* The buffer offset is the logical byte offset, assuming contiguous storage.
copytobuf_contig(from
, lebuf
, boff
, len
)
* Just call bcopy() to do the work.
bcopy(from
, ((char *)lebuf
) + boff
, len
);
copyfrombuf_contig(lebuf
, boff
, to
, len
)
* Just call bcopy() to do the work.
bcopy(((char *)lebuf
) + boff
, to
, len
);
bzerobuf_contig(lebuf
, boff
, len
)
* Just let bzero() do the work
bzero(((char *)lebuf
) + boff
, len
);
* For the pmax the buffer consists of shorts (2 bytes) interspersed with
* short (2 byte) spaces and must be accessed with halfword load/stores.
* (don't worry about doing an extra byte)
copytobuf_gap2(from
, lebuf
, boff
, len
)
register volatile u_short
*bptr
;
/* handle unaligned first byte */
bptr
= ((volatile u_short
*)lebuf
) + (boff
- 1);
*bptr
= (*from
++ << 8) | (*bptr
& 0xff);
bptr
= ((volatile u_short
*)lebuf
) + boff
;
if ((unsigned)from
& 0x1) {
*bptr
= (from
[1] << 8) | from
[0];
/* optimize for aligned transfers */
xfer
= (int)((unsigned)len
& ~0x1);
CopyToBuffer((u_short
*)from
, bptr
, xfer
);
copyfrombuf_gap2(lebuf
, boff
, to
, len
)
register volatile u_short
*bptr
;
/* handle unaligned first byte */
bptr
= ((volatile u_short
*)lebuf
) + (boff
- 1);
*to
++ = (*bptr
>> 8) & 0xff;
bptr
= ((volatile u_short
*)lebuf
) + boff
;
if ((unsigned)to
& 0x1) {
*to
++ = (tmp
>> 8) & 0xff;
/* optimize for aligned transfers */
xfer
= (int)((unsigned)len
& ~0x1);
CopyFromBuffer(bptr
, to
, xfer
);
bzerobuf_gap2(lebuf
, boff
, len
)
register volatile u_short
*bptr
;
if ((unsigned)boff
& 0x1) {
bptr
= ((volatile u_short
*)lebuf
) + (boff
- 1);
bptr
= ((volatile u_short
*)lebuf
) + boff
;
* For the 3min and maxine, the buffers are in main memory filled in with
* 16byte blocks interspersed with 16byte spaces.
copytobuf_gap16(from
, lebuf
, boff
, len
)
bptr
= ((char *)lebuf
) + ((boff
<< 1) & ~0x1f);
xfer
= min(len
, 16 - boff
);
bcopy(from
, ((char *)bptr
) + boff
, xfer
);
copyfrombuf_gap16(lebuf
, boff
, to
, len
)
bptr
= ((char *)lebuf
) + ((boff
<< 1) & ~0x1f);
xfer
= min(len
, 16 - boff
);
bcopy(((char *)bptr
) + boff
, to
, xfer
);
bzerobuf_gap16(lebuf
, boff
, len
)
bptr
= ((char *)lebuf
) + ((boff
<< 1) & ~0x1f);
xfer
= min(len
, 16 - boff
);
bzero(((char *)bptr
) + boff
, xfer
);