/* if_uba.c 4.1 81/11/25 */
#include "../net/if_uba.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
;
register caddr_t cp
= m_pgalloc(2 * (nmr
+ 1));
ifu
->if_uba
= &uba_hd
[uban
]->uh_uba
;
ifu
->if_r
.if_addr
= cp
+ NMBPG
- hlen
;
ifu
->if_w
.if_addr
= ifu
->if_r
.if_addr
+ (nmr
+ 1) * NMBPG
;
if (if_ubaalloc(ifu
, &ifu
->if_r
) == 0)
if (if_ubaalloc(ifu
, &ifu
->if_w
) == 0)
for (i
= 0; i
< IF_NUBAMR
; i
++)
ifu
->if_xmap
[i
] = ifu
->if_w
.if_map
[i
+1];
ubafree(ifu
->ifu_uban
, ifu
->if_r
.ifrw_info
);
m_pgfree(cp
, 2 * (nmr
+ 1));
* Setup either a ifrw structure by allocating UNIBUS map registers,
* a buffered data path, and initializing the fields of the ifrw structure
* to minimize run-time overhead.
register struct ifrw
*ifrw
;
uballoc(ifu
->ifu_uban
, ifrw
->ifrw_addr
, IF_NUBAMR
*NMBPG
+ hlen
,
ifrw
->ifrw_bdp
= UBAI_BDP(info
);
ifrw
->ifrw_proto
= UBAMR_MRV
| UBAI_DPDF(info
);
ifrw
->ifrw_mr
= &ifu
->if_uba
[UBAI_MR(info
) + 1];
* Pull read data off a interface, given length.
* Map the header into a mbuf, and then copy or
* remap the data into a chain of mbufs.
* Return 0 if there is no space, or a pointer
* to the assembled mbuf chain.
register struct ifuba
*ifu
;
struct mbuf
*mp
, *p
, *top
;
* First pull local net header off into a mbuf.
cp
= ifu
->ifu_r
.ifrw_addr
;
bcopy(cp
, mtod(m
, caddr_t
), ifu
->if_hlen
);
* Now pull data off. If whole pages
* are there, pull into pages if possible,
* otherwise copy small blocks into mbufs.
m
->m_off
= (int)p
- (int)m
;
* Cluster size data on cluster size boundary.
* Input by remapping newly allocated pages to
* UNIBUS, and taking pages with data already
* Cpte is the pte of the virtual memory which
* is mapped to the UNIBUS, and ppte is the pte
* for the fresh pages. We switch the memory
* copies of these pte's, to make the allocated
* virtual memory contain the data (using the old
* physical pages). We have to rewrite
* the UNIBUS map so that the newly allocated
* pages will be used for the next UNIBUS read,
* and invalidate the kernel translations
* for the virtual addresses of the pages
* The idea here is that this is supposed
* to take less time than copying the data.
cpte
= &Mbmap
[mtocl(cp
)];
x
= btop(cp
- ifu
->if_r
.ifrw_addr
);
ip
= (int *)&ifu
->ifu_r
.ifrw_mr
[x
+1];
for (i
= 0; i
< CLSIZE
; i
++) {
t
= *ppte
; *ppte
= *cpte
; *cpte
= t
;
*cpte
++->pg_pfnum
|ifu
->if_r
.ifrw_proto
;
p
+= NMBPG
/ sizeof (*p
);
m
->m_len
= MIN(MLEN
, len
);
bcopy(cp
, mtod(m
, caddr_t
), (unsigned)m
->m_len
);
* 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
;
int xswapd
= ifu
->ifu_xswapd
;
cp
= ifu
->ifu_w
.ifrw_addr
;
if (claligned(cp
) && claligned(dp
)) {
struct pte
*pte
; int *ip
;
x
= btop(cp
- ifu
->ifu_w
.ifrw_addr
);
ip
= &ifu
->ifu_w
.ifrw_mr
[x
+ 1];
for (i
= 0; i
< CLSIZE
; i
++)
ifu
->ifu_w
.ifrw_proto
| pte
++->pg_pfnum
;
ifu
->ifu_xswapd
|= 1 << (x
>>CLSHIFT
);
bcopy(mtod(m
, caddr_t
), cp
, (unsigned)m
->m_len
);
MFREE(m
, mp
); /* XXX too soon! */
xswapd
&= ~ifu
->ifu_xswapd
;
while (i
= ffs(xswapd
)) {
for (x
= 0; x
< CLSIZE
; x
++) {
ifu
->ifu_rw
.ifrw_mr
[i
] = ifu
->ifu_xmap
[i
];