1 /* $NetBSD: pci_kn20aa.c,v 1.59 2021/07/04 22:42:36 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1995, 1996 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@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/cdefs.h> /* RCS ID & Copyright macro defns */
31
32 __KERNEL_RCSID(0, "$NetBSD: pci_kn20aa.c,v 1.59 2021/07/04 22:42:36 thorpej Exp $");
33
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/time.h>
37 #include <sys/systm.h>
38 #include <sys/errno.h>
39 #include <sys/device.h>
40 #include <sys/syslog.h>
41
42 #include <machine/autoconf.h>
43 #include <machine/rpb.h>
44
45 #include <dev/pci/pcireg.h>
46 #include <dev/pci/pcivar.h>
47
48 #include <alpha/pci/ciareg.h>
49 #include <alpha/pci/ciavar.h>
50
51 #include "sio.h"
52 #if NSIO > 0 || NPCEB > 0
53 #include <alpha/pci/siovar.h>
54 #endif
55
56 static int dec_kn20aa_intr_map(const struct pci_attach_args *,
57 pci_intr_handle_t *);
58
59 #define KN20AA_PCEB_IRQ 31
60 #define KN20AA_MAX_IRQ 32
61 #define PCI_STRAY_MAX 5
62
63 static void kn20aa_enable_intr(pci_chipset_tag_t pc, int irq);
64 static void kn20aa_disable_intr(pci_chipset_tag_t pc, int irq);
65
66 static void
pci_kn20aa_pickintr(void * core,bus_space_tag_t iot,bus_space_tag_t memt,pci_chipset_tag_t pc)67 pci_kn20aa_pickintr(void *core, bus_space_tag_t iot, bus_space_tag_t memt,
68 pci_chipset_tag_t pc)
69 {
70 int i;
71
72 pc->pc_intr_v = core;
73 pc->pc_intr_map = dec_kn20aa_intr_map;
74 pc->pc_intr_string = alpha_pci_generic_intr_string;
75 pc->pc_intr_evcnt = alpha_pci_generic_intr_evcnt;
76 pc->pc_intr_establish = alpha_pci_generic_intr_establish;
77 pc->pc_intr_disestablish = alpha_pci_generic_intr_disestablish;
78
79 /* Not supported on KN20AA. */
80 pc->pc_pciide_compat_intr_establish = NULL;
81
82 pc->pc_intr_desc = "kn20aa";
83 pc->pc_vecbase = 0x900;
84 pc->pc_nirq = KN20AA_MAX_IRQ;
85
86 pc->pc_intr_enable = kn20aa_enable_intr;
87 pc->pc_intr_disable = kn20aa_disable_intr;
88
89 for (i = 0; i < KN20AA_MAX_IRQ; i++) {
90 kn20aa_disable_intr(pc, i);
91 }
92
93 alpha_pci_intr_alloc(pc, PCI_STRAY_MAX);
94
95 #if NSIO > 0 || NPCEB > 0
96 sio_intr_setup(pc, iot);
97 kn20aa_enable_intr(pc, KN20AA_PCEB_IRQ);
98 #endif
99 }
ALPHA_PCI_INTR_INIT(ST_DEC_KN20AA,pci_kn20aa_pickintr)100 ALPHA_PCI_INTR_INIT(ST_DEC_KN20AA, pci_kn20aa_pickintr)
101
102 static int
103 dec_kn20aa_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
104 {
105 pcitag_t bustag = pa->pa_intrtag;
106 int buspin = pa->pa_intrpin;
107 pci_chipset_tag_t pc = pa->pa_pc;
108 int device;
109 int kn20aa_irq;
110
111 if (buspin == 0) {
112 /* No IRQ used. */
113 return 1;
114 }
115 if (buspin < 0 || buspin > 4) {
116 printf("dec_kn20aa_intr_map: bad interrupt pin %d\n", buspin);
117 return 1;
118 }
119
120 /*
121 * Slot->interrupt translation. Appears to work, though it
122 * may not hold up forever.
123 *
124 * The DEC engineers who did this hardware obviously engaged
125 * in random drug testing.
126 */
127 pci_decompose_tag(pc, bustag, NULL, &device, NULL);
128 switch (device) {
129 case 11:
130 case 12:
131 kn20aa_irq = ((device - 11) + 0) * 4;
132 break;
133
134 case 7:
135 kn20aa_irq = 8;
136 break;
137
138 case 9:
139 kn20aa_irq = 12;
140 break;
141
142 case 6: /* 21040 on AlphaStation 500 */
143 kn20aa_irq = 13;
144 break;
145
146 case 8:
147 kn20aa_irq = 16;
148 break;
149
150 default:
151 printf("dec_kn20aa_intr_map: weird device number %d\n",
152 device);
153 return 1;
154 }
155
156 kn20aa_irq += buspin - 1;
157 if (kn20aa_irq > KN20AA_MAX_IRQ)
158 panic("dec_kn20aa_intr_map: kn20aa_irq too large (%d)",
159 kn20aa_irq);
160
161 alpha_pci_intr_handle_init(ihp, kn20aa_irq, 0);
162 return (0);
163 }
164
165 static void
kn20aa_enable_intr(pci_chipset_tag_t pc __unused,int irq)166 kn20aa_enable_intr(pci_chipset_tag_t pc __unused, int irq)
167 {
168
169 /*
170 * From disassembling small bits of the OSF/1 kernel:
171 * the following appears to enable a given interrupt request.
172 * "blech." I'd give valuable body parts for better docs or
173 * for a good decompiler.
174 */
175 alpha_mb();
176 REGVAL(0x8780000000L + 0x40L) |= (1 << irq); /* XXX */
177 alpha_mb();
178 }
179
180 static void
kn20aa_disable_intr(pci_chipset_tag_t pc __unused,int irq)181 kn20aa_disable_intr(pci_chipset_tag_t pc __unused, int irq)
182 {
183
184 alpha_mb();
185 REGVAL(0x8780000000L + 0x40L) &= ~(1 << irq); /* XXX */
186 alpha_mb();
187 }
188