xref: /freebsd/sys/dev/cxgbe/t4_iov.c (revision 42249ef2)
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/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/systm.h>
36 #include <dev/pci/pcivar.h>
37 
38 #ifdef PCI_IOV
39 #include <sys/nv.h>
40 #include <sys/iov_schema.h>
41 #include <dev/pci/pci_iov.h>
42 #endif
43 
44 #include "common/common.h"
45 #include "t4_if.h"
46 
47 struct t4iov_softc {
48 	device_t sc_dev;
49 	device_t sc_main;
50 	bool sc_attached;
51 };
52 
53 struct {
54 	uint16_t device;
55 	char *desc;
56 } t4iov_pciids[] = {
57 	{0x4000, "Chelsio T440-dbg"},
58 	{0x4001, "Chelsio T420-CR"},
59 	{0x4002, "Chelsio T422-CR"},
60 	{0x4003, "Chelsio T440-CR"},
61 	{0x4004, "Chelsio T420-BCH"},
62 	{0x4005, "Chelsio T440-BCH"},
63 	{0x4006, "Chelsio T440-CH"},
64 	{0x4007, "Chelsio T420-SO"},
65 	{0x4008, "Chelsio T420-CX"},
66 	{0x4009, "Chelsio T420-BT"},
67 	{0x400a, "Chelsio T404-BT"},
68 	{0x400e, "Chelsio T440-LP-CR"},
69 }, t5iov_pciids[] = {
70 	{0x5000, "Chelsio T580-dbg"},
71 	{0x5001,  "Chelsio T520-CR"},		/* 2 x 10G */
72 	{0x5002,  "Chelsio T522-CR"},		/* 2 x 10G, 2 X 1G */
73 	{0x5003,  "Chelsio T540-CR"},		/* 4 x 10G */
74 	{0x5007,  "Chelsio T520-SO"},		/* 2 x 10G, nomem */
75 	{0x5009,  "Chelsio T520-BT"},		/* 2 x 10GBaseT */
76 	{0x500a,  "Chelsio T504-BT"},		/* 4 x 1G */
77 	{0x500d,  "Chelsio T580-CR"},		/* 2 x 40G */
78 	{0x500e,  "Chelsio T540-LP-CR"},	/* 4 x 10G */
79 	{0x5010,  "Chelsio T580-LP-CR"},	/* 2 x 40G */
80 	{0x5011,  "Chelsio T520-LL-CR"},	/* 2 x 10G */
81 	{0x5012,  "Chelsio T560-CR"},		/* 1 x 40G, 2 x 10G */
82 	{0x5014,  "Chelsio T580-LP-SO-CR"},	/* 2 x 40G, nomem */
83 	{0x5015,  "Chelsio T502-BT"},		/* 2 x 1G */
84 #ifdef notyet
85 	{0x5004,  "Chelsio T520-BCH"},
86 	{0x5005,  "Chelsio T540-BCH"},
87 	{0x5006,  "Chelsio T540-CH"},
88 	{0x5008,  "Chelsio T520-CX"},
89 	{0x500b,  "Chelsio B520-SR"},
90 	{0x500c,  "Chelsio B504-BT"},
91 	{0x500f,  "Chelsio Amsterdam"},
92 	{0x5013,  "Chelsio T580-CHR"},
93 #endif
94 }, t6iov_pciids[] = {
95 	{0x6000, "Chelsio T6-DBG-25"},		/* 2 x 10/25G, debug */
96 	{0x6001, "Chelsio T6225-CR"},		/* 2 x 10/25G */
97 	{0x6002, "Chelsio T6225-SO-CR"},	/* 2 x 10/25G, nomem */
98 	{0x6003, "Chelsio T6425-CR"},		/* 4 x 10/25G */
99 	{0x6004, "Chelsio T6425-SO-CR"},	/* 4 x 10/25G, nomem */
100 	{0x6005, "Chelsio T6225-OCP-SO"},	/* 2 x 10/25G, nomem */
101 	{0x6006, "Chelsio T62100-OCP-SO"},	/* 2 x 40/50/100G, nomem */
102 	{0x6007, "Chelsio T62100-LP-CR"},	/* 2 x 40/50/100G */
103 	{0x6008, "Chelsio T62100-SO-CR"},	/* 2 x 40/50/100G, nomem */
104 	{0x6009, "Chelsio T6210-BT"},		/* 2 x 10GBASE-T */
105 	{0x600d, "Chelsio T62100-CR"},		/* 2 x 40/50/100G */
106 	{0x6010, "Chelsio T6-DBG-100"},		/* 2 x 40/50/100G, debug */
107 	{0x6011, "Chelsio T6225-LL-CR"},	/* 2 x 10/25G */
108 	{0x6014, "Chelsio T61100-OCP-SO"},	/* 1 x 40/50/100G, nomem */
109 	{0x6015, "Chelsio T6201-BT"},		/* 2 x 1000BASE-T */
110 
111 	/* Custom */
112 	{0x6080, "Chelsio T6225 80"},
113 	{0x6081, "Chelsio T62100 81"},
114 };
115 
116 static int	t4iov_attach_child(device_t dev);
117 
118 static int
119 t4iov_probe(device_t dev)
120 {
121 	uint16_t d;
122 	size_t i;
123 
124 	if (pci_get_vendor(dev) != PCI_VENDOR_ID_CHELSIO)
125 		return (ENXIO);
126 
127 	d = pci_get_device(dev);
128 	for (i = 0; i < nitems(t4iov_pciids); i++) {
129 		if (d == t4iov_pciids[i].device) {
130 			device_set_desc(dev, t4iov_pciids[i].desc);
131 			device_quiet(dev);
132 			return (BUS_PROBE_DEFAULT);
133 		}
134 	}
135 	return (ENXIO);
136 }
137 
138 static int
139 t5iov_probe(device_t dev)
140 {
141 	uint16_t d;
142 	size_t i;
143 
144 	if (pci_get_vendor(dev) != PCI_VENDOR_ID_CHELSIO)
145 		return (ENXIO);
146 
147 	d = pci_get_device(dev);
148 	for (i = 0; i < nitems(t5iov_pciids); i++) {
149 		if (d == t5iov_pciids[i].device) {
150 			device_set_desc(dev, t5iov_pciids[i].desc);
151 			device_quiet(dev);
152 			return (BUS_PROBE_DEFAULT);
153 		}
154 	}
155 	return (ENXIO);
156 }
157 
158 static int
159 t6iov_probe(device_t dev)
160 {
161 	uint16_t d;
162 	size_t i;
163 
164 	if (pci_get_vendor(dev) != PCI_VENDOR_ID_CHELSIO)
165 		return (ENXIO);
166 
167 	d = pci_get_device(dev);
168 	for (i = 0; i < nitems(t6iov_pciids); i++) {
169 		if (d == t6iov_pciids[i].device) {
170 			device_set_desc(dev, t6iov_pciids[i].desc);
171 			device_quiet(dev);
172 			return (BUS_PROBE_DEFAULT);
173 		}
174 	}
175 	return (ENXIO);
176 }
177 
178 static int
179 t4iov_attach(device_t dev)
180 {
181 	struct t4iov_softc *sc;
182 
183 	sc = device_get_softc(dev);
184 	sc->sc_dev = dev;
185 
186 	sc->sc_main = pci_find_dbsf(pci_get_domain(dev), pci_get_bus(dev),
187 	    pci_get_slot(dev), 4);
188 	if (sc->sc_main == NULL)
189 		return (ENXIO);
190 	if (T4_IS_MAIN_READY(sc->sc_main) == 0)
191 		return (t4iov_attach_child(dev));
192 	return (0);
193 }
194 
195 static int
196 t4iov_attach_child(device_t dev)
197 {
198 	struct t4iov_softc *sc;
199 #ifdef PCI_IOV
200 	nvlist_t *pf_schema, *vf_schema;
201 #endif
202 	device_t pdev;
203 	int error;
204 
205 	sc = device_get_softc(dev);
206 	MPASS(!sc->sc_attached);
207 
208 	/*
209 	 * PF0-3 are associated with a specific port on the NIC (PF0
210 	 * with port 0, etc.).  Ask the PF4 driver for the device for
211 	 * this function's associated port to determine if the port is
212 	 * present.
213 	 */
214 	error = T4_READ_PORT_DEVICE(sc->sc_main, pci_get_function(dev), &pdev);
215 	if (error)
216 		return (0);
217 
218 #ifdef PCI_IOV
219 	pf_schema = pci_iov_schema_alloc_node();
220 	vf_schema = pci_iov_schema_alloc_node();
221 	error = pci_iov_attach_name(dev, pf_schema, vf_schema, "%s",
222 	    device_get_nameunit(pdev));
223 	if (error) {
224 		device_printf(dev, "Failed to initialize SR-IOV: %d\n", error);
225 		return (0);
226 	}
227 #endif
228 
229 	sc->sc_attached = true;
230 	return (0);
231 }
232 
233 static int
234 t4iov_detach_child(device_t dev)
235 {
236 	struct t4iov_softc *sc;
237 #ifdef PCI_IOV
238 	int error;
239 #endif
240 
241 	sc = device_get_softc(dev);
242 	if (!sc->sc_attached)
243 		return (0);
244 
245 #ifdef PCI_IOV
246 	error = pci_iov_detach(dev);
247 	if (error != 0) {
248 		device_printf(dev, "Failed to disable SR-IOV\n");
249 		return (error);
250 	}
251 #endif
252 
253 	sc->sc_attached = false;
254 	return (0);
255 }
256 
257 static int
258 t4iov_detach(device_t dev)
259 {
260 	struct t4iov_softc *sc;
261 	int error;
262 
263 	sc = device_get_softc(dev);
264 	if (sc->sc_attached) {
265 		error = t4iov_detach_child(dev);
266 		if (error)
267 			return (error);
268 	}
269 	return (0);
270 }
271 
272 #ifdef PCI_IOV
273 static int
274 t4iov_iov_init(device_t dev, uint16_t num_vfs, const struct nvlist *config)
275 {
276 
277 	/* XXX: The Linux driver sets up a vf_monitor task on T4 adapters. */
278 	return (0);
279 }
280 
281 static void
282 t4iov_iov_uninit(device_t dev)
283 {
284 }
285 
286 static int
287 t4iov_add_vf(device_t dev, uint16_t vfnum, const struct nvlist *config)
288 {
289 
290 	return (0);
291 }
292 #endif
293 
294 static device_method_t t4iov_methods[] = {
295 	DEVMETHOD(device_probe,		t4iov_probe),
296 	DEVMETHOD(device_attach,	t4iov_attach),
297 	DEVMETHOD(device_detach,	t4iov_detach),
298 
299 #ifdef PCI_IOV
300 	DEVMETHOD(pci_iov_init,		t4iov_iov_init),
301 	DEVMETHOD(pci_iov_uninit,	t4iov_iov_uninit),
302 	DEVMETHOD(pci_iov_add_vf,	t4iov_add_vf),
303 #endif
304 
305 	DEVMETHOD(t4_attach_child,	t4iov_attach_child),
306 	DEVMETHOD(t4_detach_child,	t4iov_detach_child),
307 
308 	DEVMETHOD_END
309 };
310 
311 static driver_t t4iov_driver = {
312 	"t4iov",
313 	t4iov_methods,
314 	sizeof(struct t4iov_softc)
315 };
316 
317 static device_method_t t5iov_methods[] = {
318 	DEVMETHOD(device_probe,		t5iov_probe),
319 	DEVMETHOD(device_attach,	t4iov_attach),
320 	DEVMETHOD(device_detach,	t4iov_detach),
321 
322 #ifdef PCI_IOV
323 	DEVMETHOD(pci_iov_init,		t4iov_iov_init),
324 	DEVMETHOD(pci_iov_uninit,	t4iov_iov_uninit),
325 	DEVMETHOD(pci_iov_add_vf,	t4iov_add_vf),
326 #endif
327 
328 	DEVMETHOD(t4_attach_child,	t4iov_attach_child),
329 	DEVMETHOD(t4_detach_child,	t4iov_detach_child),
330 
331 	DEVMETHOD_END
332 };
333 
334 static driver_t t5iov_driver = {
335 	"t5iov",
336 	t5iov_methods,
337 	sizeof(struct t4iov_softc)
338 };
339 
340 static device_method_t t6iov_methods[] = {
341 	DEVMETHOD(device_probe,		t6iov_probe),
342 	DEVMETHOD(device_attach,	t4iov_attach),
343 	DEVMETHOD(device_detach,	t4iov_detach),
344 
345 #ifdef PCI_IOV
346 	DEVMETHOD(pci_iov_init,		t4iov_iov_init),
347 	DEVMETHOD(pci_iov_uninit,	t4iov_iov_uninit),
348 	DEVMETHOD(pci_iov_add_vf,	t4iov_add_vf),
349 #endif
350 
351 	DEVMETHOD(t4_attach_child,	t4iov_attach_child),
352 	DEVMETHOD(t4_detach_child,	t4iov_detach_child),
353 
354 	DEVMETHOD_END
355 };
356 
357 static driver_t t6iov_driver = {
358 	"t6iov",
359 	t6iov_methods,
360 	sizeof(struct t4iov_softc)
361 };
362 
363 static devclass_t t4iov_devclass, t5iov_devclass, t6iov_devclass;
364 
365 DRIVER_MODULE(t4iov, pci, t4iov_driver, t4iov_devclass, 0, 0);
366 MODULE_VERSION(t4iov, 1);
367 
368 DRIVER_MODULE(t5iov, pci, t5iov_driver, t5iov_devclass, 0, 0);
369 MODULE_VERSION(t5iov, 1);
370 
371 DRIVER_MODULE(t6iov, pci, t6iov_driver, t6iov_devclass, 0, 0);
372 MODULE_VERSION(t6iov, 1);
373