xref: /freebsd/sys/dev/cxgbe/t4_iov.c (revision c4fde87a3236b500246d4fce76dbca2a3d64f73a)
1 /*-
2  * Copyright (c) 2015-2016 Chelsio Communications, Inc.
3  * All rights reserved.
4  * Written by: John Baldwin <jhb@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/param.h>
29 #include <sys/bus.h>
30 #include <sys/kernel.h>
31 #include <sys/module.h>
32 #include <sys/socket.h>
33 #include <sys/systm.h>
34 #include <sys/iov.h>
35 #include <dev/pci/pcivar.h>
36 #include <net/if.h>
37 #include <net/if_vlan_var.h>
38 
39 #ifdef PCI_IOV
40 #include <sys/nv.h>
41 #include <sys/iov_schema.h>
42 #include <dev/pci/pci_iov.h>
43 #endif
44 
45 #include "common/common.h"
46 #include "common/t4_regs.h"
47 #include "t4_if.h"
48 
49 struct t4iov_softc {
50 	device_t sc_dev;
51 	device_t sc_main;
52 	struct port_info *sc_port;
53 	bool sc_attached;
54 
55 	int pf;
56 	int regs_rid;
57 	struct resource *regs_res;
58 };
59 
60 struct {
61 	uint16_t device;
62 	char *desc;
63 } t4iov_pciids[] = {
64 	{0x4000, "Chelsio T440-dbg"},
65 	{0x4001, "Chelsio T420-CR"},
66 	{0x4002, "Chelsio T422-CR"},
67 	{0x4003, "Chelsio T440-CR"},
68 	{0x4004, "Chelsio T420-BCH"},
69 	{0x4005, "Chelsio T440-BCH"},
70 	{0x4006, "Chelsio T440-CH"},
71 	{0x4007, "Chelsio T420-SO"},
72 	{0x4008, "Chelsio T420-CX"},
73 	{0x4009, "Chelsio T420-BT"},
74 	{0x400a, "Chelsio T404-BT"},
75 	{0x400e, "Chelsio T440-LP-CR"},
76 }, t5iov_pciids[] = {
77 	{0x5000, "Chelsio T580-dbg"},
78 	{0x5001,  "Chelsio T520-CR"},		/* 2 x 10G */
79 	{0x5002,  "Chelsio T522-CR"},		/* 2 x 10G, 2 X 1G */
80 	{0x5003,  "Chelsio T540-CR"},		/* 4 x 10G */
81 	{0x5007,  "Chelsio T520-SO"},		/* 2 x 10G, nomem */
82 	{0x5009,  "Chelsio T520-BT"},		/* 2 x 10GBaseT */
83 	{0x500a,  "Chelsio T504-BT"},		/* 4 x 1G */
84 	{0x500d,  "Chelsio T580-CR"},		/* 2 x 40G */
85 	{0x500e,  "Chelsio T540-LP-CR"},	/* 4 x 10G */
86 	{0x5010,  "Chelsio T580-LP-CR"},	/* 2 x 40G */
87 	{0x5011,  "Chelsio T520-LL-CR"},	/* 2 x 10G */
88 	{0x5012,  "Chelsio T560-CR"},		/* 1 x 40G, 2 x 10G */
89 	{0x5014,  "Chelsio T580-LP-SO-CR"},	/* 2 x 40G, nomem */
90 	{0x5015,  "Chelsio T502-BT"},		/* 2 x 1G */
91 	{0x5018,  "Chelsio T540-BT"},		/* 4 x 10GBaseT */
92 	{0x5019,  "Chelsio T540-LP-BT"},	/* 4 x 10GBaseT */
93 	{0x501a,  "Chelsio T540-SO-BT"},	/* 4 x 10GBaseT, nomem */
94 	{0x501b,  "Chelsio T540-SO-CR"},	/* 4 x 10G, nomem */
95 }, t6iov_pciids[] = {
96 	{0x6000, "Chelsio T6-DBG-25"},		/* 2 x 10/25G, debug */
97 	{0x6001, "Chelsio T6225-CR"},		/* 2 x 10/25G */
98 	{0x6002, "Chelsio T6225-SO-CR"},	/* 2 x 10/25G, nomem */
99 	{0x6003, "Chelsio T6425-CR"},		/* 4 x 10/25G */
100 	{0x6004, "Chelsio T6425-SO-CR"},	/* 4 x 10/25G, nomem */
101 	{0x6005, "Chelsio T6225-SO-OCP3"},	/* 2 x 10/25G, nomem */
102 	{0x6006, "Chelsio T6225-OCP3"},		/* 2 x 10/25G */
103 	{0x6007, "Chelsio T62100-LP-CR"},	/* 2 x 40/50/100G */
104 	{0x6008, "Chelsio T62100-SO-CR"},	/* 2 x 40/50/100G, nomem */
105 	{0x6009, "Chelsio T6210-BT"},		/* 2 x 10GBASE-T */
106 	{0x600d, "Chelsio T62100-CR"},		/* 2 x 40/50/100G */
107 	{0x6010, "Chelsio T6-DBG-100"},		/* 2 x 40/50/100G, debug */
108 	{0x6011, "Chelsio T6225-LL-CR"},	/* 2 x 10/25G */
109 	{0x6014, "Chelsio T62100-SO-OCP3"},	/* 2 x 40/50/100G, nomem */
110 	{0x6015, "Chelsio T6201-BT"},		/* 2 x 1000BASE-T */
111 
112 	/* Custom */
113 	{0x6080, "Chelsio T6225 80"},
114 	{0x6081, "Chelsio T62100 81"},
115 	{0x6082, "Chelsio T6225-CR 82"},
116 	{0x6083, "Chelsio T62100-CR 83"},
117 	{0x6084, "Chelsio T64100-CR 84"},
118 	{0x6085, "Chelsio T6240-SO 85"},
119 	{0x6086, "Chelsio T6225-SO-CR 86"},
120 	{0x6087, "Chelsio T6225-CR 87"},
121 }, t7iov_pciids[] = {
122 	{0xd000, "Chelsio Terminator 7 FPGA"},	/* T7 PE12K FPGA */
123 	{0x7000, "Chelsio T72200-DBG"},		/* 2 x 200G, debug */
124 	{0x7001, "Chelsio T7250"},		/* 2 x 10/25/50G, 1 mem */
125 	{0x7002, "Chelsio S7250"},		/* 2 x 10/25/50G, nomem */
126 	{0x7003, "Chelsio T7450"},		/* 4 x 10/25/50G, 1 mem */
127 	{0x7004, "Chelsio S7450"},		/* 4 x 10/25/50G, nomem */
128 	{0x7005, "Chelsio T72200"},		/* 2 x 40/100/200G, 1 mem */
129 	{0x7006, "Chelsio S72200"},		/* 2 x 40/100/200G, nomem */
130 	{0x7007, "Chelsio T72200-FH"},		/* 2 x 40/100/200G, 2 mem */
131 	{0x7008, "Chelsio T71400"},		/* 1 x 400G, nomem */
132 	{0x7009, "Chelsio S7210-BT"},		/* 2 x 10GBASE-T, nomem */
133 	{0x700a, "Chelsio T7450-RC"},		/* 4 x 10/25/50G, 1 mem, RC */
134 	{0x700b, "Chelsio T72200-RC"},		/* 2 x 40/100/200G, 1 mem, RC */
135 	{0x700c, "Chelsio T72200-FH-RC"},	/* 2 x 40/100/200G, 2 mem, RC */
136 	{0x700d, "Chelsio S72200-OCP3"},	/* 2 x 40/100/200G OCP3 */
137 	{0x700e, "Chelsio S7450-OCP3"},		/* 4 x 1/20/25/50G OCP3 */
138 	{0x700f, "Chelsio S7410-BT-OCP3"},	/* 4 x 10GBASE-T OCP3 */
139 	{0x7010, "Chelsio S7210-BT-A"},		/* 2 x 10GBASE-T */
140 	{0x7011, "Chelsio T7_MAYRA_7"},		/* Motherboard */
141 
142 	{0x7080, "Custom T7"},
143 };
144 
145 static inline uint32_t
146 t4iov_read_reg(struct t4iov_softc *sc, uint32_t reg)
147 {
148 
149 	return bus_read_4(sc->regs_res, reg);
150 }
151 
152 static int	t4iov_attach_child(device_t dev);
153 
154 static int
155 t4iov_probe(device_t dev)
156 {
157 	uint16_t d;
158 	size_t i;
159 
160 	if (pci_get_vendor(dev) != PCI_VENDOR_ID_CHELSIO)
161 		return (ENXIO);
162 
163 	d = pci_get_device(dev);
164 	for (i = 0; i < nitems(t4iov_pciids); i++) {
165 		if (d == t4iov_pciids[i].device) {
166 			device_set_desc(dev, t4iov_pciids[i].desc);
167 			device_quiet(dev);
168 			return (BUS_PROBE_DEFAULT);
169 		}
170 	}
171 	return (ENXIO);
172 }
173 
174 static int
175 t5iov_probe(device_t dev)
176 {
177 	uint16_t d;
178 	size_t i;
179 
180 	if (pci_get_vendor(dev) != PCI_VENDOR_ID_CHELSIO)
181 		return (ENXIO);
182 
183 	d = pci_get_device(dev);
184 	for (i = 0; i < nitems(t5iov_pciids); i++) {
185 		if (d == t5iov_pciids[i].device) {
186 			device_set_desc(dev, t5iov_pciids[i].desc);
187 			device_quiet(dev);
188 			return (BUS_PROBE_DEFAULT);
189 		}
190 	}
191 	return (ENXIO);
192 }
193 
194 static int
195 t6iov_probe(device_t dev)
196 {
197 	uint16_t d;
198 	size_t i;
199 
200 	if (pci_get_vendor(dev) != PCI_VENDOR_ID_CHELSIO)
201 		return (ENXIO);
202 
203 	d = pci_get_device(dev);
204 	for (i = 0; i < nitems(t6iov_pciids); i++) {
205 		if (d == t6iov_pciids[i].device) {
206 			device_set_desc(dev, t6iov_pciids[i].desc);
207 			device_quiet(dev);
208 			return (BUS_PROBE_DEFAULT);
209 		}
210 	}
211 	return (ENXIO);
212 }
213 
214 static int
215 chiov_probe(device_t dev)
216 {
217 	uint16_t d;
218 	size_t i;
219 
220 	if (pci_get_vendor(dev) != PCI_VENDOR_ID_CHELSIO)
221 		return (ENXIO);
222 
223 	d = pci_get_device(dev);
224 	for (i = 0; i < nitems(t7iov_pciids); i++) {
225 		if (d == t7iov_pciids[i].device) {
226 			device_set_desc(dev, t7iov_pciids[i].desc);
227 			device_quiet(dev);
228 			return (BUS_PROBE_DEFAULT);
229 		}
230 	}
231 	return (ENXIO);
232 }
233 
234 static int
235 t4iov_attach(device_t dev)
236 {
237 	struct t4iov_softc *sc;
238 	uint32_t pl_rev, whoami;
239 	int error;
240 
241 	sc = device_get_softc(dev);
242 	sc->sc_dev = dev;
243 
244 	sc->regs_rid = PCIR_BAR(0);
245 	sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
246 	    &sc->regs_rid, RF_ACTIVE);
247 	if (sc->regs_res == NULL) {
248 		device_printf(dev, "cannot map registers.\n");
249 		return (ENXIO);
250 	}
251 
252 	pl_rev = t4iov_read_reg(sc, A_PL_REV);
253 	whoami = t4iov_read_reg(sc, A_PL_WHOAMI);
254 	if (G_CHIPID(pl_rev) <= CHELSIO_T5)
255 		sc->pf = G_SOURCEPF(whoami);
256 	else
257 		sc->pf = G_T6_SOURCEPF(whoami);
258 
259 	sc->sc_main = pci_find_dbsf(pci_get_domain(dev), pci_get_bus(dev),
260 	    pci_get_slot(dev), 4);
261 	if (sc->sc_main == NULL) {
262 		bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid,
263 		    sc->regs_res);
264 		return (ENXIO);
265 	}
266 	if (T4_IS_MAIN_READY(sc->sc_main) == 0) {
267 		error = t4iov_attach_child(dev);
268 		if (error != 0)
269 			bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid,
270 			    sc->regs_res);
271 		return (error);
272 	}
273 	return (0);
274 }
275 
276 static int
277 t4iov_attach_child(device_t dev)
278 {
279 	struct t4iov_softc *sc;
280 #ifdef PCI_IOV
281 	struct adapter *adap;
282 	nvlist_t *pf_schema, *vf_schema;
283 #endif
284 	device_t pdev;
285 	int error;
286 
287 	sc = device_get_softc(dev);
288 	MPASS(!sc->sc_attached);
289 
290 	/*
291 	 * PF0-3 are associated with a specific port on the NIC (PF0
292 	 * with port 0, etc.).  Ask the PF4 driver for the device for
293 	 * this function's associated port to determine if the port is
294 	 * present.
295 	 */
296 	error = T4_READ_PORT_DEVICE(sc->sc_main, pci_get_function(dev), &pdev);
297 	if (error)
298 		return (0);
299 
300 #ifdef PCI_IOV
301 	pf_schema = pci_iov_schema_alloc_node();
302 	vf_schema = pci_iov_schema_alloc_node();
303 	pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
304 	pci_iov_schema_add_vlan(vf_schema, "vlan", 0, 0);
305 	error = pci_iov_attach_name(dev, pf_schema, vf_schema, "%s",
306 	    device_get_nameunit(pdev));
307 	if (error) {
308 		device_printf(dev, "Failed to initialize SR-IOV: %d\n", error);
309 		return (0);
310 	}
311 	sc->sc_port = device_get_softc(pdev);
312 	adap = device_get_softc(sc->sc_main);
313 	error = begin_synchronized_op(adap, NULL, SLEEP_OK, "t4iovatt");
314 	if (error != 0) {
315 		(void)pci_iov_detach(dev);
316 		sc->sc_port = NULL;
317 		return (error);
318 	}
319 	sc->sc_port->iov_status_supported = true;
320 	end_synchronized_op(adap, 0);
321 #endif
322 
323 	sc->sc_attached = true;
324 	return (0);
325 }
326 
327 static int
328 t4iov_detach_child(device_t dev)
329 {
330 	struct t4iov_softc *sc;
331 #ifdef PCI_IOV
332 	struct adapter *adap;
333 	int error;
334 #endif
335 
336 	sc = device_get_softc(dev);
337 	if (!sc->sc_attached)
338 		return (0);
339 
340 #ifdef PCI_IOV
341 	error = pci_iov_detach(dev);
342 	if (error != 0) {
343 		device_printf(dev, "Failed to disable SR-IOV\n");
344 		return (error);
345 	}
346 	adap = device_get_softc(sc->sc_main);
347 	error = begin_synchronized_op(adap, NULL, SLEEP_OK, "t4iovdet");
348 	if (error != 0)
349 		return (error);
350 	sc->sc_port->iov_status_supported = false;
351 	end_synchronized_op(adap, 0);
352 	sc->sc_port = NULL;
353 #endif
354 
355 	sc->sc_attached = false;
356 	return (0);
357 }
358 
359 static int
360 t4iov_detach(device_t dev)
361 {
362 	struct t4iov_softc *sc;
363 	int error;
364 
365 	sc = device_get_softc(dev);
366 	if (sc->sc_attached) {
367 		error = t4iov_detach_child(dev);
368 		if (error)
369 			return (error);
370 	}
371 	if (sc->regs_res) {
372 		bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid,
373 		    sc->regs_res);
374 	}
375 	return (0);
376 }
377 
378 #ifdef PCI_IOV
379 static int
380 t4iov_iov_init(device_t dev, uint16_t num_vfs, const struct nvlist *config)
381 {
382 	struct t4iov_softc *sc;
383 	struct t4_vf_info *vfs;
384 	struct adapter *adap;
385 	int error;
386 
387 	/* XXX: The Linux driver sets up a vf_monitor task on T4 adapters. */
388 	sc = device_get_softc(dev);
389 	MPASS(sc->sc_port != NULL);
390 	vfs = mallocarray(num_vfs, sizeof(*vfs), M_CXGBE,
391 	    M_WAITOK | M_ZERO);
392 	adap = device_get_softc(sc->sc_main);
393 	error = begin_synchronized_op(adap, NULL, SLEEP_OK, "t4vfinit");
394 	if (error != 0) {
395 		free(vfs, M_CXGBE);
396 		return (error);
397 	}
398 	MPASS(sc->sc_port->iov_vfs == NULL);
399 	sc->sc_port->iov_vfs = vfs;
400 	sc->sc_port->iov_num_vfs = num_vfs;
401 	end_synchronized_op(adap, 0);
402 	return (0);
403 }
404 
405 static void
406 t4iov_iov_uninit(device_t dev)
407 {
408 	struct t4iov_softc *sc;
409 	struct t4_vf_info *vfs;
410 	struct adapter *adap;
411 
412 	sc = device_get_softc(dev);
413 	MPASS(sc->sc_port != NULL);
414 	adap = device_get_softc(sc->sc_main);
415 	if (begin_synchronized_op(adap, NULL, SLEEP_OK, "t4vffini") != 0)
416 		return;
417 	vfs = sc->sc_port->iov_vfs;
418 	sc->sc_port->iov_vfs = NULL;
419 	sc->sc_port->iov_num_vfs = 0;
420 	end_synchronized_op(adap, 0);
421 	free(vfs, M_CXGBE);
422 }
423 
424 static int
425 t4iov_add_vf(device_t dev, uint16_t vfnum, const struct nvlist *config)
426 {
427 	const void *mac;
428 	struct t4iov_softc *sc;
429 	struct adapter *adap;
430 	uint8_t ma[ETHER_ADDR_LEN];
431 	uint16_t vlan;
432 	bool access_vlan, has_mac, has_vlan;
433 	size_t size;
434 	int rc;
435 
436 	sc = device_get_softc(dev);
437 	MPASS(sc->sc_attached);
438 	MPASS(sc->sc_main != NULL);
439 	adap = device_get_softc(sc->sc_main);
440 	memset(ma, 0, sizeof(ma));
441 	vlan = 0;
442 	access_vlan = false;
443 	has_mac = nvlist_exists_binary(config, "mac-addr");
444 	has_vlan = nvlist_exists_number(config, "vlan");
445 
446 	if (has_mac) {
447 		mac = nvlist_get_binary(config, "mac-addr", &size);
448 		bcopy(mac, ma, ETHER_ADDR_LEN);
449 	}
450 
451 	if (has_vlan) {
452 		vlan = nvlist_get_number(config, "vlan");
453 
454 		/* We can't restrict to VID 0 */
455 		if (vlan == DOT1Q_VID_NULL)
456 			return (ENOTSUP);
457 
458 		if (vlan == VF_VLAN_TRUNK)
459 			vlan = DOT1Q_VID_NULL;
460 		else
461 			access_vlan = true;
462 	}
463 
464 	if (begin_synchronized_op(adap, NULL, SLEEP_OK | INTR_OK,
465 	    "t4vfadd") != 0)
466 		return (ENXIO);
467 
468 	if (has_mac) {
469 		rc = -t4_set_vf_mac(adap, sc->pf, vfnum + 1, 1, ma);
470 		if (rc != 0) {
471 			device_printf(dev,
472 			    "Failed to set VF%d MAC address to "
473 			    "%02x:%02x:%02x:%02x:%02x:%02x, rc = %d\n", vfnum,
474 			    ma[0], ma[1], ma[2], ma[3], ma[4], ma[5], rc);
475 			goto out;
476 		}
477 	}
478 
479 	if (has_vlan) {
480 		rc = t4_set_vlan_acl(adap, sc->pf, vfnum + 1, vlan);
481 		if (rc != 0) {
482 			device_printf(dev,
483 			    "Failed to set VF%d VLAN to %d, rc = %d\n",
484 			    vfnum, vlan, rc);
485 			goto out;
486 		}
487 	}
488 
489 	if (has_mac)
490 		memcpy(sc->sc_port->iov_vfs[vfnum].mac, ma,
491 		    ETHER_ADDR_LEN);
492 	sc->sc_port->iov_vfs[vfnum].vlan = vlan;
493 	sc->sc_port->iov_vfs[vfnum].access_vlan = access_vlan;
494 	sc->sc_port->iov_vfs[vfnum].configured = true;
495 	rc = 0;
496 
497 out:
498 	end_synchronized_op(adap, 0);
499 	return (rc);
500 }
501 #endif
502 
503 static device_method_t t4iov_methods[] = {
504 	DEVMETHOD(device_probe,		t4iov_probe),
505 	DEVMETHOD(device_attach,	t4iov_attach),
506 	DEVMETHOD(device_detach,	t4iov_detach),
507 
508 #ifdef PCI_IOV
509 	DEVMETHOD(pci_iov_init,		t4iov_iov_init),
510 	DEVMETHOD(pci_iov_uninit,	t4iov_iov_uninit),
511 	DEVMETHOD(pci_iov_add_vf,	t4iov_add_vf),
512 #endif
513 
514 	DEVMETHOD(t4_attach_child,	t4iov_attach_child),
515 	DEVMETHOD(t4_detach_child,	t4iov_detach_child),
516 
517 	DEVMETHOD_END
518 };
519 
520 static driver_t t4iov_driver = {
521 	"t4iov",
522 	t4iov_methods,
523 	sizeof(struct t4iov_softc)
524 };
525 
526 static device_method_t t5iov_methods[] = {
527 	DEVMETHOD(device_probe,		t5iov_probe),
528 	DEVMETHOD(device_attach,	t4iov_attach),
529 	DEVMETHOD(device_detach,	t4iov_detach),
530 
531 #ifdef PCI_IOV
532 	DEVMETHOD(pci_iov_init,		t4iov_iov_init),
533 	DEVMETHOD(pci_iov_uninit,	t4iov_iov_uninit),
534 	DEVMETHOD(pci_iov_add_vf,	t4iov_add_vf),
535 #endif
536 
537 	DEVMETHOD(t4_attach_child,	t4iov_attach_child),
538 	DEVMETHOD(t4_detach_child,	t4iov_detach_child),
539 
540 	DEVMETHOD_END
541 };
542 
543 static driver_t t5iov_driver = {
544 	"t5iov",
545 	t5iov_methods,
546 	sizeof(struct t4iov_softc)
547 };
548 
549 static device_method_t t6iov_methods[] = {
550 	DEVMETHOD(device_probe,		t6iov_probe),
551 	DEVMETHOD(device_attach,	t4iov_attach),
552 	DEVMETHOD(device_detach,	t4iov_detach),
553 
554 #ifdef PCI_IOV
555 	DEVMETHOD(pci_iov_init,		t4iov_iov_init),
556 	DEVMETHOD(pci_iov_uninit,	t4iov_iov_uninit),
557 	DEVMETHOD(pci_iov_add_vf,	t4iov_add_vf),
558 #endif
559 
560 	DEVMETHOD(t4_attach_child,	t4iov_attach_child),
561 	DEVMETHOD(t4_detach_child,	t4iov_detach_child),
562 
563 	DEVMETHOD_END
564 };
565 
566 static driver_t t6iov_driver = {
567 	"t6iov",
568 	t6iov_methods,
569 	sizeof(struct t4iov_softc)
570 };
571 
572 static device_method_t chiov_methods[] = {
573 	DEVMETHOD(device_probe,		chiov_probe),
574 	DEVMETHOD(device_attach,	t4iov_attach),
575 	DEVMETHOD(device_detach,	t4iov_detach),
576 
577 #ifdef PCI_IOV
578 	DEVMETHOD(pci_iov_init,		t4iov_iov_init),
579 	DEVMETHOD(pci_iov_uninit,	t4iov_iov_uninit),
580 	DEVMETHOD(pci_iov_add_vf,	t4iov_add_vf),
581 #endif
582 
583 	DEVMETHOD(t4_attach_child,	t4iov_attach_child),
584 	DEVMETHOD(t4_detach_child,	t4iov_detach_child),
585 
586 	DEVMETHOD_END
587 };
588 
589 static driver_t chiov_driver = {
590 	"chiov",
591 	chiov_methods,
592 	sizeof(struct t4iov_softc)
593 };
594 DRIVER_MODULE(t4iov, pci, t4iov_driver, 0, 0);
595 MODULE_VERSION(t4iov, 1);
596 
597 DRIVER_MODULE(t5iov, pci, t5iov_driver, 0, 0);
598 MODULE_VERSION(t5iov, 1);
599 
600 DRIVER_MODULE(t6iov, pci, t6iov_driver, 0, 0);
601 MODULE_VERSION(t6iov, 1);
602 
603 DRIVER_MODULE(chiov, pci, chiov_driver, 0, 0);
604 MODULE_VERSION(chiov, 1);
605