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