need reset (maybe)
[unix-history] / usr / src / sys / tahoe / vba / vba.c
CommitLineData
c7af6552 1/* vba.c 1.9 87/06/30 */
d0afb218
MK
2
3/*
4 * Tahoe VERSAbus adapator support routines.
5 */
500486ea 6
9d915fad
SL
7#include "../tahoe/mtpr.h"
8#include "../tahoe/pte.h"
500486ea 9
9d915fad
SL
10#include "param.h"
11#include "buf.h"
12#include "cmap.h"
13#include "conf.h"
14#include "dir.h"
15#include "dk.h"
16#include "map.h"
17#include "systm.h"
18#include "user.h"
19#include "vmparam.h"
20#include "vmmac.h"
21#include "proc.h"
c0cfefe3 22#include "syslog.h"
fcba03fb 23#include "malloc.h"
9d915fad
SL
24
25#include "../tahoevba/vbavar.h"
26
1f9a1539 27#define kvtopte(v) (&Sysmap[btop((int)(v) &~ KERNBASE)])
d0afb218 28
9d915fad 29/*
d0afb218
MK
30 * Allocate private page map and intermediate buffer
31 * for a VERSAbus device, large enough for maximum transfer size.
32 * Intermediate buffer
33 * Make intermediate buffer uncacheable.
9d915fad 34 */
1f9a1539
MK
35vbainit(vb, xsize, flags)
36 register struct vb_buf *vb;
37 int xsize, flags;
38{
39 register struct pte *pte;
40 register n;
41
42 vb->vb_flags = flags;
c7af6552
MK
43 if (vbmapalloc(btoc(xsize) + 1, &vb->vb_map, &vb->vb_utl) == 0) {
44 printf("vbmap exhausted\n");
45 return (0);
46 }
1f9a1539 47 n = roundup(xsize, NBPG);
ef2ed459 48 vb->vb_bufsize = n;
1f9a1539 49 if (vb->vb_rawbuf == 0)
fcba03fb 50 vb->vb_rawbuf = (caddr_t)malloc(n, M_DEVBUF, M_NOWAIT);
c7af6552
MK
51 if (vb->vb_rawbuf == 0) {
52 printf("no memory for device buffer\n");
53 return (0);
54 }
1f9a1539 55 if ((int)vb->vb_rawbuf & PGOFSET)
d0afb218 56 panic("vbinit pgoff");
1f9a1539
MK
57 vb->vb_physbuf = vtoph((struct proc *)0, vb->vb_rawbuf);
58 if (flags & VB_20BIT)
59 vb->vb_maxphys = btoc(VB_MAXADDR20);
60 else if (flags & VB_24BIT)
61 vb->vb_maxphys = btoc(VB_MAXADDR24);
62 else
63 vb->vb_maxphys = btoc(VB_MAXADDR32);
d0afb218
MK
64 if (btoc(vb->vb_physbuf + n) > vb->vb_maxphys)
65 panic("vbinit physbuf");
1f9a1539
MK
66
67 /*
68 * Make raw buffer pages uncacheable.
69 */
70 pte = kvtopte(vb->vb_rawbuf);
71 for (n = btoc(n); n--; pte++)
72 pte->pg_nc = 1;
73 mtpr(TBIA, 0);
c7af6552 74 return (1);
1f9a1539
MK
75}
76
500486ea 77/*
d0afb218
MK
78 * Check a transfer to see whether it can be done directly
79 * to the destination buffer, or whether it must be copied.
80 * On Tahoe, the lack of a bus I/O map forces data to be copied
81 * to a physically-contiguous buffer whenever one of the following is true:
82 * 1) The data length is not a multiple of sector size.
83 * (The swapping code does this, unfortunately.)
1f9a1539
MK
84 * 2) The buffer is not physically contiguous and the controller
85 * does not support scatter-gather operations.
86 * 3) The physical address for I/O is higher than addressible
87 * by the device.
d0afb218
MK
88 * This routine is called by the start routine.
89 * If copying is necessary, the intermediate buffer is mapped;
90 * if the operation is a write, the data is copied into the buffer.
91 * It returns the physical address of the first byte for DMA, to
92 * be presented to the controller.
500486ea 93 */
1f9a1539
MK
94u_long
95vbasetup(bp, vb, sectsize)
96 register struct buf *bp;
97 register struct vb_buf *vb;
98 int sectsize;
500486ea 99{
1f9a1539
MK
100 register struct pte *spte, *dpte;
101 register int p, i;
102 int npf, o, v;
103
104 o = (int)bp->b_un.b_addr & PGOFSET;
d0afb218 105 npf = btoc(bp->b_bcount + o);
1f9a1539
MK
106 vb->vb_iskernel = (((int)bp->b_un.b_addr & KERNBASE) == KERNBASE);
107 if (vb->vb_iskernel)
108 spte = kvtopte(bp->b_un.b_addr);
109 else
110 spte = vtopte((bp->b_flags&B_DIRTY) ? &proc[2] : bp->b_proc,
111 btop(bp->b_un.b_addr));
112 if (bp->b_bcount % sectsize)
113 goto copy;
114 else if ((vb->vb_flags & VB_SCATTER) == 0 ||
115 vb->vb_maxphys != VB_MAXADDR32) {
116 dpte = spte;
d0afb218
MK
117 p = (dpte++)->pg_pfnum;
118 for (i = npf; --i > 0; dpte++) {
119 if ((v = dpte->pg_pfnum) != p + CLSIZE &&
1f9a1539
MK
120 (vb->vb_flags & VB_SCATTER) == 0)
121 goto copy;
122 if (p >= vb->vb_maxphys)
123 goto copy;
124 p = v;
125 }
126 if (p >= vb->vb_maxphys)
127 goto copy;
128 }
129 vb->vb_copy = 0;
ef2ed459
MK
130 if (vb->vb_iskernel)
131 vbastat.k_raw++;
132 else
133 vbastat.u_raw++;
1f9a1539 134 return ((spte->pg_pfnum << PGSHIFT) + o);
500486ea 135
1f9a1539
MK
136copy:
137 vb->vb_copy = 1;
ef2ed459
MK
138 if (bp->b_bcount > vb->vb_bufsize)
139 panic("vba xfer too large");
1f9a1539 140 if (vb->vb_iskernel) {
ef2ed459 141 if ((bp->b_flags & B_READ) == 0)
1f9a1539
MK
142 bcopy(bp->b_un.b_addr, vb->vb_rawbuf,
143 (unsigned)bp->b_bcount);
ef2ed459 144 vbastat.k_copy++;
1f9a1539
MK
145 } else {
146 dpte = vb->vb_map;
147 for (i = npf, p = (int)vb->vb_utl; i--; p += NBPG) {
d0afb218
MK
148 *(int *)dpte++ = (spte++)->pg_pfnum |
149 PG_V | PG_KW | PG_N;
1f9a1539 150 mtpr(TBIS, p);
500486ea 151 }
ef2ed459 152 if ((bp->b_flags & B_READ) == 0)
1f9a1539
MK
153 bcopy(vb->vb_utl + o, vb->vb_rawbuf,
154 (unsigned)bp->b_bcount);
ef2ed459 155 vbastat.u_copy++;
1f9a1539
MK
156 }
157 return (vb->vb_physbuf);
500486ea
SL
158}
159
500486ea 160/*
1f9a1539
MK
161 * Called by the driver's interrupt routine, after DMA is completed.
162 * If the operation was a read, copy data to final buffer if necessary
163 * or invalidate data cache for cacheable direct buffers.
9d915fad 164 * Similar to the vbastart routine, but in the reverse direction.
500486ea 165 */
1f9a1539 166vbadone(bp, vb)
9d915fad 167 register struct buf *bp;
1f9a1539 168 register struct vb_buf *vb;
9d915fad 169{
1f9a1539
MK
170 register npf;
171 register caddr_t v;
172 int o;
500486ea 173
1f9a1539
MK
174 if (bp->b_flags & B_READ) {
175 o = (int)bp->b_un.b_addr & PGOFSET;
176 if (vb->vb_copy) {
ef2ed459 177 if (vb->vb_iskernel)
1f9a1539
MK
178 bcopy(vb->vb_rawbuf, bp->b_un.b_addr,
179 (unsigned)(bp->b_bcount - bp->b_resid));
ef2ed459 180 else {
1f9a1539
MK
181 bcopy(vb->vb_rawbuf, vb->vb_utl + o,
182 (unsigned)(bp->b_bcount - bp->b_resid));
183 dkeyinval(bp->b_proc);
500486ea 184 }
1f9a1539
MK
185 } else {
186 if (vb->vb_iskernel) {
187 npf = btoc(bp->b_bcount + o);
188 for (v = bp->b_un.b_addr; npf--; v += NBPG)
189 mtpr(P1DC, (int)v);
ef2ed459 190 } else
1f9a1539 191 dkeyinval(bp->b_proc);
1f9a1539
MK
192 }
193 }
500486ea 194}
ef2ed459
MK
195
196/*
197 * Set up a scatter-gather operation for SMD/E controller.
198 * This code belongs half-way between vd.c and this file.
199 */
200#include "vdreg.h"
201
202vba_sgsetup(bp, vb, sg)
203 register struct buf *bp;
204 struct vb_buf *vb;
205 struct trsg *sg;
206{
207 register struct pte *spte;
208 register struct addr_chain *adr;
209 register int npf, i;
210 int o;
211
212 o = (int)bp->b_un.b_addr & PGOFSET;
213 npf = btoc(bp->b_bcount + o);
214 vb->vb_iskernel = (((int)bp->b_un.b_addr & KERNBASE) == KERNBASE);
215 vb->vb_copy = 0;
216 if (vb->vb_iskernel) {
217 spte = kvtopte(bp->b_un.b_addr);
218 vbastat.k_sg++;
219 } else {
220 spte = vtopte((bp->b_flags&B_DIRTY) ? &proc[2] : bp->b_proc,
221 btop(bp->b_un.b_addr));
222 vbastat.u_sg++;
223 }
224
225 i = min(NBPG - o, bp->b_bcount);
226 sg->start_addr.wcount = (i + 1) >> 1;
227 sg->start_addr.memadr = ((spte++)->pg_pfnum << PGSHIFT) + o;
228 i = bp->b_bcount - i;
229 if (i > VDMAXPAGES * NBPG)
230 panic("vba xfer too large");
231 i = (i + 1) >> 1;
232 for (adr = sg->addr_chain; i > 0; adr++, i -= NBPG / 2) {
233 adr->nxt_addr = (spte++)->pg_pfnum << PGSHIFT;
234 adr->nxt_len = min(i, NBPG / 2);
235 }
236 adr->nxt_addr = 0;
237 adr++->nxt_len = 0;
238 return ((adr - sg->addr_chain) * sizeof(*adr) / sizeof(long));
239}