xref: /freebsd/sys/dev/thunderbolt/tb_pcib.c (revision 2ed9833791f28e14843ac813f90cb030e45948dc)
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_acpi.h"
30*2ed98337SAymeric Wibo #include "opt_thunderbolt.h"
31*2ed98337SAymeric Wibo 
32*2ed98337SAymeric Wibo /* PCIe bridge for Thunderbolt */
33*2ed98337SAymeric Wibo #include <sys/types.h>
34*2ed98337SAymeric Wibo #include <sys/param.h>
35*2ed98337SAymeric Wibo #include <sys/systm.h>
36*2ed98337SAymeric Wibo #include <sys/kernel.h>
37*2ed98337SAymeric Wibo #include <sys/module.h>
38*2ed98337SAymeric Wibo #include <sys/bus.h>
39*2ed98337SAymeric Wibo #include <sys/conf.h>
40*2ed98337SAymeric Wibo #include <sys/malloc.h>
41*2ed98337SAymeric Wibo #include <sys/sysctl.h>
42*2ed98337SAymeric Wibo #include <sys/lock.h>
43*2ed98337SAymeric Wibo #include <sys/param.h>
44*2ed98337SAymeric Wibo #include <sys/endian.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 <machine/pci_cfgreg.h>
52*2ed98337SAymeric Wibo #include <dev/pci/pcireg.h>
53*2ed98337SAymeric Wibo #include <dev/pci/pcivar.h>
54*2ed98337SAymeric Wibo #include <dev/pci/pcib_private.h>
55*2ed98337SAymeric Wibo #include <dev/pci/pci_private.h>
56*2ed98337SAymeric Wibo 
57*2ed98337SAymeric Wibo #include <contrib/dev/acpica/include/acpi.h>
58*2ed98337SAymeric Wibo #include <contrib/dev/acpica/include/accommon.h>
59*2ed98337SAymeric Wibo #include <dev/acpica/acpivar.h>
60*2ed98337SAymeric Wibo #include <dev/acpica/acpi_pcibvar.h>
61*2ed98337SAymeric Wibo #include <machine/md_var.h>
62*2ed98337SAymeric Wibo 
63*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_reg.h>
64*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_pcib.h>
65*2ed98337SAymeric Wibo #include <dev/thunderbolt/nhi_var.h>
66*2ed98337SAymeric Wibo #include <dev/thunderbolt/nhi_reg.h>
67*2ed98337SAymeric Wibo #include <dev/thunderbolt/tbcfg_reg.h>
68*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_debug.h>
69*2ed98337SAymeric Wibo #include "tb_if.h"
70*2ed98337SAymeric Wibo 
71*2ed98337SAymeric Wibo static int	tb_pcib_probe(device_t);
72*2ed98337SAymeric Wibo static int	tb_pcib_attach(device_t);
73*2ed98337SAymeric Wibo static int	tb_pcib_detach(device_t);
74*2ed98337SAymeric Wibo static int	tb_pcib_lc_mailbox(device_t, struct tb_lcmbox_cmd *);
75*2ed98337SAymeric Wibo static int	tb_pcib_pcie2cio_read(device_t, u_int, u_int, u_int,
76*2ed98337SAymeric Wibo      uint32_t *);
77*2ed98337SAymeric Wibo static int	tb_pcib_pcie2cio_write(device_t, u_int, u_int, u_int, uint32_t);
78*2ed98337SAymeric Wibo static int	tb_pcib_find_ufp(device_t, device_t *);
79*2ed98337SAymeric Wibo static int	tb_pcib_get_debug(device_t, u_int *);
80*2ed98337SAymeric Wibo 
81*2ed98337SAymeric Wibo static int	tb_pci_probe(device_t);
82*2ed98337SAymeric Wibo static int	tb_pci_attach(device_t);
83*2ed98337SAymeric Wibo static int	tb_pci_detach(device_t);
84*2ed98337SAymeric Wibo 
85*2ed98337SAymeric Wibo struct tb_pcib_ident {
86*2ed98337SAymeric Wibo 	uint16_t	vendor;
87*2ed98337SAymeric Wibo 	uint16_t	device;
88*2ed98337SAymeric Wibo 	uint16_t	subvendor;
89*2ed98337SAymeric Wibo 	uint16_t	subdevice;
90*2ed98337SAymeric Wibo 	uint32_t	flags;		/* This follows the tb_softc flags */
91*2ed98337SAymeric Wibo 	const char	*desc;
92*2ed98337SAymeric Wibo } tb_pcib_identifiers[] = {
93*2ed98337SAymeric Wibo 	{ VENDOR_INTEL, TB_DEV_AR_2C, 0xffff, 0xffff, TB_GEN_TB3|TB_HWIF_AR,
94*2ed98337SAymeric Wibo 	    "Thunderbolt 3 PCI-PCI Bridge (Alpine Ridge 2C)" },
95*2ed98337SAymeric Wibo 	{ VENDOR_INTEL, TB_DEV_AR_LP, 0xffff, 0xffff, TB_GEN_TB3|TB_HWIF_AR,
96*2ed98337SAymeric Wibo 	    "Thunderbolt 3 PCI-PCI Bridge (Alpine Ridge LP)" },
97*2ed98337SAymeric Wibo 	{ VENDOR_INTEL, TB_DEV_AR_C_4C, 0xffff, 0xffff, TB_GEN_TB3|TB_HWIF_AR,
98*2ed98337SAymeric Wibo 	    "Thunderbolt 3 PCI-PCI Bridge (Alpine Ridge C 4C)" },
99*2ed98337SAymeric Wibo 	{ VENDOR_INTEL, TB_DEV_AR_C_2C, 0xffff, 0xffff, TB_GEN_TB3|TB_HWIF_AR,
100*2ed98337SAymeric Wibo 	    "Thunderbolt 3 PCI-PCI Bridge C (Alpine Ridge C 2C)" },
101*2ed98337SAymeric Wibo 	{ VENDOR_INTEL, TB_DEV_ICL_0, 0xffff, 0xffff, TB_GEN_TB3|TB_HWIF_ICL,
102*2ed98337SAymeric Wibo 	    "Thunderbolt 3 PCI-PCI Bridge (IceLake)" },
103*2ed98337SAymeric Wibo 	{ VENDOR_INTEL, TB_DEV_ICL_1, 0xffff, 0xffff, TB_GEN_TB3|TB_HWIF_ICL,
104*2ed98337SAymeric Wibo 	    "Thunderbolt 3 PCI-PCI Bridge (IceLake)" },
105*2ed98337SAymeric Wibo 	{ 0, 0, 0, 0, 0, NULL }
106*2ed98337SAymeric Wibo };
107*2ed98337SAymeric Wibo 
108*2ed98337SAymeric Wibo static struct tb_pcib_ident *
tb_pcib_find_ident(device_t dev)109*2ed98337SAymeric Wibo tb_pcib_find_ident(device_t dev)
110*2ed98337SAymeric Wibo {
111*2ed98337SAymeric Wibo 	struct tb_pcib_ident *n;
112*2ed98337SAymeric Wibo 	uint16_t v, d, sv, sd;
113*2ed98337SAymeric Wibo 
114*2ed98337SAymeric Wibo 	v = pci_get_vendor(dev);
115*2ed98337SAymeric Wibo 	d = pci_get_device(dev);
116*2ed98337SAymeric Wibo 	sv = pci_get_subvendor(dev);
117*2ed98337SAymeric Wibo 	sd = pci_get_subdevice(dev);
118*2ed98337SAymeric Wibo 
119*2ed98337SAymeric Wibo 	for (n = tb_pcib_identifiers; n->vendor != 0; n++) {
120*2ed98337SAymeric Wibo 		if ((n->vendor != v) || (n->device != d))
121*2ed98337SAymeric Wibo 			continue;
122*2ed98337SAymeric Wibo 		if (((n->subvendor != 0xffff) && (n->subvendor != sv)) ||
123*2ed98337SAymeric Wibo 		    ((n->subdevice != 0xffff) && (n->subdevice != sd)))
124*2ed98337SAymeric Wibo 			continue;
125*2ed98337SAymeric Wibo 		return (n);
126*2ed98337SAymeric Wibo 	}
127*2ed98337SAymeric Wibo 
128*2ed98337SAymeric Wibo 	return (NULL);
129*2ed98337SAymeric Wibo }
130*2ed98337SAymeric Wibo 
131*2ed98337SAymeric Wibo static void
tb_pcib_get_tunables(struct tb_pcib_softc * sc)132*2ed98337SAymeric Wibo tb_pcib_get_tunables(struct tb_pcib_softc *sc)
133*2ed98337SAymeric Wibo {
134*2ed98337SAymeric Wibo 	char tmpstr[80], oid[80];
135*2ed98337SAymeric Wibo 
136*2ed98337SAymeric Wibo 	/* Set the default */
137*2ed98337SAymeric Wibo 	sc->debug = 0;
138*2ed98337SAymeric Wibo 
139*2ed98337SAymeric Wibo 	/* Grab global variables */
140*2ed98337SAymeric Wibo 	bzero(oid, 80);
141*2ed98337SAymeric Wibo 	if (TUNABLE_STR_FETCH("hw.tbolt.debug_level", oid, 80) != 0)
142*2ed98337SAymeric Wibo 		tb_parse_debug(&sc->debug, oid);
143*2ed98337SAymeric Wibo 
144*2ed98337SAymeric Wibo 	/* Grab instance variables */
145*2ed98337SAymeric Wibo 	bzero(oid, 80);
146*2ed98337SAymeric Wibo 	snprintf(tmpstr, sizeof(tmpstr), "dev.tbolt.%d.debug_level",
147*2ed98337SAymeric Wibo 	    device_get_unit(sc->dev));
148*2ed98337SAymeric Wibo 	if (TUNABLE_STR_FETCH(tmpstr, oid, 80) != 0)
149*2ed98337SAymeric Wibo 		tb_parse_debug(&sc->debug, oid);
150*2ed98337SAymeric Wibo 
151*2ed98337SAymeric Wibo 	return;
152*2ed98337SAymeric Wibo }
153*2ed98337SAymeric Wibo 
154*2ed98337SAymeric Wibo static int
tb_pcib_setup_sysctl(struct tb_pcib_softc * sc)155*2ed98337SAymeric Wibo tb_pcib_setup_sysctl(struct tb_pcib_softc *sc)
156*2ed98337SAymeric Wibo {
157*2ed98337SAymeric Wibo 	struct sysctl_ctx_list	*ctx = NULL;
158*2ed98337SAymeric Wibo 	struct sysctl_oid	*tree = NULL;
159*2ed98337SAymeric Wibo 
160*2ed98337SAymeric Wibo 	ctx = device_get_sysctl_ctx(sc->dev);
161*2ed98337SAymeric Wibo 	if (ctx != NULL)
162*2ed98337SAymeric Wibo 		tree = device_get_sysctl_tree(sc->dev);
163*2ed98337SAymeric Wibo 
164*2ed98337SAymeric Wibo 	if (tree == NULL) {
165*2ed98337SAymeric Wibo 		tb_printf(sc, "Error: cannot create sysctl nodes\n");
166*2ed98337SAymeric Wibo 		return (EINVAL);
167*2ed98337SAymeric Wibo 	}
168*2ed98337SAymeric Wibo 	sc->sysctl_tree = tree;
169*2ed98337SAymeric Wibo 	sc->sysctl_ctx = ctx;
170*2ed98337SAymeric Wibo 
171*2ed98337SAymeric Wibo 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree),
172*2ed98337SAymeric Wibo 	    OID_AUTO, "debug_level", CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE,
173*2ed98337SAymeric Wibo 	    &sc->debug, 0, tb_debug_sysctl, "A", "Thunderbolt debug level");
174*2ed98337SAymeric Wibo 
175*2ed98337SAymeric Wibo 	return (0);
176*2ed98337SAymeric Wibo }
177*2ed98337SAymeric Wibo 
178*2ed98337SAymeric Wibo /*
179*2ed98337SAymeric Wibo  * This is used for both the PCI and ACPI attachments.  It shouldn't return
180*2ed98337SAymeric Wibo  * 0, doing so will force the ACPI attachment to fail.
181*2ed98337SAymeric Wibo  */
182*2ed98337SAymeric Wibo int
tb_pcib_probe_common(device_t dev,char * desc)183*2ed98337SAymeric Wibo tb_pcib_probe_common(device_t dev, char *desc)
184*2ed98337SAymeric Wibo {
185*2ed98337SAymeric Wibo 	device_t ufp;
186*2ed98337SAymeric Wibo 	struct tb_pcib_ident *n;
187*2ed98337SAymeric Wibo 	char *suffix;
188*2ed98337SAymeric Wibo 
189*2ed98337SAymeric Wibo 	if ((n = tb_pcib_find_ident(dev)) != NULL) {
190*2ed98337SAymeric Wibo 		ufp = NULL;
191*2ed98337SAymeric Wibo 		if ((TB_FIND_UFP(dev, &ufp) == 0) && (ufp == dev))
192*2ed98337SAymeric Wibo 			suffix = "(Upstream port)";
193*2ed98337SAymeric Wibo 		else
194*2ed98337SAymeric Wibo 			suffix = "(Downstream port)";
195*2ed98337SAymeric Wibo 		snprintf(desc, TB_DESC_MAX, "%s %s", n->desc, suffix);
196*2ed98337SAymeric Wibo 		return (BUS_PROBE_VENDOR);
197*2ed98337SAymeric Wibo 	}
198*2ed98337SAymeric Wibo 	return (ENXIO);
199*2ed98337SAymeric Wibo }
200*2ed98337SAymeric Wibo 
201*2ed98337SAymeric Wibo static int
tb_pcib_probe(device_t dev)202*2ed98337SAymeric Wibo tb_pcib_probe(device_t dev)
203*2ed98337SAymeric Wibo {
204*2ed98337SAymeric Wibo 	char desc[TB_DESC_MAX];
205*2ed98337SAymeric Wibo 	int val;
206*2ed98337SAymeric Wibo 
207*2ed98337SAymeric Wibo 	if ((val = tb_pcib_probe_common(dev, desc)) <= 0)
208*2ed98337SAymeric Wibo 		device_set_desc_copy(dev, desc);
209*2ed98337SAymeric Wibo 
210*2ed98337SAymeric Wibo 	return (val);
211*2ed98337SAymeric Wibo }
212*2ed98337SAymeric Wibo 
213*2ed98337SAymeric Wibo int
tb_pcib_attach_common(device_t dev)214*2ed98337SAymeric Wibo tb_pcib_attach_common(device_t dev)
215*2ed98337SAymeric Wibo {
216*2ed98337SAymeric Wibo 	device_t ufp;
217*2ed98337SAymeric Wibo 	struct tb_pcib_ident *n;
218*2ed98337SAymeric Wibo 	struct tb_pcib_softc *sc;
219*2ed98337SAymeric Wibo 	uint32_t val;
220*2ed98337SAymeric Wibo 	int error;
221*2ed98337SAymeric Wibo 
222*2ed98337SAymeric Wibo 	sc = device_get_softc(dev);
223*2ed98337SAymeric Wibo 	sc->dev = dev;
224*2ed98337SAymeric Wibo 	sc->vsec = -1;
225*2ed98337SAymeric Wibo 
226*2ed98337SAymeric Wibo 	n = tb_pcib_find_ident(dev);
227*2ed98337SAymeric Wibo 	KASSERT(n != NULL, ("Cannot find TB ident"));
228*2ed98337SAymeric Wibo 	sc->flags = n->flags;
229*2ed98337SAymeric Wibo 
230*2ed98337SAymeric Wibo 	tb_pcib_get_tunables(sc);
231*2ed98337SAymeric Wibo 	tb_pcib_setup_sysctl(sc);
232*2ed98337SAymeric Wibo 
233*2ed98337SAymeric Wibo 	/* XXX Is this necessary for ACPI attachments? */
234*2ed98337SAymeric Wibo 	tb_debug(sc, DBG_BRIDGE, "busmaster status was %s\n",
235*2ed98337SAymeric Wibo 	    (pci_read_config(dev, PCIR_COMMAND, 2) & PCIM_CMD_BUSMASTEREN)
236*2ed98337SAymeric Wibo 	    ? "enabled" : "disabled");
237*2ed98337SAymeric Wibo 	pci_enable_busmaster(dev);
238*2ed98337SAymeric Wibo 
239*2ed98337SAymeric Wibo 	/*
240*2ed98337SAymeric Wibo 	 * Determine if this is an upstream or downstream facing device, and
241*2ed98337SAymeric Wibo 	 * whether it's the root of the Thunderbolt topology.  It's too bad
242*2ed98337SAymeric Wibo 	 * that there aren't unique PCI ID's to help with this.
243*2ed98337SAymeric Wibo 	 */
244*2ed98337SAymeric Wibo 	ufp = NULL;
245*2ed98337SAymeric Wibo 	if ((TB_FIND_UFP(dev, &ufp) == 0) && (ufp != NULL)) {
246*2ed98337SAymeric Wibo 		if (ufp == dev) {
247*2ed98337SAymeric Wibo 			sc->flags |= TB_FLAGS_ISUFP;
248*2ed98337SAymeric Wibo 			if (TB_FIND_UFP(device_get_parent(dev), NULL) ==
249*2ed98337SAymeric Wibo 			    EOPNOTSUPP) {
250*2ed98337SAymeric Wibo 				sc->flags |= TB_FLAGS_ISROOT;
251*2ed98337SAymeric Wibo 			}
252*2ed98337SAymeric Wibo 		}
253*2ed98337SAymeric Wibo 	}
254*2ed98337SAymeric Wibo 
255*2ed98337SAymeric Wibo 	/*
256*2ed98337SAymeric Wibo 	 * Find the PCI Vendor Specific Extended Capability.  It's the magic
257*2ed98337SAymeric Wibo 	 * wand to configuring the Thunderbolt root bridges.
258*2ed98337SAymeric Wibo 	 */
259*2ed98337SAymeric Wibo 	if (TB_IS_AR(sc) || TB_IS_TR(sc)) {
260*2ed98337SAymeric Wibo 		error = pci_find_extcap(dev, PCIZ_VENDOR, &sc->vsec);
261*2ed98337SAymeric Wibo 		if (error) {
262*2ed98337SAymeric Wibo 			tb_printf(sc, "Cannot find VSEC capability: %d\n",
263*2ed98337SAymeric Wibo 			    error);
264*2ed98337SAymeric Wibo 			return (ENXIO);
265*2ed98337SAymeric Wibo 		}
266*2ed98337SAymeric Wibo 	}
267*2ed98337SAymeric Wibo 
268*2ed98337SAymeric Wibo 	/*
269*2ed98337SAymeric Wibo 	 * Take the AR bridge out of low-power mode.
270*2ed98337SAymeric Wibo 	 * XXX AR only?
271*2ed98337SAymeric Wibo 	 */
272*2ed98337SAymeric Wibo 	if ((1 || TB_IS_AR(sc)) && TB_IS_ROOT(sc)) {
273*2ed98337SAymeric Wibo 		struct tb_lcmbox_cmd cmd;
274*2ed98337SAymeric Wibo 
275*2ed98337SAymeric Wibo 		cmd.cmd = LC_MBOXOUT_CMD_SXEXIT_TBT;
276*2ed98337SAymeric Wibo 		cmd.data_in = 0;
277*2ed98337SAymeric Wibo 
278*2ed98337SAymeric Wibo 		error = TB_LC_MAILBOX(dev, &cmd);
279*2ed98337SAymeric Wibo 		tb_debug(sc, DBG_BRIDGE, "SXEXIT returned error= %d resp= 0x%x "
280*2ed98337SAymeric Wibo 		    "data= 0x%x\n", error, cmd.cmd_resp, cmd.data_out);
281*2ed98337SAymeric Wibo 	}
282*2ed98337SAymeric Wibo 
283*2ed98337SAymeric Wibo 	/* The downstream facing port on AR needs some help */
284*2ed98337SAymeric Wibo 	if (TB_IS_AR(sc) && TB_IS_DFP(sc)) {
285*2ed98337SAymeric Wibo 		tb_debug(sc, DBG_BRIDGE, "Doing AR L1 fixup\n");
286*2ed98337SAymeric Wibo 		val = pci_read_config(dev, sc->vsec + AR_VSCAP_1C, 4);
287*2ed98337SAymeric Wibo 		tb_debug(sc, DBG_BRIDGE|DBG_FULL, "VSEC+0x1c= 0x%08x\n", val);
288*2ed98337SAymeric Wibo 		val |= (1 << 8);
289*2ed98337SAymeric Wibo 		pci_write_config(dev, sc->vsec + AR_VSCAP_1C, val, 4);
290*2ed98337SAymeric Wibo 
291*2ed98337SAymeric Wibo 		val = pci_read_config(dev, sc->vsec + AR_VSCAP_B0, 4);
292*2ed98337SAymeric Wibo 		tb_debug(sc, DBG_BRIDGE|DBG_FULL, "VSEC+0xb0= 0x%08x\n", val);
293*2ed98337SAymeric Wibo 		val |= (1 << 12);
294*2ed98337SAymeric Wibo 		pci_write_config(dev, sc->vsec + AR_VSCAP_B0, val, 4);
295*2ed98337SAymeric Wibo 	}
296*2ed98337SAymeric Wibo 
297*2ed98337SAymeric Wibo 	return (0);
298*2ed98337SAymeric Wibo }
299*2ed98337SAymeric Wibo 
300*2ed98337SAymeric Wibo static int
tb_pcib_attach(device_t dev)301*2ed98337SAymeric Wibo tb_pcib_attach(device_t dev)
302*2ed98337SAymeric Wibo {
303*2ed98337SAymeric Wibo 	int error;
304*2ed98337SAymeric Wibo 
305*2ed98337SAymeric Wibo 	error = tb_pcib_attach_common(dev);
306*2ed98337SAymeric Wibo 	if (error)
307*2ed98337SAymeric Wibo 		return (error);
308*2ed98337SAymeric Wibo 	return (pcib_attach(dev));
309*2ed98337SAymeric Wibo }
310*2ed98337SAymeric Wibo 
311*2ed98337SAymeric Wibo static int
tb_pcib_detach(device_t dev)312*2ed98337SAymeric Wibo tb_pcib_detach(device_t dev)
313*2ed98337SAymeric Wibo {
314*2ed98337SAymeric Wibo 	struct tb_pcib_softc *sc;
315*2ed98337SAymeric Wibo 	int error;
316*2ed98337SAymeric Wibo 
317*2ed98337SAymeric Wibo 	sc = device_get_softc(dev);
318*2ed98337SAymeric Wibo 
319*2ed98337SAymeric Wibo 	tb_debug(sc, DBG_BRIDGE|DBG_ROUTER|DBG_EXTRA, "tb_pcib_detach\n");
320*2ed98337SAymeric Wibo 
321*2ed98337SAymeric Wibo 	/* Put the AR bridge back to sleep */
322*2ed98337SAymeric Wibo 	/* XXX disable this until power control for downstream switches works */
323*2ed98337SAymeric Wibo 	if (0 && TB_IS_ROOT(sc)) {
324*2ed98337SAymeric Wibo 		struct tb_lcmbox_cmd cmd;
325*2ed98337SAymeric Wibo 
326*2ed98337SAymeric Wibo 		cmd.cmd = LC_MBOXOUT_CMD_GO2SX;
327*2ed98337SAymeric Wibo 		cmd.data_in = 0;
328*2ed98337SAymeric Wibo 
329*2ed98337SAymeric Wibo 		error = TB_LC_MAILBOX(dev, &cmd);
330*2ed98337SAymeric Wibo 		tb_debug(sc, DBG_BRIDGE, "SXEXIT returned error= %d resp= 0x%x "
331*2ed98337SAymeric Wibo 		    "data= 0x%x\n", error, cmd.cmd_resp, cmd.data_out);
332*2ed98337SAymeric Wibo 	}
333*2ed98337SAymeric Wibo 
334*2ed98337SAymeric Wibo 	return (pcib_detach(dev));
335*2ed98337SAymeric Wibo }
336*2ed98337SAymeric Wibo 
337*2ed98337SAymeric Wibo /* Read/write the Link Controller registers in CFG space */
338*2ed98337SAymeric Wibo static int
tb_pcib_lc_mailbox(device_t dev,struct tb_lcmbox_cmd * cmd)339*2ed98337SAymeric Wibo tb_pcib_lc_mailbox(device_t dev, struct tb_lcmbox_cmd *cmd)
340*2ed98337SAymeric Wibo {
341*2ed98337SAymeric Wibo 	struct tb_pcib_softc *sc;
342*2ed98337SAymeric Wibo 	uint32_t regcmd, result;
343*2ed98337SAymeric Wibo 	uint16_t m_in, m_out;
344*2ed98337SAymeric Wibo 	int vsec, i;
345*2ed98337SAymeric Wibo 
346*2ed98337SAymeric Wibo 	sc = device_get_softc(dev);
347*2ed98337SAymeric Wibo 	vsec = TB_PCIB_VSEC(dev);
348*2ed98337SAymeric Wibo 	if (vsec == -1)
349*2ed98337SAymeric Wibo 		return (EOPNOTSUPP);
350*2ed98337SAymeric Wibo 
351*2ed98337SAymeric Wibo 	if (TB_IS_AR(sc)) {
352*2ed98337SAymeric Wibo 		m_in = AR_LC_MBOX_IN;
353*2ed98337SAymeric Wibo 		m_out = AR_LC_MBOX_OUT;
354*2ed98337SAymeric Wibo 	} else if (TB_IS_ICL(sc)) {
355*2ed98337SAymeric Wibo 		m_in = ICL_LC_MBOX_IN;
356*2ed98337SAymeric Wibo 		m_out = ICL_LC_MBOX_OUT;
357*2ed98337SAymeric Wibo 	} else
358*2ed98337SAymeric Wibo 		return (EOPNOTSUPP);
359*2ed98337SAymeric Wibo 
360*2ed98337SAymeric Wibo 	/* Set the valid bit to signal we're sending a command */
361*2ed98337SAymeric Wibo 	regcmd = LC_MBOXOUT_VALID | (cmd->cmd & LC_MBOXOUT_CMD_MASK);
362*2ed98337SAymeric Wibo 	regcmd |= (cmd->data_in << LC_MBOXOUT_DATA_SHIFT);
363*2ed98337SAymeric Wibo 	tb_debug(sc, DBG_BRIDGE|DBG_FULL, "Writing LC cmd 0x%x\n", regcmd);
364*2ed98337SAymeric Wibo 	pci_write_config(dev, vsec + m_out, regcmd, 4);
365*2ed98337SAymeric Wibo 
366*2ed98337SAymeric Wibo 	for (i = 0; i < 10; i++) {
367*2ed98337SAymeric Wibo 		pause("nhi", 1 * hz);
368*2ed98337SAymeric Wibo 		result = pci_read_config(dev, vsec + m_in, 4);
369*2ed98337SAymeric Wibo 		tb_debug(sc, DBG_BRIDGE|DBG_FULL, "LC Mailbox= 0x%08x\n",
370*2ed98337SAymeric Wibo 		    result);
371*2ed98337SAymeric Wibo 		if ((result & LC_MBOXIN_DONE) != 0)
372*2ed98337SAymeric Wibo 			break;
373*2ed98337SAymeric Wibo 	}
374*2ed98337SAymeric Wibo 
375*2ed98337SAymeric Wibo 	/* Clear the valid bit to signal we're done sending the command */
376*2ed98337SAymeric Wibo 	pci_write_config(dev, vsec + m_out, 0, 4);
377*2ed98337SAymeric Wibo 
378*2ed98337SAymeric Wibo 	cmd->cmd_resp = result & LC_MBOXIN_CMD_MASK;
379*2ed98337SAymeric Wibo 	cmd->data_out = result >> LC_MBOXIN_CMD_SHIFT;
380*2ed98337SAymeric Wibo 
381*2ed98337SAymeric Wibo 	if ((result & LC_MBOXIN_DONE) == 0)
382*2ed98337SAymeric Wibo 		return (ETIMEDOUT);
383*2ed98337SAymeric Wibo 
384*2ed98337SAymeric Wibo 	return (0);
385*2ed98337SAymeric Wibo }
386*2ed98337SAymeric Wibo 
387*2ed98337SAymeric Wibo static int
tb_pcib_pcie2cio_wait(device_t dev,u_int timeout)388*2ed98337SAymeric Wibo tb_pcib_pcie2cio_wait(device_t dev, u_int timeout)
389*2ed98337SAymeric Wibo {
390*2ed98337SAymeric Wibo #if 0
391*2ed98337SAymeric Wibo 	uint32_t val;
392*2ed98337SAymeric Wibo 	int vsec;
393*2ed98337SAymeric Wibo 
394*2ed98337SAymeric Wibo 	vsec = TB_PCIB_VSEC(dev);
395*2ed98337SAymeric Wibo 	do {
396*2ed98337SAymeric Wibo                 pci_read_config(dev, vsec + PCIE2CIO_CMD, &val);
397*2ed98337SAymeric Wibo                 if ((val & PCIE2CIO_CMD_START) == 0) {
398*2ed98337SAymeric Wibo                         if (val & PCIE2CIO_CMD_TIMEOUT)
399*2ed98337SAymeric Wibo                                 break;
400*2ed98337SAymeric Wibo                         return 0;
401*2ed98337SAymeric Wibo                 }
402*2ed98337SAymeric Wibo 
403*2ed98337SAymeric Wibo                 msleep(50);
404*2ed98337SAymeric Wibo         } while (time_before(jiffies, end));
405*2ed98337SAymeric Wibo 
406*2ed98337SAymeric Wibo #endif
407*2ed98337SAymeric Wibo         return ETIMEDOUT;
408*2ed98337SAymeric Wibo }
409*2ed98337SAymeric Wibo 
410*2ed98337SAymeric Wibo static int
tb_pcib_pcie2cio_read(device_t dev,u_int space,u_int port,u_int offset,uint32_t * val)411*2ed98337SAymeric Wibo tb_pcib_pcie2cio_read(device_t dev, u_int space, u_int port, u_int offset,
412*2ed98337SAymeric Wibo     uint32_t *val)
413*2ed98337SAymeric Wibo {
414*2ed98337SAymeric Wibo #if 0
415*2ed98337SAymeric Wibo 	uint32_t cmd;
416*2ed98337SAymeric Wibo 	int ret, vsec;
417*2ed98337SAymeric Wibo 
418*2ed98337SAymeric Wibo 	vsec = TB_PCIB_VSEC(dev);
419*2ed98337SAymeric Wibo 	if (vsec == -1)
420*2ed98337SAymeric Wibo 		return (EOPNOTSUPP);
421*2ed98337SAymeric Wibo 
422*2ed98337SAymeric Wibo 	cmd = index;
423*2ed98337SAymeric Wibo         cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK;
424*2ed98337SAymeric Wibo         cmd |= (space << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK;
425*2ed98337SAymeric Wibo         cmd |= PCIE2CIO_CMD_START;
426*2ed98337SAymeric Wibo 	pci_write_config(dev, vsec + PCIE2CIO_CMD, cmd, 4);
427*2ed98337SAymeric Wibo 
428*2ed98337SAymeric Wibo         if ((ret = pci2cio_wait_completion(dev, 5000)) != 0)
429*2ed98337SAymeric Wibo                 return (ret);
430*2ed98337SAymeric Wibo 
431*2ed98337SAymeric Wibo         *val = pci_read_config(dev, vsec + PCIE2CIO_RDDATA, 4);
432*2ed98337SAymeric Wibo #endif
433*2ed98337SAymeric Wibo 	return (0);
434*2ed98337SAymeric Wibo }
435*2ed98337SAymeric Wibo 
436*2ed98337SAymeric Wibo static int
tb_pcib_pcie2cio_write(device_t dev,u_int space,u_int port,u_int offset,uint32_t val)437*2ed98337SAymeric Wibo tb_pcib_pcie2cio_write(device_t dev, u_int space, u_int port, u_int offset,
438*2ed98337SAymeric Wibo     uint32_t val)
439*2ed98337SAymeric Wibo {
440*2ed98337SAymeric Wibo #if 0
441*2ed98337SAymeric Wibo 	uint32_t cmd;
442*2ed98337SAymeric Wibo 	int ret, vsec;
443*2ed98337SAymeric Wibo 
444*2ed98337SAymeric Wibo 	vsec = TB_PCIB_VSEC(dev);
445*2ed98337SAymeric Wibo 	if (vsec == -1)
446*2ed98337SAymeric Wibo 		return (EOPNOTSUPP);
447*2ed98337SAymeric Wibo 
448*2ed98337SAymeric Wibo         pci_write_config(dev, vsec + PCIE2CIO_WRDATA, val, 4);
449*2ed98337SAymeric Wibo 
450*2ed98337SAymeric Wibo         cmd = index;
451*2ed98337SAymeric Wibo         cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK;
452*2ed98337SAymeric Wibo         cmd |= (space << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK;
453*2ed98337SAymeric Wibo         cmd |= PCIE2CIO_CMD_WRITE | PCIE2CIO_CMD_START;
454*2ed98337SAymeric Wibo         pci_write_config(dev, vsec + PCIE2CIO_CMD, cmd);
455*2ed98337SAymeric Wibo 
456*2ed98337SAymeric Wibo #endif
457*2ed98337SAymeric Wibo         return (tb_pcib_pcie2cio_wait(dev, 5000));
458*2ed98337SAymeric Wibo }
459*2ed98337SAymeric Wibo 
460*2ed98337SAymeric Wibo /*
461*2ed98337SAymeric Wibo  * The Upstream Facing Port (UFP) in a switch is special, it's the function
462*2ed98337SAymeric Wibo  * that responds to some of the special programming mailboxes.  It can't be
463*2ed98337SAymeric Wibo  * differentiated by PCI ID, so a heuristic approach to identifying it is
464*2ed98337SAymeric Wibo  * required.
465*2ed98337SAymeric Wibo  */
466*2ed98337SAymeric Wibo static int
tb_pcib_find_ufp(device_t dev,device_t * ufp)467*2ed98337SAymeric Wibo tb_pcib_find_ufp(device_t dev, device_t *ufp)
468*2ed98337SAymeric Wibo {
469*2ed98337SAymeric Wibo 	device_t upstream;
470*2ed98337SAymeric Wibo 	struct tb_pcib_softc *sc;
471*2ed98337SAymeric Wibo 	uint32_t vsec, val;
472*2ed98337SAymeric Wibo 	int error;
473*2ed98337SAymeric Wibo 
474*2ed98337SAymeric Wibo 	upstream = NULL;
475*2ed98337SAymeric Wibo 	sc = device_get_softc(dev);
476*2ed98337SAymeric Wibo 	if (sc == NULL)
477*2ed98337SAymeric Wibo 		return (EOPNOTSUPP);
478*2ed98337SAymeric Wibo 
479*2ed98337SAymeric Wibo 	if (TB_IS_UFP(sc)) {
480*2ed98337SAymeric Wibo 		upstream = dev;
481*2ed98337SAymeric Wibo 		error = 0;
482*2ed98337SAymeric Wibo 		goto out;
483*2ed98337SAymeric Wibo 	}
484*2ed98337SAymeric Wibo 
485*2ed98337SAymeric Wibo 	/*
486*2ed98337SAymeric Wibo 	 * This register is supposed to be filled in on the upstream port
487*2ed98337SAymeric Wibo 	 * and tells how many downstream ports there are.  It doesn't seem
488*2ed98337SAymeric Wibo 	 * to get filled in on AR host controllers, but is on various
489*2ed98337SAymeric Wibo 	 * peripherals.
490*2ed98337SAymeric Wibo 	 */
491*2ed98337SAymeric Wibo 	error = pci_find_extcap(dev, PCIZ_VENDOR, &vsec);
492*2ed98337SAymeric Wibo 	if (error == 0) {
493*2ed98337SAymeric Wibo 		val = pci_read_config(dev, vsec + 0x18, 4);
494*2ed98337SAymeric Wibo 		if ((val & 0x1f) > 0) {
495*2ed98337SAymeric Wibo 			upstream = dev;
496*2ed98337SAymeric Wibo 			goto out;
497*2ed98337SAymeric Wibo 		}
498*2ed98337SAymeric Wibo 	}
499*2ed98337SAymeric Wibo 
500*2ed98337SAymeric Wibo 	/*
501*2ed98337SAymeric Wibo 	 * Since we can't trust that the VSEC register is filled in, the only
502*2ed98337SAymeric Wibo 	 * other option is to see if we're at the top of the topology, which
503*2ed98337SAymeric Wibo 	 * implies that we're at the upstream port of the host controller.
504*2ed98337SAymeric Wibo 	 */
505*2ed98337SAymeric Wibo 	error = TB_FIND_UFP(device_get_parent(dev), ufp);
506*2ed98337SAymeric Wibo 	if (error == EOPNOTSUPP) {
507*2ed98337SAymeric Wibo 		upstream = dev;
508*2ed98337SAymeric Wibo 		error = 0;
509*2ed98337SAymeric Wibo 		goto out;
510*2ed98337SAymeric Wibo 	} else
511*2ed98337SAymeric Wibo 		return (error);
512*2ed98337SAymeric Wibo 
513*2ed98337SAymeric Wibo out:
514*2ed98337SAymeric Wibo 	if (ufp != NULL)
515*2ed98337SAymeric Wibo 		*ufp = upstream;
516*2ed98337SAymeric Wibo 
517*2ed98337SAymeric Wibo 	return (error);
518*2ed98337SAymeric Wibo }
519*2ed98337SAymeric Wibo 
520*2ed98337SAymeric Wibo static int
tb_pcib_get_debug(device_t dev,u_int * debug)521*2ed98337SAymeric Wibo tb_pcib_get_debug(device_t dev, u_int *debug)
522*2ed98337SAymeric Wibo {
523*2ed98337SAymeric Wibo 	struct tb_pcib_softc *sc;
524*2ed98337SAymeric Wibo 
525*2ed98337SAymeric Wibo 	sc = device_get_softc(dev);
526*2ed98337SAymeric Wibo 	if ((sc == NULL) || (debug == NULL))
527*2ed98337SAymeric Wibo 		return (EOPNOTSUPP);
528*2ed98337SAymeric Wibo 
529*2ed98337SAymeric Wibo 	*debug = sc->debug;
530*2ed98337SAymeric Wibo 	return (0);
531*2ed98337SAymeric Wibo }
532*2ed98337SAymeric Wibo 
533*2ed98337SAymeric Wibo static device_method_t tb_pcib_methods[] = {
534*2ed98337SAymeric Wibo 	DEVMETHOD(device_probe, 	tb_pcib_probe),
535*2ed98337SAymeric Wibo 	DEVMETHOD(device_attach,	tb_pcib_attach),
536*2ed98337SAymeric Wibo 	DEVMETHOD(device_detach,	tb_pcib_detach),
537*2ed98337SAymeric Wibo 
538*2ed98337SAymeric Wibo 	DEVMETHOD(tb_lc_mailbox,	tb_pcib_lc_mailbox),
539*2ed98337SAymeric Wibo 	DEVMETHOD(tb_pcie2cio_read,	tb_pcib_pcie2cio_read),
540*2ed98337SAymeric Wibo 	DEVMETHOD(tb_pcie2cio_write,	tb_pcib_pcie2cio_write),
541*2ed98337SAymeric Wibo 
542*2ed98337SAymeric Wibo 	DEVMETHOD(tb_find_ufp,		tb_pcib_find_ufp),
543*2ed98337SAymeric Wibo 	DEVMETHOD(tb_get_debug,		tb_pcib_get_debug),
544*2ed98337SAymeric Wibo 
545*2ed98337SAymeric Wibo 	DEVMETHOD_END
546*2ed98337SAymeric Wibo };
547*2ed98337SAymeric Wibo 
548*2ed98337SAymeric Wibo DEFINE_CLASS_1(tbolt, tb_pcib_driver, tb_pcib_methods,
549*2ed98337SAymeric Wibo     sizeof(struct tb_pcib_softc), pcib_driver);
550*2ed98337SAymeric Wibo DRIVER_MODULE_ORDERED(tb_pcib, pci, tb_pcib_driver,
551*2ed98337SAymeric Wibo     NULL, NULL, SI_ORDER_MIDDLE);
552*2ed98337SAymeric Wibo MODULE_DEPEND(tb_pcib, pci, 1, 1, 1);
553*2ed98337SAymeric Wibo MODULE_PNP_INFO("U16:vendor;U16:device;U16:subvendor;U16:subdevice;U32:#;D:#",
554*2ed98337SAymeric Wibo     pci, tb_pcib, tb_pcib_identifiers, nitems(tb_pcib_identifiers) - 1);
555*2ed98337SAymeric Wibo 
556*2ed98337SAymeric Wibo static int
tb_pci_probe(device_t dev)557*2ed98337SAymeric Wibo tb_pci_probe(device_t dev)
558*2ed98337SAymeric Wibo {
559*2ed98337SAymeric Wibo 	struct tb_pcib_ident *n;
560*2ed98337SAymeric Wibo 
561*2ed98337SAymeric Wibo 	if ((n = tb_pcib_find_ident(device_get_parent(dev))) != NULL) {
562*2ed98337SAymeric Wibo 		switch (n->flags & TB_GEN_MASK) {
563*2ed98337SAymeric Wibo 		case TB_GEN_TB1:
564*2ed98337SAymeric Wibo 			device_set_desc(dev, "Thunderbolt 1 Link");
565*2ed98337SAymeric Wibo 			break;
566*2ed98337SAymeric Wibo 		case TB_GEN_TB2:
567*2ed98337SAymeric Wibo 			device_set_desc(dev, "Thunderbolt 2 Link");
568*2ed98337SAymeric Wibo 			break;
569*2ed98337SAymeric Wibo 		case TB_GEN_TB3:
570*2ed98337SAymeric Wibo 			device_set_desc(dev, "Thunderbolt 3 Link");
571*2ed98337SAymeric Wibo 			break;
572*2ed98337SAymeric Wibo 		case TB_GEN_USB4:
573*2ed98337SAymeric Wibo 			device_set_desc(dev, "USB4 Link");
574*2ed98337SAymeric Wibo 			break;
575*2ed98337SAymeric Wibo 		case TB_GEN_UNK:
576*2ed98337SAymeric Wibo 			/* Fallthrough */
577*2ed98337SAymeric Wibo 		default:
578*2ed98337SAymeric Wibo 			device_set_desc(dev, "Thunderbolt Link");
579*2ed98337SAymeric Wibo 		}
580*2ed98337SAymeric Wibo 		return (BUS_PROBE_VENDOR);
581*2ed98337SAymeric Wibo 	}
582*2ed98337SAymeric Wibo 	return (ENXIO);
583*2ed98337SAymeric Wibo }
584*2ed98337SAymeric Wibo 
585*2ed98337SAymeric Wibo static int
tb_pci_attach(device_t dev)586*2ed98337SAymeric Wibo tb_pci_attach(device_t dev)
587*2ed98337SAymeric Wibo {
588*2ed98337SAymeric Wibo 
589*2ed98337SAymeric Wibo 	return (pci_attach(dev));
590*2ed98337SAymeric Wibo }
591*2ed98337SAymeric Wibo 
592*2ed98337SAymeric Wibo static int
tb_pci_detach(device_t dev)593*2ed98337SAymeric Wibo tb_pci_detach(device_t dev)
594*2ed98337SAymeric Wibo {
595*2ed98337SAymeric Wibo 
596*2ed98337SAymeric Wibo 	return (pci_detach(dev));
597*2ed98337SAymeric Wibo }
598*2ed98337SAymeric Wibo 
599*2ed98337SAymeric Wibo static device_method_t tb_pci_methods[] = {
600*2ed98337SAymeric Wibo 	DEVMETHOD(device_probe, tb_pci_probe),
601*2ed98337SAymeric Wibo 	DEVMETHOD(device_attach, tb_pci_attach),
602*2ed98337SAymeric Wibo 	DEVMETHOD(device_detach, tb_pci_detach),
603*2ed98337SAymeric Wibo 
604*2ed98337SAymeric Wibo 	DEVMETHOD(tb_find_ufp, tb_generic_find_ufp),
605*2ed98337SAymeric Wibo 	DEVMETHOD(tb_get_debug, tb_generic_get_debug),
606*2ed98337SAymeric Wibo 
607*2ed98337SAymeric Wibo 	DEVMETHOD_END
608*2ed98337SAymeric Wibo };
609*2ed98337SAymeric Wibo 
610*2ed98337SAymeric Wibo DEFINE_CLASS_1(pci, tb_pci_driver, tb_pci_methods, sizeof(struct pci_softc),
611*2ed98337SAymeric Wibo     pci_driver);
612*2ed98337SAymeric Wibo DRIVER_MODULE(tb_pci, pcib, tb_pci_driver, NULL, NULL);
613*2ed98337SAymeric Wibo MODULE_DEPEND(tb_pci, pci, 1, 1, 1);
614*2ed98337SAymeric Wibo MODULE_VERSION(tb_pci, 1);
615