FreeBSD/Linux Kernel Cross Reference
sys/pci/wd82371.c
1 /*
2 * Copyright 1996 Massachusetts Institute of Technology
3 *
4 * Permission to use, copy, modify, and distribute this software and
5 * its documentation for any purpose and without fee is hereby
6 * granted, provided that both the above copyright notice and this
7 * permission notice appear in all copies, that both the above
8 * copyright notice and this permission notice appear in all
9 * supporting documentation, and that the name of M.I.T. not be used
10 * in advertising or publicity pertaining to distribution of the
11 * software without specific, written prior permission. M.I.T. makes
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied
14 * warranty.
15 *
16 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
17 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: src/sys/pci/wd82371.c,v 1.5.2.2 1999/09/05 08:21:28 peter Exp $
30 */
31
32 #include "pci.h"
33 #if NPCI > 0
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/queue.h>
38 #include <sys/proc.h>
39 #include <sys/buf.h>
40 #include <sys/malloc.h>
41 #include <sys/kernel.h>
42 #include <vm/vm.h>
43 #include <vm/pmap.h>
44
45 #include <machine/pmap.h> /* for vtophys */
46
47 #include <i386/isa/wdreg.h>
48
49 #include <pci/pcivar.h>
50 #include <pci/pcireg.h>
51 #include <pci/wd82371reg.h>
52
53 static void *piix_candma(int, int);
54 static int piix_dmasetup(void *, char *, u_long, int);
55 static void piix_dmastart(void *);
56 static int piix_dmadone(void *);
57 static int piix_status(void *);
58
59 struct piix_cookie {
60 LIST_ENTRY(piix_cookie) le;
61 int ctlr;
62 int unit;
63 struct piix_prd *prd;
64 };
65
66 struct piix_softc {
67 unsigned iobase;
68 pcici_t tag;
69 LIST_HEAD(, piix_cookie) cookies;
70 };
71
72 static struct piix_softc softc;
73
74 static struct piix_cookie *
75 mkcookie(int ctlr, int unit)
76 {
77 struct piix_cookie *cp;
78
79 cp = malloc(sizeof *cp, M_DEVBUF, M_NOWAIT);
80 if (!cp) return cp;
81 cp->ctlr = ctlr;
82 cp->unit = unit;
83 cp->prd = malloc(PRD_ALLOC_SIZE, M_DEVBUF, M_NOWAIT);
84 if (!cp->prd) {
85 FREE(cp, M_DEVBUF);
86 return 0;
87 }
88 LIST_INSERT_HEAD(&softc.cookies, cp, le);
89 return cp;
90 }
91
92 static char *
93 piix_probe(pcici_t tag, pcidi_t type)
94 {
95 if (type == 0x12308086)
96 return ("Intel 82371 (Triton) Bus-master IDE controller");
97
98 return 0;
99 }
100
101 static void
102 piix_attach(pcici_t tag, int unit)
103 {
104 u_long idetm;
105 int bmista;
106 int iobase;
107
108 if (unit) return;
109
110 softc.tag = tag;
111 iobase = softc.iobase = pci_conf_read(tag, 0x20) & 0xfff0;
112 idetm = pci_conf_read(tag, 0x40);
113
114 LIST_INIT(&softc.cookies);
115
116 if (IDETM_CTLR_0(idetm) & IDETM_ENABLE) {
117 bmista = inb(iobase + BMISTA_PORT);
118 if (bmista & BMISTA_DMA0CAP)
119 mkcookie(0, 0);
120
121 if (bmista & BMISTA_DMA1CAP)
122 mkcookie(0, 1);
123 }
124
125 if (IDETM_CTLR_1(idetm) & IDETM_ENABLE) {
126 bmista = inb(iobase + PIIX_CTLR_1 + BMISTA_PORT);
127 if (bmista & BMISTA_DMA0CAP)
128 mkcookie(1, 0);
129 if (bmista & BMISTA_DMA1CAP)
130 mkcookie(1, 1);
131 }
132
133 wddma.wdd_candma = piix_candma;
134 wddma.wdd_dmaprep = piix_dmasetup;
135 wddma.wdd_dmastart = piix_dmastart;
136 wddma.wdd_dmadone = piix_dmadone;
137 wddma.wdd_dmastatus = piix_status;
138 }
139
140 static u_long piix_count;
141
142 static struct pci_device piix_device = {
143 "piix",
144 piix_probe,
145 piix_attach,
146 &piix_count,
147 0
148 };
149
150 DATA_SET(pcidevice_set, piix_device);
151
152 /*
153 * Return a cookie if we can do DMA on the specified (ctlr, unit).
154 */
155 static void *
156 piix_candma(int ctlr, int unit)
157 {
158 struct piix_cookie *cp;
159
160 cp = softc.cookies.lh_first;
161 while(cp) {
162 if (cp->unit == unit && cp->ctlr == ctlr)
163 break;
164 cp = cp->le.le_next;
165 }
166
167 return cp;
168 }
169
170 /*
171 * Set up DMA for cp. It is the responsibility of the caller
172 * to ensure that the controller is idle before this routine
173 * is called.
174 */
175 static int
176 piix_dmasetup(void *xcp, char *vaddr, u_long count, int dir)
177 {
178 struct piix_cookie *cp = xcp;
179 struct piix_prd *prd;
180 int i;
181 u_long pgresid;
182 int iobase;
183
184 prd = cp->prd;
185 i = 0;
186 iobase = softc.iobase + cp->ctlr ? PIIX_CTLR_1 : 0;
187
188 /*
189 * Deal with transfers that don't start on a page
190 * boundary.
191 */
192 pgresid = (u_long)vaddr % PAGE_SIZE;
193 if (pgresid) {
194 prd[i].prd_base = vtophys(vaddr);
195 if (count >= (PAGE_SIZE - pgresid))
196 prd[i].prd_count = PAGE_SIZE - pgresid;
197 else
198 prd[i].prd_count = count;
199 vaddr += prd[i].prd_count;
200 count -= prd[i].prd_count;
201 prd[i].prd_eot |= PRD_EOT_BIT;
202 i++;
203 }
204
205 /*
206 * We have now ensured that vaddr is page-aligned, so just
207 * step through the pages adding each one onto the list.
208 */
209 while(count) {
210 u_long phys, n;
211
212 phys = vtophys(vaddr);
213 n = (count > PAGE_SIZE) ? PAGE_SIZE : count;
214 /*
215 * If the current page is physically contiguous with
216 * whatever we have in the previous PRD, just tack it
217 * onto the end.
218 * CAVEAT: due to a hardware deficiency, PRDs
219 * cannot cross a 64K boundary.
220 */
221 if (i > 0
222 && phys == prd[i - 1].prd_base + prd[i - 1].prd_count
223 && ((prd[i - 1].prd_base & 0xffff)
224 + prd[i - 1].prd_count + n) <= 65535) {
225
226 prd[i - 1].prd_count += n;
227 } else {
228 if (i > 0)
229 prd[i - 1].prd_eot &= ~PRD_EOT_BIT;
230 prd[i].prd_base = phys;
231 prd[i].prd_count = n;
232 prd[i].prd_eot |= PRD_EOT_BIT;
233 i++;
234 if (i >= PRD_MAX_SEGS)
235 panic("wd82371: too many segments\n");
236 }
237 count -= n;
238 vaddr += n;
239 }
240
241 /* Set up PRD base register */
242 outl(iobase + BMIDTP_PORT, vtophys(prd));
243
244 /* Set direction of transfer */
245 if (dir == B_READ) {
246 outb(iobase + BMICOM_PORT, 0);
247 } else {
248 outb(iobase + BMICOM_PORT, BMICOM_READ_WRITE);
249 }
250
251 /* Clear interrupt and error bits */
252 outb(iobase + BMISTA_PORT,
253 (inb(iobase + BMISTA_PORT)
254 & ~(BMISTA_INTERRUPT | BMISTA_DMA_ERROR)));
255
256 return 0;
257 }
258
259 static void
260 piix_dmastart(void *xcp)
261 {
262 struct piix_cookie *cp = xcp;
263 int iobase;
264
265 iobase = softc.iobase + cp->ctlr ? PIIX_CTLR_1 : 0;
266
267 outb(iobase + BMICOM_PORT,
268 inb(iobase + BMICOM_PORT) | BMICOM_STOP_START);
269 }
270
271 static int
272 piix_dmadone(void *xcp)
273 {
274 struct piix_cookie *cp = xcp;
275 int iobase, status;
276
277 status = piix_status(xcp);
278 iobase = softc.iobase + cp->ctlr ? PIIX_CTLR_1 : 0;
279
280 outb(iobase + BMICOM_PORT,
281 inb(iobase + BMICOM_PORT) & ~BMICOM_STOP_START);
282
283 return status;
284 }
285
286 static int
287 piix_status(void *xcp)
288 {
289 struct piix_cookie *cp = xcp;
290 int iobase, status, bmista;
291
292 status = 0;
293 iobase = softc.iobase + cp->ctlr ? PIIX_CTLR_1 : 0;
294
295 bmista = inb(iobase + BMISTA_PORT);
296
297 if (bmista & BMISTA_INTERRUPT)
298 status |= WDDS_INTERRUPT;
299 if (bmista & BMISTA_DMA_ERROR)
300 status |= WDDS_ERROR;
301 if (bmista & BMISTA_DMA_ACTIVE)
302 status |= WDDS_ACTIVE;
303
304 return status;
305 }
306
307 #endif /* NPCI > 0 */
Cache object: 00cefe5ad74f650f040c84f67c80cd5e
|