1*2ed98337SAymeric Wibo /*-
2*2ed98337SAymeric Wibo * SPDX-License-Identifier: BSD-2-Clause
3*2ed98337SAymeric Wibo *
4*2ed98337SAymeric Wibo * Copyright (c) 2022 Scott Long
5*2ed98337SAymeric Wibo * All rights reserved.
6*2ed98337SAymeric Wibo *
7*2ed98337SAymeric Wibo * Redistribution and use in source and binary forms, with or without
8*2ed98337SAymeric Wibo * modification, are permitted provided that the following conditions
9*2ed98337SAymeric Wibo * are met:
10*2ed98337SAymeric Wibo * 1. Redistributions of source code must retain the above copyright
11*2ed98337SAymeric Wibo * notice, this list of conditions and the following disclaimer.
12*2ed98337SAymeric Wibo * 2. Redistributions in binary form must reproduce the above copyright
13*2ed98337SAymeric Wibo * notice, this list of conditions and the following disclaimer in the
14*2ed98337SAymeric Wibo * documentation and/or other materials provided with the distribution.
15*2ed98337SAymeric Wibo *
16*2ed98337SAymeric Wibo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*2ed98337SAymeric Wibo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*2ed98337SAymeric Wibo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*2ed98337SAymeric Wibo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*2ed98337SAymeric Wibo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*2ed98337SAymeric Wibo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*2ed98337SAymeric Wibo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*2ed98337SAymeric Wibo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*2ed98337SAymeric Wibo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*2ed98337SAymeric Wibo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*2ed98337SAymeric Wibo * SUCH DAMAGE.
27*2ed98337SAymeric Wibo */
28*2ed98337SAymeric Wibo
29*2ed98337SAymeric Wibo #include "opt_thunderbolt.h"
30*2ed98337SAymeric Wibo
31*2ed98337SAymeric Wibo /* PCIe interface for Thunderbolt Native Host Interface */
32*2ed98337SAymeric Wibo #include <sys/types.h>
33*2ed98337SAymeric Wibo #include <sys/param.h>
34*2ed98337SAymeric Wibo #include <sys/systm.h>
35*2ed98337SAymeric Wibo #include <sys/kernel.h>
36*2ed98337SAymeric Wibo #include <sys/module.h>
37*2ed98337SAymeric Wibo #include <sys/bus.h>
38*2ed98337SAymeric Wibo #include <sys/conf.h>
39*2ed98337SAymeric Wibo #include <sys/malloc.h>
40*2ed98337SAymeric Wibo #include <sys/sysctl.h>
41*2ed98337SAymeric Wibo #include <sys/lock.h>
42*2ed98337SAymeric Wibo #include <sys/param.h>
43*2ed98337SAymeric Wibo #include <sys/endian.h>
44*2ed98337SAymeric Wibo #include <sys/taskqueue.h>
45*2ed98337SAymeric Wibo
46*2ed98337SAymeric Wibo #include <machine/bus.h>
47*2ed98337SAymeric Wibo #include <machine/resource.h>
48*2ed98337SAymeric Wibo #include <machine/stdarg.h>
49*2ed98337SAymeric Wibo #include <sys/rman.h>
50*2ed98337SAymeric Wibo
51*2ed98337SAymeric Wibo #include <dev/pci/pcireg.h>
52*2ed98337SAymeric Wibo #include <dev/pci/pcivar.h>
53*2ed98337SAymeric Wibo #include <dev/pci/pci_private.h>
54*2ed98337SAymeric Wibo
55*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_reg.h>
56*2ed98337SAymeric Wibo #include <dev/thunderbolt/nhi_reg.h>
57*2ed98337SAymeric Wibo #include <dev/thunderbolt/nhi_var.h>
58*2ed98337SAymeric Wibo #include <dev/thunderbolt/tbcfg_reg.h>
59*2ed98337SAymeric Wibo #include <dev/thunderbolt/router_var.h>
60*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_debug.h>
61*2ed98337SAymeric Wibo #include "tb_if.h"
62*2ed98337SAymeric Wibo
63*2ed98337SAymeric Wibo static int nhi_pci_probe(device_t);
64*2ed98337SAymeric Wibo static int nhi_pci_attach(device_t);
65*2ed98337SAymeric Wibo static int nhi_pci_detach(device_t);
66*2ed98337SAymeric Wibo static int nhi_pci_suspend(device_t);
67*2ed98337SAymeric Wibo static int nhi_pci_resume(device_t);
68*2ed98337SAymeric Wibo static void nhi_pci_free(struct nhi_softc *);
69*2ed98337SAymeric Wibo static int nhi_pci_allocate_interrupts(struct nhi_softc *);
70*2ed98337SAymeric Wibo static void nhi_pci_free_interrupts(struct nhi_softc *);
71*2ed98337SAymeric Wibo static int nhi_pci_icl_poweron(struct nhi_softc *);
72*2ed98337SAymeric Wibo
73*2ed98337SAymeric Wibo static device_method_t nhi_methods[] = {
74*2ed98337SAymeric Wibo DEVMETHOD(device_probe, nhi_pci_probe),
75*2ed98337SAymeric Wibo DEVMETHOD(device_attach, nhi_pci_attach),
76*2ed98337SAymeric Wibo DEVMETHOD(device_detach, nhi_pci_detach),
77*2ed98337SAymeric Wibo DEVMETHOD(device_suspend, nhi_pci_suspend),
78*2ed98337SAymeric Wibo DEVMETHOD(device_resume, nhi_pci_resume),
79*2ed98337SAymeric Wibo
80*2ed98337SAymeric Wibo DEVMETHOD(tb_find_ufp, tb_generic_find_ufp),
81*2ed98337SAymeric Wibo DEVMETHOD(tb_get_debug, tb_generic_get_debug),
82*2ed98337SAymeric Wibo
83*2ed98337SAymeric Wibo DEVMETHOD_END
84*2ed98337SAymeric Wibo };
85*2ed98337SAymeric Wibo
86*2ed98337SAymeric Wibo static driver_t nhi_pci_driver = {
87*2ed98337SAymeric Wibo "nhi",
88*2ed98337SAymeric Wibo nhi_methods,
89*2ed98337SAymeric Wibo sizeof(struct nhi_softc)
90*2ed98337SAymeric Wibo };
91*2ed98337SAymeric Wibo
92*2ed98337SAymeric Wibo struct nhi_ident {
93*2ed98337SAymeric Wibo uint16_t vendor;
94*2ed98337SAymeric Wibo uint16_t device;
95*2ed98337SAymeric Wibo uint16_t subvendor;
96*2ed98337SAymeric Wibo uint16_t subdevice;
97*2ed98337SAymeric Wibo uint32_t flags;
98*2ed98337SAymeric Wibo const char *desc;
99*2ed98337SAymeric Wibo } nhi_identifiers[] = {
100*2ed98337SAymeric Wibo { VENDOR_INTEL, DEVICE_AR_2C_NHI, 0xffff, 0xffff, NHI_TYPE_AR,
101*2ed98337SAymeric Wibo "Thunderbolt 3 NHI (Alpine Ridge 2C)" },
102*2ed98337SAymeric Wibo { VENDOR_INTEL, DEVICE_AR_DP_B_NHI, 0xffff, 0xffff, NHI_TYPE_AR,
103*2ed98337SAymeric Wibo "Thunderbolt 3 NHI (Alpine Ridge 4C Rev B)" },
104*2ed98337SAymeric Wibo { VENDOR_INTEL, DEVICE_AR_DP_C_NHI, 0xffff, 0xffff, NHI_TYPE_AR,
105*2ed98337SAymeric Wibo "Thunderbolt 3 NHI (Alpine Ridge 4C Rev C)" },
106*2ed98337SAymeric Wibo { VENDOR_INTEL, DEVICE_AR_LP_NHI, 0xffff, 0xffff, NHI_TYPE_AR,
107*2ed98337SAymeric Wibo "Thunderbolt 3 NHI (Alpine Ridge LP 2C)" },
108*2ed98337SAymeric Wibo { VENDOR_INTEL, DEVICE_ICL_NHI_0, 0xffff, 0xffff, NHI_TYPE_ICL,
109*2ed98337SAymeric Wibo "Thunderbolt 3 NHI Port 0 (IceLake)" },
110*2ed98337SAymeric Wibo { VENDOR_INTEL, DEVICE_ICL_NHI_1, 0xffff, 0xffff, NHI_TYPE_ICL,
111*2ed98337SAymeric Wibo "Thunderbolt 3 NHI Port 1 (IceLake)" },
112*2ed98337SAymeric Wibo { VENDOR_AMD, DEVICE_PINK_SARDINE_0, 0xffff, 0xffff, NHI_TYPE_USB4,
113*2ed98337SAymeric Wibo "USB4 NHI Port 0 (Pink Sardine)" },
114*2ed98337SAymeric Wibo { VENDOR_AMD, DEVICE_PINK_SARDINE_1, 0xffff, 0xffff, NHI_TYPE_USB4,
115*2ed98337SAymeric Wibo "USB4 NHI Port 1 (Pink Sardine)" },
116*2ed98337SAymeric Wibo { 0, 0, 0, 0, 0, NULL }
117*2ed98337SAymeric Wibo };
118*2ed98337SAymeric Wibo
119*2ed98337SAymeric Wibo DRIVER_MODULE_ORDERED(nhi, pci, nhi_pci_driver, NULL, NULL,
120*2ed98337SAymeric Wibo SI_ORDER_ANY);
121*2ed98337SAymeric Wibo MODULE_PNP_INFO("U16:vendor;U16:device;V16:subvendor;V16:subdevice;U32:#;D:#",
122*2ed98337SAymeric Wibo pci, nhi, nhi_identifiers, nitems(nhi_identifiers) - 1);
123*2ed98337SAymeric Wibo
124*2ed98337SAymeric Wibo static struct nhi_ident *
nhi_find_ident(device_t dev)125*2ed98337SAymeric Wibo nhi_find_ident(device_t dev)
126*2ed98337SAymeric Wibo {
127*2ed98337SAymeric Wibo struct nhi_ident *n;
128*2ed98337SAymeric Wibo
129*2ed98337SAymeric Wibo for (n = nhi_identifiers; n->vendor != 0; n++) {
130*2ed98337SAymeric Wibo if (n->vendor != pci_get_vendor(dev))
131*2ed98337SAymeric Wibo continue;
132*2ed98337SAymeric Wibo if (n->device != pci_get_device(dev))
133*2ed98337SAymeric Wibo continue;
134*2ed98337SAymeric Wibo if ((n->subvendor != 0xffff) &&
135*2ed98337SAymeric Wibo (n->subvendor != pci_get_subvendor(dev)))
136*2ed98337SAymeric Wibo continue;
137*2ed98337SAymeric Wibo if ((n->subdevice != 0xffff) &&
138*2ed98337SAymeric Wibo (n->subdevice != pci_get_subdevice(dev)))
139*2ed98337SAymeric Wibo continue;
140*2ed98337SAymeric Wibo return (n);
141*2ed98337SAymeric Wibo }
142*2ed98337SAymeric Wibo
143*2ed98337SAymeric Wibo return (NULL);
144*2ed98337SAymeric Wibo }
145*2ed98337SAymeric Wibo
146*2ed98337SAymeric Wibo static int
nhi_pci_probe(device_t dev)147*2ed98337SAymeric Wibo nhi_pci_probe(device_t dev)
148*2ed98337SAymeric Wibo {
149*2ed98337SAymeric Wibo struct nhi_ident *n;
150*2ed98337SAymeric Wibo
151*2ed98337SAymeric Wibo if (resource_disabled("tb", 0))
152*2ed98337SAymeric Wibo return (ENXIO);
153*2ed98337SAymeric Wibo if ((n = nhi_find_ident(dev)) != NULL) {
154*2ed98337SAymeric Wibo device_set_desc(dev, n->desc);
155*2ed98337SAymeric Wibo return (BUS_PROBE_DEFAULT);
156*2ed98337SAymeric Wibo }
157*2ed98337SAymeric Wibo return (ENXIO);
158*2ed98337SAymeric Wibo }
159*2ed98337SAymeric Wibo
160*2ed98337SAymeric Wibo static int
nhi_pci_attach(device_t dev)161*2ed98337SAymeric Wibo nhi_pci_attach(device_t dev)
162*2ed98337SAymeric Wibo {
163*2ed98337SAymeric Wibo devclass_t dc;
164*2ed98337SAymeric Wibo bus_dma_template_t t;
165*2ed98337SAymeric Wibo struct nhi_softc *sc;
166*2ed98337SAymeric Wibo struct nhi_ident *n;
167*2ed98337SAymeric Wibo int error = 0;
168*2ed98337SAymeric Wibo
169*2ed98337SAymeric Wibo sc = device_get_softc(dev);
170*2ed98337SAymeric Wibo bzero(sc, sizeof(*sc));
171*2ed98337SAymeric Wibo sc->dev = dev;
172*2ed98337SAymeric Wibo n = nhi_find_ident(dev);
173*2ed98337SAymeric Wibo sc->hwflags = n->flags;
174*2ed98337SAymeric Wibo nhi_get_tunables(sc);
175*2ed98337SAymeric Wibo
176*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT|DBG_FULL, "busmaster status was %s\n",
177*2ed98337SAymeric Wibo (pci_read_config(dev, PCIR_COMMAND, 2) & PCIM_CMD_BUSMASTEREN)
178*2ed98337SAymeric Wibo ? "enabled" : "disabled");
179*2ed98337SAymeric Wibo pci_enable_busmaster(dev);
180*2ed98337SAymeric Wibo
181*2ed98337SAymeric Wibo sc->ufp = NULL;
182*2ed98337SAymeric Wibo if ((TB_FIND_UFP(dev, &sc->ufp) != 0) || (sc->ufp == NULL)) {
183*2ed98337SAymeric Wibo dc = devclass_find("tbolt");
184*2ed98337SAymeric Wibo if (dc != NULL)
185*2ed98337SAymeric Wibo sc->ufp = devclass_get_device(dc, device_get_unit(dev));
186*2ed98337SAymeric Wibo }
187*2ed98337SAymeric Wibo if (sc->ufp == NULL)
188*2ed98337SAymeric Wibo tb_printf(sc, "Cannot find Upstream Facing Port\n");
189*2ed98337SAymeric Wibo else
190*2ed98337SAymeric Wibo tb_printf(sc, "Upstream Facing Port is %s\n",
191*2ed98337SAymeric Wibo device_get_nameunit(sc->ufp));
192*2ed98337SAymeric Wibo
193*2ed98337SAymeric Wibo if (NHI_IS_ICL(sc)) {
194*2ed98337SAymeric Wibo if ((error = nhi_pci_icl_poweron(sc)) != 0)
195*2ed98337SAymeric Wibo return (error);
196*2ed98337SAymeric Wibo }
197*2ed98337SAymeric Wibo
198*2ed98337SAymeric Wibo
199*2ed98337SAymeric Wibo /* Allocate BAR0 DMA registers */
200*2ed98337SAymeric Wibo sc->regs_rid = PCIR_BAR(0);
201*2ed98337SAymeric Wibo if ((sc->regs_resource = bus_alloc_resource_any(dev,
202*2ed98337SAymeric Wibo SYS_RES_MEMORY, &sc->regs_rid, RF_ACTIVE)) == NULL) {
203*2ed98337SAymeric Wibo tb_printf(sc, "Cannot allocate PCI registers\n");
204*2ed98337SAymeric Wibo return (ENXIO);
205*2ed98337SAymeric Wibo }
206*2ed98337SAymeric Wibo sc->regs_btag = rman_get_bustag(sc->regs_resource);
207*2ed98337SAymeric Wibo sc->regs_bhandle = rman_get_bushandle(sc->regs_resource);
208*2ed98337SAymeric Wibo
209*2ed98337SAymeric Wibo /* Allocate parent DMA tag */
210*2ed98337SAymeric Wibo bus_dma_template_init(&t, bus_get_dma_tag(dev));
211*2ed98337SAymeric Wibo if (bus_dma_template_tag(&t, &sc->parent_dmat) != 0) {
212*2ed98337SAymeric Wibo tb_printf(sc, "Cannot allocate parent DMA tag\n");
213*2ed98337SAymeric Wibo nhi_pci_free(sc);
214*2ed98337SAymeric Wibo return (ENOMEM);
215*2ed98337SAymeric Wibo }
216*2ed98337SAymeric Wibo
217*2ed98337SAymeric Wibo error = nhi_pci_allocate_interrupts(sc);
218*2ed98337SAymeric Wibo if (error == 0)
219*2ed98337SAymeric Wibo error = nhi_attach(sc);
220*2ed98337SAymeric Wibo if (error != 0)
221*2ed98337SAymeric Wibo nhi_pci_detach(sc->dev);
222*2ed98337SAymeric Wibo return (error);
223*2ed98337SAymeric Wibo }
224*2ed98337SAymeric Wibo
225*2ed98337SAymeric Wibo static int
nhi_pci_detach(device_t dev)226*2ed98337SAymeric Wibo nhi_pci_detach(device_t dev)
227*2ed98337SAymeric Wibo {
228*2ed98337SAymeric Wibo struct nhi_softc *sc;
229*2ed98337SAymeric Wibo
230*2ed98337SAymeric Wibo sc = device_get_softc(dev);
231*2ed98337SAymeric Wibo
232*2ed98337SAymeric Wibo nhi_detach(sc);
233*2ed98337SAymeric Wibo nhi_pci_free(sc);
234*2ed98337SAymeric Wibo
235*2ed98337SAymeric Wibo return (0);
236*2ed98337SAymeric Wibo }
237*2ed98337SAymeric Wibo
238*2ed98337SAymeric Wibo static int
nhi_pci_suspend(device_t dev)239*2ed98337SAymeric Wibo nhi_pci_suspend(device_t dev)
240*2ed98337SAymeric Wibo {
241*2ed98337SAymeric Wibo
242*2ed98337SAymeric Wibo return (0);
243*2ed98337SAymeric Wibo }
244*2ed98337SAymeric Wibo
245*2ed98337SAymeric Wibo static int
nhi_pci_resume(device_t dev)246*2ed98337SAymeric Wibo nhi_pci_resume(device_t dev)
247*2ed98337SAymeric Wibo {
248*2ed98337SAymeric Wibo
249*2ed98337SAymeric Wibo return (0);
250*2ed98337SAymeric Wibo }
251*2ed98337SAymeric Wibo
252*2ed98337SAymeric Wibo static void
nhi_pci_free(struct nhi_softc * sc)253*2ed98337SAymeric Wibo nhi_pci_free(struct nhi_softc *sc)
254*2ed98337SAymeric Wibo {
255*2ed98337SAymeric Wibo
256*2ed98337SAymeric Wibo nhi_pci_free_interrupts(sc);
257*2ed98337SAymeric Wibo
258*2ed98337SAymeric Wibo if (sc->parent_dmat != NULL) {
259*2ed98337SAymeric Wibo bus_dma_tag_destroy(sc->parent_dmat);
260*2ed98337SAymeric Wibo sc->parent_dmat = NULL;
261*2ed98337SAymeric Wibo }
262*2ed98337SAymeric Wibo
263*2ed98337SAymeric Wibo if (sc->regs_resource != NULL) {
264*2ed98337SAymeric Wibo bus_release_resource(sc->dev, SYS_RES_MEMORY,
265*2ed98337SAymeric Wibo sc->regs_rid, sc->regs_resource);
266*2ed98337SAymeric Wibo sc->regs_resource = NULL;
267*2ed98337SAymeric Wibo }
268*2ed98337SAymeric Wibo
269*2ed98337SAymeric Wibo return;
270*2ed98337SAymeric Wibo }
271*2ed98337SAymeric Wibo
272*2ed98337SAymeric Wibo static int
nhi_pci_allocate_interrupts(struct nhi_softc * sc)273*2ed98337SAymeric Wibo nhi_pci_allocate_interrupts(struct nhi_softc *sc)
274*2ed98337SAymeric Wibo {
275*2ed98337SAymeric Wibo int msgs, error = 0;
276*2ed98337SAymeric Wibo
277*2ed98337SAymeric Wibo /* Map the Pending Bit Array and Vector Table BARs for MSI-X */
278*2ed98337SAymeric Wibo sc->irq_pba_rid = pci_msix_pba_bar(sc->dev);
279*2ed98337SAymeric Wibo sc->irq_table_rid = pci_msix_table_bar(sc->dev);
280*2ed98337SAymeric Wibo
281*2ed98337SAymeric Wibo if (sc->irq_pba_rid != -1)
282*2ed98337SAymeric Wibo sc->irq_pba = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
283*2ed98337SAymeric Wibo &sc->irq_pba_rid, RF_ACTIVE);
284*2ed98337SAymeric Wibo if (sc->irq_table_rid != -1)
285*2ed98337SAymeric Wibo sc->irq_table = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
286*2ed98337SAymeric Wibo &sc->irq_table_rid, RF_ACTIVE);
287*2ed98337SAymeric Wibo
288*2ed98337SAymeric Wibo msgs = pci_msix_count(sc->dev);
289*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT|DBG_INTR|DBG_FULL,
290*2ed98337SAymeric Wibo "Counted %d MSI-X messages\n", msgs);
291*2ed98337SAymeric Wibo msgs = min(msgs, NHI_MSIX_MAX);
292*2ed98337SAymeric Wibo msgs = max(msgs, 1);
293*2ed98337SAymeric Wibo if (msgs != 0) {
294*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT|DBG_INTR, "Attempting to allocate %d "
295*2ed98337SAymeric Wibo "MSI-X interrupts\n", msgs);
296*2ed98337SAymeric Wibo error = pci_alloc_msix(sc->dev, &msgs);
297*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT|DBG_INTR|DBG_FULL,
298*2ed98337SAymeric Wibo "pci_alloc_msix return msgs= %d, error= %d\n", msgs, error);
299*2ed98337SAymeric Wibo }
300*2ed98337SAymeric Wibo
301*2ed98337SAymeric Wibo if ((error != 0) || (msgs <= 0)) {
302*2ed98337SAymeric Wibo tb_printf(sc, "Failed to allocate any interrupts\n");
303*2ed98337SAymeric Wibo msgs = 0;
304*2ed98337SAymeric Wibo }
305*2ed98337SAymeric Wibo
306*2ed98337SAymeric Wibo sc->msix_count = msgs;
307*2ed98337SAymeric Wibo return (error);
308*2ed98337SAymeric Wibo }
309*2ed98337SAymeric Wibo
310*2ed98337SAymeric Wibo static void
nhi_pci_free_interrupts(struct nhi_softc * sc)311*2ed98337SAymeric Wibo nhi_pci_free_interrupts(struct nhi_softc *sc)
312*2ed98337SAymeric Wibo {
313*2ed98337SAymeric Wibo int i;
314*2ed98337SAymeric Wibo
315*2ed98337SAymeric Wibo for (i = 0; i < sc->msix_count; i++) {
316*2ed98337SAymeric Wibo bus_teardown_intr(sc->dev, sc->irqs[i], sc->intrhand[i]);
317*2ed98337SAymeric Wibo bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid[i],
318*2ed98337SAymeric Wibo sc->irqs[i]);
319*2ed98337SAymeric Wibo }
320*2ed98337SAymeric Wibo
321*2ed98337SAymeric Wibo pci_release_msi(sc->dev);
322*2ed98337SAymeric Wibo
323*2ed98337SAymeric Wibo if (sc->irq_table != NULL) {
324*2ed98337SAymeric Wibo bus_release_resource(sc->dev, SYS_RES_MEMORY,
325*2ed98337SAymeric Wibo sc->irq_table_rid, sc->irq_table);
326*2ed98337SAymeric Wibo sc->irq_table = NULL;
327*2ed98337SAymeric Wibo }
328*2ed98337SAymeric Wibo
329*2ed98337SAymeric Wibo if (sc->irq_pba != NULL) {
330*2ed98337SAymeric Wibo bus_release_resource(sc->dev, SYS_RES_MEMORY,
331*2ed98337SAymeric Wibo sc->irq_pba_rid, sc->irq_pba);
332*2ed98337SAymeric Wibo sc->irq_pba = NULL;
333*2ed98337SAymeric Wibo }
334*2ed98337SAymeric Wibo
335*2ed98337SAymeric Wibo if (sc->intr_trackers != NULL)
336*2ed98337SAymeric Wibo free(sc->intr_trackers, M_NHI);
337*2ed98337SAymeric Wibo return;
338*2ed98337SAymeric Wibo }
339*2ed98337SAymeric Wibo
340*2ed98337SAymeric Wibo int
nhi_pci_configure_interrupts(struct nhi_softc * sc)341*2ed98337SAymeric Wibo nhi_pci_configure_interrupts(struct nhi_softc *sc)
342*2ed98337SAymeric Wibo {
343*2ed98337SAymeric Wibo struct nhi_intr_tracker *trkr;
344*2ed98337SAymeric Wibo int rid, i, error;
345*2ed98337SAymeric Wibo
346*2ed98337SAymeric Wibo nhi_pci_disable_interrupts(sc);
347*2ed98337SAymeric Wibo
348*2ed98337SAymeric Wibo sc->intr_trackers = malloc(sizeof(struct nhi_intr_tracker) *
349*2ed98337SAymeric Wibo sc->msix_count, M_NHI, M_ZERO | M_NOWAIT);
350*2ed98337SAymeric Wibo if (sc->intr_trackers == NULL) {
351*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT, "Cannot allocate intr trackers\n");
352*2ed98337SAymeric Wibo return (ENOMEM);
353*2ed98337SAymeric Wibo }
354*2ed98337SAymeric Wibo
355*2ed98337SAymeric Wibo for (i = 0; i < sc->msix_count; i++) {
356*2ed98337SAymeric Wibo rid = i + 1;
357*2ed98337SAymeric Wibo trkr = &sc->intr_trackers[i];
358*2ed98337SAymeric Wibo trkr->sc = sc;
359*2ed98337SAymeric Wibo trkr->ring = NULL;
360*2ed98337SAymeric Wibo trkr->vector = i;
361*2ed98337SAymeric Wibo
362*2ed98337SAymeric Wibo sc->irq_rid[i] = rid;
363*2ed98337SAymeric Wibo sc->irqs[i] = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
364*2ed98337SAymeric Wibo &sc->irq_rid[i], RF_ACTIVE);
365*2ed98337SAymeric Wibo if (sc->irqs[i] == NULL) {
366*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT,
367*2ed98337SAymeric Wibo "Cannot allocate interrupt RID %d\n",
368*2ed98337SAymeric Wibo sc->irq_rid[i]);
369*2ed98337SAymeric Wibo break;
370*2ed98337SAymeric Wibo }
371*2ed98337SAymeric Wibo error = bus_setup_intr(sc->dev, sc->irqs[i], INTR_TYPE_BIO |
372*2ed98337SAymeric Wibo INTR_MPSAFE, NULL, nhi_intr, trkr, &sc->intrhand[i]);
373*2ed98337SAymeric Wibo if (error) {
374*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT,
375*2ed98337SAymeric Wibo "cannot setup interrupt RID %d\n", sc->irq_rid[i]);
376*2ed98337SAymeric Wibo break;
377*2ed98337SAymeric Wibo }
378*2ed98337SAymeric Wibo }
379*2ed98337SAymeric Wibo
380*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT, "Set up %d interrupts\n", sc->msix_count);
381*2ed98337SAymeric Wibo
382*2ed98337SAymeric Wibo /* Set the interrupt throttle rate to 128us */
383*2ed98337SAymeric Wibo for (i = 0; i < 16; i ++)
384*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_ITR0 + i * 4, 0x1f4);
385*2ed98337SAymeric Wibo
386*2ed98337SAymeric Wibo return (error);
387*2ed98337SAymeric Wibo }
388*2ed98337SAymeric Wibo
389*2ed98337SAymeric Wibo #define NHI_SET_INTERRUPT(offset, mask, val) \
390*2ed98337SAymeric Wibo do { \
391*2ed98337SAymeric Wibo reg = offset / 32; \
392*2ed98337SAymeric Wibo offset %= 32; \
393*2ed98337SAymeric Wibo ivr[reg] &= ~(mask << offset); \
394*2ed98337SAymeric Wibo ivr[reg] |= (val << offset); \
395*2ed98337SAymeric Wibo } while (0)
396*2ed98337SAymeric Wibo
397*2ed98337SAymeric Wibo void
nhi_pci_enable_interrupt(struct nhi_ring_pair * r)398*2ed98337SAymeric Wibo nhi_pci_enable_interrupt(struct nhi_ring_pair *r)
399*2ed98337SAymeric Wibo {
400*2ed98337SAymeric Wibo struct nhi_softc *sc = r->sc;
401*2ed98337SAymeric Wibo uint32_t ivr[5];
402*2ed98337SAymeric Wibo u_int offset, reg;
403*2ed98337SAymeric Wibo
404*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT|DBG_INTR, "Enabling interrupts for ring %d\n",
405*2ed98337SAymeric Wibo r->ring_num);
406*2ed98337SAymeric Wibo /*
407*2ed98337SAymeric Wibo * Compute the routing between event type and MSI-X vector.
408*2ed98337SAymeric Wibo * 4 bits per descriptor.
409*2ed98337SAymeric Wibo */
410*2ed98337SAymeric Wibo ivr[0] = nhi_read_reg(sc, NHI_IVR0);
411*2ed98337SAymeric Wibo ivr[1] = nhi_read_reg(sc, NHI_IVR1);
412*2ed98337SAymeric Wibo ivr[2] = nhi_read_reg(sc, NHI_IVR2);
413*2ed98337SAymeric Wibo ivr[3] = nhi_read_reg(sc, NHI_IVR3);
414*2ed98337SAymeric Wibo ivr[4] = nhi_read_reg(sc, NHI_IVR4);
415*2ed98337SAymeric Wibo
416*2ed98337SAymeric Wibo /* Program TX */
417*2ed98337SAymeric Wibo offset = (r->ring_num + IVR_TX_OFFSET) * 4;
418*2ed98337SAymeric Wibo NHI_SET_INTERRUPT(offset, 0x0f, r->ring_num);
419*2ed98337SAymeric Wibo
420*2ed98337SAymeric Wibo /* Now program RX */
421*2ed98337SAymeric Wibo offset = (r->ring_num + IVR_RX_OFFSET) * 4;
422*2ed98337SAymeric Wibo NHI_SET_INTERRUPT(offset, 0x0f, r->ring_num);
423*2ed98337SAymeric Wibo
424*2ed98337SAymeric Wibo /* Last, program Nearly Empty. This one always going to vector 15 */
425*2ed98337SAymeric Wibo offset = (r->ring_num + IVR_NE_OFFSET) * 4;
426*2ed98337SAymeric Wibo NHI_SET_INTERRUPT(offset, 0x0f, 0x0f);
427*2ed98337SAymeric Wibo
428*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IVR0, ivr[0]);
429*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IVR1, ivr[1]);
430*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IVR2, ivr[2]);
431*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IVR3, ivr[3]);
432*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IVR4, ivr[4]);
433*2ed98337SAymeric Wibo
434*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT|DBG_INTR|DBG_FULL,
435*2ed98337SAymeric Wibo "Wrote IVR 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
436*2ed98337SAymeric Wibo ivr[0], ivr[1], ivr[2], ivr[3], ivr[4]);
437*2ed98337SAymeric Wibo
438*2ed98337SAymeric Wibo /* Now do the Interrupt Mask Register, 1 bit per descriptor */
439*2ed98337SAymeric Wibo ivr[0] = nhi_read_reg(sc, NHI_IMR0);
440*2ed98337SAymeric Wibo ivr[1] = nhi_read_reg(sc, NHI_IMR1);
441*2ed98337SAymeric Wibo
442*2ed98337SAymeric Wibo /* Tx */
443*2ed98337SAymeric Wibo offset = r->ring_num + IMR_TX_OFFSET;
444*2ed98337SAymeric Wibo NHI_SET_INTERRUPT(offset, 0x01, 1);
445*2ed98337SAymeric Wibo
446*2ed98337SAymeric Wibo /* Rx */
447*2ed98337SAymeric Wibo offset = r->ring_num + IMR_RX_OFFSET;
448*2ed98337SAymeric Wibo NHI_SET_INTERRUPT(offset, 0x01, 1);
449*2ed98337SAymeric Wibo
450*2ed98337SAymeric Wibo /* NE */
451*2ed98337SAymeric Wibo offset = r->ring_num + IMR_NE_OFFSET;
452*2ed98337SAymeric Wibo NHI_SET_INTERRUPT(offset, 0x01, 1);
453*2ed98337SAymeric Wibo
454*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IMR0, ivr[0]);
455*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IMR1, ivr[1]);
456*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT|DBG_FULL,
457*2ed98337SAymeric Wibo "Wrote IMR 0x%08x 0x%08x\n", ivr[0], ivr[1]);
458*2ed98337SAymeric Wibo }
459*2ed98337SAymeric Wibo
460*2ed98337SAymeric Wibo void
nhi_pci_disable_interrupts(struct nhi_softc * sc)461*2ed98337SAymeric Wibo nhi_pci_disable_interrupts(struct nhi_softc *sc)
462*2ed98337SAymeric Wibo {
463*2ed98337SAymeric Wibo
464*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT, "Disabling interrupts\n");
465*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IMR0, 0);
466*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IMR1, 0);
467*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IVR0, 0);
468*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IVR1, 0);
469*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IVR2, 0);
470*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IVR3, 0);
471*2ed98337SAymeric Wibo nhi_write_reg(sc, NHI_IVR4, 0);
472*2ed98337SAymeric Wibo
473*2ed98337SAymeric Wibo /* Dummy reads to clear pending bits */
474*2ed98337SAymeric Wibo nhi_read_reg(sc, NHI_ISR0);
475*2ed98337SAymeric Wibo nhi_read_reg(sc, NHI_ISR1);
476*2ed98337SAymeric Wibo }
477*2ed98337SAymeric Wibo
478*2ed98337SAymeric Wibo /*
479*2ed98337SAymeric Wibo * Icelake controllers need to be notified of power-on
480*2ed98337SAymeric Wibo */
481*2ed98337SAymeric Wibo static int
nhi_pci_icl_poweron(struct nhi_softc * sc)482*2ed98337SAymeric Wibo nhi_pci_icl_poweron(struct nhi_softc *sc)
483*2ed98337SAymeric Wibo {
484*2ed98337SAymeric Wibo device_t dev;
485*2ed98337SAymeric Wibo uint32_t val;
486*2ed98337SAymeric Wibo int i, error = 0;
487*2ed98337SAymeric Wibo
488*2ed98337SAymeric Wibo dev = sc->dev;
489*2ed98337SAymeric Wibo val = pci_read_config(dev, ICL_VSCAP_9, 4);
490*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT, "icl_poweron val= 0x%x\n", val);
491*2ed98337SAymeric Wibo if (val & ICL_VSCAP9_FWREADY)
492*2ed98337SAymeric Wibo return (0);
493*2ed98337SAymeric Wibo
494*2ed98337SAymeric Wibo val = pci_read_config(dev, ICL_VSCAP_22, 4);
495*2ed98337SAymeric Wibo val |= ICL_VSCAP22_FORCEPWR;
496*2ed98337SAymeric Wibo tb_debug(sc, DBG_INIT|DBG_FULL, "icl_poweron writing 0x%x\n", val);
497*2ed98337SAymeric Wibo pci_write_config(dev, ICL_VSCAP_22, val, 4);
498*2ed98337SAymeric Wibo
499*2ed98337SAymeric Wibo error = ETIMEDOUT;
500*2ed98337SAymeric Wibo for (i = 0; i < 15; i++) {
501*2ed98337SAymeric Wibo DELAY(1000000);
502*2ed98337SAymeric Wibo val = pci_read_config(dev, ICL_VSCAP_9, 4);
503*2ed98337SAymeric Wibo if (val & ICL_VSCAP9_FWREADY) {
504*2ed98337SAymeric Wibo error = 0;
505*2ed98337SAymeric Wibo break;
506*2ed98337SAymeric Wibo }
507*2ed98337SAymeric Wibo }
508*2ed98337SAymeric Wibo
509*2ed98337SAymeric Wibo return (error);
510*2ed98337SAymeric Wibo }
511*2ed98337SAymeric Wibo
512*2ed98337SAymeric Wibo /*
513*2ed98337SAymeric Wibo * Icelake and Alderlake controllers store their UUID in PCI config space
514*2ed98337SAymeric Wibo */
515*2ed98337SAymeric Wibo int
nhi_pci_get_uuid(struct nhi_softc * sc)516*2ed98337SAymeric Wibo nhi_pci_get_uuid(struct nhi_softc *sc)
517*2ed98337SAymeric Wibo {
518*2ed98337SAymeric Wibo device_t dev;
519*2ed98337SAymeric Wibo uint32_t val[4];
520*2ed98337SAymeric Wibo
521*2ed98337SAymeric Wibo dev = sc->dev;
522*2ed98337SAymeric Wibo val[0] = pci_read_config(dev, ICL_VSCAP_10, 4);
523*2ed98337SAymeric Wibo val[1] = pci_read_config(dev, ICL_VSCAP_11, 4);
524*2ed98337SAymeric Wibo val[2] = 0xffffffff;
525*2ed98337SAymeric Wibo val[3] = 0xffffffff;
526*2ed98337SAymeric Wibo
527*2ed98337SAymeric Wibo bcopy(val, &sc->uuid, 16);
528*2ed98337SAymeric Wibo return (0);
529*2ed98337SAymeric Wibo }
530