static const char *const cnxk_gpio_args[] = {
#define CNXK_GPIO_ARG_GPIOCHIP "gpiochip"
CNXK_GPIO_ARG_GPIOCHIP,
+#define CNXK_GPIO_ARG_ALLOWLIST "allowlist"
+ CNXK_GPIO_ARG_ALLOWLIST,
NULL
};
+static char *allowlist;
+
static void
cnxk_gpio_format_name(char *name, size_t len)
{
}
static int
-cnxk_gpio_parse_args(struct cnxk_gpiochip *gpiochip,
- struct rte_devargs *devargs)
+cnxk_gpio_parse_arg_allowlist(const char *key __rte_unused, const char *value,
+ void *extra_args __rte_unused)
+{
+ allowlist = strdup(value);
+ if (!allowlist)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int
+cnxk_gpio_parse_args(struct cnxk_gpiochip *gpiochip, const char *args)
{
struct rte_kvargs *kvlist;
int ret;
- kvlist = rte_kvargs_parse(devargs->args, cnxk_gpio_args);
+ kvlist = rte_kvargs_parse(args, cnxk_gpio_args);
if (!kvlist)
return 0;
goto out;
}
+ ret = rte_kvargs_count(kvlist, CNXK_GPIO_ARG_ALLOWLIST);
+ if (ret == 1) {
+ ret = rte_kvargs_process(kvlist, CNXK_GPIO_ARG_ALLOWLIST,
+ cnxk_gpio_parse_arg_allowlist, NULL);
+ if (ret)
+ goto out;
+ }
+
ret = 0;
out:
rte_kvargs_free(kvlist);
return ret;
}
+static int
+cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip)
+{
+ int i, ret, val, queue = 0;
+ char *token;
+ int *list;
+
+ list = rte_calloc(NULL, gpiochip->num_gpios, sizeof(*list), 0);
+ if (!list)
+ return -ENOMEM;
+
+ /* replace brackets with something meaningless for strtol() */
+ allowlist[0] = ' ';
+ allowlist[strlen(allowlist) - 1] = ' ';
+
+ /* quiesce -Wcast-qual */
+ token = strtok((char *)(uintptr_t)allowlist, ",");
+ do {
+ errno = 0;
+ val = strtol(token, NULL, 10);
+ if (errno) {
+ RTE_LOG(ERR, PMD, "failed to parse %s\n", token);
+ ret = -errno;
+ goto out;
+ }
+
+ if (val < 0 || val >= gpiochip->num_gpios) {
+ RTE_LOG(ERR, PMD, "gpio%d out of 0-%d range\n", val,
+ gpiochip->num_gpios - 1);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < queue; i++) {
+ if (list[i] != val)
+ continue;
+
+ RTE_LOG(WARNING, PMD, "gpio%d already allowed\n", val);
+ break;
+ }
+ if (i == queue)
+ list[queue++] = val;
+ } while ((token = strtok(NULL, ",")));
+
+ gpiochip->allowlist = list;
+ gpiochip->num_queues = queue;
+
+ return 0;
+out:
+ rte_free(list);
+
+ return ret;
+}
+
static int
cnxk_gpio_read_attr(char *attr, char *val)
{
return cnxk_gpio_write_attr(attr, buf);
}
+static bool
+cnxk_gpio_queue_valid(struct cnxk_gpiochip *gpiochip, uint16_t queue)
+{
+ return queue < gpiochip->num_queues;
+}
+
+static int
+cnxk_queue_to_gpio(struct cnxk_gpiochip *gpiochip, uint16_t queue)
+{
+ return gpiochip->allowlist ? gpiochip->allowlist[queue] : queue;
+}
+
static struct cnxk_gpio *
cnxk_gpio_lookup(struct cnxk_gpiochip *gpiochip, uint16_t queue)
{
- if (queue >= gpiochip->num_gpios)
- return NULL;
+ int gpio = cnxk_queue_to_gpio(gpiochip, queue);
- return gpiochip->gpios[queue];
+ return gpiochip->gpios[gpio];
}
static int
struct cnxk_gpiochip *gpiochip = dev->dev_private;
char buf[CNXK_GPIO_BUFSZ];
struct cnxk_gpio *gpio;
- int ret;
+ int num, ret;
RTE_SET_USED(queue_conf);
RTE_SET_USED(queue_conf_size);
+ if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
+ return -EINVAL;
+
gpio = cnxk_gpio_lookup(gpiochip, queue_id);
if (gpio)
return -EEXIST;
gpio = rte_zmalloc(NULL, sizeof(*gpio), 0);
if (!gpio)
return -ENOMEM;
- gpio->num = queue_id + gpiochip->base;
+
+ num = cnxk_queue_to_gpio(gpiochip, queue_id);
+ gpio->num = num + gpiochip->base;
gpio->gpiochip = gpiochip;
snprintf(buf, sizeof(buf), "%s/export", CNXK_GPIO_CLASS_PATH);
return ret;
}
- gpiochip->gpios[queue_id] = gpio;
+ gpiochip->gpios[num] = gpio;
return 0;
}
struct cnxk_gpiochip *gpiochip = dev->dev_private;
char buf[CNXK_GPIO_BUFSZ];
struct cnxk_gpio *gpio;
- int ret;
+ int num, ret;
+
+ if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
+ return -EINVAL;
gpio = cnxk_gpio_lookup(gpiochip, queue_id);
if (!gpio)
return -ENODEV;
snprintf(buf, sizeof(buf), "%s/unexport", CNXK_GPIO_CLASS_PATH);
- ret = cnxk_gpio_write_attr_int(buf, gpiochip->base + queue_id);
+ ret = cnxk_gpio_write_attr_int(buf, gpio->num);
if (ret)
return ret;
- gpiochip->gpios[queue_id] = NULL;
+ num = cnxk_queue_to_gpio(gpiochip, queue_id);
+ gpiochip->gpios[num] = NULL;
rte_free(gpio);
return 0;
cnxk_gpio_queue_def_conf(struct rte_rawdev *dev, uint16_t queue_id,
rte_rawdev_obj_t queue_conf, size_t queue_conf_size)
{
- unsigned int *conf;
+ struct cnxk_gpiochip *gpiochip = dev->dev_private;
+ struct cnxk_gpio_queue_conf *conf = queue_conf;
- RTE_SET_USED(dev);
- RTE_SET_USED(queue_id);
+ if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
+ return -EINVAL;
if (queue_conf_size != sizeof(*conf))
return -EINVAL;
- conf = (unsigned int *)queue_conf;
- *conf = 1;
+ conf->size = 1;
+ conf->gpio = cnxk_queue_to_gpio(gpiochip, queue_id);
return 0;
}
{
struct cnxk_gpiochip *gpiochip = dev->dev_private;
- return gpiochip->num_gpios;
+ return gpiochip->num_queues;
}
static const struct {
return ret;
}
+static bool
+cnxk_gpio_valid(struct cnxk_gpiochip *gpiochip, int gpio)
+{
+ return gpio < gpiochip->num_gpios && gpiochip->gpios[gpio];
+}
+
static int
cnxk_gpio_enqueue_bufs(struct rte_rawdev *dev, struct rte_rawdev_buf **buffers,
unsigned int count, rte_rawdev_obj_t context)
{
struct cnxk_gpiochip *gpiochip = dev->dev_private;
- unsigned int queue = (size_t)context;
+ unsigned int gpio_num = (size_t)context;
struct cnxk_gpio *gpio;
int ret;
if (count == 0)
return 0;
- gpio = cnxk_gpio_lookup(gpiochip, queue);
- if (!gpio)
- return -ENODEV;
+ if (!cnxk_gpio_valid(gpiochip, gpio_num))
+ return -EINVAL;
+ gpio = gpiochip->gpios[gpio_num];
ret = cnxk_gpio_process_buf(gpio, buffers[0]);
if (ret)
unsigned int count, rte_rawdev_obj_t context)
{
struct cnxk_gpiochip *gpiochip = dev->dev_private;
- unsigned int queue = (size_t)context;
+ unsigned int gpio_num = (size_t)context;
struct cnxk_gpio *gpio;
if (count == 0)
return 0;
- gpio = cnxk_gpio_lookup(gpiochip, queue);
- if (!gpio)
- return -ENODEV;
+ if (!cnxk_gpio_valid(gpiochip, gpio_num))
+ return -EINVAL;
+ gpio = gpiochip->gpios[gpio_num];
if (gpio->rsp) {
buffers[0]->buf_addr = gpio->rsp;
cnxk_gpio_set_defaults(gpiochip);
/* defaults may be overwritten by this call */
- ret = cnxk_gpio_parse_args(gpiochip, dev->device.devargs);
+ ret = cnxk_gpio_parse_args(gpiochip, rte_vdev_device_args(dev));
if (ret)
goto out;
RTE_LOG(ERR, PMD, "failed to read %s", buf);
goto out;
}
+ gpiochip->num_queues = gpiochip->num_gpios;
+
+ if (allowlist) {
+ ret = cnxk_gpio_parse_allowlist(gpiochip);
+ free(allowlist);
+ allowlist = NULL;
+ if (ret)
+ goto out;
+ }
gpiochip->gpios = rte_calloc(NULL, gpiochip->num_gpios,
sizeof(struct cnxk_gpio *), 0);
return 0;
out:
+ free(allowlist);
+ rte_free(gpiochip->allowlist);
rte_rawdev_pmd_release(rawdev);
return ret;
cnxk_gpio_queue_release(rawdev, gpio->num);
}
+ rte_free(gpiochip->allowlist);
rte_free(gpiochip->gpios);
cnxk_gpio_irq_fini();
rte_rawdev_pmd_release(rawdev);
};
RTE_PMD_REGISTER_VDEV(cnxk_gpio, cnxk_gpio_drv);
-RTE_PMD_REGISTER_PARAM_STRING(cnxk_gpio, "gpiochip=<int>");
+RTE_PMD_REGISTER_PARAM_STRING(cnxk_gpio,
+ "gpiochip=<int> "
+ "allowlist=<list>");
int
cnxk_gpio_selftest(uint16_t dev_id)
{
+ struct cnxk_gpio_queue_conf conf;
struct cnxk_gpiochip *gpiochip;
- unsigned int queues, i, size;
char buf[CNXK_GPIO_BUFSZ];
struct rte_rawdev *rawdev;
+ unsigned int queues, i;
struct cnxk_gpio *gpio;
- int ret;
+ int ret, ret2;
rawdev = rte_rawdev_pmd_get_named_dev("cnxk_gpio");
gpiochip = rawdev->dev_private;
return -errno;
for (i = 0; i < queues; i++) {
- RTE_LOG(INFO, PMD, "testing queue %d (gpio%d)\n", i,
- gpiochip->base + i);
-
- ret = rte_rawdev_queue_conf_get(dev_id, i, &size, sizeof(size));
+ ret = rte_rawdev_queue_conf_get(dev_id, i, &conf, sizeof(conf));
if (ret) {
RTE_LOG(ERR, PMD,
"failed to read queue configuration (%d)\n",
ret);
- continue;
+ goto out;
}
- if (size != 1) {
+ RTE_LOG(INFO, PMD, "testing queue%d (gpio%d)\n", i, conf.gpio);
+
+ if (conf.size != 1) {
RTE_LOG(ERR, PMD, "wrong queue size received\n");
- continue;
+ ret = -EIO;
+ goto out;
}
ret = rte_rawdev_queue_setup(dev_id, i, NULL, 0);
if (ret) {
RTE_LOG(ERR, PMD, "failed to setup queue (%d)\n", ret);
- continue;
+ goto out;
}
- gpio = gpiochip->gpios[i];
+ gpio = gpiochip->gpios[conf.gpio];
snprintf(buf, sizeof(buf), CNXK_GPIO_PATH_FMT, gpio->num);
if (!cnxk_gpio_attr_exists(buf)) {
RTE_LOG(ERR, PMD, "%s does not exist\n", buf);
- continue;
- }
-
- ret = cnxk_gpio_test_input(dev_id, gpiochip->base, i);
- if (ret)
+ ret = -ENOENT;
goto release;
+ }
- ret = cnxk_gpio_test_irq(dev_id, i);
+ ret = cnxk_gpio_test_input(dev_id, gpiochip->base, conf.gpio);
if (ret)
goto release;
- ret = cnxk_gpio_test_output(dev_id, gpiochip->base, i);
+ ret = cnxk_gpio_test_irq(dev_id, conf.gpio);
if (ret)
goto release;
+ ret = cnxk_gpio_test_output(dev_id, gpiochip->base, conf.gpio);
release:
+ ret2 = ret;
ret = rte_rawdev_queue_release(dev_id, i);
if (ret) {
RTE_LOG(ERR, PMD, "failed to release queue (%d)\n",
ret);
- continue;
+ break;
}
if (cnxk_gpio_attr_exists(buf)) {
RTE_LOG(ERR, PMD, "%s still exists\n", buf);
- continue;
+ ret = -EIO;
+ break;
+ }
+
+ if (ret2) {
+ ret = ret2;
+ break;
}
}
+out:
close(fd);
- return 0;
+ return ret;
}