pci_6600.c revision 1.28 1 /* $NetBSD: pci_6600.c,v 1.28 2020/09/26 02:50:41 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1999 by Ross Harvey. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Ross Harvey.
17 * 4. The name of Ross Harvey may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY ROSS HARVEY ``AS IS'' AND ANY EXPRESS
21 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURP0SE
23 * ARE DISCLAIMED. IN NO EVENT SHALL ROSS HARVEY BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33
34 #include <sys/cdefs.h>
35
36 __KERNEL_RCSID(0, "$NetBSD: pci_6600.c,v 1.28 2020/09/26 02:50:41 thorpej Exp $");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/device.h>
42 #include <sys/malloc.h>
43 #include <sys/cpu.h>
44
45 #include <machine/autoconf.h>
46 #define _ALPHA_BUS_DMA_PRIVATE
47 #include <sys/bus.h>
48 #include <machine/rpb.h>
49 #include <machine/alpha.h>
50
51 #include <dev/pci/pcireg.h>
52 #include <dev/pci/pcivar.h>
53 #include <dev/pci/pciidereg.h>
54 #include <dev/pci/pciidevar.h>
55
56 #include <alpha/pci/tsreg.h>
57 #include <alpha/pci/tsvar.h>
58 #include <alpha/pci/pci_6600.h>
59
60 #define pci_6600() { Generate ctags(1) key. }
61
62 #include "sio.h"
63 #if NSIO
64 #include <alpha/pci/siovar.h>
65 #endif
66
67 #define PCI_NIRQ 64
68 #define PCI_SIO_IRQ 55
69 #define PCI_STRAY_MAX 5
70
71 /*
72 * Some Tsunami models have a PCI device (the USB controller) with interrupts
73 * tied to ISA IRQ lines. The IRQ is encoded as:
74 *
75 * line = 0xe0 | isa_irq;
76 */
77 #define DEC_6600_LINE_IS_ISA(line) ((line) >= 0xe0 && (line) <= 0xef)
78 #define DEC_6600_LINE_ISA_IRQ(line) ((line) & 0x0f)
79
80 static struct tsp_config *sioprimary;
81
82 static void dec_6600_intr_disestablish(pci_chipset_tag_t, void *);
83 static void *dec_6600_intr_establish(pci_chipset_tag_t, pci_intr_handle_t,
84 int, int (*func)(void *), void *);
85 static const char *dec_6600_intr_string(pci_chipset_tag_t, pci_intr_handle_t,
86 char *, size_t);
87 static const struct evcnt *dec_6600_intr_evcnt(pci_chipset_tag_t,
88 pci_intr_handle_t);
89 static int dec_6600_intr_map(const struct pci_attach_args *,
90 pci_intr_handle_t *);
91
92 static void *dec_6600_pciide_compat_intr_establish(device_t,
93 const struct pci_attach_args *, int,
94 int (*)(void *), void *);
95
96 static void dec_6600_intr_enable(pci_chipset_tag_t, int irq);
97 static void dec_6600_intr_disable(pci_chipset_tag_t, int irq);
98 static void dec_6600_intr_set_affinity(pci_chipset_tag_t, int,
99 struct cpu_info *);
100
101 /*
102 * We keep 2 software copies of the interrupt enables: one global one,
103 * and one per-CPU for setting the interrupt affinity.
104 */
105 static uint64_t dec_6600_intr_enables __read_mostly;
106 static uint64_t dec_6600_cpu_intr_enables[4] __read_mostly;
107
108 void
109 pci_6600_pickintr(struct tsp_config *pcp)
110 {
111 bus_space_tag_t iot = &pcp->pc_iot;
112 pci_chipset_tag_t pc = &pcp->pc_pc;
113 char *cp;
114 int i;
115 struct cpu_info *ci;
116 CPU_INFO_ITERATOR cii;
117
118 pc->pc_intr_v = pcp;
119 pc->pc_intr_map = dec_6600_intr_map;
120 pc->pc_intr_string = dec_6600_intr_string;
121 pc->pc_intr_evcnt = dec_6600_intr_evcnt;
122 pc->pc_intr_establish = dec_6600_intr_establish;
123 pc->pc_intr_disestablish = dec_6600_intr_disestablish;
124
125 pc->pc_pciide_compat_intr_establish = NULL;
126
127 pc->pc_intr_desc = "dec 6600 irq";
128 pc->pc_vecbase = 0x900;
129 pc->pc_nirq = PCI_NIRQ;
130
131 pc->pc_intr_enable = dec_6600_intr_enable;
132 pc->pc_intr_disable = dec_6600_intr_disable;
133 pc->pc_intr_set_affinity = dec_6600_intr_set_affinity;
134
135 /* Note eligible CPUs for interrupt routing purposes. */
136 for (CPU_INFO_FOREACH(cii, ci)) {
137 KASSERT(ci->ci_cpuid < 4);
138 pc->pc_eligible_cpus |= __BIT(ci->ci_cpuid);
139 }
140
141 /*
142 * System-wide and Pchip-0-only logic...
143 */
144 if (sioprimary == NULL) {
145 sioprimary = pcp;
146 /*
147 * Unless explicitly routed, all interrupts go to the
148 * primary CPU.
149 */
150 dec_6600_cpu_intr_enables[cpu_info_primary.ci_cpuid] =
151 __BITS(0,63);
152 pc->pc_pciide_compat_intr_establish =
153 dec_6600_pciide_compat_intr_establish;
154 #define PCI_6600_IRQ_STR 8
155 pc->pc_shared_intrs = alpha_shared_intr_alloc(PCI_NIRQ,
156 PCI_6600_IRQ_STR);
157 for (i = 0; i < PCI_NIRQ; i++) {
158 alpha_shared_intr_set_maxstrays(pc->pc_shared_intrs, i,
159 PCI_STRAY_MAX);
160 alpha_shared_intr_set_private(pc->pc_shared_intrs, i,
161 sioprimary);
162
163 cp = alpha_shared_intr_string(pc->pc_shared_intrs, i);
164 snprintf(cp, PCI_6600_IRQ_STR, "irq %d", i);
165 evcnt_attach_dynamic(alpha_shared_intr_evcnt(
166 pc->pc_shared_intrs, i), EVCNT_TYPE_INTR, NULL,
167 "dec 6600", cp);
168 }
169 #if NSIO
170 sio_intr_setup(pc, iot);
171
172 mutex_enter(&cpu_lock);
173 dec_6600_intr_enable(pc, PCI_SIO_IRQ);
174 mutex_exit(&cpu_lock);
175 #endif
176 } else {
177 pc->pc_shared_intrs = sioprimary->pc_pc.pc_shared_intrs;
178 }
179 }
180
181 static int
182 dec_6600_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
183 {
184 pcitag_t bustag = pa->pa_intrtag;
185 int buspin = pa->pa_intrpin, line = pa->pa_intrline;
186 pci_chipset_tag_t pc = pa->pa_pc;
187 int bus, device, function;
188
189 if (buspin == 0) {
190 /* No IRQ used. */
191 return 1;
192 }
193 if (buspin < 0 || buspin > 4) {
194 printf("intr_map: bad interrupt pin %d\n", buspin);
195 return 1;
196 }
197
198 pci_decompose_tag(pc, bustag, &bus, &device, &function);
199
200 /*
201 * The console places the interrupt mapping in the "line" value.
202 * A value of (char)-1 indicates there is no mapping.
203 */
204 if (line == 0xff) {
205 printf("dec_6600_intr_map: no mapping for %d/%d/%d\n",
206 bus, device, function);
207 return (1);
208 }
209
210 #if NSIO == 0
211 if (DEC_6600_LINE_IS_ISA(line)) {
212 printf("dec_6600_intr_map: ISA IRQ %d for %d/%d/%d\n",
213 DEC_6600_LINE_ISA_IRQ(line), bus, device, function);
214 return (1);
215 }
216 #endif
217
218 if (DEC_6600_LINE_IS_ISA(line) == 0 && line >= PCI_NIRQ)
219 panic("dec_6600_intr_map: dec 6600 irq too large (%d)",
220 line);
221
222 alpha_pci_intr_handle_init(ihp, line, 0);
223 return (0);
224 }
225
226 static const char *
227 dec_6600_intr_string(pci_chipset_tag_t const pc, pci_intr_handle_t const ih,
228 char * const buf, size_t const len)
229 {
230 #if NSIO
231 const u_int irq = alpha_pci_intr_handle_get_irq(&ih);
232
233 if (DEC_6600_LINE_IS_ISA(irq))
234 return (sio_intr_string(NULL /*XXX*/,
235 DEC_6600_LINE_ISA_IRQ(irq), buf, len));
236 #endif
237
238 return alpha_pci_generic_intr_string(pc, ih, buf, len);
239 }
240
241 static const struct evcnt *
242 dec_6600_intr_evcnt(pci_chipset_tag_t const pc, pci_intr_handle_t const ih)
243 {
244 #if NSIO
245 const u_int irq = alpha_pci_intr_handle_get_irq(&ih);
246
247 if (DEC_6600_LINE_IS_ISA(irq))
248 return (sio_intr_evcnt(NULL /*XXX*/,
249 DEC_6600_LINE_ISA_IRQ(irq)));
250 #endif
251
252 return alpha_pci_generic_intr_evcnt(pc, ih);
253 }
254
255 static void *
256 dec_6600_intr_establish(pci_chipset_tag_t const pc, pci_intr_handle_t const ih,
257 int const level, int (*func)(void *), void *arg)
258 {
259 #if NSIO
260 const u_int irq = alpha_pci_intr_handle_get_irq(&ih);
261 const u_int flags = alpha_pci_intr_handle_get_flags(&ih);
262
263 if (DEC_6600_LINE_IS_ISA(irq))
264 return (sio_intr_establish(NULL /*XXX*/,
265 DEC_6600_LINE_ISA_IRQ(irq), IST_LEVEL, level, flags,
266 func, arg));
267 #endif
268
269 return alpha_pci_generic_intr_establish(pc, ih, level, func, arg);
270 }
271
272 static void
273 dec_6600_intr_disestablish(pci_chipset_tag_t const pc, void * const cookie)
274 {
275 #if NSIO
276 struct alpha_shared_intrhand * const ih = cookie;
277
278 /*
279 * We have to determine if this is an ISA IRQ or not! We do this
280 * by checking to see if the intrhand points back to an intrhead
281 * that points to the sioprimary TSP. If not, it's an ISA IRQ.
282 * Pretty disgusting, eh?
283 */
284 if (ih->ih_intrhead->intr_private != sioprimary) {
285 sio_intr_disestablish(NULL /*XXX*/, cookie);
286 return;
287 }
288 #endif
289
290 return alpha_pci_generic_intr_disestablish(pc, cookie);
291 }
292
293 static void
294 dec_6600_intr_program(pci_chipset_tag_t const pc)
295 {
296 unsigned int irq, cpuno, cnt;
297
298 /*
299 * Validate the configuration before we program it: each enabled
300 * IRQ must be routed to exactly one CPU.
301 */
302 for (irq = 0; irq < PCI_NIRQ; irq++) {
303 if ((dec_6600_intr_enables & __BIT(irq)) == 0)
304 continue;
305 for (cpuno = 0, cnt = 0; cpuno < 4; cpuno++) {
306 if (dec_6600_cpu_intr_enables[cpuno] != 0 &&
307 (pc->pc_eligible_cpus & __BIT(cpuno)) == 0)
308 panic("%s: interrupts enabled on non-existent CPU %u",
309 __func__, cpuno);
310 if (dec_6600_cpu_intr_enables[cpuno] & __BIT(irq))
311 cnt++;
312 }
313 if (cnt != 1) {
314 panic("%s: irq %u enabled on %u CPUs", __func__,
315 irq, cnt);
316 }
317 }
318
319 const uint64_t enab0 =
320 dec_6600_intr_enables & dec_6600_cpu_intr_enables[0];
321 const uint64_t enab1 =
322 dec_6600_intr_enables & dec_6600_cpu_intr_enables[1];
323 const uint64_t enab2 =
324 dec_6600_intr_enables & dec_6600_cpu_intr_enables[2];
325 const uint64_t enab3 =
326 dec_6600_intr_enables & dec_6600_cpu_intr_enables[3];
327
328 /* Don't touch DIMx registers for non-existent CPUs. */
329 uint64_t black_hole;
330 volatile uint64_t * const dim0 = (pc->pc_eligible_cpus & __BIT(0)) ?
331 (void *)ALPHA_PHYS_TO_K0SEG(TS_C_DIM0) : &black_hole;
332 volatile uint64_t * const dim1 = (pc->pc_eligible_cpus & __BIT(1)) ?
333 (void *)ALPHA_PHYS_TO_K0SEG(TS_C_DIM1) : &black_hole;
334 volatile uint64_t * const dim2 = (pc->pc_eligible_cpus & __BIT(2)) ?
335 (void *)ALPHA_PHYS_TO_K0SEG(TS_C_DIM2) : &black_hole;
336 volatile uint64_t * const dim3 = (pc->pc_eligible_cpus & __BIT(3)) ?
337 (void *)ALPHA_PHYS_TO_K0SEG(TS_C_DIM3) : &black_hole;
338
339 const unsigned long psl = alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH);
340
341 alpha_mb();
342 *dim0 = enab0;
343 *dim1 = enab1;
344 *dim2 = enab2;
345 *dim3 = enab3;
346 alpha_mb();
347 (void) *dim0;
348 (void) *dim1;
349 (void) *dim2;
350 (void) *dim3;
351 alpha_mb();
352
353 alpha_pal_swpipl(psl);
354 }
355
356 static void
357 dec_6600_intr_enable(pci_chipset_tag_t const pc, int const irq)
358 {
359
360 KASSERT(mutex_owned(&cpu_lock));
361
362 dec_6600_intr_enables |= __BIT(irq);
363 dec_6600_intr_program(pc);
364 }
365
366 static void
367 dec_6600_intr_disable(pci_chipset_tag_t const pc, int const irq)
368 {
369
370 KASSERT(mutex_owned(&cpu_lock));
371
372 dec_6600_intr_enables &= ~__BIT(irq);
373 dec_6600_intr_program(pc);
374 }
375
376 static void
377 dec_6600_intr_set_affinity(pci_chipset_tag_t const pc, int const irq,
378 struct cpu_info * const ci)
379 {
380 const uint64_t intr_bit = __BIT(irq);
381 cpuid_t cpuno;
382
383 KASSERT(mutex_owned(&cpu_lock));
384 KASSERT(ci->ci_cpuid < 4);
385 KASSERT(pc->pc_eligible_cpus & __BIT(ci->ci_cpuid));
386
387 for (cpuno = 0; cpuno < 4; cpuno++) {
388 if (cpuno == ci->ci_cpuid)
389 dec_6600_cpu_intr_enables[cpuno] |= intr_bit;
390 else
391 dec_6600_cpu_intr_enables[cpuno] &= ~intr_bit;
392 }
393
394 /* Only program the hardware if the irq is enabled. */
395 if (dec_6600_intr_enables & intr_bit)
396 dec_6600_intr_program(pc);
397 }
398
399 static void *
400 dec_6600_pciide_compat_intr_establish(device_t dev,
401 const struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg)
402 {
403 pci_chipset_tag_t const pc = pa->pa_pc;
404
405 /*
406 * If this isn't the TSP that holds the PCI-ISA bridge,
407 * all bets are off.
408 */
409 if (pc->pc_intr_v != sioprimary)
410 return (NULL);
411
412 return sio_pciide_compat_intr_establish(dev, pa, chan, func, arg);
413 }
414