apecs.c revision 1.2 1 /* $NetBSD: apecs.c,v 1.2 1995/08/03 00:44:57 cgd Exp $ */
2
3 /*
4 * Copyright (c) 1994, 1995 Carnegie-Mellon University.
5 * All rights reserved.
6 *
7 * Author: Chris G. Demetriou
8 *
9 * Permission to use, copy, modify and distribute this software and
10 * its documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
14 *
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
22 * School of Computer Science
23 * Carnegie Mellon University
24 * Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie the
27 * rights to redistribute these changes.
28 */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/device.h>
35 #include <vm/vm.h>
36
37 #include <machine/autoconf.h>
38 #include <machine/pio.h>
39 #include <machine/rpb.h>
40
41 #include <dev/isa/isareg.h>
42 #include <dev/isa/isavar.h>
43 #include <alpha/isa/isa_dma.h>
44
45 #include <dev/pci/pcireg.h>
46 #include <dev/pci/pcivar.h>
47 #include <alpha/pci/pci_chipset.h>
48 #include <alpha/pci/apecsreg.h>
49
50 int apecsmatch __P((struct device *, void *, void *));
51 void apecsattach __P((struct device *, struct device *, void *));
52
53 struct cfdriver apecscd = {
54 NULL, "apecs", apecsmatch, apecsattach, DV_DULL, sizeof(struct device)
55 };
56
57 static int apecsprint __P((void *, char *pnp));
58
59 #ifdef DEC_2100_A50
60 extern void pci_2100_a50_pickintr __P((void));
61 #endif
62
63 #define REGVAL(r) (*(int32_t *)phystok0seg(r))
64
65 static int nsgmapent = 1024;
66 static vm_offset_t sgmap_pci_base = 0x800000;
67 /*static */struct sgmapent *sgmap;
68 static char /* * */ sgbitmap[1024 / NBBY];
69
70 int
71 apecsmatch(parent, match, aux)
72 struct device *parent;
73 void *match, *aux;
74 {
75 struct cfdata *cf = match;
76 struct confargs *pa = aux;
77
78 /* XXX */
79
80 return (1);
81 }
82
83 /*
84 * Set up the chipset's function pointers.
85 */
86 void
87 apecs_init()
88 {
89 int pass2_epic;
90
91 pass2_epic = (REGVAL(EPIC_DCSR) & EPIC_DCSR_PASS2) != 0;
92
93 isadma_fcns = &apecs_isadma_fcns;
94 isa_pio_fcns = &apecs_pio_fcns;
95 if (!pass2_epic)
96 pci_cs_fcns = &apecs_p1e_cs_fcns;
97 else
98 pci_cs_fcns = &apecs_p2e_cs_fcns;
99 }
100
101 void
102 apecsattach(parent, self, aux)
103 struct device *parent, *self;
104 void *aux;
105 {
106 struct confargs *ca = aux;
107 struct confargs nca;
108 int pass2_comanche, widemem, pass2_epic;
109
110 pass2_comanche = (REGVAL(COMANCHE_ED) & COMANCHE_ED_PASS2) != 0;
111 widemem = (REGVAL(COMANCHE_GCR) & COMANCHE_GCR_WIDEMEM) != 0;
112 pass2_epic = (REGVAL(EPIC_DCSR) & EPIC_DCSR_PASS2) != 0;
113
114 sgmap = (struct sgmapent *)malloc(1024 * sizeof(struct sgmapent),
115 M_DEVBUF, M_WAITOK);
116
117 printf(": DECchip %s Core Logic chipset\n",
118 widemem ? "21072" : "21071");
119 printf("%s: DC21071-CA pass %d, %d-bit memory bus\n",
120 self->dv_xname, pass2_comanche ? 2 : 1, widemem ? 128 : 64);
121 printf("%s: DC21071-DA pass %d\n", self->dv_xname, pass2_epic ? 2 : 1);
122 /* XXX print bcache size */
123
124 if (!pass2_epic)
125 printf("WARNING: 21071-DA NOT PASS2... NO BETS...\n");
126
127 /* set up the chipset's functions */
128 apecs_init();
129
130 switch (hwrpb->rpb_type) {
131 #if defined(DEC_2100_A50)
132 case ST_DEC_2100_A50:
133 pci_2100_a50_pickintr();
134 break;
135 #endif
136 default:
137 panic("apecsattach: shouldn't be here, really...");
138 }
139
140 /* attach the PCI bus that hangs off of it... */
141 nca.ca_name = "pci";
142 nca.ca_slot = 0;
143 nca.ca_offset = 0;
144 nca.ca_bus = NULL;
145 if (!config_found(self, &nca, apecsprint))
146 panic("apecsattach: couldn't attach PCI bus");
147 }
148
149 static int
150 apecsprint(aux, pnp)
151 void *aux;
152 char *pnp;
153 {
154 register struct confargs *ca = aux;
155
156 if (pnp)
157 printf("%s at %s", ca->ca_name, pnp);
158 return (UNCONF);
159 }
160
161 vm_offset_t /* XXX? */
162 apecs_sgmap_alloc(va, npg, nocross, waitok)
163 caddr_t va;
164 int npg;
165 vm_size_t nocross;
166 int waitok;
167 {
168 int s;
169 int base, i, stride;
170
171 #ifdef DIAGNOSTIC
172 /* Quick sanity checks. */
173 if ((vm_offset_t)va & PGOFSET)
174 panic("apecs_sgmap_alloc: va not page aligned");
175 if ((nocross & (nocross - 1)) != 0 || nocross == 0)
176 panic("apecs_sgmap_alloc: bogus alignment 0x%lx", nocross);
177 if (npg <= 0)
178 panic("apecs_sgmap_alloc: not allocating anything");
179 if (npg > nsgmapent)
180 panic("apecs_sgmap_alloc: insane allocation");
181 if (ptoa(npg) > nocross)
182 panic("apecs_sgmap_alloc: must cross boundary");
183 #endif
184
185 stride = atop(nocross);
186 #ifdef DIAGNOSTIC
187 if (stride > nsgmapent)
188 panic("apecs_sgmap_alloc: cheesy implementation loses");
189 #endif
190
191 top:
192 s = splhigh();
193 for (base = 0; base < nsgmapent; base += stride) {
194 for (i = base; i < base + npg; i++)
195 if (isset(sgbitmap, i))
196 goto nextstride;
197 break;
198 nextstride:
199 }
200 if (base < nsgmapent) /* found a free chunk, claim it */
201 for (i = base; i < base + npg; i++)
202 setbit(sgbitmap, i);
203 splx(s);
204
205 if (base >= nsgmapent) { /* didn't find a free chunk */
206 if (!waitok)
207 return 0;
208 tsleep(&sgmap, PRIBIO+1, "sgmap", 0);
209 goto top;
210 }
211
212 for (i = base; i < base + npg; i++) {
213 #ifdef DIAGNOSTIC
214 if ((sgmap[i].val & SGMAPENT_EVAL) != 0)
215 panic("apecs_sgmap_alloc: unallocated entry valid");
216 #endif
217 sgmap[i].val = SGMAP_MAKEENTRY(atop(vtophys(va)));
218 va += PAGE_SIZE;
219 }
220
221 /* Invalidate old cached entries. */
222 REGVAL(EPIC_TBIA) = 1;
223
224 /* Return the PCI address. */
225 return (ptoa(base) + sgmap_pci_base);
226 }
227
228 void
229 apecs_sgmap_dealloc(pa, npg)
230 vm_offset_t pa;
231 int npg;
232 {
233 int i, pfn;
234
235 #ifdef DIAGNOSTIC
236 /* Quick sanity checks. */
237 if (pa & PGOFSET)
238 panic("apecs_sgmap_dealloc: pa not page aligned");
239 if (npg <= 0)
240 panic("apecs_sgmap_dealloc: not deallocating anything");
241 if (npg > nsgmapent)
242 panic("apecs_sgmap_dealloc: insane deallocation");
243 #endif
244
245 pfn = atop(pa - sgmap_pci_base);
246 #ifdef DIAGNOSTIC
247 /* Bounds check the deallocation range. Paranoid about wraparound. */
248 if (pfn < 0 || pfn >= nsgmapent || (pfn + npg) >= nsgmapent)
249 panic("apecs_sgmap_dealloc: pa out of range (%s)",
250 pfn < 0 ? "too low" : "too high");
251 #endif
252
253 for (i = 0; i < npg; i++) {
254 #ifdef DIAGNOSTIC
255 /* Make sure it's actually allocated. */
256 if (isclr(sgbitmap, i + pfn))
257 panic("apecs_sgmap_dealloc: multiple frees: entry %d",
258 i + pfn);
259 #endif
260
261 /* Clear the entries and the allocation map bits. */
262 clrbit(sgbitmap, i + pfn);
263 sgmap[i + pfn].val &= ~SGMAPENT_EVAL;
264 }
265
266 /* Invalidate old cached entries. */
267 REGVAL(EPIC_TBIA) = 1;
268
269 /* Wake up anybody waiting for map entries. */
270 wakeup(&sgmap);
271 }
272