1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright © 2021-2022 Dmitry Salychev
5 * Copyright © 2021 Bjoern A. Zeeb
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 <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 /*
33 * The DPAA2 Management Complex (MC) Bus Driver (ACPI-based).
34 *
35 * MC is a hardware resource manager which can be found in several NXP
36 * SoCs (LX2160A, for example) and provides an access to the specialized
37 * hardware objects used in network-oriented packet processing applications.
38 */
39 #include <sys/param.h>
40 #include <sys/kernel.h>
41 #include <sys/bus.h>
42 #include <sys/rman.h>
43 #include <sys/module.h>
44 #include <sys/malloc.h>
45 #include <sys/mutex.h>
46
47 #include <machine/bus.h>
48 #include <machine/resource.h>
49
50 #include <contrib/dev/acpica/include/acpi.h>
51 #include <dev/acpica/acpivar.h>
52
53 #include "acpi_bus_if.h"
54 #include "pcib_if.h"
55 #include "pci_if.h"
56
57 #include "dpaa2_mcp.h"
58 #include "dpaa2_mc.h"
59 #include "dpaa2_mc_if.h"
60
61 struct dpaa2_mac_dev_softc {
62 int uid;
63 uint64_t reg;
64 char managed[64];
65 char phy_conn_type[64];
66 char phy_mode[64];
67 ACPI_HANDLE phy_channel;
68 };
69
70 static int
71 dpaa2_mac_dev_probe(device_t dev)
72 {
73 uint64_t reg;
74 ssize_t s;
75
76 s = device_get_property(dev, "reg", ®, sizeof(reg),
77 DEVICE_PROP_UINT64);
78 if (s == -1)
79 return (ENXIO);
80
81 device_set_desc(dev, "DPAA2 MAC DEV");
82 return (BUS_PROBE_DEFAULT);
83 }
84
85 static int
86 dpaa2_mac_dev_attach(device_t dev)
87 {
88 struct dpaa2_mac_dev_softc *sc;
89 ACPI_HANDLE h;
90 ssize_t s;
91
92 sc = device_get_softc(dev);
93 h = acpi_get_handle(dev);
94 if (h == NULL)
95 return (ENXIO);
96
97 s = acpi_GetInteger(h, "_UID", &sc->uid);
98 if (ACPI_FAILURE(s)) {
99 device_printf(dev, "Cannot find '_UID' property: %zd\n", s);
100 return (ENXIO);
101 }
102
103 s = device_get_property(dev, "reg", &sc->reg, sizeof(sc->reg),
104 DEVICE_PROP_UINT64);
105 if (s == -1) {
106 device_printf(dev, "Cannot find 'reg' property: %zd\n", s);
107 return (ENXIO);
108 }
109
110 s = device_get_property(dev, "managed", sc->managed,
111 sizeof(sc->managed), DEVICE_PROP_ANY);
112 s = device_get_property(dev, "phy-connection-type", sc->phy_conn_type,
113 sizeof(sc->phy_conn_type), DEVICE_PROP_ANY);
114 s = device_get_property(dev, "phy-mode", sc->phy_mode,
115 sizeof(sc->phy_mode), DEVICE_PROP_ANY);
116 s = device_get_property(dev, "phy-handle", &sc->phy_channel,
117 sizeof(sc->phy_channel), DEVICE_PROP_HANDLE);
118
119 if (bootverbose)
120 device_printf(dev, "UID %#04x reg %#04jx managed '%s' "
121 "phy-connection-type '%s' phy-mode '%s' phy-handle '%s'\n",
122 sc->uid, sc->reg, sc->managed[0] != '\0' ? sc->managed : "",
123 sc->phy_conn_type[0] != '\0' ? sc->phy_conn_type : "",
124 sc->phy_mode[0] != '\0' ? sc->phy_mode : "",
125 sc->phy_channel != NULL ? acpi_name(sc->phy_channel) : "");
126
127 return (0);
128 }
129
130 static bool
131 dpaa2_mac_dev_match_id(device_t dev, uint32_t id)
132 {
133 struct dpaa2_mac_dev_softc *sc;
134
135 if (dev == NULL)
136 return (false);
137
138 sc = device_get_softc(dev);
139 if (sc->uid == id)
140 return (true);
141
142 return (false);
143 }
144
145 static device_t
146 dpaa2_mac_dev_get_phy_dev(device_t dev)
147 {
148 struct dpaa2_mac_dev_softc *sc;
149
150 if (dev == NULL)
151 return (NULL);
152
153 sc = device_get_softc(dev);
154 if (sc->phy_channel == NULL)
155 return (NULL);
156
157 return (acpi_get_device(sc->phy_channel));
158 }
159
160 static device_method_t dpaa2_mac_dev_methods[] = {
161 /* Device interface */
162 DEVMETHOD(device_probe, dpaa2_mac_dev_probe),
163 DEVMETHOD(device_attach, dpaa2_mac_dev_attach),
164 DEVMETHOD(device_detach, bus_generic_detach),
165
166 DEVMETHOD_END
167 };
168
169 DEFINE_CLASS_0(dpaa2_mac_dev, dpaa2_mac_dev_driver, dpaa2_mac_dev_methods,
170 sizeof(struct dpaa2_mac_dev_softc));
171
172 DRIVER_MODULE(dpaa2_mac_dev, dpaa2_mc, dpaa2_mac_dev_driver, 0, 0);
173
174 MODULE_DEPEND(dpaa2_mac_dev, memac_mdio_acpi, 1, 1, 1);
175
176 /*
177 * Device interface.
178 */
179
180 static int
181 dpaa2_mc_acpi_probe(device_t dev)
182 {
183 static char *dpaa2_mc_ids[] = { "NXP0008", NULL };
184 int rc;
185
186 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
187
188 rc = ACPI_ID_PROBE(device_get_parent(dev), dev, dpaa2_mc_ids, NULL);
189 if (rc <= 0)
190 device_set_desc(dev, "DPAA2 Management Complex");
191
192 return (rc);
193 }
194
195 /* Context for walking PRxx child devices. */
196 struct dpaa2_mc_acpi_prxx_walk_ctx {
197 device_t dev;
198 int count;
199 int countok;
200 };
201
202 static ACPI_STATUS
203 dpaa2_mc_acpi_probe_child(ACPI_HANDLE h, device_t *dev, int level, void *arg)
204 {
205 struct dpaa2_mc_acpi_prxx_walk_ctx *ctx;
206 struct acpi_device *ad;
207 device_t child;
208 uint32_t uid;
209
210 ctx = (struct dpaa2_mc_acpi_prxx_walk_ctx *)arg;
211 ctx->count++;
212
213 #if 0
214 device_printf(ctx->dev, "%s: %s level %d count %d\n", __func__,
215 acpi_name(h), level, ctx->count);
216 #endif
217
218 if (ACPI_FAILURE(acpi_GetInteger(h, "_UID", &uid)))
219 return (AE_OK);
220 #if 0
221 if (bootverbose)
222 device_printf(ctx->dev, "%s: Found child Ports _UID %u\n",
223 __func__, uid);
224 #endif
225
226 /* Technically M_ACPIDEV */
227 if ((ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL)
228 return (AE_OK);
229
230 child = device_add_child(ctx->dev, "dpaa2_mac_dev", -1);
231 if (child == NULL) {
232 free(ad, M_DEVBUF);
233 return (AE_OK);
234 }
235 ad->ad_handle = h;
236 ad->ad_cls_class = 0xffffff;
237 resource_list_init(&ad->ad_rl);
238 device_set_ivars(child, ad);
239 *dev = child;
240
241 ctx->countok++;
242 return (AE_OK);
243 }
244
245 static int
246 dpaa2_mc_acpi_attach(device_t dev)
247 {
248 struct dpaa2_mc_softc *sc;
249
250 sc = device_get_softc(dev);
251 sc->acpi_based = true;
252
253 struct dpaa2_mc_acpi_prxx_walk_ctx ctx;
254 ctx.dev = dev;
255 ctx.count = 0;
256 ctx.countok = 0;
257 ACPI_SCAN_CHILDREN(device_get_parent(dev), dev, 2,
258 dpaa2_mc_acpi_probe_child, &ctx);
259
260 #if 0
261 device_printf(dev, "Found %d child Ports in ASL, %d ok\n",
262 ctx.count, ctx.countok);
263 #endif
264
265 return (dpaa2_mc_attach(dev));
266 }
267
268 /*
269 * ACPI compat layer.
270 */
271
272 static device_t
273 dpaa2_mc_acpi_find_dpaa2_mac_dev(device_t dev, uint32_t id)
274 {
275 int devcount, error, i, len;
276 device_t *devlist, mdev;
277 const char *mdevname;
278
279 error = device_get_children(dev, &devlist, &devcount);
280 if (error != 0)
281 return (NULL);
282
283 for (i = 0; i < devcount; i++) {
284 mdev = devlist[i];
285 mdevname = device_get_name(mdev);
286 if (mdevname != NULL) {
287 len = strlen(mdevname);
288 if (strncmp("dpaa2_mac_dev", mdevname, len) != 0)
289 continue;
290 } else {
291 continue;
292 }
293 if (!device_is_attached(mdev))
294 continue;
295
296 if (dpaa2_mac_dev_match_id(mdev, id))
297 return (mdev);
298 }
299
300 return (NULL);
301 }
302
303 static int
304 dpaa2_mc_acpi_get_phy_dev(device_t dev, device_t *phy_dev, uint32_t id)
305 {
306 device_t mdev, pdev;
307
308 mdev = dpaa2_mc_acpi_find_dpaa2_mac_dev(dev, id);
309 if (mdev == NULL) {
310 device_printf(dev, "%s: error finding dpmac device with id=%u\n",
311 __func__, id);
312 return (ENXIO);
313 }
314
315 pdev = dpaa2_mac_dev_get_phy_dev(mdev);
316 if (pdev == NULL) {
317 device_printf(dev, "%s: error getting MDIO device for dpamc %s "
318 "(id=%u)\n", __func__, device_get_nameunit(mdev), id);
319 return (ENXIO);
320 }
321
322 if (phy_dev != NULL)
323 *phy_dev = pdev;
324
325 return (0);
326 }
327
328 static ssize_t
329 dpaa2_mc_acpi_get_property(device_t dev, device_t child, const char *propname,
330 void *propvalue, size_t size, device_property_type_t type)
331 {
332 return (bus_generic_get_property(dev, child, propname, propvalue, size,
333 type));
334 }
335
336 static int
337 dpaa2_mc_acpi_read_ivar(device_t dev, device_t child, int index,
338 uintptr_t *result)
339 {
340 /*
341 * This is special in that it passes "child" as second argument rather
342 * than "dev". acpi_get_handle() in dpaa2_mac_dev_attach() calls the
343 * read on parent(dev), dev and gets us here not to ACPI. Hence we
344 * need to keep child as-is and pass it to our parent which is ACPI.
345 * Only that gives the desired result.
346 */
347 return (BUS_READ_IVAR(device_get_parent(dev), child, index, result));
348 }
349
350 static device_method_t dpaa2_mc_acpi_methods[] = {
351 /* Device interface */
352 DEVMETHOD(device_probe, dpaa2_mc_acpi_probe),
353 DEVMETHOD(device_attach, dpaa2_mc_acpi_attach),
354 DEVMETHOD(device_detach, dpaa2_mc_detach),
355
356 /* Bus interface */
357 DEVMETHOD(bus_alloc_resource, dpaa2_mc_alloc_resource),
358 DEVMETHOD(bus_adjust_resource, dpaa2_mc_adjust_resource),
359 DEVMETHOD(bus_release_resource, dpaa2_mc_release_resource),
360 DEVMETHOD(bus_activate_resource, dpaa2_mc_activate_resource),
361 DEVMETHOD(bus_deactivate_resource, dpaa2_mc_deactivate_resource),
362 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
363 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
364
365 /* Pseudo-PCIB interface */
366 DEVMETHOD(pcib_alloc_msi, dpaa2_mc_alloc_msi),
367 DEVMETHOD(pcib_release_msi, dpaa2_mc_release_msi),
368 DEVMETHOD(pcib_map_msi, dpaa2_mc_map_msi),
369 DEVMETHOD(pcib_get_id, dpaa2_mc_get_id),
370
371 /* DPAA2 MC bus interface */
372 DEVMETHOD(dpaa2_mc_manage_dev, dpaa2_mc_manage_dev),
373 DEVMETHOD(dpaa2_mc_get_free_dev,dpaa2_mc_get_free_dev),
374 DEVMETHOD(dpaa2_mc_get_dev, dpaa2_mc_get_dev),
375 DEVMETHOD(dpaa2_mc_get_shared_dev, dpaa2_mc_get_shared_dev),
376 DEVMETHOD(dpaa2_mc_reserve_dev, dpaa2_mc_reserve_dev),
377 DEVMETHOD(dpaa2_mc_release_dev, dpaa2_mc_release_dev),
378 DEVMETHOD(dpaa2_mc_get_phy_dev, dpaa2_mc_acpi_get_phy_dev),
379
380 /* ACPI compar layer. */
381 DEVMETHOD(bus_read_ivar, dpaa2_mc_acpi_read_ivar),
382 DEVMETHOD(bus_get_property, dpaa2_mc_acpi_get_property),
383
384 DEVMETHOD_END
385 };
386
387 DEFINE_CLASS_1(dpaa2_mc, dpaa2_mc_acpi_driver, dpaa2_mc_acpi_methods,
388 sizeof(struct dpaa2_mc_softc), dpaa2_mc_driver);
389
390 /* Make sure miibus gets procesed first. */
391 DRIVER_MODULE_ORDERED(dpaa2_mc, acpi, dpaa2_mc_acpi_driver, NULL, NULL,
392 SI_ORDER_ANY);
393 MODULE_DEPEND(dpaa2_mc, memac_mdio_acpi, 1, 1, 1);
Cache object: 17e628e467a88e3f7ee764ac844f47f0
|