1*161d7eb6Sskrll /* $NetBSD: apple_pcie.c,v 1.6 2022/04/27 08:03:06 skrll Exp $ */
2*161d7eb6Sskrll /* $OpenBSD: aplpcie.c,v 1.13 2022/04/06 18:59:26 naddy Exp $ */
3db7e12daSjmcneill
4db7e12daSjmcneill /*-
5db7e12daSjmcneill * Copyright (c) 2021 Jared McNeill <jmcneill@invisible.ca>
6db7e12daSjmcneill * All rights reserved.
7db7e12daSjmcneill *
8db7e12daSjmcneill * Redistribution and use in source and binary forms, with or without
9db7e12daSjmcneill * modification, are permitted provided that the following conditions
10db7e12daSjmcneill * are met:
11db7e12daSjmcneill * 1. Redistributions of source code must retain the above copyright
12db7e12daSjmcneill * notice, this list of conditions and the following disclaimer.
13db7e12daSjmcneill * 2. Redistributions in binary form must reproduce the above copyright
14db7e12daSjmcneill * notice, this list of conditions and the following disclaimer in the
15db7e12daSjmcneill * documentation and/or other materials provided with the distribution.
16db7e12daSjmcneill *
17db7e12daSjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18db7e12daSjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19db7e12daSjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20db7e12daSjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21db7e12daSjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22db7e12daSjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23db7e12daSjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24db7e12daSjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25db7e12daSjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26db7e12daSjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27db7e12daSjmcneill * SUCH DAMAGE.
28db7e12daSjmcneill */
29db7e12daSjmcneill
30*161d7eb6Sskrll /*
31*161d7eb6Sskrll * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
32*161d7eb6Sskrll *
33*161d7eb6Sskrll * Permission to use, copy, modify, and distribute this software for any
34*161d7eb6Sskrll * purpose with or without fee is hereby granted, provided that the above
35*161d7eb6Sskrll * copyright notice and this permission notice appear in all copies.
36*161d7eb6Sskrll *
37*161d7eb6Sskrll * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
38*161d7eb6Sskrll * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
39*161d7eb6Sskrll * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
40*161d7eb6Sskrll * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41*161d7eb6Sskrll * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
42*161d7eb6Sskrll * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
43*161d7eb6Sskrll * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44*161d7eb6Sskrll */
45*161d7eb6Sskrll
46*161d7eb6Sskrll
47db7e12daSjmcneill #include <sys/cdefs.h>
48*161d7eb6Sskrll __KERNEL_RCSID(0, "$NetBSD: apple_pcie.c,v 1.6 2022/04/27 08:03:06 skrll Exp $");
49db7e12daSjmcneill
50db7e12daSjmcneill #include <sys/param.h>
51db7e12daSjmcneill #include <sys/device.h>
52db7e12daSjmcneill #include <sys/kernel.h>
53db7e12daSjmcneill #include <sys/systm.h>
54db7e12daSjmcneill #include <sys/bus.h>
55db7e12daSjmcneill #include <sys/kmem.h>
56db7e12daSjmcneill #include <sys/bitops.h>
57db7e12daSjmcneill
58db7e12daSjmcneill #include <dev/pci/pcireg.h>
59db7e12daSjmcneill #include <dev/pci/pcivar.h>
60db7e12daSjmcneill #include <dev/pci/pciconf.h>
61db7e12daSjmcneill
62db7e12daSjmcneill #include <dev/fdt/fdtvar.h>
63db7e12daSjmcneill
64db7e12daSjmcneill #include <arm/pci/pci_msi_machdep.h>
65db7e12daSjmcneill #include <arm/fdt/pcihost_fdtvar.h>
66db7e12daSjmcneill
67*161d7eb6Sskrll #define PCIE_CORE_LANE_CONF(port) (0x84000 + (port) * 0x4000)
68*161d7eb6Sskrll #define PCIE_CORE_LANE_CONF_REFCLK0REQ __BIT(0)
69*161d7eb6Sskrll #define PCIE_CORE_LANE_CONF_REFCLK1REQ __BIT(1)
70*161d7eb6Sskrll #define PCIE_CORE_LANE_CONF_REFCLK0ACK __BIT(2)
71*161d7eb6Sskrll #define PCIE_CORE_LANE_CONF_REFCLK1ACK __BIT(3)
72*161d7eb6Sskrll #define PCIE_CORE_LANE_CONF_REFCLK0EN __BIT(9)
73*161d7eb6Sskrll #define PCIE_CORE_LANE_CONF_REFCLK1EN __BIT(10)
74*161d7eb6Sskrll #define PCIE_CORE_LANE_CTRL(port) (0x84004 + (port) * 0x4000)
75*161d7eb6Sskrll #define PCIE_CORE_LANE_CTRL_CFGACC __BIT(15)
76*161d7eb6Sskrll
77*161d7eb6Sskrll #define PCIE_PORT_LTSSM_CTRL 0x0080
78*161d7eb6Sskrll #define PCIE_PORT_LTSSM_CTRL_START __BIT(0)
79*161d7eb6Sskrll #define PCIE_PORT_MSI_CTRL 0x0124
80*161d7eb6Sskrll #define PCIE_PORT_MSI_CTRL_EN __BIT(0)
81*161d7eb6Sskrll #define PCIE_PORT_MSI_CTRL_32 __SHIFTIN(5U, __BITS(7,4))
82*161d7eb6Sskrll #define PCIE_PORT_MSI_REMAP 0x0128
83*161d7eb6Sskrll #define PCIE_PORT_MSI_DOORBELL 0x0168
84*161d7eb6Sskrll #define PCIE_PORT_LINK_STAT 0x0208
85*161d7eb6Sskrll #define PCIE_PORT_LINK_STAT_UP __BIT(0)
86*161d7eb6Sskrll #define PCIE_PORT_APPCLK 0x0800
87*161d7eb6Sskrll #define PCIE_PORT_APPCLK_EN __BIT(0)
88*161d7eb6Sskrll #define PCIE_PORT_APPCLK_CGDIS __BIT(8)
89*161d7eb6Sskrll #define PCIE_PORT_STAT 0x0804
90*161d7eb6Sskrll #define PCIE_PORT_STAT_READY __BIT(0)
91*161d7eb6Sskrll #define PCIE_PORT_REFCLK 0x0810
92*161d7eb6Sskrll #define PCIE_PORT_REFCLK_EN __BIT(0)
93*161d7eb6Sskrll #define PCIE_PORT_REFCLK_CGDIS __BIT(8)
94*161d7eb6Sskrll #define PCIE_PORT_PERST 0x0814
95*161d7eb6Sskrll #define PCIE_PORT_PERST_DIS __BIT(0)
96db7e12daSjmcneill
9782d7f759Sjmcneill extern struct bus_space arm_generic_bs_tag;
9882d7f759Sjmcneill
99db7e12daSjmcneill struct apple_pcie_softc {
100db7e12daSjmcneill struct pcihost_softc sc_pcihost;
101db7e12daSjmcneill
102*161d7eb6Sskrll bus_space_tag_t sc_rc_bst;
103*161d7eb6Sskrll bus_space_handle_t sc_rc_bsh;
104*161d7eb6Sskrll
105db7e12daSjmcneill int sc_phandle;
106db7e12daSjmcneill struct arm_pci_msi sc_msi;
107db7e12daSjmcneill u_int sc_msi_start;
108db7e12daSjmcneill u_int sc_nmsi;
109db7e12daSjmcneill struct pci_attach_args **sc_msi_pa;
110db7e12daSjmcneill void **sc_msi_ih;
111db7e12daSjmcneill uint64_t sc_msi_addr;
112db7e12daSjmcneill };
113db7e12daSjmcneill
114db7e12daSjmcneill static int apple_pcie_match(device_t, cfdata_t, void *);
115db7e12daSjmcneill static void apple_pcie_attach(device_t, device_t, void *);
116db7e12daSjmcneill
117db7e12daSjmcneill static void apple_pcie_attach_hook(device_t, device_t,
118db7e12daSjmcneill struct pcibus_attach_args *);
119db7e12daSjmcneill static int apple_pcie_msi_init(struct apple_pcie_softc *);
120db7e12daSjmcneill
121db7e12daSjmcneill CFATTACH_DECL_NEW(apple_pcie, sizeof(struct apple_pcie_softc),
122db7e12daSjmcneill apple_pcie_match, apple_pcie_attach, NULL, NULL);
123db7e12daSjmcneill
124db7e12daSjmcneill static const struct device_compatible_entry compat_data[] = {
125db7e12daSjmcneill { .compat = "apple,pcie" },
126db7e12daSjmcneill DEVICE_COMPAT_EOL
127db7e12daSjmcneill };
128db7e12daSjmcneill
129*161d7eb6Sskrll #define RREAD4(sc, reg) \
130*161d7eb6Sskrll (bus_space_read_4((sc)->sc_rc_bst, (sc)->sc_rc_bsh, (reg)))
131*161d7eb6Sskrll #define RWRITE4(sc, reg, val) \
132*161d7eb6Sskrll bus_space_write_4((sc)->sc_rc_bst, (sc)->sc_rc_bsh, (reg), (val))
133*161d7eb6Sskrll #define RSET4(sc, reg, bits) \
134*161d7eb6Sskrll RWRITE4((sc), (reg), RREAD4((sc), (reg)) | (bits))
135*161d7eb6Sskrll #define RCLR4(sc, reg, bits) \
136*161d7eb6Sskrll RWRITE4((sc), (reg), RREAD4((sc), (reg)) & ~(bits))
137*161d7eb6Sskrll
138*161d7eb6Sskrll
139*161d7eb6Sskrll static void
apple_pcie_setup_port(struct apple_pcie_softc * sc,int phandle)140*161d7eb6Sskrll apple_pcie_setup_port(struct apple_pcie_softc *sc, int phandle)
141*161d7eb6Sskrll {
142*161d7eb6Sskrll const bus_space_tag_t bst = sc->sc_pcihost.sc_bst;
143*161d7eb6Sskrll const device_t dev = sc->sc_pcihost.sc_dev;
144*161d7eb6Sskrll const int parent = sc->sc_pcihost.sc_phandle;
145*161d7eb6Sskrll char regname[sizeof("portX")];
146*161d7eb6Sskrll bus_space_handle_t bsh;
147*161d7eb6Sskrll bus_addr_t addr;
148*161d7eb6Sskrll bus_size_t size;
149*161d7eb6Sskrll int error;
150*161d7eb6Sskrll int timo;
151*161d7eb6Sskrll int len;
152*161d7eb6Sskrll
153*161d7eb6Sskrll const u_int *reg = fdtbus_get_prop(phandle, "reg", &len);
154*161d7eb6Sskrll if (len != 5 * sizeof(uint32_t)) {
155*161d7eb6Sskrll aprint_error(": couldn't get port number\n");
156*161d7eb6Sskrll }
157*161d7eb6Sskrll
158*161d7eb6Sskrll u_int portno = __SHIFTOUT(be32toh(reg[0]), __BITS(13,11));
159*161d7eb6Sskrll snprintf(regname, sizeof(regname), "port%u", portno);
160*161d7eb6Sskrll
161*161d7eb6Sskrll if (fdtbus_get_reg_byname(parent, regname, &addr, &size) != 0) {
162*161d7eb6Sskrll aprint_error(": couldn't get %s regs\n", regname);
163*161d7eb6Sskrll return;
164*161d7eb6Sskrll }
165*161d7eb6Sskrll error = bus_space_map(bst, addr, size, 0, &bsh);
166*161d7eb6Sskrll if (error != 0) {
167*161d7eb6Sskrll aprint_error(": couldn't map %s regs\n", regname);
168*161d7eb6Sskrll return;
169*161d7eb6Sskrll }
170*161d7eb6Sskrll
171*161d7eb6Sskrll #define PREAD4(bst, bsh, reg) \
172*161d7eb6Sskrll bus_space_read_4((bst), (bsh), (reg))
173*161d7eb6Sskrll #define PWRITE4(bst, bsh, reg, val) \
174*161d7eb6Sskrll bus_space_write_4((bst), (bsh), (reg), (val))
175*161d7eb6Sskrll #define PSET4(bst, bsh, reg, bits) \
176*161d7eb6Sskrll PWRITE4((bst), (bsh), (reg), PREAD4((bst), (bsh), (reg)) | (bits))
177*161d7eb6Sskrll #define PCLR4(bst, bsh, reg, bits) \
178*161d7eb6Sskrll PWRITE4((bst), (bsh), (reg), PREAD4((bst), (bsh), (reg)) & ~(bits))
179*161d7eb6Sskrll
180*161d7eb6Sskrll /* Doorbell address must be below 4GB */
181*161d7eb6Sskrll KASSERT((sc->sc_msi_addr & ~0xffffffffUL) == 0);
182*161d7eb6Sskrll
183*161d7eb6Sskrll int pwren_gpiolen, reset_gpiolen;
184*161d7eb6Sskrll
185*161d7eb6Sskrll pwren_gpiolen = OF_getproplen(phandle, "pwren-gpios");
186*161d7eb6Sskrll reset_gpiolen = OF_getproplen(phandle, "reset-gpios");
187*161d7eb6Sskrll if (reset_gpiolen <= 0)
188*161d7eb6Sskrll return;
189*161d7eb6Sskrll
190*161d7eb6Sskrll /*
191*161d7eb6Sskrll * Set things up such that we can share the 32 available MSIs
192*161d7eb6Sskrll * across all ports.
193*161d7eb6Sskrll */
194*161d7eb6Sskrll PWRITE4(bst, bsh, PCIE_PORT_MSI_CTRL,
195*161d7eb6Sskrll PCIE_PORT_MSI_CTRL_32 | PCIE_PORT_MSI_CTRL_EN);
196*161d7eb6Sskrll PWRITE4(bst, bsh, PCIE_PORT_MSI_REMAP, 0);
197*161d7eb6Sskrll PWRITE4(bst, bsh, PCIE_PORT_MSI_DOORBELL,
198*161d7eb6Sskrll __SHIFTOUT(sc->sc_msi_addr, __BITS(31, 0)));
199*161d7eb6Sskrll
200*161d7eb6Sskrll /* Check if the link is already up. */
201*161d7eb6Sskrll uint32_t stat = PREAD4(bst, bsh, PCIE_PORT_LINK_STAT);
202*161d7eb6Sskrll if (stat & PCIE_PORT_LINK_STAT_UP) {
203*161d7eb6Sskrll aprint_debug_dev(dev, "link already up\n");
204*161d7eb6Sskrll return;
205*161d7eb6Sskrll }
206*161d7eb6Sskrll aprint_debug_dev(dev, "bringing link up\n");
207*161d7eb6Sskrll
208*161d7eb6Sskrll PSET4(bst, bsh, PCIE_PORT_APPCLK, PCIE_PORT_APPCLK_EN);
209*161d7eb6Sskrll
210*161d7eb6Sskrll struct fdtbus_gpio_pin *gpio_reset = fdtbus_gpio_acquire(phandle,
211*161d7eb6Sskrll "reset-gpios", GPIO_PIN_OUTPUT);
212*161d7eb6Sskrll
213*161d7eb6Sskrll if (gpio_reset == NULL) {
214*161d7eb6Sskrll aprint_debug_dev(dev, "failed to get reset-gpios\n");
215*161d7eb6Sskrll return;
216*161d7eb6Sskrll }
217*161d7eb6Sskrll
218*161d7eb6Sskrll fdtbus_gpio_write(gpio_reset, 1);
219*161d7eb6Sskrll
220*161d7eb6Sskrll /* Power up the device if necessary. */
221*161d7eb6Sskrll if (pwren_gpiolen > 0) {
222*161d7eb6Sskrll struct fdtbus_gpio_pin *gpio_pwren = fdtbus_gpio_acquire(phandle,
223*161d7eb6Sskrll "pwren-gpios", GPIO_PIN_OUTPUT);
224*161d7eb6Sskrll
225*161d7eb6Sskrll if (gpio_pwren == NULL) {
226*161d7eb6Sskrll aprint_debug_dev(dev, "failed to get pwren-gpios\n");
227*161d7eb6Sskrll return;
228*161d7eb6Sskrll }
229*161d7eb6Sskrll
230*161d7eb6Sskrll fdtbus_gpio_write(gpio_pwren, 1);
231*161d7eb6Sskrll }
232*161d7eb6Sskrll
233*161d7eb6Sskrll /* Setup Refclk. */
234*161d7eb6Sskrll RSET4(sc, PCIE_CORE_LANE_CTRL(portno), PCIE_CORE_LANE_CTRL_CFGACC);
235*161d7eb6Sskrll RSET4(sc, PCIE_CORE_LANE_CONF(portno), PCIE_CORE_LANE_CONF_REFCLK0REQ);
236*161d7eb6Sskrll for (timo = 500; timo > 0; timo--) {
237*161d7eb6Sskrll stat = RREAD4(sc, PCIE_CORE_LANE_CONF(portno));
238*161d7eb6Sskrll if (stat & PCIE_CORE_LANE_CONF_REFCLK0ACK)
239*161d7eb6Sskrll break;
240*161d7eb6Sskrll delay(100);
241*161d7eb6Sskrll }
242*161d7eb6Sskrll RSET4(sc, PCIE_CORE_LANE_CONF(portno), PCIE_CORE_LANE_CONF_REFCLK1REQ);
243*161d7eb6Sskrll for (timo = 500; timo > 0; timo--) {
244*161d7eb6Sskrll stat = RREAD4(sc, PCIE_CORE_LANE_CONF(portno));
245*161d7eb6Sskrll if (stat & PCIE_CORE_LANE_CONF_REFCLK1ACK)
246*161d7eb6Sskrll break;
247*161d7eb6Sskrll delay(100);
248*161d7eb6Sskrll }
249*161d7eb6Sskrll RCLR4(sc, PCIE_CORE_LANE_CTRL(portno), PCIE_CORE_LANE_CTRL_CFGACC);
250*161d7eb6Sskrll RSET4(sc, PCIE_CORE_LANE_CONF(portno),
251*161d7eb6Sskrll PCIE_CORE_LANE_CONF_REFCLK0EN | PCIE_CORE_LANE_CONF_REFCLK1EN);
252*161d7eb6Sskrll PSET4(bst, bsh, PCIE_PORT_REFCLK, PCIE_PORT_REFCLK_EN);
253*161d7eb6Sskrll
254*161d7eb6Sskrll /*
255*161d7eb6Sskrll * PERST# must remain asserted for at least 100us after the
256*161d7eb6Sskrll * reference clock becomes stable. But also has to remain
257*161d7eb6Sskrll * active at least 100ms after power up.
258*161d7eb6Sskrll */
259*161d7eb6Sskrll if (pwren_gpiolen > 0)
260*161d7eb6Sskrll delay(100000);
261*161d7eb6Sskrll else
262*161d7eb6Sskrll delay(100);
263*161d7eb6Sskrll
264*161d7eb6Sskrll /* Deassert PERST#. */
265*161d7eb6Sskrll PSET4(bst, bsh, PCIE_PORT_PERST, PCIE_PORT_PERST_DIS);
266*161d7eb6Sskrll fdtbus_gpio_write(gpio_reset, 0);
267*161d7eb6Sskrll
268*161d7eb6Sskrll for (timo = 2500; timo > 0; timo--) {
269*161d7eb6Sskrll stat = PREAD4(bst, bsh, PCIE_PORT_STAT);
270*161d7eb6Sskrll if (stat & PCIE_PORT_STAT_READY)
271*161d7eb6Sskrll break;
272*161d7eb6Sskrll delay(100);
273*161d7eb6Sskrll }
274*161d7eb6Sskrll if ((stat & PCIE_PORT_STAT_READY) == 0) {
275*161d7eb6Sskrll aprint_debug_dev(dev, "link up\n");
276*161d7eb6Sskrll return;
277*161d7eb6Sskrll }
278*161d7eb6Sskrll
279*161d7eb6Sskrll PCLR4(bst, bsh, PCIE_PORT_REFCLK, PCIE_PORT_REFCLK_CGDIS);
280*161d7eb6Sskrll PCLR4(bst, bsh, PCIE_PORT_APPCLK, PCIE_PORT_APPCLK_CGDIS);
281*161d7eb6Sskrll
282*161d7eb6Sskrll /* Bring up the link. */
283*161d7eb6Sskrll PWRITE4(bst, bsh, PCIE_PORT_LTSSM_CTRL, PCIE_PORT_LTSSM_CTRL_START);
284*161d7eb6Sskrll for (timo = 1000; timo > 0; timo--) {
285*161d7eb6Sskrll stat = PREAD4(bst, bsh, PCIE_PORT_LINK_STAT);
286*161d7eb6Sskrll if (stat & PCIE_PORT_LINK_STAT_UP)
287*161d7eb6Sskrll break;
288*161d7eb6Sskrll delay(100);
289*161d7eb6Sskrll }
290*161d7eb6Sskrll
291*161d7eb6Sskrll #undef PREAD4
292*161d7eb6Sskrll #undef PWRITE4
293*161d7eb6Sskrll #undef PCLR4
294*161d7eb6Sskrll #undef PSET4
295*161d7eb6Sskrll
296*161d7eb6Sskrll bus_space_unmap(bst, bsh, size);
297*161d7eb6Sskrll }
298*161d7eb6Sskrll
299db7e12daSjmcneill static int
apple_pcie_match(device_t parent,cfdata_t cf,void * aux)300db7e12daSjmcneill apple_pcie_match(device_t parent, cfdata_t cf, void *aux)
301db7e12daSjmcneill {
302db7e12daSjmcneill struct fdt_attach_args * const faa = aux;
303db7e12daSjmcneill
304db7e12daSjmcneill return of_compatible_match(faa->faa_phandle, compat_data);
305db7e12daSjmcneill }
306db7e12daSjmcneill
307db7e12daSjmcneill static void
apple_pcie_attach(device_t parent,device_t self,void * aux)308db7e12daSjmcneill apple_pcie_attach(device_t parent, device_t self, void *aux)
309db7e12daSjmcneill {
310db7e12daSjmcneill struct apple_pcie_softc * const asc = device_private(self);
311db7e12daSjmcneill struct pcihost_softc * const sc = &asc->sc_pcihost;
312db7e12daSjmcneill struct fdt_attach_args * const faa = aux;
313db7e12daSjmcneill const int phandle = faa->faa_phandle;
314*161d7eb6Sskrll bus_addr_t cs_addr, rc_addr;
315*161d7eb6Sskrll bus_size_t cs_size, rc_size;
316db7e12daSjmcneill int error;
317db7e12daSjmcneill
318*161d7eb6Sskrll if (fdtbus_get_reg_byname(phandle, "config", &cs_addr, &cs_size) != 0) {
319*161d7eb6Sskrll aprint_error(": couldn't get registers (%s)\n", "config");
320*161d7eb6Sskrll return;
321*161d7eb6Sskrll }
322*161d7eb6Sskrll
323*161d7eb6Sskrll if (fdtbus_get_reg_byname(phandle, "rc", &rc_addr, &rc_size) != 0) {
324*161d7eb6Sskrll aprint_error(": couldn't get registers (%s)\n", "rc");
325db7e12daSjmcneill return;
326db7e12daSjmcneill }
327db7e12daSjmcneill
328db7e12daSjmcneill sc->sc_dev = self;
329db7e12daSjmcneill sc->sc_dmat = faa->faa_dmat;
330*161d7eb6Sskrll sc->sc_bst = asc->sc_rc_bst = faa->faa_bst;
33177a7b674Sjmcneill /*
33277a7b674Sjmcneill * Create a new bus tag for PCIe devices that does not inherit the
33377a7b674Sjmcneill * nonposted MMIO flag from the host controller.
33477a7b674Sjmcneill */
33582d7f759Sjmcneill sc->sc_pci_bst = &arm_generic_bs_tag;
336db7e12daSjmcneill sc->sc_phandle = phandle;
33777a7b674Sjmcneill error = bus_space_map(faa->faa_bst, cs_addr, cs_size, 0, &sc->sc_bsh);
338db7e12daSjmcneill if (error) {
339*161d7eb6Sskrll aprint_error(": couldn't map registers (%s): %d\n", "config",
340*161d7eb6Sskrll error);
341*161d7eb6Sskrll return;
342*161d7eb6Sskrll }
343*161d7eb6Sskrll error = bus_space_map(asc->sc_rc_bst, rc_addr, rc_size, 0,
344*161d7eb6Sskrll &asc->sc_rc_bsh);
345*161d7eb6Sskrll if (error) {
346*161d7eb6Sskrll aprint_error(": couldn't map registers (%s): %d\n", "rc",
347*161d7eb6Sskrll error);
348db7e12daSjmcneill return;
349db7e12daSjmcneill }
350db7e12daSjmcneill sc->sc_type = PCIHOST_ECAM;
351db7e12daSjmcneill
352db7e12daSjmcneill if (apple_pcie_msi_init(asc) == 0) {
353db7e12daSjmcneill sc->sc_pci_flags |= PCI_FLAGS_MSI_OKAY;
354db7e12daSjmcneill #if notyet
355db7e12daSjmcneill sc->sc_pci_flags |= PCI_FLAGS_MSIX_OKAY;
356db7e12daSjmcneill #endif
357db7e12daSjmcneill }
358db7e12daSjmcneill
359db7e12daSjmcneill aprint_naive("\n");
360db7e12daSjmcneill aprint_normal(": Apple PCIe host controller\n");
361db7e12daSjmcneill
362*161d7eb6Sskrll for (int node = OF_child(phandle); node; node = OF_peer(node))
363*161d7eb6Sskrll apple_pcie_setup_port(asc, node);
364*161d7eb6Sskrll
365*161d7eb6Sskrll /*
366*161d7eb6Sskrll * Must wait at least 100ms after link training completes
367*161d7eb6Sskrll * before sending a configuration request to a device
368*161d7eb6Sskrll * immediately below a port.
369*161d7eb6Sskrll */
370*161d7eb6Sskrll delay(100000);
371*161d7eb6Sskrll
372db7e12daSjmcneill pcihost_init(&sc->sc_pc, sc);
373*161d7eb6Sskrll
374db7e12daSjmcneill sc->sc_pc.pc_attach_hook = apple_pcie_attach_hook;
375db7e12daSjmcneill pcihost_init2(sc);
376db7e12daSjmcneill }
377db7e12daSjmcneill
378db7e12daSjmcneill
379db7e12daSjmcneill
380db7e12daSjmcneill static void
apple_pcie_attach_hook(device_t parent,device_t self,struct pcibus_attach_args * pba)381db7e12daSjmcneill apple_pcie_attach_hook(device_t parent, device_t self,
382db7e12daSjmcneill struct pcibus_attach_args *pba)
383db7e12daSjmcneill {
384db7e12daSjmcneill struct apple_pcie_softc *sc = pba->pba_pc->pc_conf_v;
385db7e12daSjmcneill const int phandle = sc->sc_pcihost.sc_phandle;
386a808ce0eSjmcneill bus_dma_tag_t dmat;
387db7e12daSjmcneill
388db7e12daSjmcneill KASSERT(device_is_a(sc->sc_pcihost.sc_dev, "applepcie"));
389db7e12daSjmcneill
390a808ce0eSjmcneill /* XXX this should be per-device, not per-bus */
391a808ce0eSjmcneill const uint32_t rid = pba->pba_bus << 8;
392db7e12daSjmcneill
393a808ce0eSjmcneill dmat = fdtbus_iommu_map_pci(phandle, rid, sc->sc_pcihost.sc_dmat);
394*161d7eb6Sskrll
395a808ce0eSjmcneill pba->pba_dmat = pba->pba_dmat64 = dmat;
396db7e12daSjmcneill }
397db7e12daSjmcneill
398db7e12daSjmcneill static int
apple_pcie_msi_alloc_msi(struct apple_pcie_softc * sc,int count,const struct pci_attach_args * pa)399db7e12daSjmcneill apple_pcie_msi_alloc_msi(struct apple_pcie_softc *sc, int count,
400db7e12daSjmcneill const struct pci_attach_args *pa)
401db7e12daSjmcneill {
402db7e12daSjmcneill struct pci_attach_args *new_pa;
403db7e12daSjmcneill int msi, n;
404db7e12daSjmcneill
405*161d7eb6Sskrll for (msi = 0; msi < sc->sc_nmsi; msi += n) {
406*161d7eb6Sskrll /* Look for first empty slot */
407*161d7eb6Sskrll if (sc->sc_msi_pa[msi] != NULL) {
408*161d7eb6Sskrll /* skip the used entry */
409*161d7eb6Sskrll n = 1;
410db7e12daSjmcneill continue;
411db7e12daSjmcneill }
412db7e12daSjmcneill
413*161d7eb6Sskrll /* Now check that 'count' entries are also empty */
414*161d7eb6Sskrll for (n = 1; n < count && msi + n < sc->sc_nmsi; n++) {
415*161d7eb6Sskrll if (sc->sc_msi_pa[msi + n] != NULL) {
416*161d7eb6Sskrll break;
417*161d7eb6Sskrll }
418*161d7eb6Sskrll }
419*161d7eb6Sskrll /*
420*161d7eb6Sskrll * If 'count' empty entries weren't found then the search
421*161d7eb6Sskrll * continues.
422*161d7eb6Sskrll */
423*161d7eb6Sskrll if (n != count)
424*161d7eb6Sskrll continue;
425db7e12daSjmcneill for (n = 0; n < count; n++) {
426db7e12daSjmcneill new_pa = kmem_alloc(sizeof(*new_pa), KM_SLEEP);
427db7e12daSjmcneill memcpy(new_pa, pa, sizeof(*new_pa));
428db7e12daSjmcneill sc->sc_msi_pa[msi + n] = new_pa;
429db7e12daSjmcneill }
430db7e12daSjmcneill
431db7e12daSjmcneill return msi;
432db7e12daSjmcneill }
433db7e12daSjmcneill
434db7e12daSjmcneill return -1;
435db7e12daSjmcneill }
436db7e12daSjmcneill
437db7e12daSjmcneill static void
apple_pcie_msi_free_msi(struct apple_pcie_softc * sc,int msi)438db7e12daSjmcneill apple_pcie_msi_free_msi(struct apple_pcie_softc *sc, int msi)
439db7e12daSjmcneill {
440db7e12daSjmcneill struct pci_attach_args *pa;
441db7e12daSjmcneill
442db7e12daSjmcneill pa = sc->sc_msi_pa[msi];
443db7e12daSjmcneill sc->sc_msi_pa[msi] = NULL;
444db7e12daSjmcneill
445db7e12daSjmcneill if (pa != NULL) {
446db7e12daSjmcneill kmem_free(pa, sizeof(*pa));
447db7e12daSjmcneill }
448db7e12daSjmcneill }
449db7e12daSjmcneill
450db7e12daSjmcneill static int
apple_pcie_msi_available_msi(struct apple_pcie_softc * sc)451db7e12daSjmcneill apple_pcie_msi_available_msi(struct apple_pcie_softc *sc)
452db7e12daSjmcneill {
453db7e12daSjmcneill int msi, n;
454db7e12daSjmcneill
455db7e12daSjmcneill for (n = 0, msi = 0; msi < sc->sc_nmsi; msi++) {
456db7e12daSjmcneill if (sc->sc_msi_pa[msi] == NULL) {
457db7e12daSjmcneill n++;
458db7e12daSjmcneill }
459db7e12daSjmcneill }
460db7e12daSjmcneill
461db7e12daSjmcneill return n;
462db7e12daSjmcneill }
463db7e12daSjmcneill
464db7e12daSjmcneill static void
apple_pcie_msi_msi_enable(struct apple_pcie_softc * sc,int msi,int count)465db7e12daSjmcneill apple_pcie_msi_msi_enable(struct apple_pcie_softc *sc, int msi, int count)
466db7e12daSjmcneill {
467db7e12daSjmcneill const struct pci_attach_args *pa = sc->sc_msi_pa[msi];
468db7e12daSjmcneill pci_chipset_tag_t pc = pa->pa_pc;
469db7e12daSjmcneill pcitag_t tag = pa->pa_tag;
470db7e12daSjmcneill pcireg_t ctl;
471db7e12daSjmcneill int off;
472db7e12daSjmcneill
473db7e12daSjmcneill if (!pci_get_capability(pc, tag, PCI_CAP_MSI, &off, NULL))
474db7e12daSjmcneill panic("apple_pcie_msi_msi_enable: device is not MSI-capable");
475db7e12daSjmcneill
476db7e12daSjmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSI_CTL);
477db7e12daSjmcneill ctl &= ~PCI_MSI_CTL_MSI_ENABLE;
478db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSI_CTL, ctl);
479db7e12daSjmcneill
480db7e12daSjmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSI_CTL);
481db7e12daSjmcneill ctl &= ~PCI_MSI_CTL_MME_MASK;
482db7e12daSjmcneill ctl |= __SHIFTIN(ilog2(count), PCI_MSI_CTL_MME_MASK);
483db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSI_CTL, ctl);
484db7e12daSjmcneill
485db7e12daSjmcneill const uint64_t addr = sc->sc_msi_addr;
486db7e12daSjmcneill const uint32_t data = msi;
487db7e12daSjmcneill
488db7e12daSjmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSI_CTL);
489db7e12daSjmcneill if (ctl & PCI_MSI_CTL_64BIT_ADDR) {
490db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSI_MADDR64_LO,
491*161d7eb6Sskrll __SHIFTOUT(addr, __BITS(31, 0)));
492db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSI_MADDR64_HI,
493*161d7eb6Sskrll __SHIFTOUT(addr, __BITS(63, 32)));
494db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSI_MDATA64, data);
495db7e12daSjmcneill } else {
496db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSI_MADDR,
497*161d7eb6Sskrll __SHIFTOUT(addr, __BITS(31, 0)));
498db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSI_MDATA, data);
499db7e12daSjmcneill }
500db7e12daSjmcneill ctl |= PCI_MSI_CTL_MSI_ENABLE;
501db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSI_CTL, ctl);
502db7e12daSjmcneill }
503db7e12daSjmcneill
504db7e12daSjmcneill static void
apple_pcie_msi_msi_disable(struct apple_pcie_softc * sc,int msi)505db7e12daSjmcneill apple_pcie_msi_msi_disable(struct apple_pcie_softc *sc, int msi)
506db7e12daSjmcneill {
507db7e12daSjmcneill const struct pci_attach_args *pa = sc->sc_msi_pa[msi];
508db7e12daSjmcneill pci_chipset_tag_t pc = pa->pa_pc;
509db7e12daSjmcneill pcitag_t tag = pa->pa_tag;
510db7e12daSjmcneill pcireg_t ctl;
511db7e12daSjmcneill int off;
512db7e12daSjmcneill
513db7e12daSjmcneill if (!pci_get_capability(pc, tag, PCI_CAP_MSI, &off, NULL))
514db7e12daSjmcneill panic("apple_pcie_msi_msi_disable: device is not MSI-capable");
515db7e12daSjmcneill
516db7e12daSjmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSI_CTL);
517db7e12daSjmcneill ctl &= ~PCI_MSI_CTL_MSI_ENABLE;
518db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSI_CTL, ctl);
519db7e12daSjmcneill }
520db7e12daSjmcneill
521db7e12daSjmcneill static void
apple_pcie_msi_msix_enable(struct apple_pcie_softc * sc,int msi,int msix_vec,bus_space_tag_t bst,bus_space_handle_t bsh)522db7e12daSjmcneill apple_pcie_msi_msix_enable(struct apple_pcie_softc *sc, int msi, int msix_vec,
523db7e12daSjmcneill bus_space_tag_t bst, bus_space_handle_t bsh)
524db7e12daSjmcneill {
525db7e12daSjmcneill const struct pci_attach_args *pa = sc->sc_msi_pa[msi];
526db7e12daSjmcneill pci_chipset_tag_t pc = pa->pa_pc;
527db7e12daSjmcneill pcitag_t tag = pa->pa_tag;
528db7e12daSjmcneill pcireg_t ctl;
529db7e12daSjmcneill uint32_t val;
530db7e12daSjmcneill int off;
531db7e12daSjmcneill
532db7e12daSjmcneill if (!pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, NULL))
533db7e12daSjmcneill panic("apple_pcie_msi_msix_enable: device is not MSI-X-capable");
534db7e12daSjmcneill
535db7e12daSjmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSIX_CTL);
536db7e12daSjmcneill ctl &= ~PCI_MSIX_CTL_ENABLE;
537db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSIX_CTL, ctl);
538db7e12daSjmcneill
539db7e12daSjmcneill const uint64_t addr = sc->sc_msi_addr;
540db7e12daSjmcneill const uint32_t data = msi;
541db7e12daSjmcneill const uint64_t entry_base = PCI_MSIX_TABLE_ENTRY_SIZE * msix_vec;
542db7e12daSjmcneill bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_ADDR_LO,
543*161d7eb6Sskrll __SHIFTOUT(addr, __BITS(31, 0)));
544db7e12daSjmcneill bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_ADDR_HI,
545*161d7eb6Sskrll __SHIFTOUT(addr, __BITS(63, 32)));
546db7e12daSjmcneill bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_DATA,
547db7e12daSjmcneill data);
548db7e12daSjmcneill val = bus_space_read_4(bst, bsh,
549db7e12daSjmcneill entry_base + PCI_MSIX_TABLE_ENTRY_VECTCTL);
550db7e12daSjmcneill val &= ~PCI_MSIX_VECTCTL_MASK;
551db7e12daSjmcneill bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_VECTCTL,
552db7e12daSjmcneill val);
553db7e12daSjmcneill
554db7e12daSjmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSIX_CTL);
555db7e12daSjmcneill ctl |= PCI_MSIX_CTL_ENABLE;
556db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSIX_CTL, ctl);
557db7e12daSjmcneill }
558db7e12daSjmcneill
559db7e12daSjmcneill static void
apple_pcie_msi_msix_disable(struct apple_pcie_softc * sc,int msi)560db7e12daSjmcneill apple_pcie_msi_msix_disable(struct apple_pcie_softc *sc, int msi)
561db7e12daSjmcneill {
562db7e12daSjmcneill const struct pci_attach_args *pa = sc->sc_msi_pa[msi];
563db7e12daSjmcneill pci_chipset_tag_t pc = pa->pa_pc;
564db7e12daSjmcneill pcitag_t tag = pa->pa_tag;
565db7e12daSjmcneill pcireg_t ctl;
566db7e12daSjmcneill int off;
567db7e12daSjmcneill
568db7e12daSjmcneill if (!pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, NULL))
569db7e12daSjmcneill panic("apple_pcie_msi_msix_disable: device is not MSI-X-capable");
570db7e12daSjmcneill
571db7e12daSjmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSIX_CTL);
572db7e12daSjmcneill ctl &= ~PCI_MSIX_CTL_ENABLE;
573db7e12daSjmcneill pci_conf_write(pc, tag, off + PCI_MSIX_CTL, ctl);
574db7e12daSjmcneill }
575db7e12daSjmcneill
576db7e12daSjmcneill static pci_intr_handle_t *
apple_pcie_msi_msi_alloc(struct arm_pci_msi * msi,int * count,const struct pci_attach_args * pa,bool exact)577db7e12daSjmcneill apple_pcie_msi_msi_alloc(struct arm_pci_msi *msi, int *count,
578db7e12daSjmcneill const struct pci_attach_args *pa, bool exact)
579db7e12daSjmcneill {
580db7e12daSjmcneill struct apple_pcie_softc * const sc = msi->msi_priv;
581db7e12daSjmcneill pci_intr_handle_t *vectors;
582db7e12daSjmcneill int n, off;
583db7e12daSjmcneill
584db7e12daSjmcneill if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI, &off, NULL))
585db7e12daSjmcneill return NULL;
586db7e12daSjmcneill
587db7e12daSjmcneill const int avail = apple_pcie_msi_available_msi(sc);
588*161d7eb6Sskrll if (avail == 0)
589*161d7eb6Sskrll return NULL;
590*161d7eb6Sskrll
591db7e12daSjmcneill if (exact && *count > avail)
592db7e12daSjmcneill return NULL;
593db7e12daSjmcneill
594db7e12daSjmcneill while (*count > avail) {
595db7e12daSjmcneill (*count) >>= 1;
596db7e12daSjmcneill }
597db7e12daSjmcneill if (*count == 0)
598db7e12daSjmcneill return NULL;
599db7e12daSjmcneill
600db7e12daSjmcneill const int msi_base = apple_pcie_msi_alloc_msi(sc, *count, pa);
601db7e12daSjmcneill if (msi_base == -1)
602db7e12daSjmcneill return NULL;
603db7e12daSjmcneill
604db7e12daSjmcneill vectors = kmem_alloc(sizeof(*vectors) * *count, KM_SLEEP);
605db7e12daSjmcneill for (n = 0; n < *count; n++) {
606db7e12daSjmcneill const int msino = msi_base + n;
607db7e12daSjmcneill vectors[n] = ARM_PCI_INTR_MSI |
608db7e12daSjmcneill __SHIFTIN(msino, ARM_PCI_INTR_IRQ) |
609db7e12daSjmcneill __SHIFTIN(n, ARM_PCI_INTR_MSI_VEC) |
610db7e12daSjmcneill __SHIFTIN(msi->msi_id, ARM_PCI_INTR_FRAME);
611db7e12daSjmcneill }
612db7e12daSjmcneill
613db7e12daSjmcneill apple_pcie_msi_msi_enable(sc, msi_base, *count);
614db7e12daSjmcneill
615db7e12daSjmcneill return vectors;
616db7e12daSjmcneill }
617db7e12daSjmcneill
618db7e12daSjmcneill static pci_intr_handle_t *
apple_pcie_msi_msix_alloc(struct arm_pci_msi * msi,u_int * table_indexes,int * count,const struct pci_attach_args * pa,bool exact)619db7e12daSjmcneill apple_pcie_msi_msix_alloc(struct arm_pci_msi *msi, u_int *table_indexes,
620db7e12daSjmcneill int *count, const struct pci_attach_args *pa, bool exact)
621db7e12daSjmcneill {
622db7e12daSjmcneill struct apple_pcie_softc * const sc = msi->msi_priv;
623db7e12daSjmcneill pci_intr_handle_t *vectors;
624db7e12daSjmcneill bus_space_tag_t bst;
625db7e12daSjmcneill bus_space_handle_t bsh;
626db7e12daSjmcneill bus_size_t bsz;
627db7e12daSjmcneill uint32_t table_offset, table_size;
628db7e12daSjmcneill int n, off, bar, error;
629db7e12daSjmcneill pcireg_t tbl;
630db7e12daSjmcneill
631db7e12daSjmcneill if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSIX, &off, NULL))
632db7e12daSjmcneill return NULL;
633db7e12daSjmcneill
634db7e12daSjmcneill const int avail = apple_pcie_msi_available_msi(sc);
635db7e12daSjmcneill if (exact && *count > avail)
636db7e12daSjmcneill return NULL;
637db7e12daSjmcneill
638db7e12daSjmcneill while (*count > avail) {
639db7e12daSjmcneill (*count) >>= 1;
640db7e12daSjmcneill }
641db7e12daSjmcneill if (*count == 0)
642db7e12daSjmcneill return NULL;
643db7e12daSjmcneill
644db7e12daSjmcneill tbl = pci_conf_read(pa->pa_pc, pa->pa_tag, off + PCI_MSIX_TBLOFFSET);
645db7e12daSjmcneill bar = PCI_BAR0 + (4 * (tbl & PCI_MSIX_TBLBIR_MASK));
646db7e12daSjmcneill table_offset = tbl & PCI_MSIX_TBLOFFSET_MASK;
647db7e12daSjmcneill table_size = pci_msix_count(pa->pa_pc, pa->pa_tag) * PCI_MSIX_TABLE_ENTRY_SIZE;
648db7e12daSjmcneill if (table_size == 0)
649db7e12daSjmcneill return NULL;
650db7e12daSjmcneill
651db7e12daSjmcneill error = pci_mapreg_submap(pa, bar, pci_mapreg_type(pa->pa_pc, pa->pa_tag, bar),
652db7e12daSjmcneill BUS_SPACE_MAP_LINEAR, roundup(table_size, PAGE_SIZE), table_offset,
653db7e12daSjmcneill &bst, &bsh, NULL, &bsz);
654db7e12daSjmcneill if (error)
655db7e12daSjmcneill return NULL;
656db7e12daSjmcneill
657db7e12daSjmcneill const int msi_base = apple_pcie_msi_alloc_msi(sc, *count, pa);
658db7e12daSjmcneill if (msi_base == -1) {
659db7e12daSjmcneill bus_space_unmap(bst, bsh, bsz);
660db7e12daSjmcneill return NULL;
661db7e12daSjmcneill }
662db7e12daSjmcneill
663db7e12daSjmcneill vectors = kmem_alloc(sizeof(*vectors) * *count, KM_SLEEP);
664db7e12daSjmcneill for (n = 0; n < *count; n++) {
665db7e12daSjmcneill const int msino = msi_base + n;
666db7e12daSjmcneill const int msix_vec = table_indexes ? table_indexes[n] : n;
667db7e12daSjmcneill vectors[msix_vec] = ARM_PCI_INTR_MSIX |
668db7e12daSjmcneill __SHIFTIN(msino, ARM_PCI_INTR_IRQ) |
669db7e12daSjmcneill __SHIFTIN(msix_vec, ARM_PCI_INTR_MSI_VEC) |
670db7e12daSjmcneill __SHIFTIN(msi->msi_id, ARM_PCI_INTR_FRAME);
671db7e12daSjmcneill
672db7e12daSjmcneill apple_pcie_msi_msix_enable(sc, msino, msix_vec, bst, bsh);
673db7e12daSjmcneill }
674db7e12daSjmcneill
675db7e12daSjmcneill bus_space_unmap(bst, bsh, bsz);
676db7e12daSjmcneill
677db7e12daSjmcneill return vectors;
678db7e12daSjmcneill }
679db7e12daSjmcneill
680db7e12daSjmcneill static void *
apple_pcie_msi_intr_establish(struct arm_pci_msi * msi,pci_intr_handle_t ih,int ipl,int (* func)(void *),void * arg,const char * xname)681db7e12daSjmcneill apple_pcie_msi_intr_establish(struct arm_pci_msi *msi,
682db7e12daSjmcneill pci_intr_handle_t ih, int ipl, int (*func)(void *), void *arg, const char *xname)
683db7e12daSjmcneill {
684db7e12daSjmcneill struct apple_pcie_softc * const sc = msi->msi_priv;
685db7e12daSjmcneill
686db7e12daSjmcneill const int msino = __SHIFTOUT(ih, ARM_PCI_INTR_IRQ);
687db7e12daSjmcneill const int mpsafe = (ih & ARM_PCI_INTR_MPSAFE) ? FDT_INTR_MPSAFE : 0;
688db7e12daSjmcneill
689db7e12daSjmcneill KASSERT(sc->sc_msi_ih[msino] == NULL);
690db7e12daSjmcneill sc->sc_msi_ih[msino] = intr_establish_xname(sc->sc_msi_start + msino,
691db7e12daSjmcneill ipl, IST_LEVEL | (mpsafe ? IST_MPSAFE : 0), func, arg, xname);
692db7e12daSjmcneill
693db7e12daSjmcneill return sc->sc_msi_ih[msino];
694db7e12daSjmcneill }
695db7e12daSjmcneill
696db7e12daSjmcneill static void
apple_pcie_msi_intr_release(struct arm_pci_msi * msi,pci_intr_handle_t * pih,int count)697db7e12daSjmcneill apple_pcie_msi_intr_release(struct arm_pci_msi *msi, pci_intr_handle_t *pih,
698db7e12daSjmcneill int count)
699db7e12daSjmcneill {
700db7e12daSjmcneill struct apple_pcie_softc * const sc = msi->msi_priv;
701db7e12daSjmcneill int n;
702db7e12daSjmcneill
703db7e12daSjmcneill for (n = 0; n < count; n++) {
704db7e12daSjmcneill const int msino = __SHIFTOUT(pih[n], ARM_PCI_INTR_IRQ);
705db7e12daSjmcneill if (pih[n] & ARM_PCI_INTR_MSIX)
706db7e12daSjmcneill apple_pcie_msi_msix_disable(sc, msino);
707db7e12daSjmcneill if (pih[n] & ARM_PCI_INTR_MSI)
708db7e12daSjmcneill apple_pcie_msi_msi_disable(sc, msino);
709db7e12daSjmcneill apple_pcie_msi_free_msi(sc, msino);
710db7e12daSjmcneill if (sc->sc_msi_ih[msino] != NULL) {
711db7e12daSjmcneill intr_disestablish(sc->sc_msi_ih[msino]);
712db7e12daSjmcneill sc->sc_msi_ih[msino] = NULL;
713db7e12daSjmcneill }
714db7e12daSjmcneill }
715db7e12daSjmcneill }
716db7e12daSjmcneill
717db7e12daSjmcneill static int
apple_pcie_msi_init(struct apple_pcie_softc * sc)718db7e12daSjmcneill apple_pcie_msi_init(struct apple_pcie_softc *sc)
719db7e12daSjmcneill {
720db7e12daSjmcneill struct arm_pci_msi *msi = &sc->sc_msi;
721db7e12daSjmcneill const int phandle = sc->sc_pcihost.sc_phandle;
722db7e12daSjmcneill int len;
723db7e12daSjmcneill
724db7e12daSjmcneill const u_int *data = fdtbus_get_prop(phandle, "msi-ranges", &len);
725bbf4d957Sjmcneill switch (len) {
726bbf4d957Sjmcneill case 8:
727bbf4d957Sjmcneill /* two cells: start and count */
728bbf4d957Sjmcneill sc->sc_msi_start = be32toh(data[0]);
729bbf4d957Sjmcneill sc->sc_nmsi = be32toh(data[1]);
730bbf4d957Sjmcneill break;
731bbf4d957Sjmcneill case 20:
732bbf4d957Sjmcneill /* 5 cells: xref, specifier (3 cells), and count */
733bbf4d957Sjmcneill sc->sc_msi_start = be32toh(data[2]);
734bbf4d957Sjmcneill sc->sc_nmsi = be32toh(data[4]);
735bbf4d957Sjmcneill break;
736bbf4d957Sjmcneill default:
737db7e12daSjmcneill aprint_error_dev(sc->sc_pcihost.sc_dev,
738db7e12daSjmcneill "WARNING: bad msi-ranges property, MSI not enabled!\n");
739db7e12daSjmcneill return ENXIO;
740db7e12daSjmcneill }
741db7e12daSjmcneill sc->sc_msi_pa = kmem_zalloc(sizeof(*sc->sc_msi_pa) * sc->sc_nmsi,
742db7e12daSjmcneill KM_SLEEP);
743db7e12daSjmcneill sc->sc_msi_ih = kmem_zalloc(sizeof(*sc->sc_msi_ih) * sc->sc_nmsi,
744db7e12daSjmcneill KM_SLEEP);
745db7e12daSjmcneill
746db7e12daSjmcneill if (of_getprop_uint64(phandle, "msi-doorbell", &sc->sc_msi_addr)) {
747db7e12daSjmcneill sc->sc_msi_addr = 0xffff000ULL;
748db7e12daSjmcneill }
749db7e12daSjmcneill
750db7e12daSjmcneill msi->msi_dev = sc->sc_pcihost.sc_dev;
751db7e12daSjmcneill msi->msi_priv = sc;
752db7e12daSjmcneill msi->msi_alloc = apple_pcie_msi_msi_alloc;
753db7e12daSjmcneill msi->msix_alloc = apple_pcie_msi_msix_alloc;
754db7e12daSjmcneill msi->msi_intr_establish = apple_pcie_msi_intr_establish;
755db7e12daSjmcneill msi->msi_intr_release = apple_pcie_msi_intr_release;
756db7e12daSjmcneill
757db7e12daSjmcneill return arm_pci_msi_add(msi);
758db7e12daSjmcneill }
759