* Copyright (c) 1982, 1986, 1988 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
* @(#)if_uba.c 7.16 (Berkeley) 12/16/90
#include "../include/pte.h"
#include "../include/mtpr.h"
#include "../uba/ubareg.h"
#include "../uba/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 once for each read and once for each write buffer. We also
* allocate page frames in the mbuffer pool for these pages.
if_ubaminit(ifu
, uban
, hlen
, nmr
, ifr
, nr
, ifw
, nw
)
register struct ifubinfo
*ifu
;
int uban
, hlen
, nmr
, nr
, nw
;
register struct ifrw
*ifr
;
register struct ifxmt
*ifw
;
nclbytes
= roundup(nmr
* NBPG
, MCLBYTES
);
cp
= ifr
[0].ifrw_addr
- off
;
cp
= (caddr_t
)malloc((u_long
)((nr
+ nw
) * nclbytes
), M_DEVBUF
,
for (i
= 0; i
< nr
; i
++) {
ifr
[i
].ifrw_addr
= p
+ off
;
for (i
= 0; i
< nw
; i
++) {
ifw
[i
].ifw_addr
= p
+ off
;
ifu
->iff_uba
= uba_hd
[uban
].uh_uba
;
ifu
->iff_ubamr
= uba_hd
[uban
].uh_mr
;
if (if_ubaalloc(ifu
, &ifr
[i
], nmr
) == 0) {
if (if_ubaalloc(ifu
, &ifw
[i
].ifrw
, nmr
) == 0) {
for (i
= 0; i
< nmr
; i
++)
ifw
[nw
].ifw_wmap
[i
] = ifw
[nw
].ifw_mr
[i
];
ifw
[nw
].ifw_flags
= IFRW_W
;
ubarelse(ifu
->iff_uban
, &ifw
[nw
].ifw_info
);
ubarelse(ifu
->iff_uban
, &ifr
[nr
].ifrw_info
);
* Setup an 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
->iff_uban
, ifrw
->ifrw_addr
, nmr
*NBPG
+ ifu
->iff_hlen
,
ifrw
->ifrw_bdp
= UBAI_BDP(info
);
ifrw
->ifrw_proto
= UBAMR_MRV
| (UBAI_BDP(info
) << UBAMR_DPSHIFT
);
ifrw
->ifrw_mr
= &ifu
->iff_ubamr
[UBAI_MR(info
) + (ifu
->iff_hlen
? 1 : 0)];
* Pull read data off a interface.
* Totlen 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 header from the trailer 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.
* Save a pointer to the interface structure and the total length,
* so that protocols can determine where incoming packets arrived.
* Note: we may be called to receive from a transmit buffer by some
* devices. In that case, we must force normal mapping of the buffer,
* so that the correct data will appear (only unibus maps are
* changed when remapping the transmit buffers).
if_ubaget(ifu
, ifr
, totlen
, off
, ifp
)
register struct ifrw
*ifr
;
register caddr_t cp
= ifr
->ifrw_addr
+ ifu
->iff_hlen
, pp
;
caddr_t epkt
= cp
+ totlen
;
* Skip the trailer header (type and trailer length).
off
+= 2 * sizeof(u_short
);
totlen
-= 2 * sizeof(u_short
);
MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
return ((struct mbuf
*)NULL
);
m
->m_pkthdr
.len
= totlen
;
if (ifr
->ifrw_flags
& IFRW_W
)
rcv_xmtbuf((struct ifxmt
*)ifr
);
MGET(m
, M_DONTWAIT
, MT_DATA
);
len
= min(totlen
, epkt
- cp
);
if ((m
->m_flags
& M_EXT
) == 0)
len
= min(len
, MCLBYTES
);
* Switch pages mapped to UNIBUS with new page pp,
* as quick form of copy. Remap UNIBUS and invalidate.
x
= btop(cp
- ifr
->ifrw_addr
);
ip
= (int *)&ifr
->ifrw_mr
[x
];
for (i
= 0; i
< MCLBYTES
/NBPG
; i
++) {
t
= *ppte
; *ppte
++ = *cpte
; *cpte
= t
;
*ip
++ = cpte
++->pg_pfnum
|ifr
->ifrw_proto
;
* Place initial small packet/header at end of mbuf.
if (top
== 0 && len
+ max_linkhdr
<= m
->m_len
)
m
->m_data
+= max_linkhdr
;
bcopy(cp
, mtod(m
, caddr_t
), (unsigned)len
);
cp
= ifr
->ifrw_addr
+ ifu
->iff_hlen
;
if (ifr
->ifrw_flags
& IFRW_W
)
restor_xmtbuf((struct ifxmt
*)ifr
);
* Change the mapping on a transmit buffer so that if_ubaget may
* receive from that buffer. Copy data from any pages mapped to Unibus
* into the pages mapped to normal kernel virtual memory, so that
* they can be accessed and swapped as usual. We take advantage
* of the fact that clusters are placed on the xtofree list
* in inverse order, finding the last one.
register struct ifxmt
*ifw
;
while (i
= ffs((long)ifw
->ifw_xswapd
)) {
cp
= ifw
->ifw_base
+ i
* MCLBYTES
;
ifw
->ifw_xswapd
&= ~(1<<i
);
mprev
= &ifw
->ifw_xtofree
;
for (m
= ifw
->ifw_xtofree
; m
&& m
->m_next
; m
= m
->m_next
)
bcopy(mtod(m
, caddr_t
), cp
, MCLBYTES
);
for (i
= 0; i
< ifw
->ifw_nmr
; i
++)
ifw
->ifw_mr
[i
] = ifw
->ifw_wmap
[i
];
* Put a transmit buffer back together after doing an if_ubaget on it,
* which may have swapped pages.
register struct ifxmt
*ifw
;
for (i
= 0; i
< ifw
->ifw_nmr
; i
++)
ifw
->ifw_wmap
[i
] = ifw
->ifw_mr
[i
];
* 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 ifxmt
*ifw
;
register struct mbuf
*mp
;
if (claligned(cp
) && claligned(dp
) &&
(m
->m_len
== MCLBYTES
|| m
->m_next
== (struct mbuf
*)0)) {
x
= btop(cp
- ifw
->ifw_addr
);
ip
= (int *)&ifw
->ifw_mr
[x
];
for (i
= 0; i
< MCLBYTES
/NBPG
; i
++)
*ip
++ = ifw
->ifw_proto
| pte
++->pg_pfnum
;
xswapd
|= 1 << (x
>>(MCLSHIFT
-PGSHIFT
));
m
->m_next
= ifw
->ifw_xtofree
;
bcopy(mtod(m
, caddr_t
), cp
, (unsigned)m
->m_len
);
* Xswapd is the set of clusters we just mapped out. Ifu->iff_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.
x
= ((cc
- ifu
->iff_hlen
) + MCLBYTES
- 1) >> MCLSHIFT
;
ifw
->ifw_xswapd
&= ~xswapd
;
while (i
= ffs((long)ifw
->ifw_xswapd
)) {
ifw
->ifw_xswapd
&= ~(1<<i
);
for (t
= 0; t
< MCLBYTES
/NBPG
; t
++) {
ifw
->ifw_mr
[i
] = ifw
->ifw_wmap
[i
];
ifw
->ifw_xswapd
|= xswapd
;