* Copyright (c) 1982 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)if_uba.c 6.5 (Berkeley) %G%
#include "../machine/pte.h"
#include "../vaxuba/ubareg.h"
#include "../vaxuba/ubavar.h"
* Routines supporting UNIBUS network interfaces.
* Support interfaces using only one BDP statically.
* Init UNIBUS for interface on uban whose headers of size hlen are to
* end on a page boundary. We allocate a UNIBUS map register for the page
* with the header, and nmr more UNIBUS map registers for i/o on the adapter,
* doing this twice: once for reading and once for writing. We also
* allocate page frames in the mbuffer pool for these pages.
if_ubainit(ifu
, uban
, hlen
, nmr
)
register struct ifuba
*ifu
;
ncl
= clrnd(nmr
) / CLSIZE
;
if (ifu
->ifu_r
.ifrw_addr
)
cp
= ifu
->ifu_r
.ifrw_addr
- off
;
cp
= m_clalloc(2 * ncl
, MPG_SPACE
);
ifu
->ifu_r
.ifrw_addr
= cp
+ off
;
ifu
->ifu_w
.ifrw_addr
= ifu
->ifu_r
.ifrw_addr
+ ncl
* CLBYTES
;
ifu
->ifu_uba
= uba_hd
[uban
].uh_uba
;
if (if_ubaalloc(ifu
, &ifu
->ifu_r
, nmr
) == 0)
if (if_ubaalloc(ifu
, &ifu
->ifu_w
, nmr
) == 0)
for (i
= 0; i
< nmr
; i
++)
ifu
->ifu_wmap
[i
] = ifu
->ifu_w
.ifrw_mr
[i
];
ubarelse(ifu
->ifu_uban
, &ifu
->ifu_r
.ifrw_info
);
ifu
->ifu_r
.ifrw_addr
= 0;
* Setup either a ifrw structure by allocating UNIBUS map registers,
* possibly a buffered data path, and initializing the fields of
* the ifrw structure to minimize run-time overhead.
if_ubaalloc(ifu
, ifrw
, nmr
)
register struct ifrw
*ifrw
;
uballoc(ifu
->ifu_uban
, ifrw
->ifrw_addr
, nmr
*NBPG
+ ifu
->ifu_hlen
,
ifrw
->ifrw_bdp
= UBAI_BDP(info
);
ifrw
->ifrw_proto
= UBAMR_MRV
| (UBAI_BDP(info
) << UBAMR_DPSHIFT
);
ifrw
->ifrw_mr
= &ifu
->ifu_uba
->uba_map
[UBAI_MR(info
) + (ifu
->ifu_hlen
?
* Pull read data off a interface.
* Len is length of data, with local net header stripped.
* Off is non-zero if a trailer protocol was used, and
* gives the offset of the trailer information.
* We copy the trailer information and then all the normal
* data into mbufs. When full cluster sized units are present
* on the interface on cluster boundaries we can get them more
* easily by remapping, and take advantage of this here.
* Prepend a pointer to the interface structure,
* so that protocols can determine where incoming packets arrived.
if_rubaget(ifu
, totlen
, off0
, ifp
)
register struct ifuba
*ifu
;
struct mbuf
*top
, **mp
, *m
;
register caddr_t cp
= ifu
->ifu_r
.ifrw_addr
+ ifu
->ifu_hlen
;
MGET(m
, M_DONTWAIT
, MT_DATA
);
cp
= ifu
->ifu_r
.ifrw_addr
+ ifu
->ifu_hlen
+ off
;
* If doing the first mbuf and
* the interface pointer hasn't been put in,
* put it in a separate mbuf to preserve alignment.
len
= m
->m_len
= min(len
, CLBYTES
);
m
->m_off
= (int)p
- (int)m
;
* Switch pages mapped to UNIBUS with new page p,
* as quick form of copy. Remap UNIBUS and invalidate.
cpte
= &Mbmap
[mtocl(cp
)*CLSIZE
];
ppte
= &Mbmap
[mtocl(p
)*CLSIZE
];
x
= btop(cp
- ifu
->ifu_r
.ifrw_addr
);
ip
= (int *)&ifu
->ifu_r
.ifrw_mr
[x
];
for (i
= 0; i
< CLSIZE
; i
++) {
t
= *ppte
; *ppte
++ = *cpte
; *cpte
= t
;
cpte
++->pg_pfnum
|ifu
->ifu_r
.ifrw_proto
;
m
->m_len
= MIN(MLEN
- sizeof(ifp
), len
);
m
->m_len
= MIN(MLEN
, len
);
bcopy(cp
, mtod(m
, caddr_t
), (unsigned)m
->m_len
);
/* sort of an ALGOL-W style for statement... */
cp
= ifu
->ifu_r
.ifrw_addr
+ ifu
->ifu_hlen
;
* Prepend interface pointer to first mbuf.
*(mtod(m
, struct ifnet
**)) = ifp
;
* Map a chain of mbufs onto a network interface
* in preparation for an i/o operation.
* The argument chain of mbufs includes the local network
* header which is copied to be in the mapped, aligned
register struct ifuba
*ifu
;
register struct mbuf
*mp
;
cp
= ifu
->ifu_w
.ifrw_addr
;
if (claligned(cp
) && claligned(dp
) &&
(m
->m_len
== CLBYTES
|| m
->m_next
== (struct mbuf
*)0)) {
struct pte
*pte
; int *ip
;
pte
= &Mbmap
[mtocl(dp
)*CLSIZE
];
x
= btop(cp
- ifu
->ifu_w
.ifrw_addr
);
ip
= (int *)&ifu
->ifu_w
.ifrw_mr
[x
];
for (i
= 0; i
< CLSIZE
; i
++)
ifu
->ifu_w
.ifrw_proto
| pte
++->pg_pfnum
;
xswapd
|= 1 << (x
>>(CLSHIFT
-PGSHIFT
));
m
->m_next
= ifu
->ifu_xtofree
;
bcopy(mtod(m
, caddr_t
), cp
, (unsigned)m
->m_len
);
* Xswapd is the set of clusters we just mapped out. Ifu->ifu_xswapd
* is the set of clusters mapped out from before. We compute
* the number of clusters involved in this operation in x.
* Clusters mapped out before and involved in this operation
* should be unmapped so original pages will be accessed by the device.
cc
= cp
- ifu
->ifu_w
.ifrw_addr
;
x
= ((cc
- ifu
->ifu_hlen
) + CLBYTES
- 1) >> CLSHIFT
;
ifu
->ifu_xswapd
&= ~xswapd
;
xswapd
&= ~ifu
->ifu_xswapd
;
while (i
= ffs(ifu
->ifu_xswapd
)) {
ifu
->ifu_xswapd
&= ~(1<<i
);
for (t
= 0; t
< CLSIZE
; t
++) {
ifu
->ifu_w
.ifrw_mr
[i
] = ifu
->ifu_wmap
[i
];
ifu
->ifu_xswapd
|= xswapd
;