1*08790245Sthorpej /* $NetBSD: pq3pci.c,v 1.32 2022/07/22 19:55:38 thorpej Exp $ */
2b8ea2c8cSmatt /*-
3b8ea2c8cSmatt * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
4b8ea2c8cSmatt * All rights reserved.
5b8ea2c8cSmatt *
6b8ea2c8cSmatt * This code is derived from software contributed to The NetBSD Foundation
7b8ea2c8cSmatt * by Raytheon BBN Technologies Corp and Defense Advanced Research Projects
8b8ea2c8cSmatt * Agency and which was developed by Matt Thomas of 3am Software Foundry.
9b8ea2c8cSmatt *
10b8ea2c8cSmatt * This material is based upon work supported by the Defense Advanced Research
11b8ea2c8cSmatt * Projects Agency and Space and Naval Warfare Systems Center, Pacific, under
12b8ea2c8cSmatt * Contract No. N66001-09-C-2073.
13b8ea2c8cSmatt * Approved for Public Release, Distribution Unlimited
14b8ea2c8cSmatt *
15b8ea2c8cSmatt * Redistribution and use in source and binary forms, with or without
16b8ea2c8cSmatt * modification, are permitted provided that the following conditions
17b8ea2c8cSmatt * are met:
18b8ea2c8cSmatt * 1. Redistributions of source code must retain the above copyright
19b8ea2c8cSmatt * notice, this list of conditions and the following disclaimer.
20b8ea2c8cSmatt * 2. Redistributions in binary form must reproduce the above copyright
21b8ea2c8cSmatt * notice, this list of conditions and the following disclaimer in the
22b8ea2c8cSmatt * documentation and/or other materials provided with the distribution.
23b8ea2c8cSmatt *
24b8ea2c8cSmatt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25b8ea2c8cSmatt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26b8ea2c8cSmatt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27b8ea2c8cSmatt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28b8ea2c8cSmatt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29b8ea2c8cSmatt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30b8ea2c8cSmatt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31b8ea2c8cSmatt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32b8ea2c8cSmatt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33b8ea2c8cSmatt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34b8ea2c8cSmatt * POSSIBILITY OF SUCH DAMAGE.
35b8ea2c8cSmatt */
36b8ea2c8cSmatt
37b8ea2c8cSmatt #define PCI_PRIVATE
38b8ea2c8cSmatt #define GLOBAL_PRIVATE
39b8ea2c8cSmatt #define __INTR_PRIVATE
40b8ea2c8cSmatt
4116031f7dSrin #include <sys/cdefs.h>
42*08790245Sthorpej __KERNEL_RCSID(0, "$NetBSD: pq3pci.c,v 1.32 2022/07/22 19:55:38 thorpej Exp $");
4316031f7dSrin
44b8ea2c8cSmatt #include "locators.h"
45b8ea2c8cSmatt
4616031f7dSrin #ifdef _KERNEL_OPT
4716031f7dSrin #include "opt_mpc85xx.h"
4816031f7dSrin #include "opt_pci.h"
4916031f7dSrin #endif
50b8ea2c8cSmatt
51b8ea2c8cSmatt #include <sys/param.h>
52b8ea2c8cSmatt #include <sys/device.h>
53b8ea2c8cSmatt #include <sys/cpu.h>
54b8ea2c8cSmatt #include <sys/intr.h>
55b8ea2c8cSmatt #include <sys/bus.h>
56b8ea2c8cSmatt #include <sys/extent.h>
57b8ea2c8cSmatt #include <sys/bitops.h>
58b8ea2c8cSmatt #include <sys/kmem.h>
59b8ea2c8cSmatt #include <sys/malloc.h> /* for extent */
60e4a54b41Snonaka #include <sys/once.h>
61b8ea2c8cSmatt
62b8ea2c8cSmatt #include <dev/pci/pcireg.h>
63b8ea2c8cSmatt #include <dev/pci/pcivar.h>
64b8ea2c8cSmatt #include <dev/pci/pciconf.h>
65b8ea2c8cSmatt #include <dev/pci/pcidevs.h>
66b8ea2c8cSmatt
67b8ea2c8cSmatt #include <powerpc/booke/cpuvar.h>
68b8ea2c8cSmatt #include <powerpc/booke/spr.h>
69b8ea2c8cSmatt #include <powerpc/booke/e500var.h>
70b8ea2c8cSmatt #include <powerpc/booke/e500reg.h>
71b8ea2c8cSmatt #include <powerpc/booke/openpicreg.h>
72b8ea2c8cSmatt
73b8ea2c8cSmatt #define PORDEVSR_MPC8536_TRUTH_ENCODE(inst, field, value, result) \
74b8ea2c8cSmatt TRUTH_ENCODE(SVR_MPC8536v1, inst, PORDEVSR_##field, \
75b8ea2c8cSmatt __SHIFTIN(field##_##MPC8536##_##value, PORDEVSR_##field), result)
76b8ea2c8cSmatt #define PORDEVSR_MPC8544_TRUTH_ENCODE(inst, field, value, result) \
77b8ea2c8cSmatt TRUTH_ENCODE(SVR_MPC8544v1, inst, PORDEVSR_##field, \
78b8ea2c8cSmatt __SHIFTIN(field##_##MPC8544##_##value, PORDEVSR_##field), result)
79b8ea2c8cSmatt #define PORDEVSR_MPC8548_TRUTH_ENCODE(inst, field, value, result) \
80b8ea2c8cSmatt TRUTH_ENCODE(SVR_MPC8548v1, inst, PORDEVSR_##field, \
81b8ea2c8cSmatt __SHIFTIN(field##_##MPC8548##_##value, PORDEVSR_##field), result)
82b8ea2c8cSmatt #define PORDEVSR_MPC8555_TRUTH_ENCODE(inst, field, value, result) \
83b8ea2c8cSmatt TRUTH_ENCODE(SVR_MPC8555v1, inst, PORDEVSR_##field, \
84b8ea2c8cSmatt __SHIFTIN(field##_##MPC8555##_##value, PORDEVSR_##field), result)
85b8ea2c8cSmatt #define PORDEVSR_MPC8572_TRUTH_ENCODE(inst, field, value, result) \
86b8ea2c8cSmatt TRUTH_ENCODE(SVR_MPC8572v1, inst, PORDEVSR_##field, \
87b8ea2c8cSmatt __SHIFTIN(field##_##MPC8572##_##value, PORDEVSR_##field), result)
88065e8fe6Smatt #define PORDEVSR_P20x0_TRUTH_ENCODE(inst, field, value, result) \
8991d8d986Smatt TRUTH_ENCODE(SVR_P2020v2, inst, PORDEVSR_##field, \
90065e8fe6Smatt __SHIFTIN(field##_##P20x0##_##value, PORDEVSR_##field), result), \
9191d8d986Smatt TRUTH_ENCODE(SVR_P2010v2, inst, PORDEVSR_##field, \
92065e8fe6Smatt __SHIFTIN(field##_##P20x0##_##value, PORDEVSR_##field), result)
93c988344eSmatt #define PORDEVSR_P1025_TRUTH_ENCODE(inst, field, value, result) \
94c988344eSmatt TRUTH_ENCODE(SVR_P1025v1, inst, PORDEVSR_##field, \
95c988344eSmatt __SHIFTIN(field##_##P20x0##_##value, PORDEVSR_##field), result), \
96c988344eSmatt TRUTH_ENCODE(SVR_P1016v1, inst, PORDEVSR_##field, \
97c988344eSmatt __SHIFTIN(field##_##P20x0##_##value, PORDEVSR_##field), result)
98217677d4Snonaka #define PORDEVSR_P1023_TRUTH_ENCODE(inst, field, value, result) \
99217677d4Snonaka TRUTH_ENCODE(SVR_P1023v1, inst, PORDEVSR_##field, \
100217677d4Snonaka __SHIFTIN(field##_##value, PORDEVSR_##field), result), \
101217677d4Snonaka TRUTH_ENCODE(SVR_P1017v1, inst, PORDEVSR_##field, \
102217677d4Snonaka __SHIFTIN(field##_##value, PORDEVSR_##field), result)
103b8ea2c8cSmatt
104b8ea2c8cSmatt #define PORDEVSR_TRUTH_ENCODE(svr, inst, field, value, result) \
105b8ea2c8cSmatt TRUTH_ENCODE(svr, inst, PORDEVSR_##field, \
106b8ea2c8cSmatt __SHIFTIN(field##_##value, PORDEVSR_##field), result)
107b8ea2c8cSmatt
108b8ea2c8cSmatt const struct e500_truthtab pq3pci_pcie_lanes[] = {
109b8ea2c8cSmatt #ifdef MPC8548
110b8ea2c8cSmatt PORDEVSR_MPC8548_TRUTH_ENCODE(0, IOSEL, SRIO2500_PCIE1_X4, 4),
111b8ea2c8cSmatt PORDEVSR_MPC8548_TRUTH_ENCODE(0, IOSEL, SRIO1250_PCIE1_X4, 4),
112b8ea2c8cSmatt PORDEVSR_MPC8548_TRUTH_ENCODE(0, IOSEL, PCIE1_X8, 8),
113b8ea2c8cSmatt #endif
114b8ea2c8cSmatt
115b8ea2c8cSmatt #ifdef MPC8544
116b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(1, IOSEL, PCIE1_ON, 4),
117b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(1, IOSEL, PCIE1_SGMII_ON, 4),
118b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(1, IOSEL, PCIE12_ON, 4),
119b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(1, IOSEL, PCIE12_SGMII_ON, 4),
120b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(1, IOSEL, PCIE123_ON, 4),
121b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(1, IOSEL, PCIE123_SGMII_ON, 4),
122b8ea2c8cSmatt
123b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(2, IOSEL, PCIE12_ON, 4),
124b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(2, IOSEL, PCIE12_SGMII_ON, 4),
125b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(2, IOSEL, PCIE123_ON, 4),
126b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(2, IOSEL, PCIE123_SGMII_ON, 4),
127b8ea2c8cSmatt
128b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(3, IOSEL, PCIE123_ON, 1),
129b8ea2c8cSmatt PORDEVSR_MPC8544_TRUTH_ENCODE(3, IOSEL, PCIE123_SGMII_ON, 1),
130b8ea2c8cSmatt #endif
131b8ea2c8cSmatt
132b8ea2c8cSmatt #ifdef MPC8536
133b8ea2c8cSmatt PORDEVSR_MPC8536_TRUTH_ENCODE(1, IOSEL, PCIE1_X4, 4),
134b8ea2c8cSmatt PORDEVSR_MPC8536_TRUTH_ENCODE(1, IOSEL, PCIE1_X8, 8),
135b8ea2c8cSmatt PORDEVSR_MPC8536_TRUTH_ENCODE(1, IOSEL, PCIE12_X4, 4),
136b8ea2c8cSmatt PORDEVSR_MPC8536_TRUTH_ENCODE(1, IOSEL, PCIE1_X4_PCI23_X2, 4),
137b8ea2c8cSmatt
138b8ea2c8cSmatt PORDEVSR_MPC8536_TRUTH_ENCODE(2, IOSEL, PCIE12_X4, 4),
139b8ea2c8cSmatt PORDEVSR_MPC8536_TRUTH_ENCODE(2, IOSEL, PCIE1_X4_PCI23_X2, 2),
140b8ea2c8cSmatt
141b8ea2c8cSmatt PORDEVSR_MPC8536_TRUTH_ENCODE(3, IOSEL, PCIE1_X4_PCI23_X2, 2),
142b8ea2c8cSmatt #endif
143b8ea2c8cSmatt
144b8ea2c8cSmatt #ifdef MPC8572
145b8ea2c8cSmatt PORDEVSR_MPC8572_TRUTH_ENCODE(1, IOSEL, SRIO2500_PCIE1_X4, 4),
146b8ea2c8cSmatt PORDEVSR_MPC8572_TRUTH_ENCODE(1, IOSEL, SRIO1250_PCIE1_X4, 4),
147b8ea2c8cSmatt PORDEVSR_MPC8572_TRUTH_ENCODE(1, IOSEL, PCIE1_X4, 4),
148b8ea2c8cSmatt PORDEVSR_MPC8572_TRUTH_ENCODE(1, IOSEL, PCIE12_X4, 4),
149b8ea2c8cSmatt PORDEVSR_MPC8572_TRUTH_ENCODE(1, IOSEL, PCIE1_X4_23_X2, 4),
150b8ea2c8cSmatt PORDEVSR_MPC8572_TRUTH_ENCODE(1, IOSEL, PCIE1_X8, 8),
151b8ea2c8cSmatt
152b8ea2c8cSmatt PORDEVSR_MPC8572_TRUTH_ENCODE(2, IOSEL, PCIE12_X4, 4),
153b8ea2c8cSmatt PORDEVSR_MPC8572_TRUTH_ENCODE(2, IOSEL, PCIE1_X4_23_X2, 2),
154b8ea2c8cSmatt
155b8ea2c8cSmatt PORDEVSR_MPC8572_TRUTH_ENCODE(3, IOSEL, PCIE1_X4_23_X2, 2),
156b8ea2c8cSmatt #endif
157065e8fe6Smatt
158065e8fe6Smatt #ifdef P2020
159065e8fe6Smatt PORDEVSR_P20x0_TRUTH_ENCODE(1, IOSEL, PCIE1_X1, 1),
160065e8fe6Smatt PORDEVSR_P20x0_TRUTH_ENCODE(1, IOSEL, PCIE12_X1_3_X2, 1),
161065e8fe6Smatt PORDEVSR_P20x0_TRUTH_ENCODE(1, IOSEL, PCIE13_X2, 2),
162065e8fe6Smatt PORDEVSR_P20x0_TRUTH_ENCODE(1, IOSEL, PCIE1_X4, 4),
163065e8fe6Smatt PORDEVSR_P20x0_TRUTH_ENCODE(1, IOSEL, PCIE1_X1_SRIO2500_1X, 1),
164065e8fe6Smatt PORDEVSR_P20x0_TRUTH_ENCODE(1, IOSEL, PCIE12_X1_SGMII23, 1),
165065e8fe6Smatt PORDEVSR_P20x0_TRUTH_ENCODE(1, IOSEL, PCIE1_X2_SGMII23, 2),
166065e8fe6Smatt
167065e8fe6Smatt PORDEVSR_P20x0_TRUTH_ENCODE(2, IOSEL, PCIE12_X1_3_X2, 1),
168065e8fe6Smatt PORDEVSR_P20x0_TRUTH_ENCODE(2, IOSEL, PCIE12_X1_SGMII23, 1),
169065e8fe6Smatt
170065e8fe6Smatt PORDEVSR_P20x0_TRUTH_ENCODE(3, IOSEL, PCIE12_X1_3_X2, 2),
171065e8fe6Smatt PORDEVSR_P20x0_TRUTH_ENCODE(3, IOSEL, PCIE13_X2, 2),
172065e8fe6Smatt #endif
173c988344eSmatt
174c988344eSmatt #ifdef P1025
175c988344eSmatt PORDEVSR_P1025_TRUTH_ENCODE(1, IOSEL, PCIE1_X1, 1),
176c988344eSmatt PORDEVSR_P1025_TRUTH_ENCODE(1, IOSEL, PCIE1_X4, 4),
177c988344eSmatt PORDEVSR_P1025_TRUTH_ENCODE(1, IOSEL, PCIE12_X1_SGMII23, 1),
178c988344eSmatt PORDEVSR_P1025_TRUTH_ENCODE(1, IOSEL, PCIE1_X2_SGMII23, 2),
179c988344eSmatt
180c988344eSmatt PORDEVSR_P1025_TRUTH_ENCODE(2, IOSEL, PCIE12_X1_SGMII23, 1),
181c988344eSmatt #endif
182217677d4Snonaka
183217677d4Snonaka #ifdef P1023
184217677d4Snonaka PORDEVSR_P1023_TRUTH_ENCODE(1, IOSEL_P1023, PCIE12_X1, 1),
185217677d4Snonaka PORDEVSR_P1023_TRUTH_ENCODE(1, IOSEL_P1023, PCIE123_X1, 1),
186217677d4Snonaka PORDEVSR_P1023_TRUTH_ENCODE(1, IOSEL_P1023, PCIE123_X1_SGMII2, 1),
187217677d4Snonaka PORDEVSR_P1023_TRUTH_ENCODE(1, IOSEL_P1023, PCIE12_X1_SGMII12, 1),
188217677d4Snonaka
189217677d4Snonaka PORDEVSR_P1023_TRUTH_ENCODE(2, IOSEL_P1023, PCIE12_X1, 1),
190217677d4Snonaka PORDEVSR_P1023_TRUTH_ENCODE(2, IOSEL_P1023, PCIE123_X1, 1),
191217677d4Snonaka PORDEVSR_P1023_TRUTH_ENCODE(2, IOSEL_P1023, PCIE123_X1_SGMII2, 1),
192217677d4Snonaka PORDEVSR_P1023_TRUTH_ENCODE(2, IOSEL_P1023, PCIE12_X1_SGMII12, 1),
193217677d4Snonaka
194217677d4Snonaka PORDEVSR_P1023_TRUTH_ENCODE(3, IOSEL_P1023, PCIE123_X1, 1),
195217677d4Snonaka PORDEVSR_P1023_TRUTH_ENCODE(3, IOSEL_P1023, PCIE123_X1_SGMII2, 1),
196217677d4Snonaka #endif
197b8ea2c8cSmatt };
198b8ea2c8cSmatt
199b8ea2c8cSmatt static const struct e500_truthtab pq3pci_pci_pcix[] = {
200b8ea2c8cSmatt #ifdef MPC8548
201b8ea2c8cSmatt PORDEVSR_TRUTH_ENCODE(SVR_MPC8548v1, 1, PCI1, PCIX, 1),
202b8ea2c8cSmatt #endif
203b8ea2c8cSmatt };
204b8ea2c8cSmatt
205b8ea2c8cSmatt static const struct e500_truthtab pq3pci_pci_pci32[] = {
206b8ea2c8cSmatt #ifdef MPC8548
207b8ea2c8cSmatt PORDEVSR_TRUTH_ENCODE(SVR_MPC8548v1, 1, PCI32, FALSE, 64),
208b8ea2c8cSmatt PORDEVSR_TRUTH_ENCODE(SVR_MPC8548v1, 1, PCI32, TRUE, 32),
209b8ea2c8cSmatt #endif
210b8ea2c8cSmatt
211b8ea2c8cSmatt #ifdef MPC8555
212b8ea2c8cSmatt PORDEVSR_TRUTH_ENCODE(SVR_MPC8555v1, 0, PCI32, FALSE, 64),
213b8ea2c8cSmatt PORDEVSR_TRUTH_ENCODE(SVR_MPC8555v1, 0, PCI32, TRUE, 32),
214b8ea2c8cSmatt #endif
215b8ea2c8cSmatt };
216b8ea2c8cSmatt
217b8ea2c8cSmatt struct pq3pci_bst {
218b8ea2c8cSmatt struct powerpc_bus_space bs_tag;
2192b43b329Smatt uint8_t bs_numwin;
2202b43b329Smatt bus_addr_t bs_base[3];
2212b43b329Smatt bus_addr_t bs_offset[3];
2222b43b329Smatt bus_addr_t bs_limit[3];
223b8ea2c8cSmatt char bs_name[16];
224b8ea2c8cSmatt char bs_ex_storage[EXTENT_FIXED_STORAGE_SIZE(8)] __aligned(8);
225b8ea2c8cSmatt };
226b8ea2c8cSmatt
227b8ea2c8cSmatt typedef enum { IH_NONE, IH_INTX, IH_MSI, IH_MSIX } pq3pci_intr_class_t;
228b8ea2c8cSmatt
229b8ea2c8cSmatt struct pq3pci_genihand {
230b8ea2c8cSmatt pq3pci_intr_class_t ih_class;
231b8ea2c8cSmatt int (*ih_func)(void *);
232b8ea2c8cSmatt void *ih_arg;
233b8ea2c8cSmatt struct pq3pci_softc *ih_sc;
234b8ea2c8cSmatt };
235b8ea2c8cSmatt
236b8ea2c8cSmatt struct pq3pci_intrhand {
237b8ea2c8cSmatt struct pq3pci_genihand pih_ih;
238b8ea2c8cSmatt SIMPLEQ_ENTRY(pq3pci_intrhand) pih_link;
239b8ea2c8cSmatt int pih_ipl;
240b8ea2c8cSmatt struct pq3pci_intrsource *pih_source;
241b8ea2c8cSmatt uint64_t pih_count;
242b8ea2c8cSmatt };
243b8ea2c8cSmatt
244b8ea2c8cSmatt struct pq3pci_callhand {
245b8ea2c8cSmatt struct pq3pci_genihand pch_ih;
246b8ea2c8cSmatt struct callout pch_callout;
247b8ea2c8cSmatt int pch_ipl;
248b8ea2c8cSmatt };
249b8ea2c8cSmatt
250b8ea2c8cSmatt #define PIH_MAKE(irq, ist, nmsi) (((nmsi) << 20) | ((irq) << 8) | (ist))
251b8ea2c8cSmatt #define PIH_IST(pih) (((pih) >> 0) & 0xff)
252b8ea2c8cSmatt #define PIH_IRQ(pih) (((pih) >> 8) & 0xfff)
253b8ea2c8cSmatt #define PIH_NMSI(pih) (((pih) >> 20) & 0xff)
254b8ea2c8cSmatt
255b8ea2c8cSmatt struct pq3pci_intrsource {
256b8ea2c8cSmatt SIMPLEQ_ENTRY(pq3pci_intrsource) pis_link;
257b8ea2c8cSmatt SIMPLEQ_HEAD(,pq3pci_intrhand) pis_ihands;
258b8ea2c8cSmatt struct evcnt pis_ev;
259b8ea2c8cSmatt struct evcnt pis_ev_spurious;
260e4a54b41Snonaka kmutex_t pis_lock;
261b8ea2c8cSmatt pci_intr_handle_t pis_handle;
262e4a54b41Snonaka char pis_intrname[PCI_INTRSTR_LEN];
263b8ea2c8cSmatt void *pis_ih;
264b8ea2c8cSmatt };
265b8ea2c8cSmatt
266b8ea2c8cSmatt struct pq3pci_msihand {
267b8ea2c8cSmatt struct pq3pci_genihand msih_ih;
268b8ea2c8cSmatt struct pq3pci_msigroup *msih_group;
269b8ea2c8cSmatt struct evcnt msih_ev;
270b8ea2c8cSmatt struct evcnt msih_ev_spurious;
271b8ea2c8cSmatt pcitag_t msih_tag;
272b8ea2c8cSmatt int msih_msioff;
273b8ea2c8cSmatt };
274b8ea2c8cSmatt
275b8ea2c8cSmatt struct pq3pci_msigroup {
276e4a54b41Snonaka kmutex_t msig_lock;
277b8ea2c8cSmatt void *msig_ih;
278b8ea2c8cSmatt uint32_t msig_free_mask;
279b8ea2c8cSmatt int msig_ipl;
280b8ea2c8cSmatt u_int msig_group;
281b8ea2c8cSmatt bus_size_t msig_msir;
282b8ea2c8cSmatt struct pq3pci_msihand msig_ihands[32];
283b8ea2c8cSmatt };
284b8ea2c8cSmatt
285b8ea2c8cSmatt struct pq3pci_softc {
286b8ea2c8cSmatt device_t sc_dev;
287b8ea2c8cSmatt bus_space_tag_t sc_bst;
288b8ea2c8cSmatt bus_space_handle_t sc_bsh;
289b8ea2c8cSmatt void *sc_ih;
290b8ea2c8cSmatt bool sc_pcie;
291b8ea2c8cSmatt struct genppc_pci_chipset sc_pc;
292b8ea2c8cSmatt struct pq3pci_bst sc_pci_io_bst;
293b8ea2c8cSmatt struct pq3pci_bst sc_pci_mem_bst;
294b8ea2c8cSmatt u_int sc_pba_flags;
295b8ea2c8cSmatt kmutex_t *sc_conf_lock;
296b8ea2c8cSmatt kmutex_t *sc_intr_lock;
297b8ea2c8cSmatt struct evcnt sc_ev_spurious;
298b8ea2c8cSmatt prop_dictionary_t sc_intrmap;
299b8ea2c8cSmatt uint32_t sc_intrmask;
300b8ea2c8cSmatt };
301b8ea2c8cSmatt
302b8ea2c8cSmatt static int pq3pci_cpunode_match(device_t, cfdata_t, void *aux);
303b8ea2c8cSmatt static void pq3pci_cpunode_attach(device_t, device_t, void *aux);
304b8ea2c8cSmatt static pci_chipset_tag_t pq3pci_pci_chipset_init(struct pq3pci_softc *);
305b8ea2c8cSmatt
306e4a54b41Snonaka static ONCE_DECL(pq3pci_init_once);
307e4a54b41Snonaka static kmutex_t pq3pci_intrsources_lock;
308e4a54b41Snonaka static kmutex_t pq3pci_msigroups_lock;
309b8ea2c8cSmatt static SIMPLEQ_HEAD(,pq3pci_intrsource) pq3pci_intrsources
310b8ea2c8cSmatt = SIMPLEQ_HEAD_INITIALIZER(pq3pci_intrsources);
311b8ea2c8cSmatt static struct pq3pci_msigroup *pq3pci_msigroups[8];
312b8ea2c8cSmatt
313b8ea2c8cSmatt static struct pq3pci_intrsource *
314b8ea2c8cSmatt pq3pci_intr_source_lookup(struct pq3pci_softc *, pci_intr_handle_t);
315b8ea2c8cSmatt
316b8ea2c8cSmatt static const char msi_intr_names[8][32][8] = {
317b8ea2c8cSmatt {
318b8ea2c8cSmatt "msi 0", "msi 1", "msi 2", "msi 3",
319b8ea2c8cSmatt "msi 4", "msi 5", "msi 6", "msi 7",
320b8ea2c8cSmatt "msi 8", "msi 9", "msi 10", "msi 11",
321b8ea2c8cSmatt "msi 12", "msi 13", "msi 14", "msi 15",
322b8ea2c8cSmatt "msi 16", "msi 17", "msi 18", "msi 19",
323b8ea2c8cSmatt "msi 20", "msi 21", "msi 22", "msi 23",
324b8ea2c8cSmatt "msi 24", "msi 25", "msi 26", "msi 27",
325b8ea2c8cSmatt "msi 28", "msi 29", "msi 30", "msi 31",
326b8ea2c8cSmatt }, {
327b8ea2c8cSmatt "msi 32", "msi 33", "msi 34", "msi 35",
328b8ea2c8cSmatt "msi 36", "msi 37", "msi 38", "msi 39",
329b8ea2c8cSmatt "msi 40", "msi 41", "msi 42", "msi 43",
330b8ea2c8cSmatt "msi 44", "msi 45", "msi 46", "msi 47",
331b8ea2c8cSmatt "msi 48", "msi 49", "msi 50", "msi 51",
332b8ea2c8cSmatt "msi 52", "msi 53", "msi 54", "msi 55",
333b8ea2c8cSmatt "msi 56", "msi 57", "msi 58", "msi 59",
334b8ea2c8cSmatt "msi 60", "msi 61", "msi 62", "msi 63",
335b8ea2c8cSmatt }, {
336b8ea2c8cSmatt "msi 64", "msi 65", "msi 66", "msi 67",
337b8ea2c8cSmatt "msi 68", "msi 69", "msi 70", "msi 71",
338b8ea2c8cSmatt "msi 72", "msi 73", "msi 74", "msi 75",
339b8ea2c8cSmatt "msi 76", "msi 77", "msi 78", "msi 79",
340b8ea2c8cSmatt "msi 80", "msi 81", "msi 82", "msi 83",
341b8ea2c8cSmatt "msi 84", "msi 85", "msi 86", "msi 87",
342b8ea2c8cSmatt "msi 88", "msi 89", "msi 90", "msi 91",
343b8ea2c8cSmatt "msi 92", "msi 93", "msi 94", "msi 95",
344b8ea2c8cSmatt }, {
345b8ea2c8cSmatt "msi 96", "msi 97", "msi 98", "msi 99",
346b8ea2c8cSmatt "msi 100", "msi 101", "msi 102", "msi 103",
347b8ea2c8cSmatt "msi 104", "msi 105", "msi 106", "msi 107",
348b8ea2c8cSmatt "msi 108", "msi 109", "msi 110", "msi 111",
349b8ea2c8cSmatt "msi 112", "msi 113", "msi 114", "msi 115",
350b8ea2c8cSmatt "msi 116", "msi 117", "msi 118", "msi 119",
351b8ea2c8cSmatt "msi 120", "msi 121", "msi 122", "msi 123",
352b8ea2c8cSmatt "msi 124", "msi 125", "msi 126", "msi 127",
353b8ea2c8cSmatt }, {
354b8ea2c8cSmatt "msi 128", "msi 129", "msi 130", "msi 131",
355b8ea2c8cSmatt "msi 132", "msi 133", "msi 134", "msi 135",
356b8ea2c8cSmatt "msi 136", "msi 137", "msi 138", "msi 139",
357b8ea2c8cSmatt "msi 140", "msi 141", "msi 142", "msi 143",
358b8ea2c8cSmatt "msi 144", "msi 145", "msi 146", "msi 147",
359b8ea2c8cSmatt "msi 148", "msi 149", "msi 150", "msi 151",
360b8ea2c8cSmatt "msi 152", "msi 153", "msi 154", "msi 155",
361b8ea2c8cSmatt "msi 156", "msi 157", "msi 158", "msi 159",
362b8ea2c8cSmatt }, {
363b8ea2c8cSmatt "msi 160", "msi 161", "msi 162", "msi 163",
364b8ea2c8cSmatt "msi 164", "msi 165", "msi 166", "msi 167",
365b8ea2c8cSmatt "msi 168", "msi 169", "msi 170", "msi 171",
366b8ea2c8cSmatt "msi 172", "msi 173", "msi 174", "msi 175",
367b8ea2c8cSmatt "msi 176", "msi 177", "msi 178", "msi 179",
368b8ea2c8cSmatt "msi 180", "msi 181", "msi 182", "msi 183",
369b8ea2c8cSmatt "msi 184", "msi 185", "msi 186", "msi 187",
370b8ea2c8cSmatt "msi 188", "msi 189", "msi 190", "msi 191",
371b8ea2c8cSmatt }, {
372b8ea2c8cSmatt "msi 192", "msi 193", "msi 194", "msi 195",
373b8ea2c8cSmatt "msi 196", "msi 197", "msi 198", "msi 199",
374b8ea2c8cSmatt "msi 200", "msi 201", "msi 202", "msi 203",
375b8ea2c8cSmatt "msi 204", "msi 205", "msi 206", "msi 207",
376b8ea2c8cSmatt "msi 208", "msi 209", "msi 210", "msi 211",
377b8ea2c8cSmatt "msi 212", "msi 213", "msi 214", "msi 215",
378b8ea2c8cSmatt "msi 216", "msi 217", "msi 218", "msi 219",
379b8ea2c8cSmatt "msi 220", "msi 221", "msi 222", "msi 223",
380b8ea2c8cSmatt }, {
381b8ea2c8cSmatt "msi 224", "msi 225", "msi 226", "msi 227",
382b8ea2c8cSmatt "msi 228", "msi 229", "msi 230", "msi 231",
383b8ea2c8cSmatt "msi 232", "msi 233", "msi 234", "msi 235",
384b8ea2c8cSmatt "msi 236", "msi 237", "msi 238", "msi 239",
385b8ea2c8cSmatt "msi 240", "msi 241", "msi 242", "msi 243",
386b8ea2c8cSmatt "msi 244", "msi 245", "msi 246", "msi 247",
387b8ea2c8cSmatt "msi 248", "msi 249", "msi 250", "msi 251",
388b8ea2c8cSmatt "msi 252", "msi 253", "msi 254", "msi 255",
389b8ea2c8cSmatt },
390b8ea2c8cSmatt };
391b8ea2c8cSmatt
392b8ea2c8cSmatt CFATTACH_DECL_NEW(pq3pci_cpunode, sizeof(struct pq3pci_softc),
393b8ea2c8cSmatt pq3pci_cpunode_match, pq3pci_cpunode_attach, NULL, NULL);
394b8ea2c8cSmatt
395b8ea2c8cSmatt CFATTACH_DECL_NEW(pq3pcie_cpunode, sizeof(struct pq3pci_softc),
396b8ea2c8cSmatt pq3pci_cpunode_match, pq3pci_cpunode_attach, NULL, NULL);
397b8ea2c8cSmatt
398b8ea2c8cSmatt int
pq3pci_cpunode_match(device_t parent,cfdata_t cf,void * aux)399b8ea2c8cSmatt pq3pci_cpunode_match(device_t parent, cfdata_t cf, void *aux)
400b8ea2c8cSmatt {
401b8ea2c8cSmatt
402b8ea2c8cSmatt if (!e500_cpunode_submatch(parent, cf, cf->cf_name + 3, aux))
403b8ea2c8cSmatt return 0;
404b8ea2c8cSmatt
405b8ea2c8cSmatt return 1;
406b8ea2c8cSmatt }
407b8ea2c8cSmatt
408b8ea2c8cSmatt struct pq3pci_owin {
409b8ea2c8cSmatt uint32_t potar;
410b8ea2c8cSmatt uint32_t potear;
411b8ea2c8cSmatt uint32_t powbar;
412b8ea2c8cSmatt uint32_t powar;
413b8ea2c8cSmatt };
414b8ea2c8cSmatt
4152b43b329Smatt static void
pq3pci_owin_record(struct pq3pci_softc * sc,u_int winnum,const struct pq3pci_owin * owin)4162b43b329Smatt pq3pci_owin_record(struct pq3pci_softc *sc, u_int winnum,
417b8ea2c8cSmatt const struct pq3pci_owin *owin)
418b8ea2c8cSmatt {
419b8ea2c8cSmatt const bool io_win = (owin->powar & PEXOWAR_RTT) == PEXOWAR_RTT_IO;
420b8ea2c8cSmatt struct pq3pci_bst *bs = io_win ? &sc->sc_pci_io_bst : &sc->sc_pci_mem_bst;
421b8ea2c8cSmatt const uint64_t pci_base = ((uint64_t)owin->potar << 12)
422b8ea2c8cSmatt | ((uint64_t)owin->potear << (32+12));
423b8ea2c8cSmatt const uint64_t local_base = (uint64_t)owin->powbar << 12;
424b8ea2c8cSmatt const u_int win_size_log2 = PEXIWAR_IWS_GET(owin->powar) + 1;
4252b43b329Smatt u_int slot;
426b8ea2c8cSmatt
427b8ea2c8cSmatt bs->bs_tag.pbs_flags = _BUS_SPACE_LITTLE_ENDIAN
428b8ea2c8cSmatt | (io_win ? _BUS_SPACE_IO_TYPE : _BUS_SPACE_MEM_TYPE);
4292b43b329Smatt
4302b43b329Smatt for (slot = 0; slot < bs->bs_numwin; slot++) {
4312b43b329Smatt if (pci_base < bs->bs_base[slot]) {
4322b43b329Smatt for (size_t j = slot; j < bs->bs_numwin; j++) {
4332b43b329Smatt bs->bs_base[j+1] = bs->bs_base[j];
4342b43b329Smatt bs->bs_offset[j+1] = bs->bs_offset[j];
4352b43b329Smatt bs->bs_limit[j+1] = bs->bs_limit[j];
4362b43b329Smatt }
4372b43b329Smatt break;
4382b43b329Smatt }
4392b43b329Smatt }
4402b43b329Smatt bs->bs_base[slot] = pci_base;
4412b43b329Smatt bs->bs_offset[slot] = local_base - pci_base;
4422b43b329Smatt bs->bs_limit[slot] = pci_base + (1ULL << win_size_log2);
4432b43b329Smatt bs->bs_numwin++;
444b8ea2c8cSmatt
445b8ea2c8cSmatt #if 0
446b8ea2c8cSmatt const char units[] = " KMGTP";
447b8ea2c8cSmatt aprint_normal_dev(sc->sc_dev,
448b8ea2c8cSmatt "outbound window %u: potar=%#x, potear=%#x, powbar=%x, powar=%#x\n",
449b8ea2c8cSmatt winnum, owin->potar, owin->potear, owin->powbar, owin->powar);
450b8ea2c8cSmatt aprint_normal_dev(sc->sc_dev,
451b8ea2c8cSmatt "outbound window %u: maps %u%cB of PCI %s space @ %#"PRIx64" onto local addresses @ %#"PRIx64".\n",
452b8ea2c8cSmatt winnum, 1 << (win_size_log2 % 10), units[win_size_log2 / 10],
453b8ea2c8cSmatt (owin->powar & PEXOWAR_RTT) == PEXOWAR_RTT_IO ? "I/O" : "memory",
454b8ea2c8cSmatt local_base, pci_base);
455b8ea2c8cSmatt #endif
4562b43b329Smatt }
457b8ea2c8cSmatt
4582b43b329Smatt static bool
pq3pci_owin_init(struct pq3pci_softc * sc,struct pq3pci_bst * bs,bool io_win)4592b43b329Smatt pq3pci_owin_init(struct pq3pci_softc *sc, struct pq3pci_bst *bs, bool io_win)
4602b43b329Smatt {
4612b43b329Smatt if (bs->bs_numwin == 0)
4622b43b329Smatt return true;
4632b43b329Smatt
4642b43b329Smatt bs->bs_tag.pbs_base = bs->bs_base[0];
4652b43b329Smatt bs->bs_tag.pbs_offset = bs->bs_offset[0];
4662b43b329Smatt bs->bs_tag.pbs_limit = bs->bs_limit[bs->bs_numwin - 1];
4672b43b329Smatt
4682b43b329Smatt snprintf(bs->bs_name, sizeof(bs->bs_name), "%s-%s",
4692b43b329Smatt device_xname(sc->sc_dev), io_win ? "io" : "mem");
470b8ea2c8cSmatt
471b8ea2c8cSmatt #if 0
472b8ea2c8cSmatt printf("%s: %s: base=%#x offset=%#x limit=%#x\n", __func__, bs->bs_name,
473b8ea2c8cSmatt bs->bs_tag.pbs_base, bs->bs_tag.pbs_offset, bs->bs_tag.pbs_limit);
474b8ea2c8cSmatt #endif
475b8ea2c8cSmatt
476b8ea2c8cSmatt int error = bus_space_init(&bs->bs_tag, bs->bs_name,
477b8ea2c8cSmatt bs->bs_ex_storage, sizeof(bs->bs_ex_storage));
478b8ea2c8cSmatt if (error) {
479b8ea2c8cSmatt aprint_error(": failed to create %s bus space: %d\n",
480b8ea2c8cSmatt bs->bs_name, error);
481b8ea2c8cSmatt return false;
482b8ea2c8cSmatt }
4832b43b329Smatt for (size_t slot = 1; slot < bs->bs_numwin; slot++) {
4842b43b329Smatt if (bs->bs_limit[slot - 1] < bs->bs_base[slot]) {
4852b43b329Smatt error = extent_alloc_region(bs->bs_tag.pbs_extent,
4862b43b329Smatt bs->bs_limit[slot - 1],
4872b43b329Smatt bs->bs_base[slot] - bs->bs_limit[slot - 1],
4882b43b329Smatt EX_WAITOK);
4892b43b329Smatt if (error) {
4902b43b329Smatt aprint_error(": failed to hole in %s bus space: %d\n",
4912b43b329Smatt bs->bs_name, error);
4922b43b329Smatt return false;
4932b43b329Smatt }
4942b43b329Smatt }
4952b43b329Smatt }
496b8ea2c8cSmatt aprint_debug_dev(sc->sc_dev, "bus space %s created\n", bs->bs_name);
497b8ea2c8cSmatt sc->sc_pba_flags |=
498a6b2b839Sdyoung io_win ? PCI_FLAGS_IO_OKAY : PCI_FLAGS_MEM_OKAY;
499b8ea2c8cSmatt return true;
500b8ea2c8cSmatt }
501b8ea2c8cSmatt
502b8ea2c8cSmatt struct pq3pci_iwin {
503b8ea2c8cSmatt uint32_t pitar;
504b8ea2c8cSmatt uint32_t piwbar;
505b8ea2c8cSmatt uint32_t piwbear;
506b8ea2c8cSmatt uint32_t piwar;
507b8ea2c8cSmatt };
508b8ea2c8cSmatt
509b8ea2c8cSmatt static bool
pq3pci_iwin_setup(struct pq3pci_softc * sc,u_int winnum,const struct pq3pci_iwin * iwin)510b8ea2c8cSmatt pq3pci_iwin_setup(struct pq3pci_softc *sc, u_int winnum,
511b8ea2c8cSmatt const struct pq3pci_iwin *iwin)
512b8ea2c8cSmatt {
513b8ea2c8cSmatt const uint64_t pci_base = ((uint64_t)iwin->piwbar << 12)
514b8ea2c8cSmatt | ((uint64_t)iwin->piwbear << (32+12));
515b8ea2c8cSmatt const uint64_t local_base = (uint64_t)iwin->pitar << 12;
516b8ea2c8cSmatt const u_int win_size_log2 = PEXIWAR_IWS_GET(iwin->piwar) + 1;
517b8ea2c8cSmatt #if DEBUG > 1
518b8ea2c8cSmatt const char units[] = " KMGTP";
519b8ea2c8cSmatt aprint_normal_dev(sc->sc_dev,
520b8ea2c8cSmatt "inbound window %u: pitar=%#x, piwbar=%x, piwbear=%#x, piwar=%#x\n",
521b8ea2c8cSmatt winnum, iwin->pitar, iwin->piwbar, iwin->piwbear, iwin->piwar);
522b8ea2c8cSmatt aprint_normal_dev(sc->sc_dev,
523b8ea2c8cSmatt "inbound window %u: maps %u%cB of PCI address space @ %#"PRIx64" to local memory @ %#"PRIx64".\n",
524b8ea2c8cSmatt winnum, 1 << (win_size_log2 % 10), units[win_size_log2 / 10],
525b8ea2c8cSmatt pci_base, local_base);
526b8ea2c8cSmatt #endif /* DEBUG */
527b8ea2c8cSmatt /*
528b8ea2c8cSmatt * Let's make sure this window is usable.
529b8ea2c8cSmatt */
530b8ea2c8cSmatt if (pci_base != 0) {
531b8ea2c8cSmatt aprint_error(": invalid inbound window: "
532b8ea2c8cSmatt "PCI base (%#"PRIx64" != 0\n", pci_base);
533b8ea2c8cSmatt return false;
534b8ea2c8cSmatt }
535b8ea2c8cSmatt if (local_base != 0) {
536b8ea2c8cSmatt aprint_error(": invalid inbound window: "
537b8ea2c8cSmatt "local base (%#"PRIx64" != 0\n", local_base);
538b8ea2c8cSmatt return false;
539b8ea2c8cSmatt }
540b8ea2c8cSmatt if ((iwin->piwar & PEXIWAR_RTT) != PEXIWAR_RTT_MEM_SNOOP) {
541b8ea2c8cSmatt aprint_error(": invalid inbound window: "
542b8ea2c8cSmatt "unsupported read transaction type (%#"PRIxMAX")\n",
543b8ea2c8cSmatt iwin->piwar & PEXIWAR_RTT);
544b8ea2c8cSmatt return false;
545b8ea2c8cSmatt }
546b8ea2c8cSmatt if ((iwin->piwar & PEXIWAR_WTT) != PEXIWAR_WTT_MEM_SNOOP) {
547b8ea2c8cSmatt aprint_error(": invalid inbound window: "
548b8ea2c8cSmatt "unsupported write transaction type (%#"PRIxMAX")\n",
549b8ea2c8cSmatt iwin->piwar & PEXIWAR_WTT);
550b8ea2c8cSmatt return false;
551b8ea2c8cSmatt }
552b8ea2c8cSmatt if ((iwin->piwar & PEXIWAR_TRGT) != PEXIWAR_TRGT_LOCALMEM) {
553b8ea2c8cSmatt aprint_error(": invalid inbound window: "
554b8ea2c8cSmatt "unsupported target (%#"PRIxMAX")\n",
555b8ea2c8cSmatt iwin->piwar & PEXIWAR_TRGT);
556b8ea2c8cSmatt return false;
557b8ea2c8cSmatt }
558b8ea2c8cSmatt if (board_info_get_number("mem-size") > (1ULL << win_size_log2)) {
559b8ea2c8cSmatt aprint_error(": invalid inbound window: "
560b8ea2c8cSmatt "doesn't map all of memory (%#"PRIx64" < %#"PRIx64")\n",
561b8ea2c8cSmatt 1ULL << win_size_log2, board_info_get_number("mem-size"));
562b8ea2c8cSmatt return false;
563b8ea2c8cSmatt }
564b8ea2c8cSmatt return true;
565b8ea2c8cSmatt }
566b8ea2c8cSmatt
567b8ea2c8cSmatt static int
pq3pci_msi_spurious_intr(void * v)568b8ea2c8cSmatt pq3pci_msi_spurious_intr(void *v)
569b8ea2c8cSmatt {
570b8ea2c8cSmatt (void) v;
571b8ea2c8cSmatt
572b8ea2c8cSmatt return 0;
573b8ea2c8cSmatt }
574b8ea2c8cSmatt
575b8ea2c8cSmatt static int
pq3pci_msi_intr(void * v)576b8ea2c8cSmatt pq3pci_msi_intr(void *v)
577b8ea2c8cSmatt {
578b8ea2c8cSmatt struct pq3pci_msigroup * const msig = v;
579b8ea2c8cSmatt
580e4a54b41Snonaka mutex_spin_enter(&msig->msig_lock);
581b8ea2c8cSmatt KASSERT(curcpu()->ci_cpl == msig->msig_ipl);
582b8ea2c8cSmatt //KASSERT(curcpu()->ci_idepth == 0);
583a3fa70a4Smatt uint32_t matches = 0;
584b8ea2c8cSmatt for (int rv = 0;;) {
585b8ea2c8cSmatt uint32_t group = cpu_read_4(msig->msig_msir);
586b8ea2c8cSmatt if (group == 0) {
587e4a54b41Snonaka mutex_spin_exit(&msig->msig_lock);
588b8ea2c8cSmatt return rv;
589b8ea2c8cSmatt }
590b8ea2c8cSmatt
591b8ea2c8cSmatt const bool working_msi_p =
592b8ea2c8cSmatt msig->msig_group != 0 || (group & 1) == 0;
593b8ea2c8cSmatt if (working_msi_p) {
594b8ea2c8cSmatt /*
595b8ea2c8cSmatt * if MSIs are working, just clear the free MSIs.
596b8ea2c8cSmatt */
597a3fa70a4Smatt KASSERTMSG((group & msig->msig_free_mask) == 0,
598325494feSjym "%s: group#%u: unexpected MSIs (%#x)",
599a3fa70a4Smatt __func__, msig->msig_group,
600325494feSjym group & msig->msig_free_mask);
601b8ea2c8cSmatt group &= ~msig->msig_free_mask;
602b8ea2c8cSmatt } else {
603b8ea2c8cSmatt /*
604b8ea2c8cSmatt * If MSIs are broken, we don't really what MSIs
605b8ea2c8cSmatt * have happened.
606b8ea2c8cSmatt */
607b8ea2c8cSmatt for (struct pq3pci_msihand *msih = msig->msig_ihands + 31;
608b8ea2c8cSmatt group != 0;
609b8ea2c8cSmatt msih--) {
610b8ea2c8cSmatt const u_int n = __builtin_clz(group);
611b8ea2c8cSmatt msih -= n;
612b8ea2c8cSmatt group <<= n + 1;
613b8ea2c8cSmatt msih->msih_ev.ev_count++;
614b8ea2c8cSmatt }
615b8ea2c8cSmatt group = ~msig->msig_free_mask;
616b8ea2c8cSmatt }
617a3fa70a4Smatt uint32_t this_msi = __BIT(31);
618b8ea2c8cSmatt for (struct pq3pci_msihand *msih = msig->msig_ihands + 31;
619b8ea2c8cSmatt group != 0;
620b8ea2c8cSmatt msih--) {
621b8ea2c8cSmatt KASSERT(msig->msig_ihands <= msih);
622b8ea2c8cSmatt KASSERT(msih < &msig->msig_ihands[32]);
623b8ea2c8cSmatt const u_int n = __builtin_clz(group);
624b8ea2c8cSmatt msih -= n;
625b8ea2c8cSmatt group <<= n + 1;
626b8ea2c8cSmatt msih->msih_ev.ev_count += working_msi_p;
627b8ea2c8cSmatt if ((*msih->msih_ih.ih_func)(msih->msih_ih.ih_arg)) {
628b8ea2c8cSmatt rv = 1;
629b8ea2c8cSmatt msih->msih_ev.ev_count += !working_msi_p;
630a3fa70a4Smatt matches |= this_msi;
631a3fa70a4Smatt } else if ((matches & this_msi) == 0) {
632b8ea2c8cSmatt msih->msih_ev_spurious.ev_count += working_msi_p;
633b8ea2c8cSmatt }
634a3fa70a4Smatt this_msi >>= n + 1;
635b8ea2c8cSmatt }
636b8ea2c8cSmatt }
637b8ea2c8cSmatt }
638b8ea2c8cSmatt
639b8ea2c8cSmatt static int
pq3pci_onchip_intr(void * v)640b8ea2c8cSmatt pq3pci_onchip_intr(void *v)
641b8ea2c8cSmatt {
642b8ea2c8cSmatt panic(__func__);
643b8ea2c8cSmatt }
644b8ea2c8cSmatt
645b8ea2c8cSmatt static int
pq3pci_pis_intr(void * v)646b8ea2c8cSmatt pq3pci_pis_intr(void *v)
647b8ea2c8cSmatt {
648b8ea2c8cSmatt struct pq3pci_intrsource * const pis = v;
649b8ea2c8cSmatt struct pq3pci_intrhand *pih;
650b8ea2c8cSmatt int rv = 0;
651b8ea2c8cSmatt
652e4a54b41Snonaka mutex_spin_enter(&pis->pis_lock);
653b8ea2c8cSmatt pis->pis_ev.ev_count++;
654b8ea2c8cSmatt SIMPLEQ_FOREACH(pih, &pis->pis_ihands, pih_link) {
655b8ea2c8cSmatt struct pq3pci_softc * const sc = pih->pih_ih.ih_sc;
656b8ea2c8cSmatt int s = splraise(pih->pih_ipl);
657b8ea2c8cSmatt pih->pih_count++;
658b8ea2c8cSmatt rv = (*pih->pih_ih.ih_func)(pih->pih_ih.ih_arg);
659b8ea2c8cSmatt splx(s);
660b8ea2c8cSmatt #if 0
661b8ea2c8cSmatt printf("%s %d:%s %"PRIu64": %p(%p) %"PRIu64": %d\n", __func__,
662b8ea2c8cSmatt curcpu()->ci_idepth,
663b8ea2c8cSmatt pis->pis_ev.ev_group, pis->pis_ev.ev_count,
664b8ea2c8cSmatt pih->pih_ih.ih_func, pih->pih_ih.ih_arg, pih->pih_count, rv);
665b8ea2c8cSmatt #endif
666b8ea2c8cSmatt if (rv != 0) {
667b8ea2c8cSmatt bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCI_INT_ACK);
668b8ea2c8cSmatt break;
669b8ea2c8cSmatt }
670b8ea2c8cSmatt pih->pih_count--;
671b8ea2c8cSmatt }
672b8ea2c8cSmatt if (rv == 0)
673b8ea2c8cSmatt pis->pis_ev_spurious.ev_count++;
674e4a54b41Snonaka mutex_spin_exit(&pis->pis_lock);
675b8ea2c8cSmatt return rv;
676b8ea2c8cSmatt }
677b8ea2c8cSmatt
678b8ea2c8cSmatt static void
pq3pci_intr_source_setup(struct pq3pci_softc * sc,struct pq3pci_intrsource * pis,pci_intr_handle_t handle)679e4a54b41Snonaka pq3pci_intr_source_setup(struct pq3pci_softc *sc, struct pq3pci_intrsource *pis,
680e4a54b41Snonaka pci_intr_handle_t handle)
681b8ea2c8cSmatt {
682b8ea2c8cSmatt SIMPLEQ_INIT(&pis->pis_ihands);
683b8ea2c8cSmatt pis->pis_handle = handle;
684b8ea2c8cSmatt pis->pis_ih = intr_establish(PIH_IRQ(handle), IPL_VM, PIH_IST(handle),
685b8ea2c8cSmatt pq3pci_pis_intr, pis);
686e4a54b41Snonaka mutex_init(&pis->pis_lock, MUTEX_DEFAULT, IPL_VM);
687b8ea2c8cSmatt const char * const intrstr
688e4a54b41Snonaka = intr_string(PIH_IRQ(handle), PIH_IST(handle), pis->pis_intrname,
689e4a54b41Snonaka sizeof(pis->pis_intrname));
690e4a54b41Snonaka evcnt_attach_dynamic(&pis->pis_ev, EVCNT_TYPE_INTR, NULL, intrstr,
691e4a54b41Snonaka "intr");
692b8ea2c8cSmatt evcnt_attach_dynamic(&pis->pis_ev_spurious, EVCNT_TYPE_INTR,
693b8ea2c8cSmatt &pis->pis_ev, intrstr, "spurious intr");
694e4a54b41Snonaka KASSERT(mutex_owned(&pq3pci_intrsources_lock));
695b8ea2c8cSmatt SIMPLEQ_INSERT_TAIL(&pq3pci_intrsources, pis, pis_link);
696b8ea2c8cSmatt }
697b8ea2c8cSmatt
698b8ea2c8cSmatt static bool
pq3pci_intrmap_setup(struct pq3pci_softc * sc,const struct cpunode_locators * cnl)699b8ea2c8cSmatt pq3pci_intrmap_setup(struct pq3pci_softc *sc,
700b8ea2c8cSmatt const struct cpunode_locators *cnl)
701b8ea2c8cSmatt {
702b8ea2c8cSmatt char prop_name[32];
703b8ea2c8cSmatt snprintf(prop_name, sizeof(prop_name), "%s%u-interrupt-map",
704b8ea2c8cSmatt cnl->cnl_name, cnl->cnl_instance);
705b8ea2c8cSmatt sc->sc_intrmap = board_info_get_object(prop_name);
706b8ea2c8cSmatt if (sc->sc_intrmap == NULL) {
707b8ea2c8cSmatt aprint_error(": missing %s board property", prop_name);
708b8ea2c8cSmatt return false;
709b8ea2c8cSmatt }
710b8ea2c8cSmatt
711b8ea2c8cSmatt KASSERT(prop_object_type(sc->sc_intrmap) == PROP_TYPE_DICTIONARY);
712b8ea2c8cSmatt prop_number_t pn = prop_dictionary_get(sc->sc_intrmap, "interrupt-mask");
713b8ea2c8cSmatt KASSERT(pn != NULL);
714b8ea2c8cSmatt
715*08790245Sthorpej sc->sc_intrmask = prop_number_unsigned_value(pn);
716b8ea2c8cSmatt
717e4a54b41Snonaka sc->sc_ih = intr_establish_xname(cnl->cnl_intrs[0], IPL_VM, IST_ONCHIP,
718e4a54b41Snonaka pq3pci_onchip_intr, sc, device_xname(sc->sc_dev));
719b8ea2c8cSmatt if (sc->sc_ih == NULL)
720b8ea2c8cSmatt panic("%s: failed to establish interrupt %d\n",
721b8ea2c8cSmatt device_xname(sc->sc_dev), cnl->cnl_intrs[0]);
722b8ea2c8cSmatt
723b8ea2c8cSmatt return true;
724b8ea2c8cSmatt }
725b8ea2c8cSmatt
726e4a54b41Snonaka static int
pq3pci_once_init(void)727e4a54b41Snonaka pq3pci_once_init(void)
728e4a54b41Snonaka {
729e4a54b41Snonaka
73061749fafSrin /*
73161749fafSrin * XXX necessary??
73261749fafSrin */
73361749fafSrin mutex_init(&pq3pci_intrsources_lock, MUTEX_DEFAULT, IPL_NONE);
73461749fafSrin mutex_init(&pq3pci_msigroups_lock, MUTEX_DEFAULT, IPL_NONE);
735e4a54b41Snonaka
736e4a54b41Snonaka return 0;
737e4a54b41Snonaka }
738e4a54b41Snonaka
739b8ea2c8cSmatt void
pq3pci_cpunode_attach(device_t parent,device_t self,void * aux)740b8ea2c8cSmatt pq3pci_cpunode_attach(device_t parent, device_t self, void *aux)
741b8ea2c8cSmatt {
742b8ea2c8cSmatt struct cpunode_softc * const psc = device_private(parent);
743b8ea2c8cSmatt struct pq3pci_softc * const sc = device_private(self);
744b8ea2c8cSmatt struct cpunode_attach_args * const cna = aux;
745b8ea2c8cSmatt struct cpunode_locators * const cnl = &cna->cna_locs;
746b8ea2c8cSmatt char buf[32];
747b8ea2c8cSmatt
748b8ea2c8cSmatt sc->sc_dev = self;
749b8ea2c8cSmatt sc->sc_bst = cna->cna_memt;
750b8ea2c8cSmatt psc->sc_children |= cna->cna_childmask;
751b8ea2c8cSmatt sc->sc_pcie = strcmp(cnl->cnl_name, "pcie") == 0;
752b8ea2c8cSmatt
753e4a54b41Snonaka RUN_ONCE(&pq3pci_init_once, pq3pci_once_init);
754e4a54b41Snonaka
755b8ea2c8cSmatt const uint32_t pordevsr = cpu_read_4(GLOBAL_BASE + PORDEVSR);
756b8ea2c8cSmatt if (sc->sc_pcie) {
757b8ea2c8cSmatt u_int lanes = e500_truth_decode(cnl->cnl_instance, pordevsr,
758b8ea2c8cSmatt pq3pci_pcie_lanes, __arraycount(pq3pci_pcie_lanes), 0);
759b8ea2c8cSmatt if (lanes == 0) {
760b8ea2c8cSmatt aprint_normal(": disabled\n");
761b8ea2c8cSmatt return;
762b8ea2c8cSmatt }
763b8ea2c8cSmatt snprintf(buf, sizeof(buf), "PCI-Express x%u", lanes);
764b8ea2c8cSmatt } else {
765b8ea2c8cSmatt bool pcix_p = e500_truth_decode(cnl->cnl_instance, pordevsr,
766b8ea2c8cSmatt pq3pci_pci_pcix, __arraycount(pq3pci_pci_pcix), 0);
767b8ea2c8cSmatt u_int width = e500_truth_decode(cnl->cnl_instance, pordevsr,
768b8ea2c8cSmatt pq3pci_pci_pci32, __arraycount(pq3pci_pci_pci32), 32);
769b8ea2c8cSmatt snprintf(buf, sizeof(buf), "%u-bit PCI%s",
770b8ea2c8cSmatt width, (pcix_p ? "X" : ""));
771b8ea2c8cSmatt }
772b8ea2c8cSmatt
773b8ea2c8cSmatt if (!pq3pci_intrmap_setup(sc, cnl))
774b8ea2c8cSmatt return;
775b8ea2c8cSmatt
776b8ea2c8cSmatt evcnt_attach_dynamic(&sc->sc_ev_spurious, EVCNT_TYPE_INTR, NULL,
777b8ea2c8cSmatt device_xname(self), "spurious intr");
778b8ea2c8cSmatt
779b8ea2c8cSmatt int error = bus_space_map(sc->sc_bst, cnl->cnl_addr, cnl->cnl_size, 0,
780b8ea2c8cSmatt &sc->sc_bsh);
781b8ea2c8cSmatt if (error) {
782b8ea2c8cSmatt aprint_error(": failed to map registers: %d\n", error);
783b8ea2c8cSmatt return;
784b8ea2c8cSmatt }
785b8ea2c8cSmatt
786b8ea2c8cSmatt u_int valid_owins = 0;
787b8ea2c8cSmatt for (u_int i = 1, off = PEXOTAR1 - PEXOTAR0;
788b8ea2c8cSmatt i < 4; i++, off += PEXOTAR1 - PEXOTAR0) {
789b8ea2c8cSmatt struct pq3pci_owin owin;
790b8ea2c8cSmatt owin.potar = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
791b8ea2c8cSmatt PEXOTAR0 + off);
792b8ea2c8cSmatt owin.potear = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
793b8ea2c8cSmatt PEXOTEAR0 + off);
794b8ea2c8cSmatt owin.powbar = 0;
795b8ea2c8cSmatt if (i > 0) {
796b8ea2c8cSmatt /* Doesn't exist for outbound window 0 */
797b8ea2c8cSmatt owin.powbar = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
798b8ea2c8cSmatt PEXOWBAR1 - (PEXOTAR1 - PEXOTAR0) + off);
799b8ea2c8cSmatt }
800b8ea2c8cSmatt owin.powar = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
801b8ea2c8cSmatt PEXOWAR0 + off);
802b8ea2c8cSmatt #if 0
803b8ea2c8cSmatt aprint_normal_dev(self,
804b8ea2c8cSmatt "owin[%u]: potar=%#x potear=%#x powbar=%#x powar=%#x\n",
805b8ea2c8cSmatt i, owin.potar, owin.potear, owin.powbar, owin.powar);
806b8ea2c8cSmatt #endif
807b8ea2c8cSmatt if (owin.powar & PEXOWAR_EN) {
808b8ea2c8cSmatt valid_owins++;
8092b43b329Smatt pq3pci_owin_record(sc, i, &owin);
810b8ea2c8cSmatt }
811b8ea2c8cSmatt }
8122b43b329Smatt if (!pq3pci_owin_init(sc, &sc->sc_pci_io_bst, true)
8132b43b329Smatt || !pq3pci_owin_init(sc, &sc->sc_pci_mem_bst, false)) {
8142b43b329Smatt return;
8152b43b329Smatt }
816b8ea2c8cSmatt #ifndef PCI_NETBSD_CONFIGURE
817b8ea2c8cSmatt if (valid_owins == 0) {
818b8ea2c8cSmatt aprint_normal(": %s controller%s\n", buf,
819b8ea2c8cSmatt " (disabled)");
820b8ea2c8cSmatt return;
821b8ea2c8cSmatt }
822b8ea2c8cSmatt #endif
823b8ea2c8cSmatt
824b8ea2c8cSmatt u_int valid_iwins = 0;
825b8ea2c8cSmatt for (u_int i = 0, off = 0; i < 3; i++, off += PEXITAR2 - PEXITAR1) {
826b8ea2c8cSmatt struct pq3pci_iwin iwin;
827b8ea2c8cSmatt iwin.pitar = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
828b8ea2c8cSmatt PEXITAR1 + off);
829b8ea2c8cSmatt iwin.piwbar = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
830b8ea2c8cSmatt PEXIWBAR1 + off);
831b8ea2c8cSmatt if (i > 0) {
832b8ea2c8cSmatt /* Doesn't exist */
833b8ea2c8cSmatt iwin.piwbear = bus_space_read_4(sc->sc_bst,
834b8ea2c8cSmatt sc->sc_bsh,
835b8ea2c8cSmatt PEXIWBEAR2 - (PEXITAR2 - PEXITAR1) + off);
836b8ea2c8cSmatt } else {
837b8ea2c8cSmatt iwin.piwbear = 0;
838b8ea2c8cSmatt }
839b8ea2c8cSmatt iwin.piwar = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
840b8ea2c8cSmatt PEXIWAR1 + off);
841b8ea2c8cSmatt #if 0
842b8ea2c8cSmatt aprint_normal_dev(self,
843b8ea2c8cSmatt "iwin[%u]: pitar=%#x piwbar=%#x piwbear=%#x piwar=%#x\n",
844b8ea2c8cSmatt i, iwin.pitar, iwin.piwbar, iwin.piwbear, iwin.piwar);
845b8ea2c8cSmatt #endif
846b8ea2c8cSmatt if (iwin.piwar & PEXIWAR_EN) {
847b8ea2c8cSmatt valid_iwins++;
848b8ea2c8cSmatt if (!pq3pci_iwin_setup(sc, i, &iwin))
849b8ea2c8cSmatt return;
850b8ea2c8cSmatt }
851b8ea2c8cSmatt }
852b8ea2c8cSmatt
853b8ea2c8cSmatt sc->sc_conf_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_VM);
854b8ea2c8cSmatt
855b8ea2c8cSmatt pci_chipset_tag_t pc = pq3pci_pci_chipset_init(sc);
856b8ea2c8cSmatt
857b8ea2c8cSmatt #ifndef PCI_NETBSD_CONFIGURE
858b8ea2c8cSmatt if (valid_iwins == 0) {
859b8ea2c8cSmatt aprint_normal(": %s controller%s\n", buf,
860b8ea2c8cSmatt " (disabled)");
861b8ea2c8cSmatt return;
862b8ea2c8cSmatt }
863b8ea2c8cSmatt #else
864b8ea2c8cSmatt if (sc->sc_pcie && pci_conf_read(pc, 0, PEX_LTSSM) < LTSSM_L0) {
865b8ea2c8cSmatt aprint_normal(": %s controller%s\n", buf,
866b8ea2c8cSmatt " (offline)");
867b8ea2c8cSmatt return;
868b8ea2c8cSmatt }
869b8ea2c8cSmatt if (!sc->sc_pcie && (pci_conf_read(pc, 0, PCI_PBFR) & PBFR_PAH)) {
870b8ea2c8cSmatt aprint_normal(": %s controller%s\n", buf,
871b8ea2c8cSmatt " (agent mode)");
872b8ea2c8cSmatt return;
873b8ea2c8cSmatt }
874b8ea2c8cSmatt if (valid_iwins == 0) {
875b8ea2c8cSmatt struct pq3pci_iwin iwin = {
876b8ea2c8cSmatt .pitar = 0,
877b8ea2c8cSmatt .piwbar = 0,
878b8ea2c8cSmatt .piwbear = 0,
879b8ea2c8cSmatt .piwar = PEXIWAR_EN|PEXIWAR_PF|PEXIWAR_TRGT_LOCALMEM
880b8ea2c8cSmatt |PEXIWAR_RTT_MEM_SNOOP|PEXIWAR_WTT_MEM_SNOOP
881b8ea2c8cSmatt |__SHIFTIN(30-__builtin_clz(pmemsize),PEXIWAR_IWS),
882b8ea2c8cSmatt };
883b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXITAR2, iwin.pitar);
884b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXIWBAR2, iwin.piwbar);
885b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXIWBEAR2, iwin.piwbear);
886b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXIWAR2, iwin.piwar);
887b8ea2c8cSmatt
888b8ea2c8cSmatt if (!pq3pci_iwin_setup(sc, 2, &iwin)) {
889b8ea2c8cSmatt aprint_error(": error creating inbound window\n");
890b8ea2c8cSmatt return;
891b8ea2c8cSmatt }
892b8ea2c8cSmatt
893b8ea2c8cSmatt }
894b8ea2c8cSmatt
895b8ea2c8cSmatt if (valid_owins == 0) {
896b8ea2c8cSmatt u_long membase, iobase;
897b8ea2c8cSmatt error = extent_alloc(pcimem_ex, PCI_MEMSIZE, PCI_MEMSIZE,
898b8ea2c8cSmatt PCI_MEMSIZE, EX_WAITOK, &membase);
899b8ea2c8cSmatt if (error) {
900b8ea2c8cSmatt aprint_error(
901b8ea2c8cSmatt ": error allocating address space for %s: %d\n",
902b8ea2c8cSmatt "PCI memory", error);
903b8ea2c8cSmatt return;
904b8ea2c8cSmatt }
905b8ea2c8cSmatt struct pq3pci_owin owin1 = {
906b8ea2c8cSmatt .potar = membase >> 12,
907b8ea2c8cSmatt .potear = 0,
908b8ea2c8cSmatt .powbar = membase >> 12,
909b8ea2c8cSmatt .powar = PEXOWAR_EN|PEXOWAR_TC0
910b8ea2c8cSmatt |PEXOWAR_RTT_MEM|PEXOWAR_WTT_MEM
911b8ea2c8cSmatt |__SHIFTIN(ilog2(PCI_MEMSIZE)-1,PEXOWAR_OWS),
912b8ea2c8cSmatt };
913b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXOTAR1, owin1.potar);
914b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXOTEAR1, owin1.potear);
915b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXOWBAR1, owin1.powbar);
916b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXOWAR1, owin1.powar);
9172b43b329Smatt pq3pci_owin_record(sc, 1, &owin1);
918c7664459She if (!pq3pci_owin_init(sc, &sc->sc_pci_mem_bst, false)) {
919b8ea2c8cSmatt return;
920b8ea2c8cSmatt }
921b8ea2c8cSmatt
922b8ea2c8cSmatt error = extent_alloc(pciio_ex, PCI_IOSIZE, PCI_IOSIZE,
923b8ea2c8cSmatt PCI_IOSIZE, EX_WAITOK, &iobase);
924b8ea2c8cSmatt if (error) {
925b8ea2c8cSmatt aprint_error(
926b8ea2c8cSmatt ": error allocating address space for %s: %d\n",
927b8ea2c8cSmatt "PCI I/O space", error);
928b8ea2c8cSmatt return;
929b8ea2c8cSmatt }
930b8ea2c8cSmatt struct pq3pci_owin owin2 = {
931b8ea2c8cSmatt .potar = 0,
932b8ea2c8cSmatt .potear = 0,
933b8ea2c8cSmatt .powbar = iobase >> 12,
934b8ea2c8cSmatt .powar = PEXOWAR_EN|PEXOWAR_TC0
935b8ea2c8cSmatt |PEXOWAR_RTT_IO|PEXOWAR_WTT_IO
936b8ea2c8cSmatt |__SHIFTIN(ilog2(PCI_IOSIZE)-1,PEXOWAR_OWS),
937b8ea2c8cSmatt };
938b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXOTAR2, owin2.potar);
939b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXOTEAR2, owin2.potear);
940b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXOWBAR2, owin2.powbar);
941b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEXOWAR2, owin2.powar);
9422b43b329Smatt pq3pci_owin_record(sc, 2, &owin1);
943c7664459She if (!pq3pci_owin_init(sc, &sc->sc_pci_io_bst, true)) {
944b8ea2c8cSmatt return;
945b8ea2c8cSmatt }
946b8ea2c8cSmatt
947ca8ce3aeSthorpej struct pciconf_resources *pcires = pciconf_resource_init();
948b8ea2c8cSmatt
949ca8ce3aeSthorpej pciconf_resource_add(pcires, PCICONF_RESOURCE_IO,
950ca8ce3aeSthorpej 0, PCI_IOSIZE);
951ca8ce3aeSthorpej pciconf_resource_add(pcires, PCICONF_RESOURCE_MEM,
952ca8ce3aeSthorpej membase, PCI_MEMSIZE);
953ca8ce3aeSthorpej
954ca8ce3aeSthorpej error = pci_configure_bus(pc, pcires, 0,
955b8ea2c8cSmatt curcpu()->ci_ci.dcache_line_size);
956b8ea2c8cSmatt
957ca8ce3aeSthorpej pciconf_resource_fini(pcires);
958b8ea2c8cSmatt
959b8ea2c8cSmatt if (error) {
960b8ea2c8cSmatt aprint_normal(": configuration failed\n");
961b8ea2c8cSmatt return;
962b8ea2c8cSmatt }
963b8ea2c8cSmatt }
964b8ea2c8cSmatt #endif
965b8ea2c8cSmatt
966b8ea2c8cSmatt aprint_normal(": %s controller%s\n", buf, "");
967b8ea2c8cSmatt
968b8ea2c8cSmatt struct pcibus_attach_args pba;
969b8ea2c8cSmatt memset(&pba, 0, sizeof(pba));
970b8ea2c8cSmatt
971b8ea2c8cSmatt pba.pba_flags = sc->sc_pba_flags | PCI_FLAGS_MSI_OKAY
972b8ea2c8cSmatt | PCI_FLAGS_MSIX_OKAY;
973a6b2b839Sdyoung if (pba.pba_flags & PCI_FLAGS_IO_OKAY)
974b8ea2c8cSmatt pba.pba_iot = pc->pc_iot;
975a6b2b839Sdyoung if (pba.pba_flags & PCI_FLAGS_MEM_OKAY)
976b8ea2c8cSmatt pba.pba_memt = pc->pc_memt;
977b8ea2c8cSmatt pba.pba_dmat = cna->cna_dmat;
978b8ea2c8cSmatt pba.pba_pc = pc;
979b8ea2c8cSmatt pba.pba_bus = 0;
980b8ea2c8cSmatt
981b8ea2c8cSmatt /*
982b8ea2c8cSmatt * Program BAR0 so that MSIs can work.
983b8ea2c8cSmatt */
984b8ea2c8cSmatt pci_conf_write(pc, 0, PCI_BAR0, sc->sc_bst->pbs_offset);
985b8ea2c8cSmatt pcireg_t cmdsts = pci_conf_read(pc, 0, PCI_COMMAND_STATUS_REG);
986b8ea2c8cSmatt cmdsts |= PCI_COMMAND_INTERRUPT_DISABLE;
987b8ea2c8cSmatt pci_conf_write(pc, 0, PCI_COMMAND_STATUS_REG, cmdsts);
988b8ea2c8cSmatt
989b8ea2c8cSmatt #if 0
990b8ea2c8cSmatt /*
991b8ea2c8cSmatt *
992b8ea2c8cSmatt */
993b8ea2c8cSmatt pq3pci_intr_source_lookup(sc, PIH_MAKE(0, IST_LEVEL, 0));
994b8ea2c8cSmatt #endif
995b8ea2c8cSmatt #if 0
996b8ea2c8cSmatt if (sc->sc_pcie)
997b8ea2c8cSmatt pci_conf_print(pc, 0, NULL);
998b8ea2c8cSmatt #endif
999b8ea2c8cSmatt
1000c7fb772bSthorpej config_found(self, &pba, pcibusprint, CFARGS_NONE);
1001b8ea2c8cSmatt }
1002b8ea2c8cSmatt
1003b8ea2c8cSmatt static void
pq3pci_attach_hook(device_t parent,device_t self,struct pcibus_attach_args * pba)1004b8ea2c8cSmatt pq3pci_attach_hook(device_t parent, device_t self,
1005b8ea2c8cSmatt struct pcibus_attach_args *pba)
1006b8ea2c8cSmatt {
1007b8ea2c8cSmatt /* do nothing */
1008b8ea2c8cSmatt }
1009b8ea2c8cSmatt
1010b8ea2c8cSmatt static int
pq3pci_bus_maxdevs(void * v,int busno)1011b8ea2c8cSmatt pq3pci_bus_maxdevs(void *v, int busno)
1012b8ea2c8cSmatt {
1013b8ea2c8cSmatt struct pq3pci_softc * const sc = v;
1014b8ea2c8cSmatt return sc->sc_pcie && busno < 2 ? 1 : 32;
1015b8ea2c8cSmatt }
1016b8ea2c8cSmatt
1017b8ea2c8cSmatt static void
pq3pci_decompose_tag(void * v,pcitag_t tag,int * bus,int * dev,int * func)1018b8ea2c8cSmatt pq3pci_decompose_tag(void *v, pcitag_t tag, int *bus, int *dev, int *func)
1019b8ea2c8cSmatt {
1020b8ea2c8cSmatt if (bus)
1021b8ea2c8cSmatt *bus = (tag >> 16) & 0xff;
1022b8ea2c8cSmatt if (dev)
1023b8ea2c8cSmatt *dev = (tag >> 11) & 0x1f;
1024b8ea2c8cSmatt if (func)
1025b8ea2c8cSmatt *func = (tag >> 8) & 0x07;
1026b8ea2c8cSmatt }
1027b8ea2c8cSmatt
1028b8ea2c8cSmatt static pcitag_t
pq3pci_make_tag(void * v,int bus,int dev,int func)1029b8ea2c8cSmatt pq3pci_make_tag(void *v, int bus, int dev, int func)
1030b8ea2c8cSmatt {
1031b8ea2c8cSmatt return (bus << 16) | (dev << 11) | (func << 8);
1032b8ea2c8cSmatt }
1033b8ea2c8cSmatt
1034edb87724Sjoerg #if 0
1035b8ea2c8cSmatt static inline pcitag_t
1036b8ea2c8cSmatt pq3pci_config_addr_read(pci_chipset_tag_t pc)
1037b8ea2c8cSmatt {
1038b8ea2c8cSmatt pcitag_t v;
1039b8ea2c8cSmatt __asm volatile("lwz\t%0, 0(%1)" : "=r"(v) : "b"(pc->pc_addr));
1040b8ea2c8cSmatt __asm volatile("mbar\n\tmsync");
1041b8ea2c8cSmatt return v;
1042b8ea2c8cSmatt }
1043edb87724Sjoerg #endif
1044b8ea2c8cSmatt
1045b8ea2c8cSmatt static inline void
pq3pci_config_addr_write(pci_chipset_tag_t pc,pcitag_t v)1046b8ea2c8cSmatt pq3pci_config_addr_write(pci_chipset_tag_t pc, pcitag_t v)
1047b8ea2c8cSmatt {
1048b8ea2c8cSmatt __asm volatile("stw\t%0, 0(%1)" :: "r"(v), "b"(pc->pc_addr));
1049b8ea2c8cSmatt __asm volatile("mbar\n\tmsync");
1050b8ea2c8cSmatt }
1051b8ea2c8cSmatt
1052b8ea2c8cSmatt static inline pcireg_t
pq3pci_config_data_read(pci_chipset_tag_t pc)1053b8ea2c8cSmatt pq3pci_config_data_read(pci_chipset_tag_t pc)
1054b8ea2c8cSmatt {
1055b8ea2c8cSmatt pcireg_t v;
1056b8ea2c8cSmatt __asm volatile("lwbrx\t%0, 0, %1" : "=r"(v) : "b"(pc->pc_data));
1057b8ea2c8cSmatt __asm volatile("mbar\n\tmsync");
1058b8ea2c8cSmatt return v;
1059b8ea2c8cSmatt }
1060b8ea2c8cSmatt
1061b8ea2c8cSmatt static inline void
pq3pci_config_data_write(pci_chipset_tag_t pc,pcireg_t v)1062b8ea2c8cSmatt pq3pci_config_data_write(pci_chipset_tag_t pc, pcireg_t v)
1063b8ea2c8cSmatt {
1064b8ea2c8cSmatt __asm volatile("stwbrx\t%0, 0, %1" :: "r"(v), "r"(pc->pc_data));
1065b8ea2c8cSmatt __asm volatile("mbar\n\tmsync");
1066b8ea2c8cSmatt }
1067b8ea2c8cSmatt
1068b8ea2c8cSmatt static pcireg_t
pq3pci_conf_read(void * v,pcitag_t tag,int reg)1069b8ea2c8cSmatt pq3pci_conf_read(void *v, pcitag_t tag, int reg)
1070b8ea2c8cSmatt {
1071b8ea2c8cSmatt struct pq3pci_softc * const sc = v;
1072b8ea2c8cSmatt struct genppc_pci_chipset * const pc = &sc->sc_pc;
1073b8ea2c8cSmatt
1074605f564fSmsaitoh if (reg < 0)
1075605f564fSmsaitoh return 0xffffffff;
1076605f564fSmsaitoh if (reg >= PCI_CONF_SIZE) {
1077605f564fSmsaitoh if (!sc->sc_pcie || reg >= PCI_EXTCONF_SIZE)
1078b8ea2c8cSmatt return 0xffffffff;
1079b8ea2c8cSmatt reg = (reg & 0xff) | ((reg & 0xf00) << 16);
1080b8ea2c8cSmatt }
1081b8ea2c8cSmatt if (sc->sc_pcie && ((tag >> 16) & 0xff) != 0) {
1082b8ea2c8cSmatt // pcireg_t slot_status = pci_conf_read(pc, 0, 0x64);
1083b8ea2c8cSmatt // printf("%s: tag 0x0 slot status: %#x\n",__func__, slot_status);
1084b8ea2c8cSmatt // if ((slot_status & __BIT(6+16)) == 0)
1085b8ea2c8cSmatt // printf(" addr=%#llx ", tag | reg | PEX_CONFIG_ADDR_EN);
1086b8ea2c8cSmatt // return 0xffffffff;
1087b8ea2c8cSmatt }
1088b8ea2c8cSmatt
1089b8ea2c8cSmatt mutex_spin_enter(sc->sc_conf_lock);
1090b8ea2c8cSmatt
1091b8ea2c8cSmatt pq3pci_config_addr_write(pc, tag | reg | PEX_CONFIG_ADDR_EN);
1092b8ea2c8cSmatt pcireg_t rv = pq3pci_config_data_read(pc);
1093b8ea2c8cSmatt
1094b8ea2c8cSmatt mutex_spin_exit(sc->sc_conf_lock);
1095b8ea2c8cSmatt
1096b8ea2c8cSmatt #if 0
1097b8ea2c8cSmatt uint32_t err = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PEX_ERR_DR);
1098b8ea2c8cSmatt if (err & PEXERRDR_ICCA) {
1099b8ea2c8cSmatt aprint_error_dev(sc->sc_dev, "%s: tag %#x reg %#x icca: %#x\n",
1100b8ea2c8cSmatt __func__, tag, reg, pq3pci_config_addr_read(pc));
1101b8ea2c8cSmatt bus_space_write_4(sc->sc_bst, sc->sc_bsh, PEX_ERR_DR,
1102b8ea2c8cSmatt PEXERRDR_ICCA);
1103b8ea2c8cSmatt }
1104b8ea2c8cSmatt #endif
1105b8ea2c8cSmatt return rv;
1106b8ea2c8cSmatt }
1107b8ea2c8cSmatt
1108b8ea2c8cSmatt static void
pq3pci_conf_write(void * v,pcitag_t tag,int reg,pcireg_t data)1109b8ea2c8cSmatt pq3pci_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
1110b8ea2c8cSmatt {
1111b8ea2c8cSmatt struct pq3pci_softc * const sc = v;
1112b8ea2c8cSmatt struct genppc_pci_chipset * const pc = &sc->sc_pc;
1113b8ea2c8cSmatt
1114605f564fSmsaitoh if (reg < 0)
1115605f564fSmsaitoh return;
1116605f564fSmsaitoh if (reg >= PCI_CONF_SIZE) {
1117605f564fSmsaitoh if (!sc->sc_pcie || reg >= PCI_EXTCONF_SIZE)
1118b8ea2c8cSmatt return;
1119b8ea2c8cSmatt reg = (reg & 0xff) | ((reg & 0xf00) << 16);
1120b8ea2c8cSmatt }
1121b8ea2c8cSmatt
1122b8ea2c8cSmatt mutex_spin_enter(sc->sc_conf_lock);
1123b8ea2c8cSmatt
1124b8ea2c8cSmatt #if 0
1125b8ea2c8cSmatt aprint_error_dev(sc->sc_dev, "%s: tag %#x reg %#x data %#x\n",
1126b8ea2c8cSmatt __func__, tag, reg, data);
1127b8ea2c8cSmatt #endif
1128b8ea2c8cSmatt pq3pci_config_addr_write(pc, tag | reg | PEX_CONFIG_ADDR_EN);
1129b8ea2c8cSmatt pq3pci_config_data_write(pc, data);
1130b8ea2c8cSmatt
1131b8ea2c8cSmatt mutex_spin_exit(sc->sc_conf_lock);
1132b8ea2c8cSmatt }
1133b8ea2c8cSmatt
1134e4a54b41Snonaka #ifdef PCI_NETBSD_CONFIGURE
1135b8ea2c8cSmatt static int
pq3pci_conf_hook(void * v,int bus,int dev,int func,pcireg_t id)1136dd2488a8Smatt pq3pci_conf_hook(void *v, int bus, int dev, int func, pcireg_t id)
1137b8ea2c8cSmatt {
1138dd2488a8Smatt struct pq3pci_softc * const sc = v;
1139b8ea2c8cSmatt if (sc->sc_pcie && bus != 0) {
1140dd2488a8Smatt pcireg_t slot_status = pci_conf_read(&sc->sc_pc, 0, 0x64);
1141b8ea2c8cSmatt if ((slot_status & __BIT(6+16)) == 0)
1142b8ea2c8cSmatt return 0;
1143b8ea2c8cSmatt }
1144b8ea2c8cSmatt if (!sc->sc_pcie && bus == 0 && dev == 0) {
1145b8ea2c8cSmatt return PCI_CONF_DEFAULT ^ (PCI_CONF_MAP_IO|PCI_CONF_MAP_MEM|PCI_CONF_MAP_ROM);
1146b8ea2c8cSmatt }
1147b8ea2c8cSmatt return PCI_CONF_DEFAULT;
1148b8ea2c8cSmatt }
1149e4a54b41Snonaka #endif
1150b8ea2c8cSmatt
1151b8ea2c8cSmatt static void
pq3pci_msi_group_setup(struct pq3pci_msigroup * msig,u_int group,int ipl)1152b8ea2c8cSmatt pq3pci_msi_group_setup(struct pq3pci_msigroup *msig, u_int group, int ipl)
1153b8ea2c8cSmatt {
1154e4a54b41Snonaka char buf[12];
1155b8ea2c8cSmatt const char (*intr_names)[8] = msi_intr_names[group];
1156b8ea2c8cSmatt
1157b8ea2c8cSmatt KASSERT(ipl == IPL_VM);
1158e4a54b41Snonaka KASSERT(mutex_owned(&pq3pci_msigroups_lock));
1159b8ea2c8cSmatt
1160b8ea2c8cSmatt msig->msig_group = group;
1161b8ea2c8cSmatt msig->msig_free_mask = ~0 << (group == 0);
1162b8ea2c8cSmatt msig->msig_ipl = ipl;
1163e4a54b41Snonaka mutex_init(&msig->msig_lock, MUTEX_DEFAULT, ipl);
1164e4a54b41Snonaka snprintf(buf, sizeof(buf), "msi %d-%d", group * 32, group * 32 + 31);
1165e4a54b41Snonaka msig->msig_ih = intr_establish_xname(msig->msig_group, ipl,
1166e4a54b41Snonaka IST_MSIGROUP, pq3pci_msi_intr, msig, buf);
1167b8ea2c8cSmatt msig->msig_msir = OPENPIC_BASE + OPENPIC_MSIR(msig->msig_group);
1168b8ea2c8cSmatt for (u_int i = 0; i < __arraycount(msig->msig_ihands); i++) {
1169b8ea2c8cSmatt struct pq3pci_msihand * const msih = msig->msig_ihands + i;
1170b8ea2c8cSmatt msih->msih_ih.ih_class = IH_MSI;
1171b8ea2c8cSmatt msih->msih_ih.ih_func = pq3pci_msi_spurious_intr;
1172b8ea2c8cSmatt msih->msih_ih.ih_arg = msih;
1173b8ea2c8cSmatt msih->msih_group = msig;
1174b8ea2c8cSmatt evcnt_attach_dynamic(&msih->msih_ev, EVCNT_TYPE_INTR,
1175b8ea2c8cSmatt NULL, intr_names[i], "intr");
1176b8ea2c8cSmatt evcnt_attach_dynamic(&msih->msih_ev_spurious, EVCNT_TYPE_INTR,
1177b8ea2c8cSmatt &msih->msih_ev, intr_names[i], "spurious intr");
1178b8ea2c8cSmatt }
1179e4a54b41Snonaka pq3pci_msigroups[group] = msig;
1180e4a54b41Snonaka }
1181e4a54b41Snonaka
1182e4a54b41Snonaka static struct pq3pci_msihand *
pq3pci_msi_lookup(pci_intr_handle_t handle)1183e4a54b41Snonaka pq3pci_msi_lookup(pci_intr_handle_t handle)
1184e4a54b41Snonaka {
1185e4a54b41Snonaka const int irq = PIH_IRQ(handle);
1186e4a54b41Snonaka KASSERT(irq < 256);
1187e4a54b41Snonaka struct pq3pci_msigroup * const msig = pq3pci_msigroups[irq / 32];
1188e4a54b41Snonaka KASSERT(msig != NULL);
1189e4a54b41Snonaka return &msig->msig_ihands[irq & 31];
1190e4a54b41Snonaka }
1191e4a54b41Snonaka
1192e4a54b41Snonaka static struct pq3pci_msihand *
pq3pci_msi_claim(pci_intr_handle_t handle)1193e4a54b41Snonaka pq3pci_msi_claim(pci_intr_handle_t handle)
1194e4a54b41Snonaka {
1195e4a54b41Snonaka const int irq = PIH_IRQ(handle);
1196e4a54b41Snonaka uint32_t irq_mask = __BIT(irq & 31);
1197e4a54b41Snonaka KASSERT(irq < 256);
1198e4a54b41Snonaka struct pq3pci_msigroup * const msig = pq3pci_msigroups[irq / 32];
1199e4a54b41Snonaka KASSERT(msig != NULL);
1200e4a54b41Snonaka struct pq3pci_msihand * const msih = &msig->msig_ihands[irq & 31];
1201e4a54b41Snonaka mutex_spin_enter(&msig->msig_lock);
1202e4a54b41Snonaka msig->msig_free_mask ^= irq_mask;
1203e4a54b41Snonaka mutex_spin_exit(&msig->msig_lock);
1204e4a54b41Snonaka return msih;
1205b8ea2c8cSmatt }
1206b8ea2c8cSmatt
1207b8ea2c8cSmatt static pci_intr_handle_t
pq3pci_msi_alloc_one(int ipl)1208e4a54b41Snonaka pq3pci_msi_alloc_one(int ipl)
1209b8ea2c8cSmatt {
1210b8ea2c8cSmatt size_t freegroup = 0;
1211e4a54b41Snonaka const size_t maplen = __arraycount(pq3pci_msigroups);
1212b8ea2c8cSmatt uint32_t bitmap[maplen];
1213e4a54b41Snonaka pci_intr_handle_t handle;
1214b8ea2c8cSmatt
121561749fafSrin mutex_enter(&pq3pci_msigroups_lock);
1216b8ea2c8cSmatt for (u_int i = 0; i < maplen; i++) {
1217b8ea2c8cSmatt struct pq3pci_msigroup * const msig = pq3pci_msigroups[i];
1218b8ea2c8cSmatt if (msig == NULL) {
1219b8ea2c8cSmatt bitmap[i] = 0;
1220b8ea2c8cSmatt if (freegroup == 0)
1221b8ea2c8cSmatt freegroup = i + 1;
1222b8ea2c8cSmatt continue;
1223b8ea2c8cSmatt }
1224b8ea2c8cSmatt /*
1225b8ea2c8cSmatt * If this msigroup has the wrong IPL or there's nothing
1226b8ea2c8cSmatt * free, try the next one.
1227b8ea2c8cSmatt */
1228b8ea2c8cSmatt if (msig->msig_ipl != ipl || msig->msig_free_mask == 0) {
1229b8ea2c8cSmatt bitmap[i] = 0;
1230b8ea2c8cSmatt continue;
1231b8ea2c8cSmatt }
1232b8ea2c8cSmatt
1233b8ea2c8cSmatt bitmap[i] = msig->msig_free_mask;
1234b8ea2c8cSmatt }
1235b8ea2c8cSmatt for (u_int i = 0; i < maplen; i++) {
1236b8ea2c8cSmatt uint32_t mapbits = bitmap[i];
1237b8ea2c8cSmatt u_int n = ffs(mapbits);
1238b8ea2c8cSmatt if (n--) {
1239e4a54b41Snonaka handle = PIH_MAKE(i * 32 + n, IST_MSI, 0);
1240e4a54b41Snonaka struct pq3pci_msihand * const msih __diagused =
1241e4a54b41Snonaka pq3pci_msi_claim(handle);
1242e4a54b41Snonaka KASSERT(msih != NULL);
124361749fafSrin mutex_exit(&pq3pci_msigroups_lock);
1244e4a54b41Snonaka return handle;
1245b8ea2c8cSmatt }
1246b8ea2c8cSmatt }
1247b8ea2c8cSmatt
1248e4a54b41Snonaka if (freegroup-- == 0) {
124961749fafSrin mutex_exit(&pq3pci_msigroups_lock);
1250b8ea2c8cSmatt return 0;
1251e4a54b41Snonaka }
1252b8ea2c8cSmatt
1253b8ea2c8cSmatt struct pq3pci_msigroup * const msig =
1254e4a54b41Snonaka kmem_zalloc(sizeof(*msig), KM_NOSLEEP);
1255e4a54b41Snonaka if (msig == NULL) {
125661749fafSrin mutex_exit(&pq3pci_msigroups_lock);
1257e4a54b41Snonaka return 0;
1258e4a54b41Snonaka }
1259b8ea2c8cSmatt pq3pci_msi_group_setup(msig, freegroup, ipl);
1260b8ea2c8cSmatt u_int n = ffs(msig->msig_free_mask) - 1;
1261e4a54b41Snonaka handle = PIH_MAKE(freegroup * 32 + n, IST_MSI, 0);
1262e4a54b41Snonaka struct pq3pci_msihand * const msih __diagused =
1263e4a54b41Snonaka pq3pci_msi_claim(handle);
1264e4a54b41Snonaka KASSERT(msih != NULL);
126561749fafSrin mutex_exit(&pq3pci_msigroups_lock);
1266e4a54b41Snonaka return handle;
1267b8ea2c8cSmatt }
1268b8ea2c8cSmatt
1269e4a54b41Snonaka static int
pq3pci_msi_alloc_vectors(struct pq3pci_softc * sc,const struct pci_attach_args * pa,pci_intr_handle_t ** ihps,int count)1270e4a54b41Snonaka pq3pci_msi_alloc_vectors(struct pq3pci_softc *sc,
1271e4a54b41Snonaka const struct pci_attach_args *pa, pci_intr_handle_t **ihps, int count)
1272b8ea2c8cSmatt {
1273e4a54b41Snonaka pci_intr_handle_t *vectors;
1274e4a54b41Snonaka struct pq3pci_msihand * msih;
1275e4a54b41Snonaka pcireg_t msictl;
1276e4a54b41Snonaka int msioff;
1277e4a54b41Snonaka
1278e4a54b41Snonaka *ihps = NULL;
1279e4a54b41Snonaka
1280e4a54b41Snonaka if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI, &msioff,
1281e4a54b41Snonaka NULL))
1282e4a54b41Snonaka return ENODEV;
1283e4a54b41Snonaka
1284e4a54b41Snonaka msictl = pci_conf_read(pa->pa_pc, pa->pa_tag, msioff);
1285e4a54b41Snonaka msictl &= ~PCI_MSI_CTL_MSI_ENABLE;
1286e4a54b41Snonaka msictl &= ~PCI_MSI_CTL_MME_MASK;
1287e4a54b41Snonaka pci_conf_write(pa->pa_pc, pa->pa_tag, msioff, msictl);
1288e4a54b41Snonaka
1289e4a54b41Snonaka const size_t alloc_size = sizeof(*vectors) * count;
1290e4a54b41Snonaka vectors = kmem_zalloc(alloc_size, KM_SLEEP);
1291e4a54b41Snonaka
1292e4a54b41Snonaka for (int i = 0; i < count; ++i) {
1293e4a54b41Snonaka pci_intr_handle_t handle = pq3pci_msi_alloc_one(IPL_VM);
1294e4a54b41Snonaka if (handle == 0) {
1295e4a54b41Snonaka for (int j = i - 1; j >= 0; j--) {
1296e4a54b41Snonaka msih = pq3pci_msi_claim(vectors[j]);
1297e4a54b41Snonaka msih->msih_tag = 0;
1298e4a54b41Snonaka msih->msih_msioff = 0;
1299e4a54b41Snonaka }
1300e4a54b41Snonaka kmem_free(vectors, alloc_size);
1301e4a54b41Snonaka return EBUSY;
1302e4a54b41Snonaka }
1303e4a54b41Snonaka vectors[i] = handle;
1304e4a54b41Snonaka
1305e4a54b41Snonaka msih = pq3pci_msi_lookup(handle);
1306e4a54b41Snonaka msih->msih_tag = pa->pa_tag;
1307e4a54b41Snonaka msih->msih_msioff = msioff;
1308b8ea2c8cSmatt }
1309b8ea2c8cSmatt
1310e4a54b41Snonaka *ihps = vectors;
1311e4a54b41Snonaka return 0;
1312e4a54b41Snonaka }
1313e4a54b41Snonaka
1314e4a54b41Snonaka static void
pq3pci_msi_free_vectors(struct pq3pci_softc * sc,pci_intr_handle_t * ihp,int count)1315e4a54b41Snonaka pq3pci_msi_free_vectors(struct pq3pci_softc *sc, pci_intr_handle_t *ihp,
1316e4a54b41Snonaka int count)
1317b8ea2c8cSmatt {
1318e4a54b41Snonaka
1319e4a54b41Snonaka KASSERT(count > 0);
1320e4a54b41Snonaka
1321e4a54b41Snonaka for (int i = 0; i < count; ++i) {
1322e4a54b41Snonaka struct pq3pci_msihand * const msih __diagused =
1323e4a54b41Snonaka pq3pci_msi_claim(ihp[i]);
1324e4a54b41Snonaka KASSERT(msih != NULL);
1325e4a54b41Snonaka }
1326e4a54b41Snonaka kmem_free(ihp, sizeof(*ihp) * count);
1327b8ea2c8cSmatt }
1328b8ea2c8cSmatt
1329b8ea2c8cSmatt static struct pq3pci_intrsource *
pq3pci_intr_source_lookup(struct pq3pci_softc * sc,pci_intr_handle_t handle)1330b8ea2c8cSmatt pq3pci_intr_source_lookup(struct pq3pci_softc *sc, pci_intr_handle_t handle)
1331b8ea2c8cSmatt {
1332b8ea2c8cSmatt struct pq3pci_intrsource *pis;
133361749fafSrin mutex_enter(&pq3pci_intrsources_lock);
1334b8ea2c8cSmatt SIMPLEQ_FOREACH(pis, &pq3pci_intrsources, pis_link) {
1335e4a54b41Snonaka if (pis->pis_handle == handle) {
133661749fafSrin mutex_exit(&pq3pci_intrsources_lock);
1337b8ea2c8cSmatt return pis;
1338b8ea2c8cSmatt }
1339e4a54b41Snonaka }
1340e4a54b41Snonaka pis = kmem_zalloc(sizeof(*pis), KM_NOSLEEP);
1341e4a54b41Snonaka if (pis != NULL)
1342b8ea2c8cSmatt pq3pci_intr_source_setup(sc, pis, handle);
134361749fafSrin mutex_exit(&pq3pci_intrsources_lock);
1344b8ea2c8cSmatt return pis;
1345b8ea2c8cSmatt }
1346b8ea2c8cSmatt
1347b8ea2c8cSmatt static pci_intr_handle_t
pq3pci_intr_handle_lookup(struct pq3pci_softc * sc,const struct pci_attach_args * pa)1348d3e53912Sdyoung pq3pci_intr_handle_lookup(struct pq3pci_softc *sc,
1349d3e53912Sdyoung const struct pci_attach_args *pa)
1350b8ea2c8cSmatt {
1351b8ea2c8cSmatt prop_dictionary_t entry;
1352b8ea2c8cSmatt
1353e4a54b41Snonaka #ifndef PQ3PCI_INTR_MAP_NO_USE_MSI
1354b8ea2c8cSmatt if (sc->sc_pcie) do {
1355b8ea2c8cSmatt pcireg_t msictl;
1356b8ea2c8cSmatt int msioff;
1357b8ea2c8cSmatt if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI,
1358e4a54b41Snonaka &msioff, NULL))
1359b8ea2c8cSmatt break;
1360b8ea2c8cSmatt msictl = pci_conf_read(pa->pa_pc, pa->pa_tag, msioff);
1361b8ea2c8cSmatt msictl &= ~PCI_MSI_CTL_MSI_ENABLE;
136270183e51Sdyoung msictl &= ~PCI_MSI_CTL_MME_MASK;
1363b8ea2c8cSmatt pci_conf_write(pa->pa_pc, pa->pa_tag, msioff, msictl);
1364e4a54b41Snonaka pci_intr_handle_t handle = pq3pci_msi_alloc_one(IPL_VM);
1365b8ea2c8cSmatt struct pq3pci_msihand * const msih = pq3pci_msi_lookup(handle);
1366b8ea2c8cSmatt msih->msih_tag = pa->pa_tag;
1367b8ea2c8cSmatt msih->msih_msioff = msioff;
1368b8ea2c8cSmatt return handle;
1369b8ea2c8cSmatt } while (false);
1370e4a54b41Snonaka #endif
1371b8ea2c8cSmatt
1372b8ea2c8cSmatt if (sc->sc_intrmask == 0) {
1373b8ea2c8cSmatt entry = prop_dictionary_get(sc->sc_intrmap, "000000");
1374b8ea2c8cSmatt } else {
1375b8ea2c8cSmatt char prop_name[8];
1376b8ea2c8cSmatt u_int intrinc = __LOWEST_SET_BIT(sc->sc_intrmask);
1377b8ea2c8cSmatt pcitag_t tag = (pa->pa_intrpin - PCI_INTERRUPT_PIN_A) * intrinc;
1378b8ea2c8cSmatt
1379b8ea2c8cSmatt snprintf(prop_name, sizeof(prop_name), "%06x",
1380b8ea2c8cSmatt tag & sc->sc_intrmask);
1381b8ea2c8cSmatt
1382b8ea2c8cSmatt #if 0
1383b8ea2c8cSmatt printf("%s: %#x %#x %u (%u) -> %#x & %#x -> %#x <%s>\n",
1384b8ea2c8cSmatt __func__, pa->pa_tag, pa->pa_intrtag, pa->pa_intrpin, pa->pa_rawintrpin,
1385b8ea2c8cSmatt tag, sc->sc_intrmask, tag & sc->sc_intrmask, prop_name);
1386b8ea2c8cSmatt #endif
1387b8ea2c8cSmatt
1388b8ea2c8cSmatt entry = prop_dictionary_get(sc->sc_intrmap, prop_name);
1389b8ea2c8cSmatt }
1390b8ea2c8cSmatt KASSERT(entry != NULL);
1391b8ea2c8cSmatt KASSERT(prop_object_type(entry) == PROP_TYPE_DICTIONARY);
1392b8ea2c8cSmatt
1393b8ea2c8cSmatt prop_number_t pn_irq = prop_dictionary_get(entry, "interrupt");
1394b8ea2c8cSmatt KASSERT(pn_irq != NULL);
1395b8ea2c8cSmatt KASSERT(prop_object_type(pn_irq) == PROP_TYPE_NUMBER);
1396*08790245Sthorpej int irq = prop_number_unsigned_value(pn_irq);
1397b8ea2c8cSmatt prop_number_t pn_ist = prop_dictionary_get(entry, "type");
1398b8ea2c8cSmatt KASSERT(pn_ist != NULL);
1399b8ea2c8cSmatt KASSERT(prop_object_type(pn_ist) == PROP_TYPE_NUMBER);
1400*08790245Sthorpej int ist = prop_number_unsigned_value(pn_ist);
1401b8ea2c8cSmatt
1402b8ea2c8cSmatt return PIH_MAKE(irq, ist, 0);
1403b8ea2c8cSmatt }
1404b8ea2c8cSmatt
1405b8ea2c8cSmatt static int
pq3pci_intr_map(const struct pci_attach_args * pa,pci_intr_handle_t * handlep)1406d3e53912Sdyoung pq3pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *handlep)
1407b8ea2c8cSmatt {
1408b8ea2c8cSmatt struct pq3pci_softc * const sc = pa->pa_pc->pc_intr_v;
1409b8ea2c8cSmatt
1410b8ea2c8cSmatt if (pa->pa_intrpin == PCI_INTERRUPT_PIN_NONE)
1411b8ea2c8cSmatt return ENOENT;
1412b8ea2c8cSmatt
1413b8ea2c8cSmatt *handlep = pq3pci_intr_handle_lookup(sc, pa);
1414b8ea2c8cSmatt
1415b8ea2c8cSmatt return 0;
1416b8ea2c8cSmatt }
1417b8ea2c8cSmatt
1418b8ea2c8cSmatt static const char *
pq3pci_intr_string(void * v,pci_intr_handle_t handle,char * buf,size_t len)1419e58a356cSchristos pq3pci_intr_string(void *v, pci_intr_handle_t handle, char *buf, size_t len)
1420b8ea2c8cSmatt {
1421b8ea2c8cSmatt if (PIH_IST(handle) == IST_MSI) {
1422b8ea2c8cSmatt const char (*intr_names)[8] = msi_intr_names[0];
1423e58a356cSchristos strlcpy(buf, intr_names[PIH_IRQ(handle)], len);
1424e58a356cSchristos return buf;
1425b8ea2c8cSmatt }
1426b8ea2c8cSmatt
1427e58a356cSchristos return intr_string(PIH_IRQ(handle), PIH_IST(handle), buf, len);
1428b8ea2c8cSmatt }
1429b8ea2c8cSmatt
1430b8ea2c8cSmatt static const struct evcnt *
pq3pci_intr_evcnt(void * v,pci_intr_handle_t handle)1431b8ea2c8cSmatt pq3pci_intr_evcnt(void *v, pci_intr_handle_t handle)
1432b8ea2c8cSmatt {
1433b8ea2c8cSmatt struct pq3pci_softc * const sc = v;
1434e4a54b41Snonaka if (PIH_IST(handle) == IST_MSI) {
1435e4a54b41Snonaka struct pq3pci_msihand * const msih = pq3pci_msi_lookup(handle);
1436e4a54b41Snonaka
1437e4a54b41Snonaka KASSERT(msih != NULL);
1438e4a54b41Snonaka
1439e4a54b41Snonaka return &msih->msih_ev;
1440e4a54b41Snonaka }
1441b8ea2c8cSmatt struct pq3pci_intrsource * const pis =
1442b8ea2c8cSmatt pq3pci_intr_source_lookup(sc, handle);
1443e4a54b41Snonaka if (pis != NULL)
1444b8ea2c8cSmatt return &pis->pis_ev;
1445e4a54b41Snonaka return NULL;
1446b8ea2c8cSmatt }
1447b8ea2c8cSmatt
1448b8ea2c8cSmatt static void *
pq3pci_intr_establish(void * v,pci_intr_handle_t handle,int ipl,int (* func)(void *),void * arg,const char * xname)1449b8ea2c8cSmatt pq3pci_intr_establish(void *v, pci_intr_handle_t handle, int ipl,
1450e4a54b41Snonaka int (*func)(void *), void *arg, const char *xname)
1451b8ea2c8cSmatt {
1452b8ea2c8cSmatt struct pq3pci_softc * const sc = v;
1453b8ea2c8cSmatt const int ist = PIH_IST(handle);
1454b8ea2c8cSmatt
1455b8ea2c8cSmatt if (ist == IST_MSI) {
1456b8ea2c8cSmatt pci_chipset_tag_t pc = &sc->sc_pc;
1457e4a54b41Snonaka struct pq3pci_msihand * const msih = pq3pci_msi_lookup(handle);
1458b8ea2c8cSmatt pcireg_t cmdsts, msictl;
1459b8ea2c8cSmatt
1460b8ea2c8cSmatt if (msih == NULL)
1461b8ea2c8cSmatt return NULL;
1462b8ea2c8cSmatt
1463b8ea2c8cSmatt struct pq3pci_msigroup * const msig = msih->msih_group;
1464b8ea2c8cSmatt const pcitag_t tag = msih->msih_tag;
1465b8ea2c8cSmatt
1466e4a54b41Snonaka mutex_spin_enter(&msig->msig_lock);
1467b8ea2c8cSmatt msih->msih_ih.ih_class = IH_MSI;
1468b8ea2c8cSmatt msih->msih_ih.ih_arg = arg;
1469b8ea2c8cSmatt msih->msih_ih.ih_func = func;
1470b8ea2c8cSmatt msih->msih_ih.ih_sc = sc;
1471b8ea2c8cSmatt
1472b8ea2c8cSmatt int off = msih->msih_msioff;
1473b8ea2c8cSmatt msictl = pci_conf_read(pc, tag, off);
1474b8ea2c8cSmatt
1475b8ea2c8cSmatt /*
1476b8ea2c8cSmatt * The PCSRBAR has already been setup as a 1:1 BAR so we point
1477b8ea2c8cSmatt * MSIs at the MSII register in the OpenPIC.
1478b8ea2c8cSmatt */
1479b8ea2c8cSmatt off += 4;
1480b8ea2c8cSmatt pci_conf_write(pc, tag, off,
1481b8ea2c8cSmatt sc->sc_bst->pbs_offset + OPENPIC_BASE + OPENPIC_MSIIR);
1482b8ea2c8cSmatt
1483b8ea2c8cSmatt /*
1484b8ea2c8cSmatt * Upper address is going to be 0.
1485b8ea2c8cSmatt */
1486b8ea2c8cSmatt if (msictl & PCI_MSI_CTL_64BIT_ADDR) {
1487b8ea2c8cSmatt off += 4;
1488b8ea2c8cSmatt pci_conf_write(pc, tag, off, 0);
1489b8ea2c8cSmatt }
1490b8ea2c8cSmatt
1491b8ea2c8cSmatt /*
1492b8ea2c8cSmatt * Set the magic value. Since PCI writes this to the least
1493b8ea2c8cSmatt * significant byte of AD[31:0], let's hope the bridge byte
1494b8ea2c8cSmatt * swaps to so it's the most significant bytes or nothing is
1495b8ea2c8cSmatt * going to happen.
1496b8ea2c8cSmatt */
1497b8ea2c8cSmatt off += 4;
1498b8ea2c8cSmatt pci_conf_write(pc, tag, off, PIH_IRQ(handle));
1499b8ea2c8cSmatt
1500b8ea2c8cSmatt /*
1501b8ea2c8cSmatt * Should the driver do this? How would it know to do it?
1502b8ea2c8cSmatt */
1503b8ea2c8cSmatt if (msictl & PCI_MSI_CTL_PERVEC_MASK) {
1504b8ea2c8cSmatt off += 4;
1505b8ea2c8cSmatt pci_conf_write(pc, tag, off, 0);
1506b8ea2c8cSmatt }
1507b8ea2c8cSmatt
1508b8ea2c8cSmatt /*
1509b8ea2c8cSmatt * Let's make sure he won't raise any INTx. Technically
1510b8ea2c8cSmatt * setting MSI enable will prevent that as well but might
1511b8ea2c8cSmatt * as well be as safe as possible.
1512b8ea2c8cSmatt */
1513b8ea2c8cSmatt cmdsts = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
1514b8ea2c8cSmatt cmdsts |= PCI_COMMAND_INTERRUPT_DISABLE;
1515b8ea2c8cSmatt pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, cmdsts);
1516b8ea2c8cSmatt
1517b8ea2c8cSmatt #if 1
1518b8ea2c8cSmatt /*
1519b8ea2c8cSmatt * Now we can enable the MSI
1520b8ea2c8cSmatt */
1521b8ea2c8cSmatt msictl |= PCI_MSI_CTL_MSI_ENABLE;
1522b8ea2c8cSmatt pci_conf_write(pc, tag, msih->msih_msioff, msictl);
1523b8ea2c8cSmatt #endif
1524b8ea2c8cSmatt
1525e4a54b41Snonaka mutex_spin_exit(&msig->msig_lock);
1526b8ea2c8cSmatt
1527b8ea2c8cSmatt return msih;
1528e4a54b41Snonaka }
1529e4a54b41Snonaka
1530b8ea2c8cSmatt struct pq3pci_intrsource * const pis =
1531b8ea2c8cSmatt pq3pci_intr_source_lookup(sc, handle);
1532e4a54b41Snonaka if (pis == NULL)
1533e4a54b41Snonaka return NULL;
1534b8ea2c8cSmatt
1535b8ea2c8cSmatt struct pq3pci_intrhand * const pih =
1536b8ea2c8cSmatt kmem_zalloc(sizeof(*pih), KM_SLEEP);
1537b8ea2c8cSmatt pih->pih_ih.ih_class = IH_INTX;
1538b8ea2c8cSmatt pih->pih_ih.ih_func = func;
1539b8ea2c8cSmatt pih->pih_ih.ih_arg = arg;
1540b8ea2c8cSmatt pih->pih_ih.ih_sc = sc;
1541b8ea2c8cSmatt pih->pih_ipl = ipl;
1542b8ea2c8cSmatt pih->pih_source = pis;
1543b8ea2c8cSmatt
1544e4a54b41Snonaka mutex_spin_enter(&pis->pis_lock);
1545b8ea2c8cSmatt SIMPLEQ_INSERT_TAIL(&pis->pis_ihands, pih, pih_link);
1546e4a54b41Snonaka mutex_spin_exit(&pis->pis_lock);
1547b8ea2c8cSmatt
1548b8ea2c8cSmatt return pih;
1549b8ea2c8cSmatt }
1550b8ea2c8cSmatt
1551b8ea2c8cSmatt static void
pq3pci_intr_disestablish(void * v,void * ih)1552b8ea2c8cSmatt pq3pci_intr_disestablish(void *v, void *ih)
1553b8ea2c8cSmatt {
1554b8ea2c8cSmatt struct pq3pci_genihand * const gih = ih;
1555b8ea2c8cSmatt
1556b8ea2c8cSmatt if (gih->ih_class == IH_INTX) {
1557b8ea2c8cSmatt struct pq3pci_intrhand * const pih = ih;
1558b8ea2c8cSmatt struct pq3pci_intrsource * const pis = pih->pih_source;
1559b8ea2c8cSmatt
1560e4a54b41Snonaka mutex_spin_enter(&pis->pis_lock);
1561b8ea2c8cSmatt SIMPLEQ_REMOVE(&pis->pis_ihands, pih, pq3pci_intrhand, pih_link);
1562e4a54b41Snonaka mutex_spin_exit(&pis->pis_lock);
1563b8ea2c8cSmatt
1564b8ea2c8cSmatt kmem_free(pih, sizeof(*pih));
1565b8ea2c8cSmatt return;
1566b8ea2c8cSmatt }
1567e4a54b41Snonaka
1568b8ea2c8cSmatt struct pq3pci_msihand * const msih = ih;
1569b8ea2c8cSmatt struct pq3pci_msigroup * const msig = msih->msih_group;
1570b8ea2c8cSmatt struct genppc_pci_chipset * const pc = &msih->msih_ih.ih_sc->sc_pc;
1571b8ea2c8cSmatt const pcitag_t tag = msih->msih_tag;
1572b8ea2c8cSmatt
1573e4a54b41Snonaka mutex_spin_enter(&msig->msig_lock);
1574b8ea2c8cSmatt
1575b8ea2c8cSmatt /*
1576b8ea2c8cSmatt * disable the MSI
1577b8ea2c8cSmatt */
1578b8ea2c8cSmatt pcireg_t msictl = pci_conf_read(pc, tag, msih->msih_msioff);
1579b8ea2c8cSmatt msictl &= ~PCI_MSI_CTL_MSI_ENABLE;
1580b8ea2c8cSmatt pci_conf_write(pc, tag, msih->msih_msioff, msictl);
1581b8ea2c8cSmatt
1582b8ea2c8cSmatt msih->msih_ih.ih_func = pq3pci_msi_spurious_intr;
1583b8ea2c8cSmatt msih->msih_ih.ih_arg = msig;
1584b8ea2c8cSmatt msih->msih_ih.ih_sc = NULL;
1585b8ea2c8cSmatt msih->msih_tag = 0;
1586b8ea2c8cSmatt msih->msih_msioff = 0;
1587e4a54b41Snonaka mutex_spin_exit(&msig->msig_lock);
1588e4a54b41Snonaka }
1589e4a54b41Snonaka
1590e4a54b41Snonaka static pci_intr_type_t
pq3pci_intr_type(void * v,pci_intr_handle_t handle)1591e4a54b41Snonaka pq3pci_intr_type(void *v, pci_intr_handle_t handle)
1592e4a54b41Snonaka {
1593e4a54b41Snonaka const int ist = PIH_IST(handle);
1594e4a54b41Snonaka
1595e4a54b41Snonaka if (ist == IST_MSI)
1596e4a54b41Snonaka return PCI_INTR_TYPE_MSI;
1597e4a54b41Snonaka return PCI_INTR_TYPE_INTX;
1598e4a54b41Snonaka }
1599e4a54b41Snonaka
1600e4a54b41Snonaka static int
pq3pci_intr_alloc(const struct pci_attach_args * pa,pci_intr_handle_t ** ihps,int * counts,pci_intr_type_t max_type)1601e4a54b41Snonaka pq3pci_intr_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
1602e4a54b41Snonaka int *counts, pci_intr_type_t max_type)
1603e4a54b41Snonaka {
1604e4a54b41Snonaka int cnt[PCI_INTR_TYPE_SIZE];
1605e4a54b41Snonaka int error;
1606e4a54b41Snonaka
1607e4a54b41Snonaka memset(cnt, 0, sizeof(cnt));
1608e4a54b41Snonaka if (counts == NULL) {
1609e4a54b41Snonaka /* simple pattern */
1610e4a54b41Snonaka cnt[PCI_INTR_TYPE_INTX] = 1;
1611e4a54b41Snonaka cnt[PCI_INTR_TYPE_MSI] = 1;
1612e4a54b41Snonaka } else {
1613e4a54b41Snonaka switch (max_type) {
1614e4a54b41Snonaka case PCI_INTR_TYPE_MSIX:
1615e4a54b41Snonaka cnt[PCI_INTR_TYPE_MSIX] = counts[PCI_INTR_TYPE_MSIX];
1616e4a54b41Snonaka /*FALLTHROUGH*/
1617e4a54b41Snonaka case PCI_INTR_TYPE_MSI:
1618e4a54b41Snonaka cnt[PCI_INTR_TYPE_MSI] = counts[PCI_INTR_TYPE_MSI];
1619e4a54b41Snonaka /*FALLTHROUGH*/
1620e4a54b41Snonaka case PCI_INTR_TYPE_INTX:
1621e4a54b41Snonaka cnt[PCI_INTR_TYPE_INTX] = counts[PCI_INTR_TYPE_INTX];
1622e4a54b41Snonaka break;
1623e4a54b41Snonaka default:
1624e4a54b41Snonaka return EINVAL;
1625e4a54b41Snonaka }
1626e4a54b41Snonaka }
1627e4a54b41Snonaka
1628e4a54b41Snonaka if (counts != NULL)
1629e4a54b41Snonaka memset(counts, 0, sizeof(counts[0]) * (max_type + 1));
1630e4a54b41Snonaka error = EINVAL;
1631e4a54b41Snonaka
1632e4a54b41Snonaka /* try MSI-X */
1633e4a54b41Snonaka if (cnt[PCI_INTR_TYPE_MSIX] == -1) /* use hardware max */
1634e4a54b41Snonaka cnt[PCI_INTR_TYPE_MSIX] = pci_msix_count(pa->pa_pc, pa->pa_tag);
1635e4a54b41Snonaka if (cnt[PCI_INTR_TYPE_MSIX] > 0) {
1636e4a54b41Snonaka error = pci_msix_alloc_exact(pa, ihps, cnt[PCI_INTR_TYPE_MSIX]);
1637e4a54b41Snonaka if (error == 0) {
1638e4a54b41Snonaka KASSERTMSG(counts != NULL,
1639e4a54b41Snonaka "If MSI-X is used, counts must not be NULL.");
1640e4a54b41Snonaka counts[PCI_INTR_TYPE_MSIX] = cnt[PCI_INTR_TYPE_MSIX];
1641e4a54b41Snonaka goto out;
1642e4a54b41Snonaka }
1643e4a54b41Snonaka }
1644e4a54b41Snonaka
1645e4a54b41Snonaka /* try MSI */
1646e4a54b41Snonaka if (cnt[PCI_INTR_TYPE_MSI] == -1) /* use hardware max */
1647e4a54b41Snonaka cnt[PCI_INTR_TYPE_MSI] = pci_msi_count(pa->pa_pc, pa->pa_tag);
1648e4a54b41Snonaka if (cnt[PCI_INTR_TYPE_MSI] > 0) {
1649e4a54b41Snonaka error = pci_msi_alloc_exact(pa, ihps, cnt[PCI_INTR_TYPE_MSI]);
1650e4a54b41Snonaka if (error == 0) {
1651e4a54b41Snonaka if (counts != NULL) {
1652e4a54b41Snonaka counts[PCI_INTR_TYPE_MSI] =
1653e4a54b41Snonaka cnt[PCI_INTR_TYPE_MSI];
1654e4a54b41Snonaka }
1655e4a54b41Snonaka goto out;
1656e4a54b41Snonaka }
1657e4a54b41Snonaka }
1658e4a54b41Snonaka
1659e4a54b41Snonaka /* try INTx */
1660e4a54b41Snonaka if (cnt[PCI_INTR_TYPE_INTX] > 0) {
1661e4a54b41Snonaka error = pci_intx_alloc(pa, ihps);
1662e4a54b41Snonaka if (error == 0 && counts != NULL) {
1663e4a54b41Snonaka counts[PCI_INTR_TYPE_INTX] = 1;
1664e4a54b41Snonaka }
1665e4a54b41Snonaka }
1666e4a54b41Snonaka
1667e4a54b41Snonaka out:
1668e4a54b41Snonaka return error;
1669e4a54b41Snonaka }
1670e4a54b41Snonaka
1671e4a54b41Snonaka static void
pq3pci_intr_release(void * v,pci_intr_handle_t * ihps,int count)1672e4a54b41Snonaka pq3pci_intr_release(void *v, pci_intr_handle_t *ihps, int count)
1673e4a54b41Snonaka {
1674e4a54b41Snonaka
1675e4a54b41Snonaka if (ihps == NULL)
1676e4a54b41Snonaka return;
1677e4a54b41Snonaka
1678e4a54b41Snonaka const int ist = PIH_IST(*ihps);
1679e4a54b41Snonaka if (ist == IST_MSI)
1680e4a54b41Snonaka pq3pci_msi_free_vectors(v, ihps, count);
1681e4a54b41Snonaka else
1682e4a54b41Snonaka genppc_pci_intr_release(v, ihps, count);
1683b8ea2c8cSmatt }
1684b8ea2c8cSmatt
1685b8ea2c8cSmatt static void
pq3pci_conf_interrupt(void * v,int bus,int dev,int pin,int swiz,int * iline)1686dd2488a8Smatt pq3pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz, int *iline)
1687b8ea2c8cSmatt {
1688b8ea2c8cSmatt }
1689b8ea2c8cSmatt
1690e4a54b41Snonaka /* experimental MSI support */
1691e4a54b41Snonaka
1692e4a54b41Snonaka /*
1693e4a54b41Snonaka * This function is used by device drivers like pci_intr_map().
1694e4a54b41Snonaka *
1695e4a54b41Snonaka * "ihps" is the array of vector numbers which MSI used instead of IRQ number.
1696c11ca9eaSandvar * "count" must be power of 2.
1697c11ca9eaSandvar * "count" can decrease if struct intrsource cannot be allocated.
1698e4a54b41Snonaka * if count == 0, return non-zero value.
1699e4a54b41Snonaka */
1700e4a54b41Snonaka static int
pq3pci_msi_alloc(const struct pci_attach_args * pa,pci_intr_handle_t ** ihps,int * count,bool exact)1701e4a54b41Snonaka pq3pci_msi_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
1702e4a54b41Snonaka int *count, bool exact)
1703e4a54b41Snonaka {
1704e4a54b41Snonaka struct pq3pci_softc * const sc = pa->pa_pc->pc_msi_v;
1705e4a54b41Snonaka int hw_max;
1706e4a54b41Snonaka int error;
1707e4a54b41Snonaka
1708e4a54b41Snonaka if (*count < 1)
1709e4a54b41Snonaka return EINVAL;
1710e4a54b41Snonaka if (((*count - 1) & *count) != 0)
1711e4a54b41Snonaka return EINVAL;
1712e4a54b41Snonaka
1713e4a54b41Snonaka hw_max = pci_msi_count(pa->pa_pc, pa->pa_tag);
1714e4a54b41Snonaka if (hw_max == 0)
1715e4a54b41Snonaka return ENODEV;
1716e4a54b41Snonaka
1717e4a54b41Snonaka if (*count > hw_max)
1718e4a54b41Snonaka *count = hw_max;
1719e4a54b41Snonaka
1720e4a54b41Snonaka *ihps = NULL;
1721e4a54b41Snonaka for (; *count > 0; (*count) >>= 1) {
1722e4a54b41Snonaka error = pq3pci_msi_alloc_vectors(sc, pa, ihps, *count);
1723e4a54b41Snonaka if (error == 0)
1724e4a54b41Snonaka break;
1725e4a54b41Snonaka if (exact)
1726e4a54b41Snonaka return error;
1727e4a54b41Snonaka }
1728e4a54b41Snonaka if (*ihps == NULL)
1729e4a54b41Snonaka return ENXIO;
1730e4a54b41Snonaka
1731e4a54b41Snonaka return 0;
1732e4a54b41Snonaka }
1733e4a54b41Snonaka
1734b8ea2c8cSmatt static pci_chipset_tag_t
pq3pci_pci_chipset_init(struct pq3pci_softc * sc)1735b8ea2c8cSmatt pq3pci_pci_chipset_init(struct pq3pci_softc *sc)
1736b8ea2c8cSmatt {
1737b8ea2c8cSmatt struct genppc_pci_chipset * const pc = &sc->sc_pc;
1738b8ea2c8cSmatt
1739b8ea2c8cSmatt pc->pc_conf_v = sc;
1740b8ea2c8cSmatt pc->pc_attach_hook = pq3pci_attach_hook;
1741b8ea2c8cSmatt pc->pc_bus_maxdevs = pq3pci_bus_maxdevs;
1742b8ea2c8cSmatt pc->pc_make_tag = pq3pci_make_tag;
1743b8ea2c8cSmatt pc->pc_conf_read = pq3pci_conf_read;
1744b8ea2c8cSmatt pc->pc_conf_write = pq3pci_conf_write;
1745b8ea2c8cSmatt #ifdef PCI_NETBSD_CONFIGURE
1746b8ea2c8cSmatt pc->pc_conf_hook = pq3pci_conf_hook;
1747b8ea2c8cSmatt #endif
1748b8ea2c8cSmatt
1749b8ea2c8cSmatt pc->pc_intr_v = sc;
1750b8ea2c8cSmatt pc->pc_intr_map = pq3pci_intr_map;
1751b8ea2c8cSmatt pc->pc_intr_string = pq3pci_intr_string;
1752b8ea2c8cSmatt pc->pc_intr_evcnt = pq3pci_intr_evcnt;
1753b8ea2c8cSmatt pc->pc_intr_establish = pq3pci_intr_establish;
1754b8ea2c8cSmatt pc->pc_intr_disestablish = pq3pci_intr_disestablish;
1755e4a54b41Snonaka pc->pc_intr_type = pq3pci_intr_type;
1756e4a54b41Snonaka pc->pc_intr_alloc = pq3pci_intr_alloc;
1757e4a54b41Snonaka pc->pc_intr_release = pq3pci_intr_release;
1758c3a83ebdSrin pc->pc_intr_setattr = genppc_pci_intr_setattr;
1759e4a54b41Snonaka pc->pc_intx_alloc = genppc_pci_intx_alloc;
17601f2907adSmatt
17611f2907adSmatt pc->pc_msi_v = sc;
1762e4a54b41Snonaka pc->pc_msi_alloc = pq3pci_msi_alloc;
17631f2907adSmatt
1764e4a54b41Snonaka pc->pc_msix_v = sc;
1765e4a54b41Snonaka genppc_pci_chipset_msix_init(pc);
1766e4a54b41Snonaka
1767e4a54b41Snonaka pc->pc_conf_interrupt = pq3pci_conf_interrupt;
1768b8ea2c8cSmatt pc->pc_decompose_tag = pq3pci_decompose_tag;
1769b8ea2c8cSmatt
1770b8ea2c8cSmatt /*
1771b8ea2c8cSmatt * This is a horrible kludge but it makes life easier.
1772b8ea2c8cSmatt */
1773b8ea2c8cSmatt pc->pc_addr = (void *)(sc->sc_bsh + PEX_CONFIG_ADDR);
1774b8ea2c8cSmatt pc->pc_data = (void *)(sc->sc_bsh + PEX_CONFIG_DATA);
1775b8ea2c8cSmatt pc->pc_bus = 0;
1776b8ea2c8cSmatt pc->pc_memt = &sc->sc_pci_mem_bst.bs_tag;
1777b8ea2c8cSmatt pc->pc_iot = &sc->sc_pci_io_bst.bs_tag;
1778b8ea2c8cSmatt
1779b8ea2c8cSmatt SIMPLEQ_INIT(&pc->pc_pbi);
1780b8ea2c8cSmatt
1781b8ea2c8cSmatt return pc;
1782b8ea2c8cSmatt }
1783