* Copyright (c) 1987, 1988 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of California at Berkeley. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
* @(#)vba.c 7.1 (Berkeley) %G%
* Tahoe VERSAbus adapator support routines.
#include "../tahoe/mtpr.h"
#include "../tahoe/pte.h"
#include "../tahoevba/vbavar.h"
* Allocate private page map and intermediate buffer
* for a VERSAbus device, large enough for maximum transfer size.
* Make intermediate buffer uncacheable.
vbainit(vb
, xsize
, flags
)
register struct vb_buf
*vb
;
register struct pte
*pte
;
if (vbmapalloc((int)btoc(xsize
) + 1, &vb
->vb_map
, &vb
->vb_utl
) == 0) {
printf("vbmap exhausted\n");
n
= roundup(xsize
, NBPG
);
vb
->vb_rawbuf
= (caddr_t
)malloc((u_long
)n
, M_DEVBUF
, M_NOWAIT
);
if (vb
->vb_rawbuf
== 0) {
printf("no memory for device buffer\n");
if ((int)vb
->vb_rawbuf
& PGOFSET
)
vb
->vb_physbuf
= (u_long
)kvtophys(vb
->vb_rawbuf
);
vb
->vb_maxphys
= btoc(VB_MAXADDR20
);
else if (flags
& VB_24BIT
)
vb
->vb_maxphys
= btoc(VB_MAXADDR24
);
vb
->vb_maxphys
= btoc(VB_MAXADDR32
);
if (btoc(vb
->vb_physbuf
+ n
) > vb
->vb_maxphys
)
* Make raw buffer pages uncacheable.
pte
= kvtopte(vb
->vb_rawbuf
);
for (n
= btoc(n
); n
--; pte
++)
* Due to unknown hardware or software errors, some sites have problems
* with strange crashes or corruption of text images when DMA is attempted
* to kernel addresses spanning a page boundary, or to user addresses
* (even if the buffer is physically contiguous). To avoid this behavior,
* the following toggles inhibit such transfers when set.
* vba_copyk: copy transfers to kernel address that span a page boundary
* vba_copyu: copy transfers to user addresses
* Check a transfer to see whether it can be done directly
* to the destination buffer, or whether it must be copied.
* On Tahoe, the lack of a bus I/O map forces data to be copied
* to a physically-contiguous buffer whenever one of the following is true:
* 1) The data length is not a multiple of sector size.
* (The swapping code does this, unfortunately.)
* 2) The buffer is not physically contiguous and the controller
* does not support scatter-gather operations.
* 3) The physical address for I/O is higher than addressible
* This routine is called by the start routine.
* If copying is necessary, the intermediate buffer is mapped;
* if the operation is a write, the data is copied into the buffer.
* It returns the physical address of the first byte for DMA, to
* be presented to the controller.
vbasetup(bp
, vb
, sectsize
)
register struct vb_buf
*vb
;
register struct pte
*spte
, *dpte
;
o
= (int)bp
->b_un
.b_addr
& PGOFSET
;
npf
= btoc(bp
->b_bcount
+ o
);
vb
->vb_iskernel
= (((int)bp
->b_un
.b_addr
& KERNBASE
) == KERNBASE
);
spte
= kvtopte(bp
->b_un
.b_addr
);
if (vba_copyk
&& (o
!= 0 || npf
> 1)) goto copy
;
spte
= vtopte((bp
->b_flags
&B_DIRTY
) ? &proc
[2] : bp
->b_proc
,
if (vba_copyu
) goto copy
;
if (bp
->b_bcount
% sectsize
!= 0 || (o
& (sizeof(long) - 1)) != 0)
else if ((vb
->vb_flags
& VB_SCATTER
) == 0 ||
vb
->vb_maxphys
!= btoc(VB_MAXADDR32
)) {
for (i
= npf
; --i
> 0; dpte
++) {
if ((v
= dpte
->pg_pfnum
) != p
+ CLSIZE
&&
(vb
->vb_flags
& VB_SCATTER
) == 0)
return ((spte
->pg_pfnum
<< PGSHIFT
) + o
);
if (bp
->b_bcount
> vb
->vb_bufsize
)
panic("vba xfer too large");
if ((bp
->b_flags
& B_READ
) == 0)
bcopy(bp
->b_un
.b_addr
, vb
->vb_rawbuf
,
for (i
= npf
, p
= (int)vb
->vb_utl
; i
--; p
+= NBPG
) {
*(int *)dpte
++ = (spte
++)->pg_pfnum
|
if ((bp
->b_flags
& B_READ
) == 0)
bcopy(vb
->vb_utl
+ o
, vb
->vb_rawbuf
,
* Called by the driver's interrupt routine, after DMA is completed.
* If the operation was a read, copy data to final buffer if necessary
* or invalidate data cache for cacheable direct buffers.
* Similar to the vbastart routine, but in the reverse direction.
register struct vb_buf
*vb
;
if (bp
->b_flags
& B_READ
) {
o
= (int)bp
->b_un
.b_addr
& PGOFSET
;
bcopy(vb
->vb_rawbuf
, bp
->b_un
.b_addr
,
(unsigned)(bp
->b_bcount
- bp
->b_resid
));
bcopy(vb
->vb_rawbuf
, vb
->vb_utl
+ o
,
(unsigned)(bp
->b_bcount
- bp
->b_resid
));
npf
= btoc(bp
->b_bcount
+ o
);
for (v
= bp
->b_un
.b_addr
; npf
--; v
+= NBPG
)
* Set up a scatter-gather operation for SMD/E controller.
* This code belongs half-way between vd.c and this file.
register struct pte
*spte
;
register struct addr_chain
*adr
;
o
= (int)bp
->b_un
.b_addr
& PGOFSET
;
vb
->vb_iskernel
= (((int)bp
->b_un
.b_addr
& KERNBASE
) == KERNBASE
);
spte
= kvtopte(bp
->b_un
.b_addr
);
spte
= vtopte((bp
->b_flags
&B_DIRTY
) ? &proc
[2] : bp
->b_proc
,
i
= min(NBPG
- o
, bp
->b_bcount
);
sg
->start_addr
.wcount
= (i
+ 1) >> 1;
sg
->start_addr
.memadr
= ((spte
++)->pg_pfnum
<< PGSHIFT
) + o
;
if (i
> VDMAXPAGES
* NBPG
)
panic("vba xfer too large");
for (adr
= sg
->addr_chain
; i
> 0; adr
++, i
-= NBPG
/ 2) {
adr
->nxt_addr
= (spte
++)->pg_pfnum
<< PGSHIFT
;
adr
->nxt_len
= imin(i
, NBPG
/ 2);
return ((adr
- sg
->addr_chain
) * sizeof(*adr
) / sizeof(long));