199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright 2016 NXP
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
599a2dd95SBruce Richardson #include <stdio.h>
699a2dd95SBruce Richardson #include <string.h>
799a2dd95SBruce Richardson #include <sys/queue.h>
899a2dd95SBruce Richardson
9a04322f6SDavid Marchand #include <bus_driver.h>
1099a2dd95SBruce Richardson #include <rte_debug.h>
1199a2dd95SBruce Richardson #include <rte_string_fns.h>
1299a2dd95SBruce Richardson #include <rte_errno.h>
1399a2dd95SBruce Richardson
1499a2dd95SBruce Richardson #include "eal_private.h"
1599a2dd95SBruce Richardson
1699a2dd95SBruce Richardson static struct rte_bus_list rte_bus_list =
1799a2dd95SBruce Richardson TAILQ_HEAD_INITIALIZER(rte_bus_list);
1899a2dd95SBruce Richardson
19148c51a3SDavid Marchand const char *
rte_bus_name(const struct rte_bus * bus)20148c51a3SDavid Marchand rte_bus_name(const struct rte_bus *bus)
21148c51a3SDavid Marchand {
22148c51a3SDavid Marchand return bus->name;
23148c51a3SDavid Marchand }
24148c51a3SDavid Marchand
2599a2dd95SBruce Richardson void
rte_bus_register(struct rte_bus * bus)2699a2dd95SBruce Richardson rte_bus_register(struct rte_bus *bus)
2799a2dd95SBruce Richardson {
2899a2dd95SBruce Richardson RTE_VERIFY(bus);
29148c51a3SDavid Marchand RTE_VERIFY(rte_bus_name(bus) && strlen(rte_bus_name(bus)));
3099a2dd95SBruce Richardson /* A bus should mandatorily have the scan implemented */
3199a2dd95SBruce Richardson RTE_VERIFY(bus->scan);
3299a2dd95SBruce Richardson RTE_VERIFY(bus->probe);
3399a2dd95SBruce Richardson RTE_VERIFY(bus->find_device);
3499a2dd95SBruce Richardson /* Buses supporting driver plug also require unplug. */
3599a2dd95SBruce Richardson RTE_VERIFY(!bus->plug || bus->unplug);
3699a2dd95SBruce Richardson
3799a2dd95SBruce Richardson TAILQ_INSERT_TAIL(&rte_bus_list, bus, next);
38*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Registered [%s] bus.", rte_bus_name(bus));
3999a2dd95SBruce Richardson }
4099a2dd95SBruce Richardson
4199a2dd95SBruce Richardson void
rte_bus_unregister(struct rte_bus * bus)4299a2dd95SBruce Richardson rte_bus_unregister(struct rte_bus *bus)
4399a2dd95SBruce Richardson {
4499a2dd95SBruce Richardson TAILQ_REMOVE(&rte_bus_list, bus, next);
45*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Unregistered [%s] bus.", rte_bus_name(bus));
4699a2dd95SBruce Richardson }
4799a2dd95SBruce Richardson
4899a2dd95SBruce Richardson /* Scan all the buses for registered devices */
4999a2dd95SBruce Richardson int
rte_bus_scan(void)5099a2dd95SBruce Richardson rte_bus_scan(void)
5199a2dd95SBruce Richardson {
5299a2dd95SBruce Richardson int ret;
5399a2dd95SBruce Richardson struct rte_bus *bus = NULL;
5499a2dd95SBruce Richardson
5599a2dd95SBruce Richardson TAILQ_FOREACH(bus, &rte_bus_list, next) {
5699a2dd95SBruce Richardson ret = bus->scan();
5799a2dd95SBruce Richardson if (ret)
58*ae67895bSDavid Marchand EAL_LOG(ERR, "Scan for (%s) bus failed.",
59148c51a3SDavid Marchand rte_bus_name(bus));
6099a2dd95SBruce Richardson }
6199a2dd95SBruce Richardson
6299a2dd95SBruce Richardson return 0;
6399a2dd95SBruce Richardson }
6499a2dd95SBruce Richardson
6599a2dd95SBruce Richardson /* Probe all devices of all buses */
6699a2dd95SBruce Richardson int
rte_bus_probe(void)6799a2dd95SBruce Richardson rte_bus_probe(void)
6899a2dd95SBruce Richardson {
6999a2dd95SBruce Richardson int ret;
7099a2dd95SBruce Richardson struct rte_bus *bus, *vbus = NULL;
7199a2dd95SBruce Richardson
7299a2dd95SBruce Richardson TAILQ_FOREACH(bus, &rte_bus_list, next) {
73148c51a3SDavid Marchand if (!strcmp(rte_bus_name(bus), "vdev")) {
7499a2dd95SBruce Richardson vbus = bus;
7599a2dd95SBruce Richardson continue;
7699a2dd95SBruce Richardson }
7799a2dd95SBruce Richardson
7899a2dd95SBruce Richardson ret = bus->probe();
7999a2dd95SBruce Richardson if (ret)
80*ae67895bSDavid Marchand EAL_LOG(ERR, "Bus (%s) probe failed.",
81148c51a3SDavid Marchand rte_bus_name(bus));
8299a2dd95SBruce Richardson }
8399a2dd95SBruce Richardson
8499a2dd95SBruce Richardson if (vbus) {
8599a2dd95SBruce Richardson ret = vbus->probe();
8699a2dd95SBruce Richardson if (ret)
87*ae67895bSDavid Marchand EAL_LOG(ERR, "Bus (%s) probe failed.",
88148c51a3SDavid Marchand rte_bus_name(vbus));
8999a2dd95SBruce Richardson }
9099a2dd95SBruce Richardson
9199a2dd95SBruce Richardson return 0;
9299a2dd95SBruce Richardson }
9399a2dd95SBruce Richardson
941cab1a40SKevin Laatz /* Clean up all devices of all buses */
951cab1a40SKevin Laatz int
eal_bus_cleanup(void)961cab1a40SKevin Laatz eal_bus_cleanup(void)
971cab1a40SKevin Laatz {
981cab1a40SKevin Laatz int ret = 0;
991cab1a40SKevin Laatz struct rte_bus *bus;
1001cab1a40SKevin Laatz
1011cab1a40SKevin Laatz TAILQ_FOREACH(bus, &rte_bus_list, next) {
1021cab1a40SKevin Laatz if (bus->cleanup == NULL)
1031cab1a40SKevin Laatz continue;
1041cab1a40SKevin Laatz if (bus->cleanup() != 0)
1051cab1a40SKevin Laatz ret = -1;
1061cab1a40SKevin Laatz }
1071cab1a40SKevin Laatz
1081cab1a40SKevin Laatz return ret;
1091cab1a40SKevin Laatz }
1101cab1a40SKevin Laatz
11199a2dd95SBruce Richardson /* Dump information of a single bus */
11299a2dd95SBruce Richardson static int
bus_dump_one(FILE * f,struct rte_bus * bus)11399a2dd95SBruce Richardson bus_dump_one(FILE *f, struct rte_bus *bus)
11499a2dd95SBruce Richardson {
11599a2dd95SBruce Richardson int ret;
11699a2dd95SBruce Richardson
11799a2dd95SBruce Richardson /* For now, dump only the bus name */
118148c51a3SDavid Marchand ret = fprintf(f, " %s\n", rte_bus_name(bus));
11999a2dd95SBruce Richardson
12099a2dd95SBruce Richardson /* Error in case of inability in writing to stream */
12199a2dd95SBruce Richardson if (ret < 0)
12299a2dd95SBruce Richardson return ret;
12399a2dd95SBruce Richardson
12499a2dd95SBruce Richardson return 0;
12599a2dd95SBruce Richardson }
12699a2dd95SBruce Richardson
12799a2dd95SBruce Richardson void
rte_bus_dump(FILE * f)12899a2dd95SBruce Richardson rte_bus_dump(FILE *f)
12999a2dd95SBruce Richardson {
13099a2dd95SBruce Richardson int ret;
13199a2dd95SBruce Richardson struct rte_bus *bus;
13299a2dd95SBruce Richardson
13399a2dd95SBruce Richardson TAILQ_FOREACH(bus, &rte_bus_list, next) {
13499a2dd95SBruce Richardson ret = bus_dump_one(f, bus);
13599a2dd95SBruce Richardson if (ret) {
136*ae67895bSDavid Marchand EAL_LOG(ERR, "Unable to write to stream (%d)",
13799a2dd95SBruce Richardson ret);
13899a2dd95SBruce Richardson break;
13999a2dd95SBruce Richardson }
14099a2dd95SBruce Richardson }
14199a2dd95SBruce Richardson }
14299a2dd95SBruce Richardson
14399a2dd95SBruce Richardson struct rte_bus *
rte_bus_find(const struct rte_bus * start,rte_bus_cmp_t cmp,const void * data)14499a2dd95SBruce Richardson rte_bus_find(const struct rte_bus *start, rte_bus_cmp_t cmp,
14599a2dd95SBruce Richardson const void *data)
14699a2dd95SBruce Richardson {
14799a2dd95SBruce Richardson struct rte_bus *bus;
14899a2dd95SBruce Richardson
14999a2dd95SBruce Richardson if (start != NULL)
15099a2dd95SBruce Richardson bus = TAILQ_NEXT(start, next);
15199a2dd95SBruce Richardson else
15299a2dd95SBruce Richardson bus = TAILQ_FIRST(&rte_bus_list);
15399a2dd95SBruce Richardson while (bus != NULL) {
15499a2dd95SBruce Richardson if (cmp(bus, data) == 0)
15599a2dd95SBruce Richardson break;
15699a2dd95SBruce Richardson bus = TAILQ_NEXT(bus, next);
15799a2dd95SBruce Richardson }
15899a2dd95SBruce Richardson return bus;
15999a2dd95SBruce Richardson }
16099a2dd95SBruce Richardson
16199a2dd95SBruce Richardson static int
cmp_rte_device(const struct rte_device * dev1,const void * _dev2)16299a2dd95SBruce Richardson cmp_rte_device(const struct rte_device *dev1, const void *_dev2)
16399a2dd95SBruce Richardson {
16499a2dd95SBruce Richardson const struct rte_device *dev2 = _dev2;
16599a2dd95SBruce Richardson
16699a2dd95SBruce Richardson return dev1 != dev2;
16799a2dd95SBruce Richardson }
16899a2dd95SBruce Richardson
16999a2dd95SBruce Richardson static int
bus_find_device(const struct rte_bus * bus,const void * _dev)17099a2dd95SBruce Richardson bus_find_device(const struct rte_bus *bus, const void *_dev)
17199a2dd95SBruce Richardson {
17299a2dd95SBruce Richardson struct rte_device *dev;
17399a2dd95SBruce Richardson
17499a2dd95SBruce Richardson dev = bus->find_device(NULL, cmp_rte_device, _dev);
17599a2dd95SBruce Richardson return dev == NULL;
17699a2dd95SBruce Richardson }
17799a2dd95SBruce Richardson
17899a2dd95SBruce Richardson struct rte_bus *
rte_bus_find_by_device(const struct rte_device * dev)17999a2dd95SBruce Richardson rte_bus_find_by_device(const struct rte_device *dev)
18099a2dd95SBruce Richardson {
18199a2dd95SBruce Richardson return rte_bus_find(NULL, bus_find_device, (const void *)dev);
18299a2dd95SBruce Richardson }
18399a2dd95SBruce Richardson
18499a2dd95SBruce Richardson static int
cmp_bus_name(const struct rte_bus * bus,const void * _name)18599a2dd95SBruce Richardson cmp_bus_name(const struct rte_bus *bus, const void *_name)
18699a2dd95SBruce Richardson {
18799a2dd95SBruce Richardson const char *name = _name;
18899a2dd95SBruce Richardson
189148c51a3SDavid Marchand return strcmp(rte_bus_name(bus), name);
19099a2dd95SBruce Richardson }
19199a2dd95SBruce Richardson
19299a2dd95SBruce Richardson struct rte_bus *
rte_bus_find_by_name(const char * busname)19399a2dd95SBruce Richardson rte_bus_find_by_name(const char *busname)
19499a2dd95SBruce Richardson {
19599a2dd95SBruce Richardson return rte_bus_find(NULL, cmp_bus_name, (const void *)busname);
19699a2dd95SBruce Richardson }
19799a2dd95SBruce Richardson
19899a2dd95SBruce Richardson static int
bus_can_parse(const struct rte_bus * bus,const void * _name)19999a2dd95SBruce Richardson bus_can_parse(const struct rte_bus *bus, const void *_name)
20099a2dd95SBruce Richardson {
20199a2dd95SBruce Richardson const char *name = _name;
20299a2dd95SBruce Richardson
20399a2dd95SBruce Richardson return !(bus->parse && bus->parse(name, NULL) == 0);
20499a2dd95SBruce Richardson }
20599a2dd95SBruce Richardson
20699a2dd95SBruce Richardson struct rte_bus *
rte_bus_find_by_device_name(const char * str)20799a2dd95SBruce Richardson rte_bus_find_by_device_name(const char *str)
20899a2dd95SBruce Richardson {
20999a2dd95SBruce Richardson char name[RTE_DEV_NAME_MAX_LEN];
21099a2dd95SBruce Richardson char *c;
21199a2dd95SBruce Richardson
21299a2dd95SBruce Richardson strlcpy(name, str, sizeof(name));
21399a2dd95SBruce Richardson c = strchr(name, ',');
21499a2dd95SBruce Richardson if (c != NULL)
21599a2dd95SBruce Richardson c[0] = '\0';
21699a2dd95SBruce Richardson return rte_bus_find(NULL, bus_can_parse, name);
21799a2dd95SBruce Richardson }
21899a2dd95SBruce Richardson
21999a2dd95SBruce Richardson
22099a2dd95SBruce Richardson /*
22199a2dd95SBruce Richardson * Get iommu class of devices on the bus.
22299a2dd95SBruce Richardson */
22399a2dd95SBruce Richardson enum rte_iova_mode
rte_bus_get_iommu_class(void)22499a2dd95SBruce Richardson rte_bus_get_iommu_class(void)
22599a2dd95SBruce Richardson {
22699a2dd95SBruce Richardson enum rte_iova_mode mode = RTE_IOVA_DC;
22799a2dd95SBruce Richardson bool buses_want_va = false;
22899a2dd95SBruce Richardson bool buses_want_pa = false;
22999a2dd95SBruce Richardson struct rte_bus *bus;
23099a2dd95SBruce Richardson
23199a2dd95SBruce Richardson TAILQ_FOREACH(bus, &rte_bus_list, next) {
23299a2dd95SBruce Richardson enum rte_iova_mode bus_iova_mode;
23399a2dd95SBruce Richardson
23499a2dd95SBruce Richardson if (bus->get_iommu_class == NULL)
23599a2dd95SBruce Richardson continue;
23699a2dd95SBruce Richardson
23799a2dd95SBruce Richardson bus_iova_mode = bus->get_iommu_class();
238*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Bus %s wants IOVA as '%s'",
239148c51a3SDavid Marchand rte_bus_name(bus),
24099a2dd95SBruce Richardson bus_iova_mode == RTE_IOVA_DC ? "DC" :
24199a2dd95SBruce Richardson (bus_iova_mode == RTE_IOVA_PA ? "PA" : "VA"));
242bc97752cSViacheslav Ovsiienko if (bus_iova_mode == RTE_IOVA_PA) {
24399a2dd95SBruce Richardson buses_want_pa = true;
244bc97752cSViacheslav Ovsiienko if (!RTE_IOVA_IN_MBUF)
245*ae67895bSDavid Marchand EAL_LOG(WARNING,
246*ae67895bSDavid Marchand "Bus %s wants IOVA as PA not compatible with 'enable_iova_as_pa=false' build option.",
247bc97752cSViacheslav Ovsiienko rte_bus_name(bus));
248bc97752cSViacheslav Ovsiienko } else if (bus_iova_mode == RTE_IOVA_VA)
24999a2dd95SBruce Richardson buses_want_va = true;
25099a2dd95SBruce Richardson }
25199a2dd95SBruce Richardson if (buses_want_va && !buses_want_pa) {
25299a2dd95SBruce Richardson mode = RTE_IOVA_VA;
25399a2dd95SBruce Richardson } else if (buses_want_pa && !buses_want_va) {
25499a2dd95SBruce Richardson mode = RTE_IOVA_PA;
25599a2dd95SBruce Richardson } else {
25699a2dd95SBruce Richardson mode = RTE_IOVA_DC;
25799a2dd95SBruce Richardson if (buses_want_va) {
258*ae67895bSDavid Marchand EAL_LOG(WARNING, "Some buses want 'VA' but forcing 'DC' because other buses want 'PA'.");
259*ae67895bSDavid Marchand EAL_LOG(WARNING, "Depending on the final decision by the EAL, not all buses may be able to initialize.");
26099a2dd95SBruce Richardson }
26199a2dd95SBruce Richardson }
26299a2dd95SBruce Richardson
26399a2dd95SBruce Richardson return mode;
26499a2dd95SBruce Richardson }
26599a2dd95SBruce Richardson
26699a2dd95SBruce Richardson static int
bus_handle_sigbus(const struct rte_bus * bus,const void * failure_addr)26799a2dd95SBruce Richardson bus_handle_sigbus(const struct rte_bus *bus,
26899a2dd95SBruce Richardson const void *failure_addr)
26999a2dd95SBruce Richardson {
27099a2dd95SBruce Richardson int ret;
27199a2dd95SBruce Richardson
27299a2dd95SBruce Richardson if (!bus->sigbus_handler)
27399a2dd95SBruce Richardson return -1;
27499a2dd95SBruce Richardson
27599a2dd95SBruce Richardson ret = bus->sigbus_handler(failure_addr);
27699a2dd95SBruce Richardson
27799a2dd95SBruce Richardson /* find bus but handle failed, keep the errno be set. */
27899a2dd95SBruce Richardson if (ret < 0 && rte_errno == 0)
27999a2dd95SBruce Richardson rte_errno = ENOTSUP;
28099a2dd95SBruce Richardson
28199a2dd95SBruce Richardson return ret > 0;
28299a2dd95SBruce Richardson }
28399a2dd95SBruce Richardson
28499a2dd95SBruce Richardson int
rte_bus_sigbus_handler(const void * failure_addr)28599a2dd95SBruce Richardson rte_bus_sigbus_handler(const void *failure_addr)
28699a2dd95SBruce Richardson {
28799a2dd95SBruce Richardson struct rte_bus *bus;
28899a2dd95SBruce Richardson
28999a2dd95SBruce Richardson int ret = 0;
29099a2dd95SBruce Richardson int old_errno = rte_errno;
29199a2dd95SBruce Richardson
29299a2dd95SBruce Richardson rte_errno = 0;
29399a2dd95SBruce Richardson
29499a2dd95SBruce Richardson bus = rte_bus_find(NULL, bus_handle_sigbus, failure_addr);
29599a2dd95SBruce Richardson /* can not find bus. */
29699a2dd95SBruce Richardson if (!bus)
29799a2dd95SBruce Richardson return 1;
29899a2dd95SBruce Richardson /* find bus but handle failed, pass on the new errno. */
29999a2dd95SBruce Richardson else if (rte_errno != 0)
30099a2dd95SBruce Richardson return -1;
30199a2dd95SBruce Richardson
30299a2dd95SBruce Richardson /* restore the old errno. */
30399a2dd95SBruce Richardson rte_errno = old_errno;
30499a2dd95SBruce Richardson
30599a2dd95SBruce Richardson return ret;
30699a2dd95SBruce Richardson }
307