]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/alpha/pci/apecs.c
Clone Kip's Xen on stable/6 tree so that I can work on improving FreeBSD/amd64
[FreeBSD/FreeBSD.git] / 6 / sys / alpha / pci / apecs.c
1 /*-
2  * Copyright (c) 1998 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 /*-
28  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
29  * All rights reserved.
30  *
31  * Author: Chris G. Demetriou
32  * 
33  * Permission to use, copy, modify and distribute this software and
34  * its documentation is hereby granted, provided that both the copyright
35  * notice and this permission notice appear in all copies of the
36  * software, derivative works or modified versions, and any portions
37  * thereof, and that both notices appear in supporting documentation.
38  * 
39  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
40  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
41  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
42  * 
43  * Carnegie Mellon requests users of this software to return to
44  *
45  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
46  *  School of Computer Science
47  *  Carnegie Mellon University
48  *  Pittsburgh PA 15213-3890
49  *
50  * any improvements or extensions that they make and grant Carnegie the
51  * rights to redistribute these changes.
52  */
53 /*-
54  * Additional Copyright (c) 1998 by Andrew Gallatin for Duke University 
55  */
56
57 #include <sys/cdefs.h>
58 __FBSDID("$FreeBSD$");
59
60 #define __RMAN_RESOURCE_VISIBLE
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/kernel.h>
64 #include <sys/lock.h>
65 #include <sys/malloc.h>
66 #include <sys/module.h>
67 #include <sys/mutex.h>
68 #include <sys/bus.h>
69 #include <machine/bus.h>
70 #include <sys/proc.h>
71 #include <sys/rman.h>
72 #include <sys/interrupt.h>
73
74 #include <alpha/pci/apecsreg.h>
75 #include <alpha/pci/apecsvar.h>
76 #include <alpha/isa/isavar.h>
77
78 #include <machine/cpuconf.h>
79 #include <machine/intr.h>
80 #include <machine/intrcnt.h>
81 #include <machine/md_var.h>
82 #include <machine/resource.h>
83 #include <machine/rpb.h>
84 #include <machine/sgmap.h>
85 #include <machine/swiz.h>
86
87 #include <vm/vm.h>
88 #include <vm/vm_page.h>
89
90 #define KV(pa)                  ALPHA_PHYS_TO_K0SEG(pa)
91
92 static devclass_t       apecs_devclass;
93 static device_t         apecs0;         /* XXX only one for now */
94
95 struct apecs_softc {
96         vm_offset_t     dmem_base;      /* dense memory */
97         vm_offset_t     smem_base;      /* sparse memory */
98         vm_offset_t     io_base;        /* dense i/o */
99         vm_offset_t     cfg0_base;      /* dense pci0 config */
100         vm_offset_t     cfg1_base;      /* dense pci1 config */
101 };
102
103 #define APECS_SOFTC(dev)        (struct apecs_softc*) device_get_softc(dev)
104
105 static alpha_chipset_read_hae_t apecs_read_hae;
106 static alpha_chipset_write_hae_t apecs_write_hae;
107
108 static alpha_chipset_t apecs_swiz_chipset = {
109         apecs_read_hae,
110         apecs_write_hae,
111 };
112
113 /*
114  * Memory functions.
115  * 
116  * XXX linux does 32-bit reads/writes via dense space.  This doesn't
117  *     appear to work for devices behind a ppb.  I'm using sparse
118  *     accesses & they appear to work just fine everywhere.
119  */
120
121 static u_int32_t        apecs_hae_mem;
122
123 #define REG1 (1UL << 24)
124 static u_int32_t
125 apecs_set_hae_mem(void *arg, u_int32_t pa)
126 {
127         int s; 
128         u_int32_t msb;
129         if (pa >= REG1){
130                 msb = pa & 0xf8000000;
131                 pa -= msb;
132                 s = splhigh();
133                 if (msb != apecs_hae_mem) {
134                         apecs_hae_mem = msb;
135                         REGVAL(EPIC_HAXR1) = apecs_hae_mem;
136                         alpha_mb();
137                         apecs_hae_mem = REGVAL(EPIC_HAXR1);
138                 }
139                 splx(s);
140         }
141         return pa;
142 }
143
144 static u_int64_t
145 apecs_read_hae(void)
146 {
147         return apecs_hae_mem & 0xf8000000;
148 }
149
150 static void
151 apecs_write_hae(u_int64_t hae)
152 {
153         u_int32_t pa = hae;
154         apecs_set_hae_mem(0, pa);
155 }
156
157 static int apecs_probe(device_t dev);
158 static int apecs_attach(device_t dev);
159 static int apecs_setup_intr(device_t dev, device_t child,
160                             struct resource *irq, int flags,
161                             driver_intr_t *intr, void *arg, void **cookiep);
162 static int apecs_teardown_intr(device_t dev, device_t child,
163                              struct resource *irq, void *cookie);
164
165 static device_method_t apecs_methods[] = {
166         /* Device interface */
167         DEVMETHOD(device_probe,         apecs_probe),
168         DEVMETHOD(device_attach,        apecs_attach),
169
170         /* Bus interface */
171         DEVMETHOD(bus_setup_intr,       apecs_setup_intr),
172         DEVMETHOD(bus_teardown_intr,    apecs_teardown_intr),
173
174         { 0, 0 }
175 };
176
177 static driver_t apecs_driver = {
178         "apecs",
179         apecs_methods,
180         sizeof(struct apecs_softc),
181 };
182
183 #define APECS_SGMAP_BASE                (8*1024*1024)
184 #define APECS_SGMAP_SIZE                (8*1024*1024)
185
186 static void
187 apecs_sgmap_invalidate(void)
188 {
189         alpha_mb();
190         REGVAL(EPIC_TBIA) = 0;
191         alpha_mb();
192 }
193
194 static void
195 apecs_sgmap_map(void *arg, bus_addr_t ba, vm_offset_t pa)
196 {
197         u_int64_t *sgtable = arg;
198         int index = alpha_btop(ba - APECS_SGMAP_BASE);
199
200         if (pa) {
201                 if (pa > (1L<<32))
202                         panic("apecs_sgmap_map: can't map address 0x%lx", pa);
203                 sgtable[index] = ((pa >> 13) << 1) | 1;
204         } else {
205                 sgtable[index] = 0;
206         }
207         alpha_mb();
208         apecs_sgmap_invalidate();
209 }
210
211 static void
212 apecs_init_sgmap(void)
213 {
214         void *sgtable;
215
216         /*
217          * First setup Window 0 to map 8Mb to 16Mb with an
218          * sgmap. Allocate the map aligned to a 32 boundary.
219          */
220         REGVAL(EPIC_PCI_BASE_1) = APECS_SGMAP_BASE |
221                 EPIC_PCI_BASE_SGEN | EPIC_PCI_BASE_WENB;
222         alpha_mb();
223
224         REGVAL(EPIC_PCI_MASK_1) = EPIC_PCI_MASK_8M;
225         alpha_mb();
226
227         sgtable = contigmalloc(8192, M_DEVBUF, M_NOWAIT,
228                                0, (1L<<34),
229                                32*1024, (1L<<34));
230         if (!sgtable)
231                 panic("apecs_init_sgmap: can't allocate page table");
232         REGVAL(EPIC_TBASE_1) =
233                 (pmap_kextract((vm_offset_t) sgtable) >> EPIC_TBASE_SHIFT);
234
235         chipset.sgmap = sgmap_map_create(APECS_SGMAP_BASE,
236                                          APECS_SGMAP_BASE + APECS_SGMAP_SIZE,
237                                          apecs_sgmap_map, sgtable);
238 }
239
240 void
241 apecs_init()
242 {
243         static int initted = 0;
244         static struct swiz_space io_space, mem_space;
245
246         if (initted) return;
247         initted = 1;
248
249         swiz_init_space(&io_space, KV(APECS_PCI_SIO));
250         swiz_init_space_hae(&mem_space, KV(APECS_PCI_SPARSE),
251                             apecs_set_hae_mem, 0);
252
253         busspace_isa_io = (struct alpha_busspace *) &io_space;
254         busspace_isa_mem = (struct alpha_busspace *) &mem_space;
255
256         chipset = apecs_swiz_chipset;
257
258         if (platform.pci_intr_init)
259                 platform.pci_intr_init();
260
261 }
262
263 static int
264 apecs_probe(device_t dev)
265 {
266         int memwidth;
267         if (apecs0)
268                 return ENXIO;
269         apecs0 = dev;
270         memwidth = (REGVAL(COMANCHE_GCR) & COMANCHE_GCR_WIDEMEM) != 0 ? 128 : 64;
271         if(memwidth == 64){
272                 device_set_desc(dev, "DECchip 21071 Core Logic chipset");
273         } else {
274                 device_set_desc(dev, "DECchip 21072 Core Logic chipset");
275         }
276         apecs_hae_mem = REGVAL(EPIC_HAXR1);
277
278         isa_init_intr();
279         apecs_init_sgmap();
280
281         device_add_child(dev, "pcib", 0);
282
283         return 0;
284 }
285
286 static int
287 apecs_attach(device_t dev)
288 {
289         struct apecs_softc* sc = APECS_SOFTC(dev);
290         apecs_init();
291
292         sc->dmem_base = APECS_PCI_DENSE;
293         sc->smem_base = APECS_PCI_SPARSE;
294         sc->io_base = APECS_PCI_SIO;
295         sc->cfg0_base = KV(APECS_PCI_CONF);
296         sc->cfg1_base = 0;
297
298         set_iointr(alpha_dispatch_intr);
299
300         snprintf(chipset_type, sizeof(chipset_type), "apecs");
301         chipset_bwx = 0;
302         chipset_ports = APECS_PCI_SIO;
303         chipset_memory = APECS_PCI_SPARSE;
304         chipset_dense = APECS_PCI_DENSE;
305         chipset_hae_mask = EPIC_HAXR1_EADDR;
306
307         bus_generic_attach(dev);
308         return 0;
309 }
310
311 static void
312 apecs_disable_intr(uintptr_t vector)
313 {
314         int irq;
315
316         irq = (vector - 0x900) >> 4;
317         mtx_lock_spin(&icu_lock);
318         platform.pci_intr_disable(irq);
319         mtx_unlock_spin(&icu_lock);
320 }
321
322 static void
323 apecs_enable_intr(uintptr_t vector)
324 {
325         int irq;
326
327         irq = (vector - 0x900) >> 4;
328         mtx_lock_spin(&icu_lock);
329         platform.pci_intr_enable(irq);
330         mtx_unlock_spin(&icu_lock);
331 }
332
333 static int
334 apecs_setup_intr(device_t dev, device_t child,
335                struct resource *irq, int flags,
336                driver_intr_t *intr, void *arg, void **cookiep)
337 {
338         int error;
339         
340         /* 
341          *  the avanti routes interrupts through the isa interrupt
342          *  controller, so we need to special case it 
343          */
344         if(hwrpb->rpb_type == ST_DEC_2100_A50)
345                 return isa_setup_intr(dev, child, irq, flags,
346                                       intr, arg, cookiep);
347
348         error = rman_activate_resource(irq);
349         if (error)
350                 return error;
351
352         error = alpha_setup_intr(device_get_nameunit(child ? child : dev),
353                         0x900 + (irq->r_start << 4), intr, arg, flags, cookiep,
354                         &intrcnt[INTRCNT_EB64PLUS_IRQ + irq->r_start],
355                         apecs_disable_intr, apecs_enable_intr);
356         if (error)
357                 return error;
358
359         /* Enable PCI interrupt */
360         mtx_lock_spin(&icu_lock);
361         platform.pci_intr_enable(irq->r_start);
362         mtx_unlock_spin(&icu_lock);
363
364         device_printf(child, "interrupting at APECS irq %d\n",
365                       (int) irq->r_start);
366
367
368         return 0;
369 }
370
371 static int
372 apecs_teardown_intr(device_t dev, device_t child,
373                   struct resource *irq, void *cookie)
374 {
375         /* 
376          *  the avanti routes interrupts through the isa interrupt
377          *  controller, so we need to special case it 
378          */
379         if(hwrpb->rpb_type == ST_DEC_2100_A50)
380                 return isa_teardown_intr(dev, child, irq, cookie);
381
382         alpha_teardown_intr(cookie);
383         return rman_deactivate_resource(irq);
384 }
385
386 DRIVER_MODULE(apecs, root, apecs_driver, apecs_devclass, 0, 0);
387