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