146521ca2SGaetan Rivet /* SPDX-License-Identifier: BSD-3-Clause
246521ca2SGaetan Rivet * Copyright 2018 Gaëtan Rivet
346521ca2SGaetan Rivet */
446521ca2SGaetan Rivet
5f1f6ebc0SWilliam Tu #include <sys/queue.h>
6f1f6ebc0SWilliam Tu
7a04322f6SDavid Marchand #include <bus_driver.h>
84410c1b0SGaetan Rivet #include <rte_bus_pci.h>
91acb7f54SDavid Marchand #include <dev_driver.h>
1046521ca2SGaetan Rivet #include <rte_errno.h>
1146521ca2SGaetan Rivet #include <rte_kvargs.h>
12d2a66ad7SXueming Li #include <rte_devargs.h>
1346521ca2SGaetan Rivet #include <rte_pci.h>
14d2a66ad7SXueming Li #include <rte_debug.h>
1546521ca2SGaetan Rivet
1646521ca2SGaetan Rivet #include "private.h"
1746521ca2SGaetan Rivet
1846521ca2SGaetan Rivet enum pci_params {
193f7a40c6SThomas Monjalon RTE_PCI_PARAM_ADDR,
203f7a40c6SThomas Monjalon RTE_PCI_PARAM_MAX,
2146521ca2SGaetan Rivet };
2246521ca2SGaetan Rivet
2346521ca2SGaetan Rivet static const char * const pci_params_keys[] = {
243f7a40c6SThomas Monjalon [RTE_PCI_PARAM_ADDR] = "addr",
253f7a40c6SThomas Monjalon [RTE_PCI_PARAM_MAX] = NULL,
2646521ca2SGaetan Rivet };
2746521ca2SGaetan Rivet
2846521ca2SGaetan Rivet static int
pci_addr_kv_cmp(const char * key __rte_unused,const char * value,void * _addr2)294410c1b0SGaetan Rivet pci_addr_kv_cmp(const char *key __rte_unused,
304410c1b0SGaetan Rivet const char *value,
314410c1b0SGaetan Rivet void *_addr2)
324410c1b0SGaetan Rivet {
334410c1b0SGaetan Rivet struct rte_pci_addr _addr1;
344410c1b0SGaetan Rivet struct rte_pci_addr *addr1 = &_addr1;
354410c1b0SGaetan Rivet struct rte_pci_addr *addr2 = _addr2;
364410c1b0SGaetan Rivet
374410c1b0SGaetan Rivet if (rte_pci_addr_parse(value, addr1))
384410c1b0SGaetan Rivet return -1;
394410c1b0SGaetan Rivet return -abs(rte_pci_addr_cmp(addr1, addr2));
404410c1b0SGaetan Rivet }
414410c1b0SGaetan Rivet
424410c1b0SGaetan Rivet static int
pci_dev_match(const struct rte_device * dev,const void * _kvlist)4346521ca2SGaetan Rivet pci_dev_match(const struct rte_device *dev,
4446521ca2SGaetan Rivet const void *_kvlist)
4546521ca2SGaetan Rivet {
4646521ca2SGaetan Rivet const struct rte_kvargs *kvlist = _kvlist;
474410c1b0SGaetan Rivet const struct rte_pci_device *pdev;
4846521ca2SGaetan Rivet
494410c1b0SGaetan Rivet if (kvlist == NULL)
504410c1b0SGaetan Rivet /* Empty string matches everything. */
514410c1b0SGaetan Rivet return 0;
524410c1b0SGaetan Rivet pdev = RTE_DEV_TO_PCI_CONST(dev);
534410c1b0SGaetan Rivet /* if any field does not match. */
543f7a40c6SThomas Monjalon if (rte_kvargs_process(kvlist, pci_params_keys[RTE_PCI_PARAM_ADDR],
554410c1b0SGaetan Rivet &pci_addr_kv_cmp,
564410c1b0SGaetan Rivet (void *)(intptr_t)&pdev->addr))
574410c1b0SGaetan Rivet return 1;
5846521ca2SGaetan Rivet return 0;
5946521ca2SGaetan Rivet }
6046521ca2SGaetan Rivet
6146521ca2SGaetan Rivet void *
rte_pci_dev_iterate(const void * start,const char * str,const struct rte_dev_iterator * it __rte_unused)6246521ca2SGaetan Rivet rte_pci_dev_iterate(const void *start,
6346521ca2SGaetan Rivet const char *str,
6446521ca2SGaetan Rivet const struct rte_dev_iterator *it __rte_unused)
6546521ca2SGaetan Rivet {
6646521ca2SGaetan Rivet rte_bus_find_device_t find_device;
6746521ca2SGaetan Rivet struct rte_kvargs *kvargs = NULL;
6846521ca2SGaetan Rivet struct rte_device *dev;
6946521ca2SGaetan Rivet
7046521ca2SGaetan Rivet if (str != NULL) {
7146521ca2SGaetan Rivet kvargs = rte_kvargs_parse(str, pci_params_keys);
7246521ca2SGaetan Rivet if (kvargs == NULL) {
73*849f773bSDavid Marchand PCI_LOG(ERR, "cannot parse argument list");
7446521ca2SGaetan Rivet rte_errno = EINVAL;
7546521ca2SGaetan Rivet return NULL;
7646521ca2SGaetan Rivet }
7746521ca2SGaetan Rivet }
7846521ca2SGaetan Rivet find_device = rte_pci_bus.bus.find_device;
7946521ca2SGaetan Rivet dev = find_device(start, pci_dev_match, kvargs);
8046521ca2SGaetan Rivet rte_kvargs_free(kvargs);
8146521ca2SGaetan Rivet return dev;
8246521ca2SGaetan Rivet }
83d2a66ad7SXueming Li
84d2a66ad7SXueming Li int
rte_pci_devargs_parse(struct rte_devargs * da)85d2a66ad7SXueming Li rte_pci_devargs_parse(struct rte_devargs *da)
86d2a66ad7SXueming Li {
87d2a66ad7SXueming Li struct rte_kvargs *kvargs;
88d2a66ad7SXueming Li const char *addr_str;
89d2a66ad7SXueming Li struct rte_pci_addr addr;
905adef306SXueming Li int ret = 0;
91d2a66ad7SXueming Li
925adef306SXueming Li if (da == NULL || da->bus_str == NULL)
93d2a66ad7SXueming Li return 0;
94d2a66ad7SXueming Li
95d2a66ad7SXueming Li kvargs = rte_kvargs_parse(da->bus_str, NULL);
96d2a66ad7SXueming Li if (kvargs == NULL) {
97*849f773bSDavid Marchand PCI_LOG(ERR, "cannot parse argument list: %s", da->bus_str);
98d2a66ad7SXueming Li ret = -ENODEV;
99d2a66ad7SXueming Li goto out;
100d2a66ad7SXueming Li }
101d2a66ad7SXueming Li
102d2a66ad7SXueming Li addr_str = rte_kvargs_get(kvargs, pci_params_keys[RTE_PCI_PARAM_ADDR]);
103d2a66ad7SXueming Li if (addr_str == NULL) {
104*849f773bSDavid Marchand PCI_LOG(DEBUG, "No PCI address specified using '%s=<id>' in: %s",
105d2a66ad7SXueming Li pci_params_keys[RTE_PCI_PARAM_ADDR], da->bus_str);
106d2a66ad7SXueming Li goto out;
107d2a66ad7SXueming Li }
108d2a66ad7SXueming Li
109d2a66ad7SXueming Li ret = rte_pci_addr_parse(addr_str, &addr);
110d2a66ad7SXueming Li if (ret != 0) {
111*849f773bSDavid Marchand PCI_LOG(ERR, "PCI address invalid: %s", da->bus_str);
112d2a66ad7SXueming Li ret = -EINVAL;
113d2a66ad7SXueming Li goto out;
114d2a66ad7SXueming Li }
115d2a66ad7SXueming Li
116d2a66ad7SXueming Li rte_pci_device_name(&addr, da->name, sizeof(da->name));
117d2a66ad7SXueming Li
118d2a66ad7SXueming Li out:
119d2a66ad7SXueming Li rte_kvargs_free(kvargs);
120d2a66ad7SXueming Li if (ret != 0)
121d2a66ad7SXueming Li rte_errno = -ret;
122d2a66ad7SXueming Li return ret;
123d2a66ad7SXueming Li }
124