1 /*        $NetBSD: mainbus.c,v 1.32 2021/08/07 16:19:01 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 2007 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Tim Rightnour
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.32 2021/08/07 16:19:01 thorpej Exp $");
34 
35 #include "opt_interrupt.h"
36 #include "opt_multiprocessor.h"
37 
38 #include <sys/param.h>
39 #include <sys/device.h>
40 #include <sys/systm.h>
41 
42 #include <dev/pci/pcivar.h>
43 #include <dev/ofw/openfirm.h>
44 #include <dev/ofw/ofw_pci.h>
45 #include <arch/powerpc/pic/picvar.h>
46 #ifdef MULTIPROCESSOR
47 #include <arch/powerpc/pic/ipivar.h>
48 #endif
49 #include <machine/pci_machdep.h>
50 #include <machine/autoconf.h>
51 
52 #include <dev/isa/isareg.h>
53 #include <dev/isa/isavar.h>
54 
55 int       mainbus_match(device_t, cfdata_t, void *);
56 void      mainbus_attach(device_t, device_t, void *);
57 
58 CFATTACH_DECL_NEW(mainbus, 0,
59     mainbus_match, mainbus_attach, NULL, NULL);
60 
61 int mainbus_found = 0;
62 struct pic_ops *isa_pic;
63 
64 #ifdef PIC_PREPIVR
65 vaddr_t prep_intr_reg;
66 uint32_t prep_intr_reg_off;
67 #endif
68 
69 extern ofw_pic_node_t picnodes[8];
70 extern int nrofpics;
71 extern int primary_pic;
72 
73 #ifdef PIC_PREPIVR
74 static struct pic_ops *
init_prepivr(int node)75 init_prepivr(int node)
76 {
77           int pcinode;
78           uint32_t ivr;
79 
80           pcinode = OF_finddevice("/pci");
81           if (OF_getprop(pcinode, "8259-interrupt-acknowledge", &ivr,
82                     sizeof(ivr)) != sizeof(ivr)) {
83                     aprint_error("Incorrectly identified i8259 as prepivr\n");
84                     return setup_i8259();
85           }
86           prep_intr_reg = (vaddr_t)mapiodev(ivr, sizeof(uint32_t), false);
87           prep_intr_reg_off = 0; /* hack */
88           if (!prep_intr_reg)
89                     panic("startup: no room for interrupt register");
90 
91           return setup_prepivr(PIC_IVR_MOT);
92 }
93 #endif
94 
95 static int
init_openpic(int node)96 init_openpic(int node)
97 {
98           struct ofw_pci_register aadr;
99           struct ranges {
100                     uint32_t pci_hi, pci_mid, pci_lo;
101                     uint32_t host;
102                     uint32_t size_hi, size_lo;
103           } ranges[6];
104           uint32_t reg[12];
105           int parent, len;
106 #if defined(PIC_OPENPIC) || defined(PIC_DISTOPENPIC)
107           unsigned char *baseaddr;
108 #endif
109 #ifdef PIC_OPENPIC
110           struct ranges *rp = ranges;
111 #endif
112 #ifdef PIC_DISTOPENPIC
113           unsigned char *isu[OPENPIC_MAX_ISUS];
114           int i, j;
115           int isumap[OPENPIC_MAX_ISUS];
116 #endif
117 
118           if (OF_getprop(node, "assigned-addresses", &aadr, sizeof(aadr))
119               != sizeof(aadr))
120                     goto noaadr;
121 
122           parent = OF_parent(node);
123           len = OF_getprop(parent, "ranges", ranges, sizeof(ranges));
124           if (len == -1)
125                     goto noaadr;
126 
127 #ifdef PIC_OPENPIC
128           while (len >= sizeof(ranges[0])) {
129                     if ((rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) ==
130                         (aadr.phys_hi & OFW_PCI_PHYS_HI_SPACEMASK) &&
131                         (aadr.size_lo + aadr.phys_lo <= (rp->size_lo+rp->host))) {
132                               baseaddr = (unsigned char *)mapiodev(
133                                   rp->host | aadr.phys_lo, aadr.size_lo, false);
134                               aprint_normal("Found openpic at %08x\n",
135                                   rp->host | aadr.phys_lo);
136                               setup_openpic(baseaddr, 0);
137 #ifdef MULTIPROCESSOR
138                               setup_openpic_ipi();
139                               ipiops.ppc_establish_ipi(IST_LEVEL, IPL_HIGH, NULL);
140                               for (i=1; i < ncpu; i++) {
141                                         aprint_verbose("Enabling interrupts "
142                                             "for cpu%d\n", i);
143                                         openpic_set_priority(i, 0);
144                               }
145 #endif
146                               return TRUE;
147                     }
148                     rp++;
149                     len -= sizeof(ranges[0]);
150           }
151 #endif
152           return FALSE;
153  noaadr:
154           /* this isn't a PCI-attached openpic */
155           len = OF_getprop(node, "reg", &reg, sizeof(reg));
156           if (len < sizeof(int)*2)
157                     return FALSE;
158 
159           if (len == sizeof(int)*2) {
160                     aprint_verbose("Found openpic at %08x\n", reg[0]);
161 #ifdef PIC_OPENPIC
162                     baseaddr = (unsigned char *)mapiodev(reg[0], reg[1], false);
163                     (void)setup_openpic(baseaddr, 0);
164 #ifdef MULTIPROCESSOR
165                     setup_openpic_ipi();
166                     ipiops.ppc_establish_ipi(IST_LEVEL, IPL_HIGH, NULL);
167                     for (i=1; i < ncpu; i++) {
168                               aprint_verbose("Enabling interrupts for cpu%d\n", i);
169                               openpic_set_priority(i, 0);
170                     }
171 #endif
172                     return TRUE;
173 #else
174                     aprint_error("No openpic support compiled into kernel!");
175                     return FALSE;
176 #endif
177           }
178 
179 #ifdef PIC_DISTOPENPIC
180           /* otherwise, we have a distributed openpic */
181           i = len/(sizeof(int)*2) - 1;
182           if (i == 0)
183                     return FALSE;
184           if (i > OPENPIC_MAX_ISUS)
185                     aprint_error("Increase OPENPIC_MAX_ISUS to %d\n", i);
186 
187           baseaddr = (unsigned char *)mapiodev(reg[0], 0x40000, false);
188           aprint_verbose("Found openpic at %08x\n", reg[0]);
189 
190           for (j=0; j < i; j++) {
191                     isu[j] = (unsigned char *)mapiodev(reg[(j+1)*2],
192                         reg[(j+1)*2+1], false);
193                     isumap[j] = reg[(j+1)*2+1];
194           }
195           (void)setup_distributed_openpic(baseaddr, i, (void **)isu, isumap);
196 #ifdef MULTIPROCESSOR
197           setup_openpic_ipi();
198           ipiops.ppc_establish_ipi(IST_LEVEL, IPL_HIGH, NULL);
199           for (i=1; i < ncpu; i++) {
200                     aprint_verbose("Enabling interrupts for cpu%d\n", i);
201                     openpic_set_priority(i, 0);
202           }
203 #endif
204           return TRUE;
205 #endif
206           aprint_error("PIC support not present or PIC error\n");
207           return FALSE;
208 }
209 
210 
211 /*
212  * Probe for the mainbus; always succeeds.
213  */
214 int
mainbus_match(device_t parent,cfdata_t cf,void * aux)215 mainbus_match(device_t parent, cfdata_t cf, void *aux)
216 {
217           if (mainbus_found)
218                     return 0;
219           return 1;
220 }
221 
222 /*
223  * Attach the mainbus.
224  */
225 void
mainbus_attach(device_t parent,device_t self,void * aux)226 mainbus_attach(device_t parent, device_t self, void *aux)
227 {
228           struct ofbus_attach_args oba;
229           struct confargs ca;
230           int node, rtnode, i;
231           u_int32_t reg[4];
232           char name[32];
233 
234           mainbus_found = 1;
235 
236           aprint_normal("\n");
237 
238           /* Find rtas first */
239           rtnode = OF_finddevice("/rtas");
240           if (rtnode != -1) {
241                     memset(name, 0, sizeof(name));
242                     if (OF_getprop(rtnode, "name", name, sizeof(name)) != -1) {
243                               ca.ca_name = name;
244                               ca.ca_node = rtnode;
245                               ca.ca_nreg = OF_getprop(rtnode, "reg", reg,
246                                   sizeof(reg));
247                               ca.ca_reg  = reg;
248                               config_found(self, &ca, NULL, CFARGS_NONE);
249                     }
250           }
251 
252           /* Now find CPU's */
253           for (i = 0; i < CPU_MAXNUM; i++) {
254                     ca.ca_name = "cpu";
255                     ca.ca_reg = reg;
256                     reg[0] = i;
257                     config_found(self, &ca, NULL, CFARGS_NONE);
258           }
259 
260           node = OF_peer(0);
261           if (node) {
262                     oba.oba_busname = "ofw";
263                     oba.oba_phandle = node;
264                     config_found(self, &oba, NULL, CFARGS_NONE);
265           }
266 
267           if (strcmp(model_name, "Pegasos2") == 0) {
268                     /*
269                      * Configure to System Controller MV64361.
270                      * And skip other devices.  These attached from it.
271                      */
272                     ca.ca_name = "gt";
273 
274                     config_found(self, &ca, NULL, CFARGS_NONE);
275 
276                     goto config_fin;
277           }
278 
279           /* this primarily searches for pci bridges on the root bus */
280           for (node = OF_child(OF_finddevice("/")); node; node = OF_peer(node)) {
281                     memset(name, 0, sizeof(name));
282                     if (OF_getprop(node, "name", name, sizeof(name)) == -1)
283                               continue;
284                     /* skip rtas */
285                     if (node == rtnode)
286                               continue;
287 
288                     ca.ca_name = name;
289                     ca.ca_node = node;
290                     ca.ca_nreg = OF_getprop(node, "reg", reg, sizeof(reg));
291                     ca.ca_reg  = reg;
292 
293                     config_found(self, &ca, NULL, CFARGS_NONE);
294           }
295 
296 config_fin:
297           pic_finish_setup();
298 }
299 
300 void
init_interrupt(void)301 init_interrupt(void)
302 {
303           /* Do nothing, not ready yet */
304 }
305 
306 void
init_ofppc_interrupt(void)307 init_ofppc_interrupt(void)
308 {
309           int node, i, isa_cascade = 0;
310 
311           /* Now setup the PIC's */
312           node = OF_finddevice("/");
313           if (node <= 0)
314                     panic("Can't find root OFW device node\n");
315           genofw_find_ofpics(node);
316           genofw_fixup_picnode_offsets();
317           pic_init();
318 
319           /* find ISA first */
320           for (i = 0; i < nrofpics; i++) {
321                     if (picnodes[i].type == PICNODE_TYPE_8259) {
322                               aprint_debug("calling i8259 setup\n");
323                               isa_pic = setup_i8259();
324                     }
325                     if (picnodes[i].type == PICNODE_TYPE_IVR) {
326                               aprint_debug("calling prepivr setup\n");
327 #ifdef PIC_PREPIVR
328                               isa_pic = init_prepivr(picnodes[i].node);
329 #else
330                               isa_pic = setup_i8259();
331 #endif
332                     }
333           }
334           for (i = 0; i < nrofpics; i++) {
335                     if (picnodes[i].type == PICNODE_TYPE_8259)
336                               continue;
337                     if (picnodes[i].type == PICNODE_TYPE_IVR)
338                               continue;
339                     if (picnodes[i].type == PICNODE_TYPE_OPENPIC) {
340                               aprint_debug("calling openpic setup\n");
341                               if (isa_pic != NULL)
342                                         isa_cascade = 1;
343                               (void)init_openpic(picnodes[i].node);
344                     } else
345                               aprint_error("Unhandled pic node type node=%x\n",
346                                   picnodes[i].node);
347           }
348           if (isa_cascade) {
349                     primary_pic = 1;
350                     intr_establish(16, IST_LEVEL, IPL_HIGH, pic_handle_intr,
351                         isa_pic);
352           }
353 }
354