@@ -21,6 +21,7 @@ Following features are available:
- set GPIO edge that triggers interrupt
- set GPIO active low
- register interrupt handler for specific GPIO
+- multiprocess aware
Requirements
------------
@@ -30,6 +31,12 @@ for installing interrupt handlers for low latency signal processing.
Driver is shipped with Marvell SDK.
+Limitations
+-----------
+
+In multiprocess mode user-space application must ensure no GPIO sharing across
+processes takes place.
+
Device Setup
------------
@@ -19,6 +19,12 @@
#define CNXK_GPIO_BUFSZ 128
#define CNXK_GPIO_CLASS_PATH "/sys/class/gpio"
+#define CNXK_GPIO_PARAMS_MZ_NAME "cnxk_gpio_params_mz"
+
+struct cnxk_gpio_params {
+ unsigned int num;
+ char allowlist[];
+};
static const char *const cnxk_gpio_args[] = {
#define CNXK_GPIO_ARG_GPIOCHIP "gpiochip"
@@ -28,8 +34,6 @@ static const char *const cnxk_gpio_args[] = {
NULL
};
-static char *allowlist;
-
static void
cnxk_gpio_format_name(char *name, size_t len)
{
@@ -44,78 +48,138 @@ cnxk_gpio_filter_gpiochip(const struct dirent *dirent)
return !strncmp(dirent->d_name, pattern, strlen(pattern));
}
-static void
-cnxk_gpio_set_defaults(struct cnxk_gpiochip *gpiochip)
+static int
+cnxk_gpio_set_defaults(struct cnxk_gpio_params *params)
{
struct dirent **namelist;
- int n;
+ int ret = 0, n;
n = scandir(CNXK_GPIO_CLASS_PATH, &namelist, cnxk_gpio_filter_gpiochip,
alphasort);
if (n < 0 || n == 0)
- return;
+ return -ENODEV;
+
+ if (sscanf(namelist[0]->d_name, "gpiochip%d", ¶ms->num) != 1)
+ ret = -EINVAL;
- sscanf(namelist[0]->d_name, "gpiochip%d", &gpiochip->num);
while (n--)
free(namelist[n]);
free(namelist);
+
+ return ret;
}
static int
cnxk_gpio_parse_arg_gpiochip(const char *key __rte_unused, const char *value,
void *extra_args)
{
- long val;
+ unsigned long val;
errno = 0;
- val = strtol(value, NULL, 10);
+ val = strtoul(value, NULL, 10);
if (errno)
return -errno;
- *(int *)extra_args = (int)val;
+ *(unsigned int *)extra_args = val;
return 0;
}
static int
-cnxk_gpio_parse_arg_allowlist(const char *key __rte_unused, const char *value,
- void *extra_args __rte_unused)
+cnxk_gpio_parse_arg_allowlist(const char *key __rte_unused, const char *value, void *extra_args)
{
- allowlist = strdup(value);
- if (!allowlist)
- return -ENOMEM;
+ *(const char **)extra_args = value;
+
+ return 0;
+}
+
+static int
+cnxk_gpio_params_restore(struct cnxk_gpio_params **params)
+{
+ const struct rte_memzone *mz;
+
+ mz = rte_memzone_lookup(CNXK_GPIO_PARAMS_MZ_NAME);
+ if (!mz)
+ return -ENODEV;
+
+ *params = mz->addr;
return 0;
}
+static struct cnxk_gpio_params *
+cnxk_gpio_params_reserve(size_t len)
+{
+ const struct rte_memzone *mz;
+
+ mz = rte_memzone_reserve(CNXK_GPIO_PARAMS_MZ_NAME, len, rte_socket_id(), 0);
+ if (!mz)
+ return NULL;
+
+ return mz->addr;
+}
+
+static void
+cnxk_gpio_params_release(void)
+{
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+ rte_memzone_free(rte_memzone_lookup(CNXK_GPIO_PARAMS_MZ_NAME));
+}
+
static int
-cnxk_gpio_parse_args(struct cnxk_gpiochip *gpiochip, const char *args)
+cnxk_gpio_parse_arg(struct rte_kvargs *kvlist, const char *arg, arg_handler_t handler, void *data)
{
+ int ret;
+
+ ret = rte_kvargs_count(kvlist, arg);
+ if (ret == 0)
+ return 0;
+ if (ret > 1)
+ return -EINVAL;
+
+ return rte_kvargs_process(kvlist, arg, handler, data) ? -EIO : 1;
+}
+
+static int
+cnxk_gpio_parse_store_args(struct cnxk_gpio_params **params, const char *args)
+{
+ size_t len = sizeof(**params);
+ const char *allowlist = NULL;
struct rte_kvargs *kvlist;
int ret;
kvlist = rte_kvargs_parse(args, cnxk_gpio_args);
- if (!kvlist)
- return 0;
+ if (!kvlist) {
+ *params = cnxk_gpio_params_reserve(len);
+ if (!*params)
+ return -ENOMEM;
- ret = rte_kvargs_count(kvlist, CNXK_GPIO_ARG_GPIOCHIP);
- if (ret == 1) {
- ret = rte_kvargs_process(kvlist, CNXK_GPIO_ARG_GPIOCHIP,
- cnxk_gpio_parse_arg_gpiochip,
- &gpiochip->num);
+ ret = cnxk_gpio_set_defaults(*params);
if (ret)
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;
+ return 0;
}
- ret = 0;
+ ret = cnxk_gpio_parse_arg(kvlist, CNXK_GPIO_ARG_ALLOWLIST, cnxk_gpio_parse_arg_allowlist,
+ &allowlist);
+ if (ret < 0)
+ goto out;
+
+ if (allowlist)
+ len += strlen(allowlist) + 1;
+
+ *params = cnxk_gpio_params_reserve(len);
+ if (!(*params))
+ return -ENOMEM;
+
+ strlcpy((*params)->allowlist, allowlist, strlen(allowlist) + 1);
+
+ ret = cnxk_gpio_parse_arg(kvlist, CNXK_GPIO_ARG_GPIOCHIP, cnxk_gpio_parse_arg_gpiochip,
+ &(*params)->num);
+ if (ret == 0)
+ ret = cnxk_gpio_set_defaults(*params);
+
out:
rte_kvargs_free(kvlist);
@@ -123,7 +187,7 @@ cnxk_gpio_parse_args(struct cnxk_gpiochip *gpiochip, const char *args)
}
static int
-cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip)
+cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip, char *allowlist)
{
int i, ret, val, queue = 0;
char *token;
@@ -133,6 +197,12 @@ cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip)
if (!list)
return -ENOMEM;
+ allowlist = strdup(allowlist);
+ if (!allowlist) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
/* replace brackets with something meaningless for strtol() */
allowlist[0] = ' ';
allowlist[strlen(allowlist) - 1] = ' ';
@@ -166,11 +236,13 @@ cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip)
list[queue++] = val;
} while ((token = strtok(NULL, ",")));
+ free(allowlist);
gpiochip->allowlist = list;
gpiochip->num_queues = queue;
return 0;
out:
+ free(allowlist);
rte_free(list);
return ret;
@@ -562,8 +634,7 @@ cnxk_gpio_process_buf(struct cnxk_gpio *gpio, struct rte_rawdev_buf *rbuf)
*(int *)rsp = val;
break;
case CNXK_GPIO_MSG_TYPE_REGISTER_IRQ:
- ret = cnxk_gpio_register_irq(gpio,
- (struct cnxk_gpio_irq *)msg->data);
+ ret = cnxk_gpio_register_irq(gpio, (struct cnxk_gpio_irq *)msg->data);
break;
case CNXK_GPIO_MSG_TYPE_UNREGISTER_IRQ:
ret = cnxk_gpio_unregister_irq(gpio);
@@ -659,17 +730,14 @@ static int
cnxk_gpio_probe(struct rte_vdev_device *dev)
{
char name[RTE_RAWDEV_NAME_MAX_LEN];
+ struct cnxk_gpio_params *params;
struct cnxk_gpiochip *gpiochip;
struct rte_rawdev *rawdev;
char buf[CNXK_GPIO_BUFSZ];
int ret;
- if (rte_eal_process_type() != RTE_PROC_PRIMARY)
- return 0;
-
cnxk_gpio_format_name(name, sizeof(name));
- rawdev = rte_rawdev_pmd_allocate(name, sizeof(*gpiochip),
- rte_socket_id());
+ rawdev = rte_rawdev_pmd_allocate(name, sizeof(*gpiochip), rte_socket_id());
if (!rawdev) {
RTE_LOG(ERR, PMD, "failed to allocate %s rawdev", name);
return -ENOMEM;
@@ -678,22 +746,26 @@ cnxk_gpio_probe(struct rte_vdev_device *dev)
rawdev->dev_ops = &cnxk_gpio_rawdev_ops;
rawdev->device = &dev->device;
rawdev->driver_name = dev->device.name;
-
gpiochip = rawdev->dev_private;
- cnxk_gpio_set_defaults(gpiochip);
- /* defaults may be overwritten by this call */
- ret = cnxk_gpio_parse_args(gpiochip, rte_vdev_device_args(dev));
- if (ret)
- goto out;
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+ ret = cnxk_gpio_parse_store_args(¶ms, rte_vdev_device_args(dev));
+ if (ret < 0)
+ goto out;
+ } else {
+ ret = cnxk_gpio_params_restore(¶ms);
+ if (ret)
+ goto out;
+ }
+
+ gpiochip->num = params->num;
ret = cnxk_gpio_irq_init(gpiochip);
if (ret)
goto out;
/* read gpio base */
- snprintf(buf, sizeof(buf), "%s/gpiochip%d/base", CNXK_GPIO_CLASS_PATH,
- gpiochip->num);
+ snprintf(buf, sizeof(buf), "%s/gpiochip%d/base", CNXK_GPIO_CLASS_PATH, gpiochip->num);
ret = cnxk_gpio_read_attr_int(buf, &gpiochip->base);
if (ret) {
RTE_LOG(ERR, PMD, "failed to read %s", buf);
@@ -701,8 +773,7 @@ cnxk_gpio_probe(struct rte_vdev_device *dev)
}
/* read number of available gpios */
- snprintf(buf, sizeof(buf), "%s/gpiochip%d/ngpio", CNXK_GPIO_CLASS_PATH,
- gpiochip->num);
+ snprintf(buf, sizeof(buf), "%s/gpiochip%d/ngpio", CNXK_GPIO_CLASS_PATH, gpiochip->num);
ret = cnxk_gpio_read_attr_int(buf, &gpiochip->num_gpios);
if (ret) {
RTE_LOG(ERR, PMD, "failed to read %s", buf);
@@ -710,16 +781,13 @@ cnxk_gpio_probe(struct rte_vdev_device *dev)
}
gpiochip->num_queues = gpiochip->num_gpios;
- if (allowlist) {
- ret = cnxk_gpio_parse_allowlist(gpiochip);
- free(allowlist);
- allowlist = NULL;
- if (ret)
- goto out;
+ ret = cnxk_gpio_parse_allowlist(gpiochip, params->allowlist);
+ if (ret) {
+ RTE_LOG(ERR, PMD, "failed to parse allowed gpios\n");
+ goto out;
}
- gpiochip->gpios = rte_calloc(NULL, gpiochip->num_gpios,
- sizeof(struct cnxk_gpio *), 0);
+ gpiochip->gpios = rte_calloc(NULL, gpiochip->num_gpios, sizeof(struct cnxk_gpio *), 0);
if (!gpiochip->gpios) {
RTE_LOG(ERR, PMD, "failed to allocate gpios memory");
ret = -ENOMEM;
@@ -728,8 +796,8 @@ cnxk_gpio_probe(struct rte_vdev_device *dev)
return 0;
out:
- free(allowlist);
rte_free(gpiochip->allowlist);
+ cnxk_gpio_params_release();
rte_rawdev_pmd_release(rawdev);
return ret;
@@ -746,9 +814,6 @@ cnxk_gpio_remove(struct rte_vdev_device *dev)
RTE_SET_USED(dev);
- if (rte_eal_process_type() != RTE_PROC_PRIMARY)
- return 0;
-
cnxk_gpio_format_name(name, sizeof(name));
rawdev = rte_rawdev_pmd_get_named_dev(name);
if (!rawdev)
@@ -769,6 +834,7 @@ cnxk_gpio_remove(struct rte_vdev_device *dev)
rte_free(gpiochip->allowlist);
rte_free(gpiochip->gpios);
cnxk_gpio_irq_fini();
+ cnxk_gpio_params_release();
rte_rawdev_pmd_release(rawdev);
return 0;