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