24d979bed8617512e9184e6e2645c0d257626e2c
* Tahoe VERSAbus adapator support routines.
#include "../tahoe/mtpr.h"
#include "../tahoe/pte.h"
#include "../tahoevba/vbavar.h"
#define kvtopte(v) (&Sysmap[btop((int)(v) &~ KERNBASE)])
* 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
;
vbmapalloc(btoc(xsize
) + 1, &vb
->vb_map
, &vb
->vb_utl
);
n
= roundup(xsize
, NBPG
);
vb
->vb_rawbuf
= calloc(n
);
if ((int)vb
->vb_rawbuf
& PGOFSET
)
vb
->vb_physbuf
= vtoph((struct proc
*)0, 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
++)
* 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
);
spte
= vtopte((bp
->b_flags
&B_DIRTY
) ? &proc
[2] : bp
->b_proc
,
if (bp
->b_bcount
% sectsize
)
else if ((vb
->vb_flags
& VB_SCATTER
) == 0 ||
vb
->vb_maxphys
!= 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
;
npf
= btoc(bp
->b_bcount
+ o
);
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
= min(i
, NBPG
/ 2);
return ((adr
- sg
->addr_chain
) * sizeof(*adr
) / sizeof(long));