From patchwork Fri Apr 11 07:26:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071357 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpD83MBSz1yM4 for ; Fri, 11 Apr 2025 17:27:20 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38nV-0002L9-8G; Fri, 11 Apr 2025 07:27:33 +0000 Received: from smtp-relay-internal-0.internal ([10.131.114.225] helo=smtp-relay-internal-0.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38nS-0002Ht-HP for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:30 +0000 Received: from mail-pg1-f197.google.com (mail-pg1-f197.google.com [209.85.215.197]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id AFE783F169 for ; Fri, 11 Apr 2025 07:27:29 +0000 (UTC) Received: by mail-pg1-f197.google.com with SMTP id 41be03b00d2f7-af53a6bc0b6so804293a12.1 for ; Fri, 11 Apr 2025 00:27:29 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356448; x=1744961248; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=bTSrVK3Uk9AGUWjoNY3dQU4LDAyWoeIvoS1HgfJaNT0=; b=IDV4nLNl0TF3YHVFvHf4yVNa468Uiu7mPazpSU5IpYZTG+vi86HT93dKvfwfYCG66F hw7HXekCZs1mdx4iv6xHmBHceXhqabPvTDa5jswHNZQUGTQxF5kOo9d+Cp6Qs/8mp9an dkt54fkCkHIBnctoi9Nw1N68Mw4vJGk25KuNvI+HOpPg2BuYjXOXEGYbO+2kgtiZUXIe buwWwgyhS7r8IA8OkjbbIwkt58WVzeHniGqlzCZuernqZ60kKCePacmQokXSDQhfwMGP 9nG8SnTBTyLd/aeeBqeILgtrj+fbMgftFtNM+cseCiR10AxvZrKVEWyxT6UDbQ+H70vH wDGw== X-Gm-Message-State: AOJu0Yx0R3iIRvHZF4Q7zyxoFx6sd2ab+t5tfTSNmDDZ1lKSg53WD8N8 Z8d/fuDyTOnxQ5GGpoWNF+ztQzEuyF0e4fAF9Xw3QuS8Iw1fVAdUyFwyCl8UT54IQyXBX4/jStR z0C6WV+ZUXdKDufXRCnM8wSoqVyWtC/H0t3QNaDctPREEewap0MqI6sr0rV13E/LtuP50/Estyg LJbKrj8Rr/Iw== X-Gm-Gg: ASbGncub2ADGN/JwLKeJM+Bvghgoefxf9ihu6SBuPqlMSErbA2smHvx+jkQy4Cct2is 1b/aeB87trNSL/froFnSDnyHNkzSOS+SlIcKychGinTm41Haxx7odDzgmVgIPdnEe+jHRItv77Z 08D+qgh+BkWTFr+PFMC1b5cMD6Hsy26N69u4W803A2kzilAE7PA/R2P0SfW7nRNSnmNS6ys/vVp QLTHr71atumS5f2Vtdx9jBypzt9Xvqpn8fSGljPHjn28OHReCicPktf6Pz0Rz2zkS6xvjISMyd2 hX8Yx0Uy696eLdbu/uDSnKyY2b8K8Q== X-Received: by 2002:a17:903:19ed:b0:224:1eaa:5de1 with SMTP id d9443c01a7336-22bea4ade1fmr24607455ad.18.1744356448158; Fri, 11 Apr 2025 00:27:28 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGkGnJrzGvxV8ZxOfbcen2DqJj+odObE7fVRQ+qXTjnDu7wcbUUQJ9hFAsIaL5vduUGSL+s/A== X-Received: by 2002:a17:903:19ed:b0:224:1eaa:5de1 with SMTP id d9443c01a7336-22bea4ade1fmr24607245ad.18.1744356447644; Fri, 11 Apr 2025 00:27:27 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.26 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:27 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 01/13] gpio: introduce utilities for synchronous fake device creation Date: Fri, 11 Apr 2025 16:26:23 +0900 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 Both gpio-sim and gpio-virtuser share a mechanism to instantiate a platform device, wait for probe completion, and retrieve the probe success or error status synchronously. With gpio-aggregator planned to adopt this approach for its configfs interface, it's time to factor out the common code. Add dev-sync-probe.[ch] to house helper functions used by all such implementations. No functional change. Signed-off-by: Koichiro Den Link: https://lore.kernel.org/r/20250221133501.2203897-2-koichiro.den@canonical.com (cherry picked from commit eb5ab6ffb4ca2d28121455dd7452061367ed5588) Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 3 ++ drivers/gpio/Makefile | 3 ++ drivers/gpio/dev-sync-probe.c | 97 +++++++++++++++++++++++++++++++++++ drivers/gpio/dev-sync-probe.h | 25 +++++++++ 4 files changed, 128 insertions(+) create mode 100644 drivers/gpio/dev-sync-probe.c create mode 100644 drivers/gpio/dev-sync-probe.h diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2be612f9ce55..21ac40bde9c4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1935,3 +1935,6 @@ config GPIO_VIRTUSER endmenu endif + +config DEV_SYNC_PROBE + tristate diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index e6b6355c66d4..a18cf557eca6 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -19,6 +19,9 @@ obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o # directly supported by gpio-generic gpio-generic-$(CONFIG_GPIO_GENERIC) += gpio-mmio.o +# Utilities for drivers that need synchronous fake device creation +obj-$(CONFIG_DEV_SYNC_PROBE) += dev-sync-probe.o + obj-$(CONFIG_GPIO_104_DIO_48E) += gpio-104-dio-48e.o obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o diff --git a/drivers/gpio/dev-sync-probe.c b/drivers/gpio/dev-sync-probe.c new file mode 100644 index 000000000000..9ea733b863b2 --- /dev/null +++ b/drivers/gpio/dev-sync-probe.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Common code for drivers creating fake platform devices. + * + * Provides synchronous device creation: waits for probe completion and + * returns the probe success or error status to the device creator. + * + * Copyright (C) 2021 Bartosz Golaszewski + * Copyright (C) 2025 Koichiro Den + */ + +#include +#include + +#include "dev-sync-probe.h" + +static int dev_sync_probe_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct dev_sync_probe_data *pdata; + struct device *dev = data; + + pdata = container_of(nb, struct dev_sync_probe_data, bus_notifier); + if (!device_match_name(dev, pdata->name)) + return NOTIFY_DONE; + + switch (action) { + case BUS_NOTIFY_BOUND_DRIVER: + pdata->driver_bound = true; + break; + case BUS_NOTIFY_DRIVER_NOT_BOUND: + pdata->driver_bound = false; + break; + default: + return NOTIFY_DONE; + } + + complete(&pdata->probe_completion); + return NOTIFY_OK; +} + +void dev_sync_probe_init(struct dev_sync_probe_data *data) +{ + memset(data, 0, sizeof(*data)); + init_completion(&data->probe_completion); + data->bus_notifier.notifier_call = dev_sync_probe_notifier_call; +} +EXPORT_SYMBOL_GPL(dev_sync_probe_init); + +int dev_sync_probe_register(struct dev_sync_probe_data *data, + struct platform_device_info *pdevinfo) +{ + struct platform_device *pdev; + char *name; + + name = kasprintf(GFP_KERNEL, "%s.%d", pdevinfo->name, pdevinfo->id); + if (!name) + return -ENOMEM; + + data->driver_bound = false; + data->name = name; + reinit_completion(&data->probe_completion); + bus_register_notifier(&platform_bus_type, &data->bus_notifier); + + pdev = platform_device_register_full(pdevinfo); + if (IS_ERR(pdev)) { + bus_unregister_notifier(&platform_bus_type, &data->bus_notifier); + kfree(data->name); + return PTR_ERR(pdev); + } + + wait_for_completion(&data->probe_completion); + bus_unregister_notifier(&platform_bus_type, &data->bus_notifier); + + if (!data->driver_bound) { + platform_device_unregister(pdev); + kfree(data->name); + return -ENXIO; + } + + data->pdev = pdev; + return 0; +} +EXPORT_SYMBOL_GPL(dev_sync_probe_register); + +void dev_sync_probe_unregister(struct dev_sync_probe_data *data) +{ + platform_device_unregister(data->pdev); + kfree(data->name); + data->pdev = NULL; +} +EXPORT_SYMBOL_GPL(dev_sync_probe_unregister); + +MODULE_AUTHOR("Bartosz Golaszewski "); +MODULE_AUTHOR("Koichiro Den "); +MODULE_DESCRIPTION("Utilities for synchronous fake device creation"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/dev-sync-probe.h b/drivers/gpio/dev-sync-probe.h new file mode 100644 index 000000000000..4b3d52b70519 --- /dev/null +++ b/drivers/gpio/dev-sync-probe.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef DEV_SYNC_PROBE_H +#define DEV_SYNC_PROBE_H + +#include +#include +#include + +struct dev_sync_probe_data { + struct platform_device *pdev; + const char *name; + + /* Synchronize with probe */ + struct notifier_block bus_notifier; + struct completion probe_completion; + bool driver_bound; +}; + +void dev_sync_probe_init(struct dev_sync_probe_data *data); +int dev_sync_probe_register(struct dev_sync_probe_data *data, + struct platform_device_info *pdevinfo); +void dev_sync_probe_unregister(struct dev_sync_probe_data *data); + +#endif /* DEV_SYNC_PROBE_H */ From patchwork Fri Apr 11 07:26:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071356 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpD82Wn9z1yLl for ; Fri, 11 Apr 2025 17:27:20 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38nU-0002Kq-Tp; Fri, 11 Apr 2025 07:27:32 +0000 Received: from smtp-relay-internal-1.internal ([10.131.114.114] helo=smtp-relay-internal-1.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38nT-0002IR-2h for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:31 +0000 Received: from mail-pg1-f199.google.com (mail-pg1-f199.google.com [209.85.215.199]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id BB955400AF for ; Fri, 11 Apr 2025 07:27:30 +0000 (UTC) Received: by mail-pg1-f199.google.com with SMTP id 41be03b00d2f7-6c8f99fef10so1773419a12.3 for ; Fri, 11 Apr 2025 00:27:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356449; x=1744961249; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=m5b2WrwstZXzBBtKnhaqZo7EjBKygUuwpAfg2ky8XNw=; b=O+OkvK+rqqpU/nPVozgNbzgLYJ7dcU6a9/dzAWEty9hkdtS3QtqIdTwFHfjgSIxvCN 3o64LFp7lu+Gvu0Tjti0F1Fbs5ByBqiSSex9l7nmCJj9aCc0IKd91F8U31LIqgdsWLh9 5z4gcG0hRbqNzYHNI2uD2cmRERdk3gqrL2GHKkaGJNEsEuKq9P1xKtepJwthLhAG910S hD3UbTcoBWdzTDtUFv0lSjAHuAftdlBxwTRGWHm3GkhOk5PnZxmcrf4+A0ylmqZpNjPb 1lSIV6rEsu4oQrT4+ipgb8ejEyrdG1HdkGxak2v5Tl1HM/G95JrYgXsXomzBE0McKBki Vh/Q== X-Gm-Message-State: AOJu0YzD2TXV/DUpUWQC+3h6xVH0eOv+F56abV0rJyYtkFIFV/BSOGMF AB1S5d0XObOJRrBdx1eOI2+VzkxDCHb0E9Tlinljjnl4HS5ccIiGs7m5nFqzqM4zIsgZMMUr6Wk 7Ptvt0i2kscHQ6FqFbQulsZ7fALumC2TGqHOy6gbuAGv1wjqknLtzPU9uQpuQvctk2Cfi0NH6a0 GiE0D8R5LY/w== X-Gm-Gg: ASbGncv+L874tFK9L2AL1LzW3W7Wz6pBIVpHEhccLaxYnc7f2iaRGymiET5a7CmbfzO YE+5NAs/lO0OK622qHWNGOQCN76akamgVUzyuRzYw9zcOWb847yIcLztIt35FmoBRFQysRAYHB0 utbAq4+KAZQKZcZzcdxZpDme+oRZwq6QJiPsKPyT8MBsYXnrn24+XQ6nmSYY0Y7KF+pgk8WMkGl O0A1lB2a4zB8A+u/gdm4bfassDaXxDtvCuHS0xL71o3mrMN8vMYXsIHCJr/T9XgVGYC9qC6ztS/ lJhf4++LSVPimvYN+7Fq4NomQYeb+Q== X-Received: by 2002:a17:903:41ce:b0:226:252e:b6ef with SMTP id d9443c01a7336-22bea4a1d3emr21760665ad.7.1744356449250; Fri, 11 Apr 2025 00:27:29 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEhHLvOVDphqxGF//GVU5Qph1d4iC/HrAs+mK53kHFid9Phv/j2eTi+52NHhGxOXzhaYPDhnA== X-Received: by 2002:a17:903:41ce:b0:226:252e:b6ef with SMTP id d9443c01a7336-22bea4a1d3emr21760475ad.7.1744356448804; Fri, 11 Apr 2025 00:27:28 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.27 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:28 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 02/13] gpio: aggregator: simplify aggr_parse() with scoped bitmap Date: Fri, 11 Apr 2025 16:26:24 +0900 Message-ID: <88e17402e7621f8410c669229baee7bd4892ae6a.1744350629.git.koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Bartosz Golaszewski BugLink: https://bugs.launchpad.net/bugs/2103496 The bitmap allocated in aggr_parse() is always freed before the function returns so use __free(bitmap) to simplify it and drop the goto label. Reviewed-by: Linus Walleij Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240930163207.80276-1-brgl@bgdev.pl Signed-off-by: Bartosz Golaszewski (cherry picked from commit 22dec5aa596ef805cccbcd3fbe5ebffbcb4fa559) Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 38e0fff9afe7..65f41cc3eafc 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -65,11 +65,11 @@ static int aggr_parse(struct gpio_aggregator *aggr) { char *args = skip_spaces(aggr->args); char *name, *offsets, *p; - unsigned long *bitmap; unsigned int i, n = 0; int error = 0; - bitmap = bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL); + unsigned long *bitmap __free(bitmap) = + bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL); if (!bitmap) return -ENOMEM; @@ -82,7 +82,7 @@ static int aggr_parse(struct gpio_aggregator *aggr) /* Named GPIO line */ error = aggr_add_gpio(aggr, name, U16_MAX, &n); if (error) - goto free_bitmap; + return error; name = offsets; continue; @@ -92,13 +92,13 @@ static int aggr_parse(struct gpio_aggregator *aggr) error = bitmap_parselist(offsets, bitmap, AGGREGATOR_MAX_GPIOS); if (error) { pr_err("Cannot parse %s: %d\n", offsets, error); - goto free_bitmap; + return error; } for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { error = aggr_add_gpio(aggr, name, i, &n); if (error) - goto free_bitmap; + return error; } args = next_arg(args, &name, &p); @@ -106,12 +106,10 @@ static int aggr_parse(struct gpio_aggregator *aggr) if (!n) { pr_err("No GPIOs specified\n"); - error = -EINVAL; + return -EINVAL; } -free_bitmap: - bitmap_free(bitmap); - return error; + return 0; } static ssize_t new_device_store(struct device_driver *driver, const char *buf, From patchwork Fri Apr 11 07:26:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071358 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpDB389rz1yHt for ; Fri, 11 Apr 2025 17:27:22 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38nX-0002OW-Nn; Fri, 11 Apr 2025 07:27:35 +0000 Received: from smtp-relay-internal-0.internal ([10.131.114.225] helo=smtp-relay-internal-0.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38nW-0002Mj-Eu for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:34 +0000 Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 34FCC3F169 for ; Fri, 11 Apr 2025 07:27:32 +0000 (UTC) Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-2242ce15cc3so13868475ad.1 for ; Fri, 11 Apr 2025 00:27:32 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356450; x=1744961250; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=512ty5KKynv5bozfQVKcLi1tWYbnfRanlAvdcNmnRTk=; b=oskGdsziyexqQoXCVc7W7da9EPxJRcpA6iN4oTzSK3eNr5Ww8wWE/j8B0sy2mf/7DC LLo7vXUhiYNwtXoEBPB2ZV48nj/jcR/nbanbjs6j2K0rYYXuZy7rifhpwpwFPXd+KWhh 2zOWx5hGGHDIw/J3YyC8Lp+wPUgPMbezYZ4tVgYLD4KtgTQJ4fvn6pKdFYncPIFR4mEU W69Sa3WrmETF8eZfN6AtYRL8d+uNzLympp184MRU2zcs7ZHgcKbhyQLvGbnXbtX75cVV tJdqkDY92x1Spxk0EsCMoIahVo4TftVvMd24Y8lIORFkMxZU/lEGE+Vhi1YfOUr4ydap aW/g== X-Gm-Message-State: AOJu0Yw+euo5gjywuBHxczBaA/YVhlSGRuCGKeyCKLRCgdkYhz6zAXPm 4WYNPcI06iZ22fXoV/M0YjZOG4zF06Xbw2QyWca6dDyoeWL3TVH/jXsy819T3n1xNPDm/7KRkCP 2jON6QCfJ4WnvqNnOl+NXv0YAFFcSXNa/A30RvCtqrlCXlu1YlgFutjck/NMh4+1vVlnk5R7nVb EkQ3R6Hwds/Q== X-Gm-Gg: ASbGncvQj4HFD+xI5AnXrpzT2rd6iO76pDpqaQhBAanL0Sxf3IV+3yHB0LesIr4O1Qd Ay8pY1fFLRwFRwWwspleyH2ULMRQ7Tw5ZeCWgxGfsmMD9hiz6N7mp/jKPxc8drU7oFGH8UZ2oez ogH4yGriEO48/G17538FLn7OR+de+DjCvqVvCt7MnquEgZn6B2VTZOnh+pDBVI21bUMR3uAZn8l enP/CefxhHDvvb3uFRrrl+kb0vEzG0PWXFp9468qvlq16PumA3MRm4qm/WCAq97l7HmWHOu9iAQ 703+HrMzlAOPNhuO/zzhL3LNNf7S8g== X-Received: by 2002:a17:902:f710:b0:223:39ae:a98 with SMTP id d9443c01a7336-22bea4abaa9mr29472205ad.22.1744356450528; Fri, 11 Apr 2025 00:27:30 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHJC/u6cQUn/+3GerJ+JOVFXqpL6IIhsNlMgn2KMTvN4rmqT1jilmzDShIDo9rC0est7FZ36w== X-Received: by 2002:a17:902:f710:b0:223:39ae:a98 with SMTP id d9443c01a7336-22bea4abaa9mr29471975ad.22.1744356450098; Fri, 11 Apr 2025 00:27:30 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.29 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:29 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 03/13] gpio: aggregator: protect driver attr handlers against module unload Date: Fri, 11 Apr 2025 16:26:25 +0900 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 Both new_device_store and delete_device_store touch module global resources (e.g. gpio_aggregator_lock). To prevent race conditions with module unload, a reference needs to be held. Add try_module_get() in these handlers. For new_device_store, this eliminates what appears to be the most dangerous scenario: if an id is allocated from gpio_aggregator_idr but platform_device_register has not yet been called or completed, a concurrent module unload could fail to unregister/delete the device, leaving behind a dangling platform device/GPIO forwarder. This can result in various issues. The following simple reproducer demonstrates these problems: #!/bin/bash while :; do # note: whether 'gpiochip0 0' exists or not does not matter. echo 'gpiochip0 0' > /sys/bus/platform/drivers/gpio-aggregator/new_device done & while :; do modprobe gpio-aggregator modprobe -r gpio-aggregator done & wait Starting with the following warning, several kinds of warnings will appear and the system may become unstable: ------------[ cut here ]------------ list_del corruption, ffff888103e2e980->next is LIST_POISON1 (dead000000000100) WARNING: CPU: 1 PID: 1327 at lib/list_debug.c:56 __list_del_entry_valid_or_report+0xa3/0x120 [...] RIP: 0010:__list_del_entry_valid_or_report+0xa3/0x120 [...] Call Trace: ? __list_del_entry_valid_or_report+0xa3/0x120 ? __warn.cold+0x93/0xf2 ? __list_del_entry_valid_or_report+0xa3/0x120 ? report_bug+0xe6/0x170 ? __irq_work_queue_local+0x39/0xe0 ? handle_bug+0x58/0x90 ? exc_invalid_op+0x13/0x60 ? asm_exc_invalid_op+0x16/0x20 ? __list_del_entry_valid_or_report+0xa3/0x120 gpiod_remove_lookup_table+0x22/0x60 new_device_store+0x315/0x350 [gpio_aggregator] kernfs_fop_write_iter+0x137/0x1f0 vfs_write+0x262/0x430 ksys_write+0x60/0xd0 do_syscall_64+0x6c/0x180 entry_SYSCALL_64_after_hwframe+0x76/0x7e [...] ---[ end trace 0000000000000000 ]--- Fixes: 828546e24280 ("gpio: Add GPIO Aggregator") Cc: stable@vger.kernel.org Signed-off-by: Koichiro Den Link: https://lore.kernel.org/r/20250224143134.3024598-2-koichiro.den@canonical.com Signed-off-by: Bartosz Golaszewski (cherry picked from commit 12f65d1203507f7db3ba59930fe29a3b8eee9945) Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 65f41cc3eafc..d668ddb2e81d 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -119,10 +119,15 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, struct platform_device *pdev; int res, id; + if (!try_module_get(THIS_MODULE)) + return -ENOENT; + /* kernfs guarantees string termination, so count + 1 is safe */ aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); - if (!aggr) - return -ENOMEM; + if (!aggr) { + res = -ENOMEM; + goto put_module; + } memcpy(aggr->args, buf, count + 1); @@ -161,6 +166,7 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, } aggr->pdev = pdev; + module_put(THIS_MODULE); return count; remove_table: @@ -175,6 +181,8 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, kfree(aggr->lookups); free_ga: kfree(aggr); +put_module: + module_put(THIS_MODULE); return res; } @@ -203,13 +211,19 @@ static ssize_t delete_device_store(struct device_driver *driver, if (error) return error; + if (!try_module_get(THIS_MODULE)) + return -ENOENT; + mutex_lock(&gpio_aggregator_lock); aggr = idr_remove(&gpio_aggregator_idr, id); mutex_unlock(&gpio_aggregator_lock); - if (!aggr) + if (!aggr) { + module_put(THIS_MODULE); return -ENOENT; + } gpio_aggregator_free(aggr); + module_put(THIS_MODULE); return count; } static DRIVER_ATTR_WO(delete_device); From patchwork Fri Apr 11 07:26:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071360 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpDC3mRVz1yHt for ; Fri, 11 Apr 2025 17:27:23 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38nY-0002Ox-32; Fri, 11 Apr 2025 07:27:36 +0000 Received: from smtp-relay-internal-0.internal ([10.131.114.225] helo=smtp-relay-internal-0.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38nX-0002OM-JL for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:35 +0000 Received: from mail-pj1-f71.google.com (mail-pj1-f71.google.com [209.85.216.71]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 9B6063F169 for ; Fri, 11 Apr 2025 07:27:34 +0000 (UTC) Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-2ff6aaa18e8so1544004a91.1 for ; Fri, 11 Apr 2025 00:27:34 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356452; x=1744961252; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=qAD8crgP1GwovrXi5PAYv3n6vbP3h72slPcyr4t71sE=; b=sxsqMiYAepBFrYHhNZEo+FaNaxn2LFOdZrysCFtJvZ91gM7eDUIymYB7Mlye+WTQBW wg23zPnTr7aTAorqFzcB6YGs3TkD5wJNvKlib2Wr3sHsk12o4eGdzPpnYRkvNcHQCJha N52Vvd8zV/qAp9CNHFSzcAzFa9vzH23qTVhUMm1RxCoNO8W4YSPMdrw1naQKXQVssCiP 5g+Bb0cHuAa0DmDlv7HfTpU5cYmZJASL3eeiok0NPbHTnC2SzQLJYCct9NqaKF53hY77 zYoyqho5Ntxx4utpuCQVc1CsBA6XQk2Dk750oXmApqbwLsj/nogBf+aHKRUCjmAxB6gm JeKg== X-Gm-Message-State: AOJu0YwLaiwzL9bHefBbz0FBOnP3MMTSQvrVuR2LFYtp+ukHQ9Dgxr3K 1rEnl4+Lbr44OhpPVM5MHNSyuirpeDZ63yelQUXWmGwN7znW6lHOpFIYn9EPvNdUufKfVdj+kHA iojZXXai3m3WCJaV6nghLmhfWnNGOoi615Sfk7Rlpf+4ql0A6JSg1wmphtvT7S+sNtweGjnLfZA +qp9fT1leCGw== X-Gm-Gg: ASbGnct7uBVUacLEdAaW4JkaCLPKAU4tBPj+QF+Sve78hTgSUEI1cErX7FRwGBLWox1 5VDvr2M2j8JSBp3dl0ucpeswnf2f2lpQvit3BPI1zk1nTvqO0FK8/B5E9oBd9ZpjlfmHalYV+KA 2nRg8uEUaXl/BtuG5IxrV1yrLBAWsjxUEJaB3WjFtVbfiU5IX3qai0P/zE938CUEtGUkL5Qb+xD nyd0M0t7+JHomAZ5g7CacPlqORaaB/Hz2I1Uiub8g9qQL+z8/okfpZCm+0aMsy/Lugrhp775v2j 8VW2zxkekjmyj8Uo0h5cC1fxceSf4Q== X-Received: by 2002:a17:90b:4c03:b0:2fe:d766:ad95 with SMTP id 98e67ed59e1d1-30823670243mr2994871a91.9.1744356451708; Fri, 11 Apr 2025 00:27:31 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFvXIJJKuXbRaxJyHJn3VAqKYqZQ9/1ZZronOZ8lxHN6JqLk+QarRC39JNx4Tb+/ALWMKBzQQ== X-Received: by 2002:a17:90b:4c03:b0:2fe:d766:ad95 with SMTP id 98e67ed59e1d1-30823670243mr2994845a91.9.1744356451277; Fri, 11 Apr 2025 00:27:31 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.30 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:31 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 04/13] gpio: aggregator: reorder functions to prepare for configfs introduction Date: Fri, 11 Apr 2025 16:26:26 +0900 Message-ID: <6c16af2d91cc1635bf75ebb96394c171d11f38f8.1744350629.git.koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 Reorder functions in drivers/gpio/gpio-aggregator.c to prepare for the configfs-based interface additions in subsequent commits. Arrange the code so that the configfs implementations will appear above the existing sysfs-specific code, since the latter will partly depend on the configfs interface implementations when it starts to expose the settings to configfs. The order in drivers/gpio/gpio-aggregator.c will be as follows: * Basic gpio_aggregator/gpio_aggregator_line representations * Common utility functions * GPIO Forwarder implementations * Configfs interface implementations * Sysfs interface implementations * Platform device implementations * Module init/exit implementations This separate commit ensures a clean diff for the subsequent commits. No functional change. Reviewed-by: Geert Uytterhoeven (cherry picked from commit 7a56efeabffd13a162073068b8e29113c65f9e64 linux-next) Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 380 +++++++++++++++++---------------- 1 file changed, 192 insertions(+), 188 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index d668ddb2e81d..893cd56de867 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -61,194 +61,6 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key, return 0; } -static int aggr_parse(struct gpio_aggregator *aggr) -{ - char *args = skip_spaces(aggr->args); - char *name, *offsets, *p; - unsigned int i, n = 0; - int error = 0; - - unsigned long *bitmap __free(bitmap) = - bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL); - if (!bitmap) - return -ENOMEM; - - args = next_arg(args, &name, &p); - while (*args) { - args = next_arg(args, &offsets, &p); - - p = get_options(offsets, 0, &error); - if (error == 0 || *p) { - /* Named GPIO line */ - error = aggr_add_gpio(aggr, name, U16_MAX, &n); - if (error) - return error; - - name = offsets; - continue; - } - - /* GPIO chip + offset(s) */ - error = bitmap_parselist(offsets, bitmap, AGGREGATOR_MAX_GPIOS); - if (error) { - pr_err("Cannot parse %s: %d\n", offsets, error); - return error; - } - - for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { - error = aggr_add_gpio(aggr, name, i, &n); - if (error) - return error; - } - - args = next_arg(args, &name, &p); - } - - if (!n) { - pr_err("No GPIOs specified\n"); - return -EINVAL; - } - - return 0; -} - -static ssize_t new_device_store(struct device_driver *driver, const char *buf, - size_t count) -{ - struct gpio_aggregator *aggr; - struct platform_device *pdev; - int res, id; - - if (!try_module_get(THIS_MODULE)) - return -ENOENT; - - /* kernfs guarantees string termination, so count + 1 is safe */ - aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); - if (!aggr) { - res = -ENOMEM; - goto put_module; - } - - memcpy(aggr->args, buf, count + 1); - - aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1), - GFP_KERNEL); - if (!aggr->lookups) { - res = -ENOMEM; - goto free_ga; - } - - mutex_lock(&gpio_aggregator_lock); - id = idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL); - mutex_unlock(&gpio_aggregator_lock); - - if (id < 0) { - res = id; - goto free_table; - } - - aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id); - if (!aggr->lookups->dev_id) { - res = -ENOMEM; - goto remove_idr; - } - - res = aggr_parse(aggr); - if (res) - goto free_dev_id; - - gpiod_add_lookup_table(aggr->lookups); - - pdev = platform_device_register_simple(DRV_NAME, id, NULL, 0); - if (IS_ERR(pdev)) { - res = PTR_ERR(pdev); - goto remove_table; - } - - aggr->pdev = pdev; - module_put(THIS_MODULE); - return count; - -remove_table: - gpiod_remove_lookup_table(aggr->lookups); -free_dev_id: - kfree(aggr->lookups->dev_id); -remove_idr: - mutex_lock(&gpio_aggregator_lock); - idr_remove(&gpio_aggregator_idr, id); - mutex_unlock(&gpio_aggregator_lock); -free_table: - kfree(aggr->lookups); -free_ga: - kfree(aggr); -put_module: - module_put(THIS_MODULE); - return res; -} - -static DRIVER_ATTR_WO(new_device); - -static void gpio_aggregator_free(struct gpio_aggregator *aggr) -{ - platform_device_unregister(aggr->pdev); - gpiod_remove_lookup_table(aggr->lookups); - kfree(aggr->lookups->dev_id); - kfree(aggr->lookups); - kfree(aggr); -} - -static ssize_t delete_device_store(struct device_driver *driver, - const char *buf, size_t count) -{ - struct gpio_aggregator *aggr; - unsigned int id; - int error; - - if (!str_has_prefix(buf, DRV_NAME ".")) - return -EINVAL; - - error = kstrtouint(buf + strlen(DRV_NAME "."), 10, &id); - if (error) - return error; - - if (!try_module_get(THIS_MODULE)) - return -ENOENT; - - mutex_lock(&gpio_aggregator_lock); - aggr = idr_remove(&gpio_aggregator_idr, id); - mutex_unlock(&gpio_aggregator_lock); - if (!aggr) { - module_put(THIS_MODULE); - return -ENOENT; - } - - gpio_aggregator_free(aggr); - module_put(THIS_MODULE); - return count; -} -static DRIVER_ATTR_WO(delete_device); - -static struct attribute *gpio_aggregator_attrs[] = { - &driver_attr_new_device.attr, - &driver_attr_delete_device.attr, - NULL -}; -ATTRIBUTE_GROUPS(gpio_aggregator); - -static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data) -{ - gpio_aggregator_free(p); - return 0; -} - -static void __exit gpio_aggregator_remove_all(void) -{ - mutex_lock(&gpio_aggregator_lock); - idr_for_each(&gpio_aggregator_idr, gpio_aggregator_idr_remove, NULL); - idr_destroy(&gpio_aggregator_idr); - mutex_unlock(&gpio_aggregator_lock); -} - /* * GPIO Forwarder @@ -573,6 +385,184 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, } +/* + * Sysfs interface + */ +static int aggr_parse(struct gpio_aggregator *aggr) +{ + char *args = skip_spaces(aggr->args); + char *name, *offsets, *p; + unsigned int i, n = 0; + int error = 0; + + unsigned long *bitmap __free(bitmap) = + bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL); + if (!bitmap) + return -ENOMEM; + + args = next_arg(args, &name, &p); + while (*args) { + args = next_arg(args, &offsets, &p); + + p = get_options(offsets, 0, &error); + if (error == 0 || *p) { + /* Named GPIO line */ + error = aggr_add_gpio(aggr, name, U16_MAX, &n); + if (error) + return error; + + name = offsets; + continue; + } + + /* GPIO chip + offset(s) */ + error = bitmap_parselist(offsets, bitmap, AGGREGATOR_MAX_GPIOS); + if (error) { + pr_err("Cannot parse %s: %d\n", offsets, error); + return error; + } + + for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { + error = aggr_add_gpio(aggr, name, i, &n); + if (error) + return error; + } + + args = next_arg(args, &name, &p); + } + + if (!n) { + pr_err("No GPIOs specified\n"); + return -EINVAL; + } + + return 0; +} + +static ssize_t new_device_store(struct device_driver *driver, const char *buf, + size_t count) +{ + struct gpio_aggregator *aggr; + struct platform_device *pdev; + int res, id; + + if (!try_module_get(THIS_MODULE)) + return -ENOENT; + + /* kernfs guarantees string termination, so count + 1 is safe */ + aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); + if (!aggr) { + res = -ENOMEM; + goto put_module; + } + + memcpy(aggr->args, buf, count + 1); + + aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1), + GFP_KERNEL); + if (!aggr->lookups) { + res = -ENOMEM; + goto free_ga; + } + + mutex_lock(&gpio_aggregator_lock); + id = idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL); + mutex_unlock(&gpio_aggregator_lock); + + if (id < 0) { + res = id; + goto free_table; + } + + aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id); + if (!aggr->lookups->dev_id) { + res = -ENOMEM; + goto remove_idr; + } + + res = aggr_parse(aggr); + if (res) + goto free_dev_id; + + gpiod_add_lookup_table(aggr->lookups); + + pdev = platform_device_register_simple(DRV_NAME, id, NULL, 0); + if (IS_ERR(pdev)) { + res = PTR_ERR(pdev); + goto remove_table; + } + + aggr->pdev = pdev; + module_put(THIS_MODULE); + return count; + +remove_table: + gpiod_remove_lookup_table(aggr->lookups); +free_dev_id: + kfree(aggr->lookups->dev_id); +remove_idr: + mutex_lock(&gpio_aggregator_lock); + idr_remove(&gpio_aggregator_idr, id); + mutex_unlock(&gpio_aggregator_lock); +free_table: + kfree(aggr->lookups); +free_ga: + kfree(aggr); +put_module: + module_put(THIS_MODULE); + return res; +} + +static DRIVER_ATTR_WO(new_device); + +static void gpio_aggregator_free(struct gpio_aggregator *aggr) +{ + platform_device_unregister(aggr->pdev); + gpiod_remove_lookup_table(aggr->lookups); + kfree(aggr->lookups->dev_id); + kfree(aggr->lookups); + kfree(aggr); +} + +static ssize_t delete_device_store(struct device_driver *driver, + const char *buf, size_t count) +{ + struct gpio_aggregator *aggr; + unsigned int id; + int error; + + if (!str_has_prefix(buf, DRV_NAME ".")) + return -EINVAL; + + error = kstrtouint(buf + strlen(DRV_NAME "."), 10, &id); + if (error) + return error; + + if (!try_module_get(THIS_MODULE)) + return -ENOENT; + + mutex_lock(&gpio_aggregator_lock); + aggr = idr_remove(&gpio_aggregator_idr, id); + mutex_unlock(&gpio_aggregator_lock); + if (!aggr) { + module_put(THIS_MODULE); + return -ENOENT; + } + + gpio_aggregator_free(aggr); + module_put(THIS_MODULE); + return count; +} +static DRIVER_ATTR_WO(delete_device); + +static struct attribute *gpio_aggregator_attrs[] = { + &driver_attr_new_device.attr, + &driver_attr_delete_device.attr, + NULL +}; +ATTRIBUTE_GROUPS(gpio_aggregator); + + /* * GPIO Aggregator platform device */ @@ -630,6 +620,20 @@ static struct platform_driver gpio_aggregator_driver = { }, }; +static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data) +{ + gpio_aggregator_free(p); + return 0; +} + +static void __exit gpio_aggregator_remove_all(void) +{ + mutex_lock(&gpio_aggregator_lock); + idr_for_each(&gpio_aggregator_idr, gpio_aggregator_idr_remove, NULL); + idr_destroy(&gpio_aggregator_idr); + mutex_unlock(&gpio_aggregator_lock); +} + static int __init gpio_aggregator_init(void) { return platform_driver_register(&gpio_aggregator_driver); From patchwork Fri Apr 11 07:26:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071359 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpDC2Lm4z1yJZ for ; Fri, 11 Apr 2025 17:27:23 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38nY-0002Pq-GX; Fri, 11 Apr 2025 07:27:36 +0000 Received: from smtp-relay-internal-1.internal ([10.131.114.114] helo=smtp-relay-internal-1.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38nW-0002NC-R4 for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:34 +0000 Received: from mail-pj1-f69.google.com (mail-pj1-f69.google.com [209.85.216.69]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 9F7C7400AF for ; Fri, 11 Apr 2025 07:27:34 +0000 (UTC) Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-2ff52e1c56fso2114714a91.2 for ; Fri, 11 Apr 2025 00:27:34 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356453; x=1744961253; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=tV2PFa98tVyrVVP+npSmDplUBtTKAnGTyIxrNUDrPw0=; b=daUxeQfp393g1KYLKpeCVJia021ihm0rZhE8k6D7X/Cwk2s0b1xTJalGMXYkiAVSsk gEK0vr9zFolBWfYbx6wpYQU28KB6/VKuLZgrSGt9ZBxF7LKFkm/qrgCGVV5sg78ScXZY lQY+QhBq8faj3N+hjbqFmLFy9ineI4yf3USYPsYFzjctlWEH6H6Lh6ChsO9r2LjEN5E5 FlhymyQAaNBMWX7TZru1j7dbbftAv6eyOQpYg85B2/KHMaGHTyAbDOAzwMWzmKe6AHS6 tJqi/diWvGWyMimGXgtDzh3dLNG7flcTflVyvpFuUIhIWz9OZnu14aN1YoMjAiqqTsWm a22A== X-Gm-Message-State: AOJu0Yy3LbqsFOjuo52bm6wnOFIulRsuznFHbc9Ducr3FFScyo/Tvlwg nMDVZhc08vaAj2yWz8r7VGjHmgFE1pUMa7w9x60cjyYzp/0/HT3NUTDABpUdTY5ntCFyq5lZH1v dAux8uBx+cGupyxEXsyVz6ezzvVholHlD9CAnUoQlC3lomf1oSIqkh0r+gfNWjsN7APJLQIH98x LbpFdqdkGK1g== X-Gm-Gg: ASbGncucNg1jRuSvAvE1Eo8V6uTx/smVqKIbu2Y8I4xlXkEvpbuf+nVhztTfo3JIRbE vgadcEEk7eH0xznDdqKR5sf+VYngwqdtVGuNPGoezzcN3+ovhMw5YOz4Zfe+ozj5lZvSG4123VA cvONJMZvIjTInNN6KnH3EFwXpryY68sQweBf1diEOGkqRC0A5kWUBXq5cHZtKLk4aSJK4R7Av4y 1aO+yvCtMbLbaKJDIsYWAS3Y2C7TLOXs9Kc4sc1xaLTuSRX876T28xIVUqOudmvv77SZYms52qA 8BIcfkJBtv0/ofvjPD9wh4z/eb4GnA== X-Received: by 2002:a17:90b:534d:b0:2fa:17dd:6afa with SMTP id 98e67ed59e1d1-30823646a87mr3379005a91.17.1744356452930; Fri, 11 Apr 2025 00:27:32 -0700 (PDT) X-Google-Smtp-Source: AGHT+IH1DEMCJuP3Pa/EuHcF9OhkJT53XXIj0seshINRmUvNNI5ouhXycObheSt6ohElLZhn+5i8JA== X-Received: by 2002:a17:90b:534d:b0:2fa:17dd:6afa with SMTP id 98e67ed59e1d1-30823646a87mr3378978a91.17.1744356452538; Fri, 11 Apr 2025 00:27:32 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.31 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:32 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 05/13] gpio: aggregator: unify function naming Date: Fri, 11 Apr 2025 16:26:27 +0900 Message-ID: <4121c72abb7e69c0178e978ec38c0ff45ac7abf1.1744350629.git.koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 Unify function names to use gpio_aggregator_ prefix (except GPIO forwarder implementations, which remain unchanged in subsequent commits). While at it, rename the pre-existing gpio_aggregator_free() to gpio_aggregator_destory(), since that name will be used by new alloc/free functions introduced in the next commit, for which the name is more appropriate. No functional change. Signed-off-by: Koichiro Den Link: https://lore.kernel.org/r/20250407043019.4105613-3-koichiro.den@canonical.com Signed-off-by: Bartosz Golaszewski (cherry picked from commit 7616dd97ae22e5f69b24774455673d183d4191c9 linux-next) Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 37 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 893cd56de867..92cb18830d42 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -42,8 +42,8 @@ struct gpio_aggregator { static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */ static DEFINE_IDR(gpio_aggregator_idr); -static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key, - int hwnum, unsigned int *n) +static int gpio_aggregator_add_gpio(struct gpio_aggregator *aggr, + const char *key, int hwnum, unsigned int *n) { struct gpiod_lookup_table *lookups; @@ -388,7 +388,7 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, /* * Sysfs interface */ -static int aggr_parse(struct gpio_aggregator *aggr) +static int gpio_aggregator_parse(struct gpio_aggregator *aggr) { char *args = skip_spaces(aggr->args); char *name, *offsets, *p; @@ -407,7 +407,7 @@ static int aggr_parse(struct gpio_aggregator *aggr) p = get_options(offsets, 0, &error); if (error == 0 || *p) { /* Named GPIO line */ - error = aggr_add_gpio(aggr, name, U16_MAX, &n); + error = gpio_aggregator_add_gpio(aggr, name, U16_MAX, &n); if (error) return error; @@ -423,7 +423,7 @@ static int aggr_parse(struct gpio_aggregator *aggr) } for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { - error = aggr_add_gpio(aggr, name, i, &n); + error = gpio_aggregator_add_gpio(aggr, name, i, &n); if (error) return error; } @@ -439,8 +439,8 @@ static int aggr_parse(struct gpio_aggregator *aggr) return 0; } -static ssize_t new_device_store(struct device_driver *driver, const char *buf, - size_t count) +static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, + const char *buf, size_t count) { struct gpio_aggregator *aggr; struct platform_device *pdev; @@ -480,7 +480,7 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, goto remove_idr; } - res = aggr_parse(aggr); + res = gpio_aggregator_parse(aggr); if (res) goto free_dev_id; @@ -513,9 +513,10 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, return res; } -static DRIVER_ATTR_WO(new_device); +static struct driver_attribute driver_attr_gpio_aggregator_new_device = + __ATTR(new_device, 0200, NULL, gpio_aggregator_new_device_store); -static void gpio_aggregator_free(struct gpio_aggregator *aggr) +static void gpio_aggregator_destroy(struct gpio_aggregator *aggr) { platform_device_unregister(aggr->pdev); gpiod_remove_lookup_table(aggr->lookups); @@ -524,8 +525,8 @@ static void gpio_aggregator_free(struct gpio_aggregator *aggr) kfree(aggr); } -static ssize_t delete_device_store(struct device_driver *driver, - const char *buf, size_t count) +static ssize_t gpio_aggregator_delete_device_store(struct device_driver *driver, + const char *buf, size_t count) { struct gpio_aggregator *aggr; unsigned int id; @@ -549,15 +550,17 @@ static ssize_t delete_device_store(struct device_driver *driver, return -ENOENT; } - gpio_aggregator_free(aggr); + gpio_aggregator_destroy(aggr); module_put(THIS_MODULE); return count; } -static DRIVER_ATTR_WO(delete_device); + +static struct driver_attribute driver_attr_gpio_aggregator_delete_device = + __ATTR(delete_device, 0200, NULL, gpio_aggregator_delete_device_store); static struct attribute *gpio_aggregator_attrs[] = { - &driver_attr_new_device.attr, - &driver_attr_delete_device.attr, + &driver_attr_gpio_aggregator_new_device.attr, + &driver_attr_gpio_aggregator_delete_device.attr, NULL }; ATTRIBUTE_GROUPS(gpio_aggregator); @@ -622,7 +625,7 @@ static struct platform_driver gpio_aggregator_driver = { static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data) { - gpio_aggregator_free(p); + gpio_aggregator_destroy(p); return 0; } From patchwork Fri Apr 11 07:26:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071361 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpDG4T3jz1yHt for ; Fri, 11 Apr 2025 17:27:26 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38nb-0002Y8-Df; Fri, 11 Apr 2025 07:27:39 +0000 Received: from smtp-relay-internal-1.internal ([10.131.114.114] helo=smtp-relay-internal-1.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38nY-0002Ow-Gz for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:36 +0000 Received: from mail-pl1-f200.google.com (mail-pl1-f200.google.com [209.85.214.200]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id D02AA400AF for ; Fri, 11 Apr 2025 07:27:35 +0000 (UTC) Received: by mail-pl1-f200.google.com with SMTP id d9443c01a7336-225ab228a37so15229485ad.2 for ; Fri, 11 Apr 2025 00:27:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356454; x=1744961254; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=EjT+z9DhbLon52nrw+r9YMwREsiKYQZHkZRglAKRCQI=; b=AVqhx22pZCtjqAtYnU0cJeSeZgZvYQIkFbOl7jOj7yFQHKBtBZAYzwNy3uIvCnxOnC zDRfWrQvfAZmgPuKGfqDJB6AF7R4g+CdHpMo4i1YITTzUCO4MvIySo0I3YUvLlv1wLSy n5oqU5mzyGPXKjDBZfk3yjeJTCCOhkTL1iEalwrFcqUQMJ+YoPGu4UWmwKxKfJ2p1QmY KrmuMgdYfesK6WyyGYRoNOilZ5OgclfX2sXUT+dKv6xMEUtij1Kmpd38DTGlngE/TzWY Z1f+iNqOSJ7TchGM8PlZmnZaUJ+lxDHv0Bi4Jrfo85mNAzZjbGyJq0oUBtMJzMTn7lCj Uogg== X-Gm-Message-State: AOJu0Yy3tlaLpLDp3/9kSmKdOqKcfD5jDJlyCmy9TMGTM3EbmDbb+g0M 6ERjK6NHLByMHVNm9/t3wWdxx6YeNJ7dT0ViMU3j49ka5H5l/LEb87g+oCJS8BYI00fpzuv2Dd9 W8m2P/4KMkqYN2cPiNKLzipbgMIiTIbmzRk7o9EawY2l4qnYjZaYdPuZusXJpfkyfPt6Wn9+Rf7 HNUCSq20LKGg== X-Gm-Gg: ASbGnctDVHVsJd3Q3exEb+q6lgOM4tipXdEHliCSUjHkZMIRiSgRCaOmyjX3lF1Z5w1 4e2N/C4HUgambAXHpKtoa7wSTFs+YIo5tlCjpFDa7qLTSZSb0pRGI+vbot2FiaHOhU7zsCrChxB f+LZlg/4rf7AU5wix3+cl6rAcBj26B09HgmdqNaFtYl9QzjLtypzR6f1bbOO+ceTD/58F5DKC/B AFBZHxuAjMjNX03XXUSJpbqgr/xmICu0DUFu/BAfg5ouR+wwexG+x7QzX2e72z4c3NBj35YB+6J CvggWLAaEiY7UsvqAooMqGUcdDiM5g== X-Received: by 2002:a17:903:3202:b0:224:c46:d167 with SMTP id d9443c01a7336-22bea4ac744mr26227455ad.16.1744356454097; Fri, 11 Apr 2025 00:27:34 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEyp41JGitFvgymomm5ECdIGrWVZc1rkuMI/VIbIXjTSPqE38mRsA7CSZqzN87vW4pwNXA4rg== X-Received: by 2002:a17:903:3202:b0:224:c46:d167 with SMTP id d9443c01a7336-22bea4ac744mr26227375ad.16.1744356453765; Fri, 11 Apr 2025 00:27:33 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.32 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:33 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 06/13] gpio: aggregator: add gpio_aggregator_{alloc, free}() Date: Fri, 11 Apr 2025 16:26:28 +0900 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 Prepare for the upcoming configfs interface. These functions will be used by both the existing sysfs interface and the new configfs interface, reducing code duplication. No functional change. Signed-off-by: Koichiro Den Link: https://lore.kernel.org/r/20250407043019.4105613-4-koichiro.den@canonical.com Signed-off-by: Bartosz Golaszewski (cherry picked from commit 88fe1d1a646b3b01dcc335c44e7b33ea510f620e linux-next) Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 58 +++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 92cb18830d42..f34581a76b06 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -36,12 +36,41 @@ struct gpio_aggregator { struct gpiod_lookup_table *lookups; struct platform_device *pdev; + int id; char args[]; }; static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */ static DEFINE_IDR(gpio_aggregator_idr); +static int gpio_aggregator_alloc(struct gpio_aggregator **aggr, size_t arg_size) +{ + int ret; + + struct gpio_aggregator *new __free(kfree) = kzalloc( + sizeof(*new) + arg_size, GFP_KERNEL); + if (!new) + return -ENOMEM; + + scoped_guard(mutex, &gpio_aggregator_lock) + ret = idr_alloc(&gpio_aggregator_idr, new, 0, 0, GFP_KERNEL); + + if (ret < 0) + return ret; + + new->id = ret; + *aggr = no_free_ptr(new); + return 0; +} + +static void gpio_aggregator_free(struct gpio_aggregator *aggr) +{ + scoped_guard(mutex, &gpio_aggregator_lock) + idr_remove(&gpio_aggregator_idr, aggr->id); + + kfree(aggr); +} + static int gpio_aggregator_add_gpio(struct gpio_aggregator *aggr, const char *key, int hwnum, unsigned int *n) { @@ -444,17 +473,15 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, { struct gpio_aggregator *aggr; struct platform_device *pdev; - int res, id; + int res; if (!try_module_get(THIS_MODULE)) return -ENOENT; /* kernfs guarantees string termination, so count + 1 is safe */ - aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); - if (!aggr) { - res = -ENOMEM; + res = gpio_aggregator_alloc(&aggr, count + 1); + if (res) goto put_module; - } memcpy(aggr->args, buf, count + 1); @@ -465,19 +492,10 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, goto free_ga; } - mutex_lock(&gpio_aggregator_lock); - id = idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL); - mutex_unlock(&gpio_aggregator_lock); - - if (id < 0) { - res = id; - goto free_table; - } - - aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id); + aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, aggr->id); if (!aggr->lookups->dev_id) { res = -ENOMEM; - goto remove_idr; + goto free_table; } res = gpio_aggregator_parse(aggr); @@ -486,7 +504,7 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, gpiod_add_lookup_table(aggr->lookups); - pdev = platform_device_register_simple(DRV_NAME, id, NULL, 0); + pdev = platform_device_register_simple(DRV_NAME, aggr->id, NULL, 0); if (IS_ERR(pdev)) { res = PTR_ERR(pdev); goto remove_table; @@ -500,14 +518,10 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, gpiod_remove_lookup_table(aggr->lookups); free_dev_id: kfree(aggr->lookups->dev_id); -remove_idr: - mutex_lock(&gpio_aggregator_lock); - idr_remove(&gpio_aggregator_idr, id); - mutex_unlock(&gpio_aggregator_lock); free_table: kfree(aggr->lookups); free_ga: - kfree(aggr); + gpio_aggregator_free(aggr); put_module: module_put(THIS_MODULE); return res; From patchwork Fri Apr 11 07:26:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071362 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpDH13p4z1yJZ for ; Fri, 11 Apr 2025 17:27:27 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38nb-0002Yv-Nq; Fri, 11 Apr 2025 07:27:39 +0000 Received: from smtp-relay-internal-1.internal ([10.131.114.114] helo=smtp-relay-internal-1.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38na-0002Ti-Px for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:38 +0000 Received: from mail-pg1-f199.google.com (mail-pg1-f199.google.com [209.85.215.199]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 86B76400AF for ; Fri, 11 Apr 2025 07:27:37 +0000 (UTC) Received: by mail-pg1-f199.google.com with SMTP id 41be03b00d2f7-af96cdd7f5bso1206258a12.1 for ; Fri, 11 Apr 2025 00:27:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356456; x=1744961256; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=pdY0YyClgf+x1DfmCoSURwe78TDo+PWav0t27CbFiz8=; b=jauDa2TvuOWa7qHfMWjPHlzx2+A7yJ7U1HLRmOHROzZdpRhXOI7GjMRFByZWvrXl6c FaoFIJsSCd2JiXOa+lJ1MEtHqjFesf/WhmUk3o9UbVG27/wRnYdjaD+MP4WoMi0g5Vwc 9YBps1p+rirH67zBCoSMOKgEPkw469T+m1jZD3v+XQswVxGu/4YMzz0JYRwN8E0igXnD A7TzxF8e5xXtG7Sr/68DqpeeGxPqvZ4ayrsPnIH2Veqg4UD+FNentf98E5utCEWDdQwn 8EuvB7X0121JKmjTfBE3Tr1e+ZkjzwQHWzmuxi5KDaD/OQny6rxW+gvkoCCQtlrodSX8 hTEw== X-Gm-Message-State: AOJu0Yxl40IsFdTfAgww/lhyj2gv/uOynEIcj/5+b3N2rVdxqJqan3CK lph6Gh0tNXisKWK96SuNsXXs6KYDaOpZvQ77ulysfXS6UZ80qYEjePBSfAAg1uJa4VUCvjcELFS OpromC5nuAO87iwFkXtZUTbh43R9awiUZA4QzBjxFYi3ZAx87WZj5dAOr7ZkLF2yC7yHbdrN2VB 7qTGrOqmgKrw== X-Gm-Gg: ASbGncsrkgLcMlfp05YAlnU8shMifaO3zm7y+gCfqoY+i0HG6JO45aXLbI1lAsucUas hwPDOKuyD3J+B5Nud/RSjqdDcQkNbZWL1nWYUn29weoEbWAYafMneuYsdER+mBzsKuAq0tQO648 QWq9f3l8TXUPoNALqfnNSP5O3qSrMy7QgVrmg77LEe4Gg8gAcFVDDjb+FikLp4bTVrRbe+gFA+e ez51erkN4vewa4bV+afR4Trv13kRXtY/GcfTG3dziNtdMtAVu8N/TypNfbk3AiMYrRL4ZJdzmm1 Nn9lxpTdjADNIen5Z8m9x/Vc8Ss11A== X-Received: by 2002:a17:902:f78c:b0:223:2630:6b82 with SMTP id d9443c01a7336-22bea494e3amr32524305ad.10.1744356455645; Fri, 11 Apr 2025 00:27:35 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFqyqOmJX4IxYIW2pXU3+DsL6BVJbv7rJis2X7YzZnN1y0K5z5Hkpfb6iIFPxBdffLhbdPvHg== X-Received: by 2002:a17:902:f78c:b0:223:2630:6b82 with SMTP id d9443c01a7336-22bea494e3amr32523845ad.10.1744356455010; Fri, 11 Apr 2025 00:27:35 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.34 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:34 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 07/13] gpio: aggregator: introduce basic configfs interface Date: Fri, 11 Apr 2025 16:26:29 +0900 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 The existing sysfs 'new_device' interface has several limitations: * No way to determine when GPIO aggregator creation is complete. * No way to retrieve errors when creating a GPIO aggregator. * No way to trace a GPIO line of an aggregator back to its corresponding physical device. * The 'new_device' echo does not indicate which virtual gpiochip was created. * No way to assign names to GPIO lines exported through an aggregator. Introduce the new configfs interface for gpio-aggregator to address these limitations. It provides a more streamlined, modern, and extensible configuration method. For backward compatibility, the 'new_device' interface and its behavior is retained for now. This commit implements basic functionalities: /config/gpio-aggregator// /config/gpio-aggregator//live /config/gpio-aggregator//dev_name /config/gpio-aggregator/// /config/gpio-aggregator///key /config/gpio-aggregator///offset /config/gpio-aggregator///name Basic setup flow is: 1. Create a directory for a GPIO aggregator. 2. Create subdirectories for each line you want to instantiate. 3. In each line directory, configure the key and offset. The key/offset semantics are as follows: * If offset is >= 0: - key specifies the name of the chip this GPIO belongs to - offset specifies the line offset within that chip. * If offset is <0: - key needs to specify the GPIO line name. 4. Return to the aggregator's root directory and write '1' to the live attribute. For example, the command in the existing kernel doc: echo 'e6052000.gpio 19 e6050000.gpio 20-21' > new_device is equivalent to: mkdir /sys/kernel/config/gpio-aggregator/ # Change to name of your choice (e.g. "aggr0") cd /sys/kernel/config/gpio-aggregator/ mkdir line0 line1 line2 # Only "line" naming allowed. echo e6052000.gpio > line0/key echo 19 > line0/offset echo e6050000.gpio > line1/key echo 20 > line1/offset echo e6050000.gpio > line2/key echo 21 > line2/offset echo 1 > live The corresponding gpio_device id can be identified as follows: cd /sys/kernel/config/gpio-aggregator/ ls -d /sys/devices/platform/`cat dev_name`/gpiochip* Also, via configfs, custom GPIO line name can be set like this: cd /sys/kernel/config/gpio-aggregator/ echo "abc" > line1/name Signed-off-by: Koichiro Den Link: https://lore.kernel.org/r/20250407043019.4105613-5-koichiro.den@canonical.com [Bartosz: remove stray newlines] Signed-off-by: Bartosz Golaszewski (cherry picked from commit 86f162e73d2d81ef6d819c06a3b6c2fda77a79b8 linux-next) Signed-off-by: Koichiro Den --- drivers/gpio/Kconfig | 2 + drivers/gpio/gpio-aggregator.c | 637 ++++++++++++++++++++++++++++++++- 2 files changed, 626 insertions(+), 13 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 21ac40bde9c4..f8682b580a22 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1855,6 +1855,8 @@ menu "Virtual GPIO drivers" config GPIO_AGGREGATOR tristate "GPIO Aggregator" + select CONFIGFS_FS + select DEV_SYNC_PROBE help Say yes here to enable the GPIO Aggregator, which provides a way to aggregate existing GPIO lines into a new virtual GPIO chip. diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index f34581a76b06..f492b7259ec5 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -9,10 +9,13 @@ #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -27,6 +30,8 @@ #include #include +#include "dev-sync-probe.h" + #define AGGREGATOR_MAX_GPIOS 512 /* @@ -34,12 +39,38 @@ */ struct gpio_aggregator { + struct dev_sync_probe_data probe_data; + struct config_group group; struct gpiod_lookup_table *lookups; - struct platform_device *pdev; + struct mutex lock; int id; + + /* List of gpio_aggregator_line. Always added in order */ + struct list_head list_head; + + /* used by legacy sysfs interface only */ + bool init_via_sysfs; char args[]; }; +struct gpio_aggregator_line { + struct config_group group; + struct gpio_aggregator *parent; + struct list_head entry; + + /* Line index within the aggregator device */ + unsigned int idx; + + /* Custom name for the virtual line */ + const char *name; + /* GPIO chip label or line name */ + const char *key; + /* Can be negative to indicate lookup by line name */ + int offset; + + enum gpio_lookup_flags flags; +}; + static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */ static DEFINE_IDR(gpio_aggregator_idr); @@ -59,6 +90,8 @@ static int gpio_aggregator_alloc(struct gpio_aggregator **aggr, size_t arg_size) return ret; new->id = ret; + INIT_LIST_HEAD(&new->list_head); + mutex_init(&new->lock); *aggr = no_free_ptr(new); return 0; } @@ -68,6 +101,7 @@ static void gpio_aggregator_free(struct gpio_aggregator *aggr) scoped_guard(mutex, &gpio_aggregator_lock) idr_remove(&gpio_aggregator_idr, aggr->id); + mutex_destroy(&aggr->lock); kfree(aggr); } @@ -90,6 +124,71 @@ static int gpio_aggregator_add_gpio(struct gpio_aggregator *aggr, return 0; } +static bool gpio_aggregator_is_active(struct gpio_aggregator *aggr) +{ + lockdep_assert_held(&aggr->lock); + + return aggr->probe_data.pdev && platform_get_drvdata(aggr->probe_data.pdev); +} + +static size_t gpio_aggregator_count_lines(struct gpio_aggregator *aggr) +{ + lockdep_assert_held(&aggr->lock); + + return list_count_nodes(&aggr->list_head); +} + +static struct gpio_aggregator_line * +gpio_aggregator_line_alloc(struct gpio_aggregator *parent, unsigned int idx, + char *key, int offset) +{ + struct gpio_aggregator_line *line; + + line = kzalloc(sizeof(*line), GFP_KERNEL); + if (!line) + return ERR_PTR(-ENOMEM); + + if (key) { + line->key = kstrdup(key, GFP_KERNEL); + if (!line->key) { + kfree(line); + return ERR_PTR(-ENOMEM); + } + } + + line->flags = GPIO_LOOKUP_FLAGS_DEFAULT; + line->parent = parent; + line->idx = idx; + line->offset = offset; + INIT_LIST_HEAD(&line->entry); + + return line; +} + +static void gpio_aggregator_line_add(struct gpio_aggregator *aggr, + struct gpio_aggregator_line *line) +{ + struct gpio_aggregator_line *tmp; + + lockdep_assert_held(&aggr->lock); + + list_for_each_entry(tmp, &aggr->list_head, entry) { + if (tmp->idx > line->idx) { + list_add_tail(&line->entry, &tmp->entry); + return; + } + } + list_add_tail(&line->entry, &aggr->list_head); +} + +static void gpio_aggregator_line_del(struct gpio_aggregator *aggr, + struct gpio_aggregator_line *line) +{ + lockdep_assert_held(&aggr->lock); + + list_del(&line->entry); +} + /* * GPIO Forwarder @@ -413,6 +512,473 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, return fwd; } +/* + * Configfs interface + */ + +static struct gpio_aggregator * +to_gpio_aggregator(struct config_item *item) +{ + struct config_group *group = to_config_group(item); + + return container_of(group, struct gpio_aggregator, group); +} + +static struct gpio_aggregator_line * +to_gpio_aggregator_line(struct config_item *item) +{ + struct config_group *group = to_config_group(item); + + return container_of(group, struct gpio_aggregator_line, group); +} + +static struct fwnode_handle * +gpio_aggregator_make_device_sw_node(struct gpio_aggregator *aggr) +{ + struct property_entry properties[2]; + struct gpio_aggregator_line *line; + size_t num_lines; + int n = 0; + + memset(properties, 0, sizeof(properties)); + + num_lines = gpio_aggregator_count_lines(aggr); + if (num_lines == 0) + return NULL; + + const char **line_names __free(kfree) = kcalloc( + num_lines, sizeof(*line_names), GFP_KERNEL); + if (!line_names) + return ERR_PTR(-ENOMEM); + + /* The list is always sorted as new elements are inserted in order. */ + list_for_each_entry(line, &aggr->list_head, entry) + line_names[n++] = line->name ?: ""; + + properties[0] = PROPERTY_ENTRY_STRING_ARRAY_LEN( + "gpio-line-names", + line_names, num_lines); + + return fwnode_create_software_node(properties, NULL); +} + +static int gpio_aggregator_activate(struct gpio_aggregator *aggr) +{ + struct platform_device_info pdevinfo; + struct gpio_aggregator_line *line; + struct fwnode_handle *swnode; + unsigned int n = 0; + int ret = 0; + + if (gpio_aggregator_count_lines(aggr) == 0) + return -EINVAL; + + aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1), + GFP_KERNEL); + if (!aggr->lookups) + return -ENOMEM; + + swnode = gpio_aggregator_make_device_sw_node(aggr); + if (IS_ERR(swnode)) + goto err_remove_lookups; + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo.name = DRV_NAME; + pdevinfo.id = aggr->id; + pdevinfo.fwnode = swnode; + + /* The list is always sorted as new elements are inserted in order. */ + list_for_each_entry(line, &aggr->list_head, entry) { + /* + * - Either GPIO chip label or line name must be configured + * (i.e. line->key must be non-NULL) + * - Line directories must be named with sequential numeric + * suffixes starting from 0. (i.e. ./line0, ./line1, ...) + */ + if (!line->key || line->idx != n) { + ret = -EINVAL; + goto err_remove_swnode; + } + + if (line->offset < 0) + ret = gpio_aggregator_add_gpio(aggr, line->key, + U16_MAX, &n); + else + ret = gpio_aggregator_add_gpio(aggr, line->key, + line->offset, &n); + if (ret) + goto err_remove_swnode; + } + + aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, aggr->id); + if (!aggr->lookups->dev_id) { + ret = -ENOMEM; + goto err_remove_swnode; + } + + gpiod_add_lookup_table(aggr->lookups); + + ret = dev_sync_probe_register(&aggr->probe_data, &pdevinfo); + if (ret) + goto err_remove_lookup_table; + + return 0; + +err_remove_lookup_table: + kfree(aggr->lookups->dev_id); + gpiod_remove_lookup_table(aggr->lookups); +err_remove_swnode: + fwnode_remove_software_node(swnode); +err_remove_lookups: + kfree(aggr->lookups); + + return ret; +} + +static void gpio_aggregator_deactivate(struct gpio_aggregator *aggr) +{ + dev_sync_probe_unregister(&aggr->probe_data); + gpiod_remove_lookup_table(aggr->lookups); + kfree(aggr->lookups->dev_id); + kfree(aggr->lookups); +} + +static void gpio_aggregator_lockup_configfs(struct gpio_aggregator *aggr, + bool lock) +{ + struct configfs_subsystem *subsys = aggr->group.cg_subsys; + struct gpio_aggregator_line *line; + + /* + * The device only needs to depend on leaf lines. This is + * sufficient to lock up all the configfs entries that the + * instantiated, alive device depends on. + */ + list_for_each_entry(line, &aggr->list_head, entry) { + if (lock) + configfs_depend_item_unlocked( + subsys, &line->group.cg_item); + else + configfs_undepend_item_unlocked( + &line->group.cg_item); + } +} + +static ssize_t +gpio_aggregator_line_key_show(struct config_item *item, char *page) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + + guard(mutex)(&aggr->lock); + + return sysfs_emit(page, "%s\n", line->key ?: ""); +} + +static ssize_t +gpio_aggregator_line_key_store(struct config_item *item, const char *page, + size_t count) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + + char *key __free(kfree) = kstrndup(skip_spaces(page), count, + GFP_KERNEL); + if (!key) + return -ENOMEM; + + strim(key); + + guard(mutex)(&aggr->lock); + + if (gpio_aggregator_is_active(aggr)) + return -EBUSY; + + kfree(line->key); + line->key = no_free_ptr(key); + + return count; +} +CONFIGFS_ATTR(gpio_aggregator_line_, key); + +static ssize_t +gpio_aggregator_line_name_show(struct config_item *item, char *page) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + + guard(mutex)(&aggr->lock); + + return sysfs_emit(page, "%s\n", line->name ?: ""); +} + +static ssize_t +gpio_aggregator_line_name_store(struct config_item *item, const char *page, + size_t count) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + + char *name __free(kfree) = kstrndup(skip_spaces(page), count, + GFP_KERNEL); + if (!name) + return -ENOMEM; + + strim(name); + + guard(mutex)(&aggr->lock); + + if (gpio_aggregator_is_active(aggr)) + return -EBUSY; + + kfree(line->name); + line->name = no_free_ptr(name); + + return count; +} +CONFIGFS_ATTR(gpio_aggregator_line_, name); + +static ssize_t +gpio_aggregator_line_offset_show(struct config_item *item, char *page) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + + guard(mutex)(&aggr->lock); + + return sysfs_emit(page, "%d\n", line->offset); +} + +static ssize_t +gpio_aggregator_line_offset_store(struct config_item *item, const char *page, + size_t count) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + int offset, ret; + + ret = kstrtoint(page, 0, &offset); + if (ret) + return ret; + + /* + * When offset == -1, 'key' represents a line name to lookup. + * When 0 <= offset < 65535, 'key' represents the label of the chip with + * the 'offset' value representing the line within that chip. + * + * GPIOLIB uses the U16_MAX value to indicate lookup by line name so + * the greatest offset we can accept is (U16_MAX - 1). + */ + if (offset > (U16_MAX - 1) || offset < -1) + return -EINVAL; + + guard(mutex)(&aggr->lock); + + if (gpio_aggregator_is_active(aggr)) + return -EBUSY; + + line->offset = offset; + + return count; +} +CONFIGFS_ATTR(gpio_aggregator_line_, offset); + +static struct configfs_attribute *gpio_aggregator_line_attrs[] = { + &gpio_aggregator_line_attr_key, + &gpio_aggregator_line_attr_name, + &gpio_aggregator_line_attr_offset, + NULL +}; + +static ssize_t +gpio_aggregator_device_dev_name_show(struct config_item *item, char *page) +{ + struct gpio_aggregator *aggr = to_gpio_aggregator(item); + struct platform_device *pdev; + + guard(mutex)(&aggr->lock); + + pdev = aggr->probe_data.pdev; + if (pdev) + return sysfs_emit(page, "%s\n", dev_name(&pdev->dev)); + + return sysfs_emit(page, "%s.%d\n", DRV_NAME, aggr->id); +} +CONFIGFS_ATTR_RO(gpio_aggregator_device_, dev_name); + +static ssize_t +gpio_aggregator_device_live_show(struct config_item *item, char *page) +{ + struct gpio_aggregator *aggr = to_gpio_aggregator(item); + + guard(mutex)(&aggr->lock); + + return sysfs_emit(page, "%c\n", + gpio_aggregator_is_active(aggr) ? '1' : '0'); +} + +static ssize_t +gpio_aggregator_device_live_store(struct config_item *item, const char *page, + size_t count) +{ + struct gpio_aggregator *aggr = to_gpio_aggregator(item); + int ret = 0; + bool live; + + ret = kstrtobool(page, &live); + if (ret) + return ret; + + if (!try_module_get(THIS_MODULE)) + return -ENOENT; + + if (live) + gpio_aggregator_lockup_configfs(aggr, true); + + scoped_guard(mutex, &aggr->lock) { + if (live == gpio_aggregator_is_active(aggr)) + ret = -EPERM; + else if (live) + ret = gpio_aggregator_activate(aggr); + else + gpio_aggregator_deactivate(aggr); + } + + /* + * Undepend is required only if device disablement (live == 0) + * succeeds or if device enablement (live == 1) fails. + */ + if (live == !!ret) + gpio_aggregator_lockup_configfs(aggr, false); + + module_put(THIS_MODULE); + + return ret ?: count; +} +CONFIGFS_ATTR(gpio_aggregator_device_, live); + +static struct configfs_attribute *gpio_aggregator_device_attrs[] = { + &gpio_aggregator_device_attr_dev_name, + &gpio_aggregator_device_attr_live, + NULL +}; + +static void +gpio_aggregator_line_release(struct config_item *item) +{ + struct gpio_aggregator_line *line = to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr = line->parent; + + guard(mutex)(&aggr->lock); + + gpio_aggregator_line_del(aggr, line); + kfree(line->key); + kfree(line->name); + kfree(line); +} + +static struct configfs_item_operations gpio_aggregator_line_item_ops = { + .release = gpio_aggregator_line_release, +}; + +static const struct config_item_type gpio_aggregator_line_type = { + .ct_item_ops = &gpio_aggregator_line_item_ops, + .ct_attrs = gpio_aggregator_line_attrs, + .ct_owner = THIS_MODULE, +}; + +static void gpio_aggregator_device_release(struct config_item *item) +{ + struct gpio_aggregator *aggr = to_gpio_aggregator(item); + + /* + * If the aggregator is active, this code wouldn't be reached, + * so calling gpio_aggregator_deactivate() is always unnecessary. + */ + gpio_aggregator_free(aggr); +} + +static struct configfs_item_operations gpio_aggregator_device_item_ops = { + .release = gpio_aggregator_device_release, +}; + +static struct config_group * +gpio_aggregator_device_make_group(struct config_group *group, const char *name) +{ + struct gpio_aggregator *aggr = to_gpio_aggregator(&group->cg_item); + struct gpio_aggregator_line *line; + unsigned int idx; + int ret, nchar; + + ret = sscanf(name, "line%u%n", &idx, &nchar); + if (ret != 1 || nchar != strlen(name)) + return ERR_PTR(-EINVAL); + + guard(mutex)(&aggr->lock); + + if (gpio_aggregator_is_active(aggr)) + return ERR_PTR(-EBUSY); + + list_for_each_entry(line, &aggr->list_head, entry) + if (line->idx == idx) + return ERR_PTR(-EINVAL); + + line = gpio_aggregator_line_alloc(aggr, idx, NULL, -1); + if (!line) + return ERR_PTR(-ENOMEM); + + config_group_init_type_name(&line->group, name, &gpio_aggregator_line_type); + + gpio_aggregator_line_add(aggr, line); + + return &line->group; +} + +static struct configfs_group_operations gpio_aggregator_device_group_ops = { + .make_group = gpio_aggregator_device_make_group, +}; + +static const struct config_item_type gpio_aggregator_device_type = { + .ct_group_ops = &gpio_aggregator_device_group_ops, + .ct_item_ops = &gpio_aggregator_device_item_ops, + .ct_attrs = gpio_aggregator_device_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group * +gpio_aggregator_make_group(struct config_group *group, const char *name) +{ + struct gpio_aggregator *aggr; + int ret; + + /* arg space is unneeded */ + ret = gpio_aggregator_alloc(&aggr, 0); + if (ret) + return ERR_PTR(ret); + + config_group_init_type_name(&aggr->group, name, &gpio_aggregator_device_type); + dev_sync_probe_init(&aggr->probe_data); + + return &aggr->group; +} + +static struct configfs_group_operations gpio_aggregator_group_ops = { + .make_group = gpio_aggregator_make_group, +}; + +static const struct config_item_type gpio_aggregator_type = { + .ct_group_ops = &gpio_aggregator_group_ops, + .ct_owner = THIS_MODULE, +}; + +static struct configfs_subsystem gpio_aggregator_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = DRV_NAME, + .ci_type = &gpio_aggregator_type, + }, + }, +}; /* * Sysfs interface @@ -485,6 +1051,7 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, memcpy(aggr->args, buf, count + 1); + aggr->init_via_sysfs = true; aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1), GFP_KERNEL); if (!aggr->lookups) { @@ -510,7 +1077,7 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, goto remove_table; } - aggr->pdev = pdev; + aggr->probe_data.pdev = pdev; module_put(THIS_MODULE); return count; @@ -532,10 +1099,7 @@ static struct driver_attribute driver_attr_gpio_aggregator_new_device = static void gpio_aggregator_destroy(struct gpio_aggregator *aggr) { - platform_device_unregister(aggr->pdev); - gpiod_remove_lookup_table(aggr->lookups); - kfree(aggr->lookups->dev_id); - kfree(aggr->lookups); + gpio_aggregator_deactivate(aggr); kfree(aggr); } @@ -557,12 +1121,19 @@ static ssize_t gpio_aggregator_delete_device_store(struct device_driver *driver, return -ENOENT; mutex_lock(&gpio_aggregator_lock); - aggr = idr_remove(&gpio_aggregator_idr, id); - mutex_unlock(&gpio_aggregator_lock); - if (!aggr) { + aggr = idr_find(&gpio_aggregator_idr, id); + /* + * For simplicity, devices created via configfs cannot be deleted + * via sysfs. + */ + if (aggr && aggr->init_via_sysfs) + idr_remove(&gpio_aggregator_idr, id); + else { + mutex_unlock(&gpio_aggregator_lock); module_put(THIS_MODULE); return -ENOENT; } + mutex_unlock(&gpio_aggregator_lock); gpio_aggregator_destroy(aggr); module_put(THIS_MODULE); @@ -579,7 +1150,6 @@ static struct attribute *gpio_aggregator_attrs[] = { }; ATTRIBUTE_GROUPS(gpio_aggregator); - /* * GPIO Aggregator platform device */ @@ -639,21 +1209,61 @@ static struct platform_driver gpio_aggregator_driver = { static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data) { + /* + * There should be no aggregator created via configfs, as their + * presence would prevent module unloading. + */ gpio_aggregator_destroy(p); return 0; } static void __exit gpio_aggregator_remove_all(void) { - mutex_lock(&gpio_aggregator_lock); + /* + * Configfs callbacks acquire gpio_aggregator_lock when accessing + * gpio_aggregator_idr, so to prevent lock inversion deadlock, we + * cannot protect idr_for_each invocation here with + * gpio_aggregator_lock, as gpio_aggregator_idr_remove() accesses + * configfs groups. Fortunately, the new_device/delete_device path + * and the module unload path are mutually exclusive, thanks to an + * explicit try_module_get inside of those driver attr handlers. + * Also, when we reach here, no configfs entries present or being + * created. Therefore, no need to protect with gpio_aggregator_lock + * below. + */ idr_for_each(&gpio_aggregator_idr, gpio_aggregator_idr_remove, NULL); idr_destroy(&gpio_aggregator_idr); - mutex_unlock(&gpio_aggregator_lock); } static int __init gpio_aggregator_init(void) { - return platform_driver_register(&gpio_aggregator_driver); + int ret = 0; + + config_group_init(&gpio_aggregator_subsys.su_group); + mutex_init(&gpio_aggregator_subsys.su_mutex); + ret = configfs_register_subsystem(&gpio_aggregator_subsys); + if (ret) { + pr_err("Failed to register the '%s' configfs subsystem: %d\n", + gpio_aggregator_subsys.su_group.cg_item.ci_namebuf, ret); + mutex_destroy(&gpio_aggregator_subsys.su_mutex); + return ret; + } + + /* + * CAVEAT: This must occur after configfs registration. Otherwise, + * a race condition could arise: driver attribute groups might be + * exposed and accessed by users before configfs registration + * completes. new_device_store() does not expect a partially + * initialized configfs state. + */ + ret = platform_driver_register(&gpio_aggregator_driver); + if (ret) { + pr_err("Failed to register the platform driver: %d\n", ret); + mutex_destroy(&gpio_aggregator_subsys.su_mutex); + configfs_unregister_subsystem(&gpio_aggregator_subsys); + } + + return ret; } module_init(gpio_aggregator_init); @@ -661,6 +1271,7 @@ static void __exit gpio_aggregator_exit(void) { gpio_aggregator_remove_all(); platform_driver_unregister(&gpio_aggregator_driver); + configfs_unregister_subsystem(&gpio_aggregator_subsys); } module_exit(gpio_aggregator_exit); From patchwork Fri Apr 11 07:26:30 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071363 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpDJ3nBcz1yHt for ; Fri, 11 Apr 2025 17:27:28 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38nd-0002cq-B1; Fri, 11 Apr 2025 07:27:41 +0000 Received: from smtp-relay-internal-0.internal ([10.131.114.225] helo=smtp-relay-internal-0.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38na-0002WB-O5 for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:38 +0000 Received: from mail-pl1-f199.google.com (mail-pl1-f199.google.com [209.85.214.199]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 34CF83F169 for ; Fri, 11 Apr 2025 07:27:38 +0000 (UTC) Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-2264e5b2b7cso15607255ad.2 for ; Fri, 11 Apr 2025 00:27:38 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356456; x=1744961256; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=gYt1RG+kTh3F+xrckj6T4AuQ9DrghbrrtWm3G+eIz1w=; b=xVPLweMe83dR1vfZdAtwzYBp7ZmGqhCpniir9JE8yjmWLEbbxiPkdpB8bXKsQmUKjx pZCmZJt1RvVmsjaGBxE+RJtlcv+iBGVphdfbIMjmwZEJNwg+RsISiLjV+jtu3oOqLuVh ujTVdPVQOwiU/AQyXaptxqpZO5ll6x+x1D78w+r/R3A/A+SglZUkoWz+dJ9tTxIYpMdM csrcLUGtmFRNQmHkyYeV0HAyAFLS1Wgo9idK6r5ixOK6tuOabIzcXOgIuLUYTsoVw8/9 NKIh4/5usZrGB0ojnF1aO0TVkijl/c3Z1oFsqdvinPepxMuO1+LVFeRTuEw7A3Ynk6oQ VhRQ== X-Gm-Message-State: AOJu0Yxx+HZviLEerCmJRo/Sd89DT9enWhGDE0SrxttuOu/5NLUK3SPP Pane+/vrblCp7FKo6H/JTmsMYTaTv9nhn37vNJLYpNdG/wkCcWVg0m4MdDQUs0U/NPcJQOGTPpF PEtRfElF8BLgWrZuG9WoyAjSzq5imnzs9LanSxpKH4vPm2cyPGvcnw9oYhOJ3pZZLh0eCTzagJz D5TjAGPof9rA== X-Gm-Gg: ASbGnct50iWQuj44YXVenCIC8BSO82JnwVMV4Ixz+FQ1tT7RccMdMicKBXWV4/qpEdV JiucHaFiAQ4rdpE8aBQ8tgMebwbw3C46YhBha8xrfXYwizs+0KROhlCLH68Xp+JNJvl9fAtejr2 uAZOc6wT1taX0a0/IHkrG7gIbycqd8SCw38p6h4HA65kXFoNj4XmhS6LflxEirFKGnrHeutjX/I zcG2toR5x1IuwkeJ0dAPNUrFTNnUNqgsnp9UXE+GovAu7PUsL26VWuofzlCBhpMb7fTdoY1ZO9t SGLHXvr++OsHcsuqprudqbA3jMvn1Q== X-Received: by 2002:a17:903:1b0b:b0:21f:4649:fd49 with SMTP id d9443c01a7336-22bea4fd04emr29257395ad.49.1744356456625; Fri, 11 Apr 2025 00:27:36 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFw/hGMkRpSUQs1BdRhwGVSUfX9CI3VUJAm6ajM0nAgxTcnMxOxDDs0+uABEYxNZbLFGP8zFQ== X-Received: by 2002:a17:903:1b0b:b0:21f:4649:fd49 with SMTP id d9443c01a7336-22bea4fd04emr29257185ad.49.1744356456181; Fri, 11 Apr 2025 00:27:36 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.35 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:35 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 08/13] UBUNTU: [Config] updateconfigs for DEV_SYNC_PROBE Date: Fri, 11 Apr 2025 16:26:30 +0900 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 Signed-off-by: Koichiro Den --- debian.master/config/annotations | 1 + 1 file changed, 1 insertion(+) diff --git a/debian.master/config/annotations b/debian.master/config/annotations index c134dd85a7f8..ef8a398a62e3 100644 --- a/debian.master/config/annotations +++ b/debian.master/config/annotations @@ -3995,6 +3995,7 @@ CONFIG_DEV_DAX_HMEM policy<{'amd64': 'm', 'arm64': ' CONFIG_DEV_DAX_HMEM_DEVICES policy<{'amd64': 'y', 'arm64': 'y', 'riscv64': 'y'}> CONFIG_DEV_DAX_KMEM policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm', 'riscv64': 'm', 's390x': 'm'}> CONFIG_DEV_DAX_PMEM policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm', 'riscv64': 'm'}> +CONFIG_DEV_SYNC_PROBE policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm', 'riscv64': 'm', 's390x': 'm'}> CONFIG_DHT11 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm', 'riscv64': 'm'}> CONFIG_DIAG288_WATCHDOG policy<{'s390x': 'm'}> CONFIG_DIMLIB policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 'riscv64': 'y', 's390x': 'y'}> From patchwork Fri Apr 11 07:26:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071364 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpDM1MFyz1yHt for ; Fri, 11 Apr 2025 17:27:31 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38nf-0002m8-Un; Fri, 11 Apr 2025 07:27:43 +0000 Received: from smtp-relay-internal-0.internal ([10.131.114.225] helo=smtp-relay-internal-0.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38nb-0002Yu-N1 for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:39 +0000 Received: from mail-pj1-f71.google.com (mail-pj1-f71.google.com [209.85.216.71]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 5E0093F169 for ; Fri, 11 Apr 2025 07:27:39 +0000 (UTC) Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-2ff8340d547so1543572a91.2 for ; Fri, 11 Apr 2025 00:27:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356458; x=1744961258; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=7VRUwPVIYBjWLmriN8iuIt4TEtiIrj93r/68+Uf/cUk=; b=t1t7UWxqzYF3t4GRt3UEKJ73bSww9ezIKlPmd7qmRnT0LZp0NU5/n9sXc6kQyGwvQa MW34iCmUg3fwfpljRN9r2SqODPn3FfCTGZJ6BWiaHMZHRfvX06zLQGoBCj2Ff3xq696Q rV6qRavMb9PyFtllx7+yAfw+tNm4mXkPFo+Ee+JlbhDaO98UpbMahEw75yyHMZJAtjka zkXJ4+Xkbnv88EnaKS7b3xEozwV31GGUcvxz+aGnFIk2RWfngHXtPEWqYiTBwZijvsh3 hGxhQF1882DnSMgq5XC9q8OCFT4NvwUBeyKV4+9bm5h5tIe9061RulepPomWcoJQNTff Fzhw== X-Gm-Message-State: AOJu0YxaraZ51zeLLy4yOe8F+ppvPMXy+SC+qzL4EJD3U4kSV2vFpU5d hhuJC85l6Tr4qjG5bGFVHFe1gl7oRun55O7U1Opxmo+WqoON1YUI7V8CeC82nEjeUxpnyC5QX6e vnoPYAsDucfRWrLh4QjTyYcn4nlnKA88coOQTuUh6pRO92swzTHuDA6TbImQlDgVK/+878ng+/7 ShHMrq1JI5ww== X-Gm-Gg: ASbGncuMdySkt3LZJBePrw0AvVTi+hzZl74OXKCSWsBL5a6HZAuVcy7rtOEmq7DTbYP jSoaS8DPU9zHognuRHZ9bS5ZPDEBiSiAdnXGrizOoq3E9/zNYHAQ4gYaesObw6kpF8ZgzqKUJYr usKOCfkO3k+xBNJE4faYgJpCRzA7oC6rlb4Db+psXJEmcLg6rlMa1LUWLYylhvhxOvi3l1N9eaz sWTr5yzcTvdD84+jMYSzKKGuL4r6Z+IYURtRajjtW+zpbYltBJWrEV7Q8Ugju5crv3wxAnuJ/Oj o46M2Xymrd5zX93yT7dp7Qfeap63MQ== X-Received: by 2002:a17:90b:270d:b0:2ff:7b28:a51a with SMTP id 98e67ed59e1d1-30823642c9amr3565871a91.17.1744356457723; Fri, 11 Apr 2025 00:27:37 -0700 (PDT) X-Google-Smtp-Source: AGHT+IG8X1/oeHL1rCtXkkDTSBF4ZaP1QJXZKtmwhRbWS3ECv1PJWUXa/bcLnAeZYgrton0gngipKQ== X-Received: by 2002:a17:90b:270d:b0:2ff:7b28:a51a with SMTP id 98e67ed59e1d1-30823642c9amr3565851a91.17.1744356457415; Fri, 11 Apr 2025 00:27:37 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.36 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:37 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 09/13] gpio: aggregator: rename 'name' to 'key' in gpio_aggregator_parse() Date: Fri, 11 Apr 2025 16:26:31 +0900 Message-ID: <9c0f5c6f233f3338d87e5913beb998ec61f7820f.1744350629.git.koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 Rename the local variable 'name' in gpio_aggregator_parse() to 'key' because struct gpio_aggregator_line now uses the 'name' field for the custom line name and the local variable actually represents a 'key'. This change prepares for the next but one commit. No functional change. Reviewed-by: Geert Uytterhoeven Signed-off-by: Koichiro Den Link: https://lore.kernel.org/r/20250407043019.4105613-6-koichiro.den@canonical.com Signed-off-by: Bartosz Golaszewski (cherry picked from commit 4ec2315d7fabeb08e9ad7995bd16f34118e4633b linux-next) Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index f492b7259ec5..b00b2065e534 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -986,7 +986,7 @@ static struct configfs_subsystem gpio_aggregator_subsys = { static int gpio_aggregator_parse(struct gpio_aggregator *aggr) { char *args = skip_spaces(aggr->args); - char *name, *offsets, *p; + char *key, *offsets, *p; unsigned int i, n = 0; int error = 0; @@ -995,18 +995,18 @@ static int gpio_aggregator_parse(struct gpio_aggregator *aggr) if (!bitmap) return -ENOMEM; - args = next_arg(args, &name, &p); + args = next_arg(args, &key, &p); while (*args) { args = next_arg(args, &offsets, &p); p = get_options(offsets, 0, &error); if (error == 0 || *p) { /* Named GPIO line */ - error = gpio_aggregator_add_gpio(aggr, name, U16_MAX, &n); + error = gpio_aggregator_add_gpio(aggr, key, U16_MAX, &n); if (error) return error; - name = offsets; + key = offsets; continue; } @@ -1018,12 +1018,12 @@ static int gpio_aggregator_parse(struct gpio_aggregator *aggr) } for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { - error = gpio_aggregator_add_gpio(aggr, name, i, &n); + error = gpio_aggregator_add_gpio(aggr, key, i, &n); if (error) return error; } - args = next_arg(args, &name, &p); + args = next_arg(args, &key, &p); } if (!n) { From patchwork Fri Apr 11 07:26:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071367 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpDQ0ZgWz1yHt for ; Fri, 11 Apr 2025 17:27:34 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38ni-0002vc-83; Fri, 11 Apr 2025 07:27:46 +0000 Received: from smtp-relay-internal-1.internal ([10.131.114.114] helo=smtp-relay-internal-1.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38nd-0002d3-5S for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:41 +0000 Received: from mail-pj1-f72.google.com (mail-pj1-f72.google.com [209.85.216.72]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id D64ED400AF for ; Fri, 11 Apr 2025 07:27:40 +0000 (UTC) Received: by mail-pj1-f72.google.com with SMTP id 98e67ed59e1d1-306e5d9c9a6so2948593a91.1 for ; Fri, 11 Apr 2025 00:27:40 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356459; x=1744961259; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=79A7XdhGDKPV8uL/DxcNXfGga2zfo7hU8mm+hG1OwPw=; b=o/lmJbYfhgaImR08zQ86+zfmB3vIGO5JOO7RP7VRIMci0e3EFUhR5ofQzo8+V486by kwV13PMNqTAor6XI4GeEI7N2wn580Daa2ATzheGqjp9wLf/T7ZhTZIMp8FjL8qJaIJL8 +TcaUtNv8lWvPjbW9H+UptMhg4qELHymdeYShT5F0OD5kqCjAWtC4fKhtOibUlq9zLH1 XL/N1H0+m+pYp50uTrsaCs6Qqs8z+UTD8d9LfyT3bZso2FcXoGEz/AJT3N9ONQPJYkNK tjREDO1kPFcR9P/I5940Xf0J59yPl4dNpeZWvatbeNEA2/hiP2ZgxkRL/T679ftqup0I 0U3A== X-Gm-Message-State: AOJu0YwTVm4ftua5iO63WCB1uUUyGf5pV6Euyryd8pyZbe+0A2baN0qS HBy7lE9FdfMHrAPeex+sigAH0OFsmxbsrF5EI0kXR9M7XiR3pS0v5pbEi0/mMeXMK8iSkx4i2kl uR/MI+wZT/lgymIUZFYteF1O5a5qKQolB6vB3IKWfkZ6VGCB9xOlTbXkRfuDGZC+/g9PL1Ed5A1 ECzdhOVMEccg== X-Gm-Gg: ASbGncuR8nADiOrZAuoIjlN/MNNxkv9sZUjU+Vb11ZBB0OgxulrswZ2qE/ANEF/SbWT dAg9y5o7o4mpAecS9bVjcGj5O/C+bOkdM+4w6Qxg+k5jt+qNwx9zi3uELtSdCyEaq4qqjx9lXOb VX4lepgOZKZijgMpen5ZnCJl2OU0ogYGuWpJYdhGKFaewViuvY3gRC3OSD0urjFMj9OQJGweX1n cnv6ZGz7Rgzd8I4lSt24tFlnMpEDDZfE6hKLmWI5GkcBxG3KBUTsF2S8P/gDnKLJaMe9I8+3KCr 2sIMyTZI/bFrNXZiR5NEqxfeMdY+AQ== X-Received: by 2002:a17:90b:524f:b0:2ee:d024:e4fc with SMTP id 98e67ed59e1d1-3082367f7b5mr3348153a91.33.1744356459186; Fri, 11 Apr 2025 00:27:39 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHVHiDesUNm6IKHohFixLsCeexBOh81Ov1Y2zOBli1jyRJ3VeBJ/LxM7Rfld4ycb6JJ7fz34Q== X-Received: by 2002:a17:90b:524f:b0:2ee:d024:e4fc with SMTP id 98e67ed59e1d1-3082367f7b5mr3348117a91.33.1744356458628; Fri, 11 Apr 2025 00:27:38 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.37 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:38 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 10/13] gpio: aggregator: expose aggregator created via legacy sysfs to configfs Date: Fri, 11 Apr 2025 16:26:32 +0900 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 Expose settings for aggregators created using the sysfs 'new_device' interface to configfs. Once written to 'new_device', an "_sysfs." path appears in the configfs regardless of whether the probe succeeds. Consequently, users can no longer use that prefix for custom GPIO aggregator names. The 'live' attribute changes to 1 when the probe succeeds and the GPIO forwarder is instantiated. Note that the aggregator device created via sysfs is asynchronous, i.e. writing into 'new_device' returns without waiting for probe completion, and the probe may succeed, fail, or eventually succeed via deferred probe. Thus, the 'live' attribute may change from 0 to 1 asynchronously without notice. So, editing key/offset/name while it's waiting for deferred probe is prohibited. The configfs auto-generation relies on create_default_group(), which inherently prohibits rmdir(2). To align with the limitation, this commit also prohibits mkdir(2) for them. When users want to change the number of lines for an aggregator initialized via 'new_device', they need to tear down the device using 'delete_device' and reconfigure it from scratch. This does not break previous behavior; users of legacy sysfs interface simply gain additional almost read-only configfs exposure. Still, users can write to the 'live' attribute to toggle the device unless it's waiting for deferred probe. So once probe succeeds, they can deactivate it in the same manner as the devices initialized via configfs. Signed-off-by: Koichiro Den Link: https://lore.kernel.org/r/20250407043019.4105613-7-koichiro.den@canonical.com Signed-off-by: Bartosz Golaszewski (cherry picked from commit 83c8e3df642f5fde320278a5e6ce9e46f9689d1a linux-next) Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 138 ++++++++++++++++++++++++++++++--- 1 file changed, 126 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index b00b2065e534..6f4333553733 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -33,6 +33,7 @@ #include "dev-sync-probe.h" #define AGGREGATOR_MAX_GPIOS 512 +#define AGGREGATOR_LEGACY_PREFIX "_sysfs" /* * GPIO Aggregator sysfs interface @@ -131,6 +132,14 @@ static bool gpio_aggregator_is_active(struct gpio_aggregator *aggr) return aggr->probe_data.pdev && platform_get_drvdata(aggr->probe_data.pdev); } +/* Only aggregators created via legacy sysfs can be "activating". */ +static bool gpio_aggregator_is_activating(struct gpio_aggregator *aggr) +{ + lockdep_assert_held(&aggr->lock); + + return aggr->probe_data.pdev && !platform_get_drvdata(aggr->probe_data.pdev); +} + static size_t gpio_aggregator_count_lines(struct gpio_aggregator *aggr) { lockdep_assert_held(&aggr->lock); @@ -189,6 +198,30 @@ static void gpio_aggregator_line_del(struct gpio_aggregator *aggr, list_del(&line->entry); } +static void gpio_aggregator_free_lines(struct gpio_aggregator *aggr) +{ + struct gpio_aggregator_line *line, *tmp; + + list_for_each_entry_safe(line, tmp, &aggr->list_head, entry) { + configfs_unregister_group(&line->group); + /* + * Normally, we acquire aggr->lock within the configfs + * callback. However, in the legacy sysfs interface case, + * calling configfs_(un)register_group while holding + * aggr->lock could cause a deadlock. Fortunately, this is + * unnecessary because the new_device/delete_device path + * and the module unload path are mutually exclusive, + * thanks to an explicit try_module_get. That's why this + * minimal scoped_guard suffices. + */ + scoped_guard(mutex, &aggr->lock) + gpio_aggregator_line_del(aggr, line); + kfree(line->key); + kfree(line->name); + kfree(line); + } +} + /* * GPIO Forwarder @@ -691,7 +724,8 @@ gpio_aggregator_line_key_store(struct config_item *item, const char *page, guard(mutex)(&aggr->lock); - if (gpio_aggregator_is_active(aggr)) + if (gpio_aggregator_is_activating(aggr) || + gpio_aggregator_is_active(aggr)) return -EBUSY; kfree(line->key); @@ -728,7 +762,8 @@ gpio_aggregator_line_name_store(struct config_item *item, const char *page, guard(mutex)(&aggr->lock); - if (gpio_aggregator_is_active(aggr)) + if (gpio_aggregator_is_activating(aggr) || + gpio_aggregator_is_active(aggr)) return -EBUSY; kfree(line->name); @@ -774,7 +809,8 @@ gpio_aggregator_line_offset_store(struct config_item *item, const char *page, guard(mutex)(&aggr->lock); - if (gpio_aggregator_is_active(aggr)) + if (gpio_aggregator_is_activating(aggr) || + gpio_aggregator_is_active(aggr)) return -EBUSY; line->offset = offset; @@ -832,11 +868,12 @@ gpio_aggregator_device_live_store(struct config_item *item, const char *page, if (!try_module_get(THIS_MODULE)) return -ENOENT; - if (live) + if (live && !aggr->init_via_sysfs) gpio_aggregator_lockup_configfs(aggr, true); scoped_guard(mutex, &aggr->lock) { - if (live == gpio_aggregator_is_active(aggr)) + if (gpio_aggregator_is_activating(aggr) || + (live == gpio_aggregator_is_active(aggr))) ret = -EPERM; else if (live) ret = gpio_aggregator_activate(aggr); @@ -848,7 +885,7 @@ gpio_aggregator_device_live_store(struct config_item *item, const char *page, * Undepend is required only if device disablement (live == 0) * succeeds or if device enablement (live == 1) fails. */ - if (live == !!ret) + if (live == !!ret && !aggr->init_via_sysfs) gpio_aggregator_lockup_configfs(aggr, false); module_put(THIS_MODULE); @@ -892,7 +929,7 @@ static void gpio_aggregator_device_release(struct config_item *item) struct gpio_aggregator *aggr = to_gpio_aggregator(item); /* - * If the aggregator is active, this code wouldn't be reached, + * At this point, aggr is neither active nor activating, * so calling gpio_aggregator_deactivate() is always unnecessary. */ gpio_aggregator_free(aggr); @@ -914,6 +951,15 @@ gpio_aggregator_device_make_group(struct config_group *group, const char *name) if (ret != 1 || nchar != strlen(name)) return ERR_PTR(-EINVAL); + if (aggr->init_via_sysfs) + /* + * Aggregators created via legacy sysfs interface are exposed as + * default groups, which means rmdir(2) is prohibited for them. + * For simplicity, and to avoid confusion, we also prohibit + * mkdir(2). + */ + return ERR_PTR(-EPERM); + guard(mutex)(&aggr->lock); if (gpio_aggregator_is_active(aggr)) @@ -951,6 +997,14 @@ gpio_aggregator_make_group(struct config_group *group, const char *name) struct gpio_aggregator *aggr; int ret; + /* + * "_sysfs" prefix is reserved for auto-generated config group + * for devices create via legacy sysfs interface. + */ + if (strncmp(name, AGGREGATOR_LEGACY_PREFIX, + sizeof(AGGREGATOR_LEGACY_PREFIX)) == 0) + return ERR_PTR(-EINVAL); + /* arg space is unneeded */ ret = gpio_aggregator_alloc(&aggr, 0); if (ret) @@ -986,6 +1040,8 @@ static struct configfs_subsystem gpio_aggregator_subsys = { static int gpio_aggregator_parse(struct gpio_aggregator *aggr) { char *args = skip_spaces(aggr->args); + struct gpio_aggregator_line *line; + char name[CONFIGFS_ITEM_NAME_LEN]; char *key, *offsets, *p; unsigned int i, n = 0; int error = 0; @@ -1002,9 +1058,24 @@ static int gpio_aggregator_parse(struct gpio_aggregator *aggr) p = get_options(offsets, 0, &error); if (error == 0 || *p) { /* Named GPIO line */ + scnprintf(name, sizeof(name), "line%u", n); + line = gpio_aggregator_line_alloc(aggr, n, key, -1); + if (!line) { + error = -ENOMEM; + goto err; + } + config_group_init_type_name(&line->group, name, + &gpio_aggregator_line_type); + error = configfs_register_group(&aggr->group, + &line->group); + if (error) + goto err; + scoped_guard(mutex, &aggr->lock) + gpio_aggregator_line_add(aggr, line); + error = gpio_aggregator_add_gpio(aggr, key, U16_MAX, &n); if (error) - return error; + goto err; key = offsets; continue; @@ -1018,9 +1089,24 @@ static int gpio_aggregator_parse(struct gpio_aggregator *aggr) } for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { + scnprintf(name, sizeof(name), "line%u", n); + line = gpio_aggregator_line_alloc(aggr, n, key, i); + if (!line) { + error = -ENOMEM; + goto err; + } + config_group_init_type_name(&line->group, name, + &gpio_aggregator_line_type); + error = configfs_register_group(&aggr->group, + &line->group); + if (error) + goto err; + scoped_guard(mutex, &aggr->lock) + gpio_aggregator_line_add(aggr, line); + error = gpio_aggregator_add_gpio(aggr, key, i, &n); if (error) - return error; + goto err; } args = next_arg(args, &key, &p); @@ -1028,15 +1114,20 @@ static int gpio_aggregator_parse(struct gpio_aggregator *aggr) if (!n) { pr_err("No GPIOs specified\n"); - return -EINVAL; + goto err; } return 0; + +err: + gpio_aggregator_free_lines(aggr); + return error; } static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, const char *buf, size_t count) { + char name[CONFIGFS_ITEM_NAME_LEN]; struct gpio_aggregator *aggr; struct platform_device *pdev; int res; @@ -1065,10 +1156,25 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, goto free_table; } - res = gpio_aggregator_parse(aggr); + scnprintf(name, sizeof(name), "%s.%d", AGGREGATOR_LEGACY_PREFIX, aggr->id); + config_group_init_type_name(&aggr->group, name, &gpio_aggregator_device_type); + + /* + * Since the device created by sysfs might be toggled via configfs + * 'live' attribute later, this initialization is needed. + */ + dev_sync_probe_init(&aggr->probe_data); + + /* Expose to configfs */ + res = configfs_register_group(&gpio_aggregator_subsys.su_group, + &aggr->group); if (res) goto free_dev_id; + res = gpio_aggregator_parse(aggr); + if (res) + goto unregister_group; + gpiod_add_lookup_table(aggr->lookups); pdev = platform_device_register_simple(DRV_NAME, aggr->id, NULL, 0); @@ -1083,6 +1189,8 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, remove_table: gpiod_remove_lookup_table(aggr->lookups); +unregister_group: + configfs_unregister_group(&aggr->group); free_dev_id: kfree(aggr->lookups->dev_id); free_table: @@ -1099,7 +1207,13 @@ static struct driver_attribute driver_attr_gpio_aggregator_new_device = static void gpio_aggregator_destroy(struct gpio_aggregator *aggr) { - gpio_aggregator_deactivate(aggr); + scoped_guard(mutex, &aggr->lock) { + if (gpio_aggregator_is_activating(aggr) || + gpio_aggregator_is_active(aggr)) + gpio_aggregator_deactivate(aggr); + } + gpio_aggregator_free_lines(aggr); + configfs_unregister_group(&aggr->group); kfree(aggr); } From patchwork Fri Apr 11 07:26:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071366 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpDQ18xzz1yJZ for ; Fri, 11 Apr 2025 17:27:34 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38ni-0002wn-It; Fri, 11 Apr 2025 07:27:46 +0000 Received: from smtp-relay-internal-1.internal ([10.131.114.114] helo=smtp-relay-internal-1.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38ne-0002fm-Pn for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:42 +0000 Received: from mail-pl1-f198.google.com (mail-pl1-f198.google.com [209.85.214.198]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id CA301400AF for ; Fri, 11 Apr 2025 07:27:41 +0000 (UTC) Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-2255ae39f8fso25910165ad.0 for ; Fri, 11 Apr 2025 00:27:41 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356460; x=1744961260; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=dbtnNHlcSQqIis4ezm3k/i4X8N405Aa/YQATf/wYO9M=; b=HB1huAAi55FYVbYc+TBitKhQJHyWiaU3A1NwzUhrz2Rv804cDw38WBiCrSlkCOjcW2 Q1qA44pV51s/f8cfOyKSC/bsD+wJlxbl0bqrotqJaARa/krB8lgyFDLW9Ra7KyD4KbBN rdK01dbcxpdBBASisbBHTFLl0xuQJfV1DxDuqOVx1w+WOFLfc3Si5UPXhIN95Bd3Ebh4 Fr255eD5hjqdhFfAZ44WHgghQdlTXGO8YICJcsgp8tqQChVrjafEm92qyhOBF5f8Yllu gHOr2f1fKcB9UY513J8zWuAeriMOXpR0CQtMKRQuG1tPfuZiLPDETiy63Kph3OdLipoX W2bA== X-Gm-Message-State: AOJu0Yxr2H3c7zl8mD3t6gcCs/T2bN6uZDkPZuxqG2+DdnHoQDk3hcZg uzzeOH1m453eQx0rTctukcfPBX071GWC9RsI6fdx5XEk9kfCaONPNdFXDRmyqos+y+D2An7xFIK +K/py9PPzOGNnQzXD7PQfpoMu/K98PjVHALa4STIcqXaiff8baVT1IY7jPuccNelypJYpIjzSVy 8s1Z4xtwgfKQ== X-Gm-Gg: ASbGncsW0MehcU2Qy8XzADlliBZN7IqOSd+tLbJ6Ny6O6Ufx1vXodvHzA7ZTPWFMxHa rPbzJf4Ngr6olS+J60D8qOl2MDPUMC1t/kU08+mt2gvKoFx4mwDXeJTHxnEyjCvRxW3BiMceVm8 WvE1wbPDXC9sLClnbDFoH22Qni+rWzbiI4p174b0eI2FveUX9HZy9l5Pa1W6QFfj9U+oWquKHLO VeHzNGzHzmbgOnpauNcHYea9yySdkaaki00xYHFsAuGvSSue3aZ6pxj2eXXR2fiXKB1il2tBu02 hsBChhaKc+7h9R3m92/RX3FtBJkxzw== X-Received: by 2002:a17:903:1b0b:b0:215:a303:24e9 with SMTP id d9443c01a7336-22bea0253b4mr30939775ad.3.1744356460192; Fri, 11 Apr 2025 00:27:40 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFKjHvnkRQJoHR7q8BKEig3lOZ04tRgRK4Bbcwpqm0sr0g9gZWLwQ1v2Cw2FvAmJhhmgtcDDg== X-Received: by 2002:a17:903:1b0b:b0:215:a303:24e9 with SMTP id d9443c01a7336-22bea0253b4mr30939575ad.3.1744356459771; Fri, 11 Apr 2025 00:27:39 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.38 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:39 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 11/13] gpio: aggregator: cancel deferred probe for devices created via configfs Date: Fri, 11 Apr 2025 16:26:33 +0900 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 For aggregators initialized via configfs, write 1 to 'live' waits for probe completion and returns an error if the probe fails, unlike the legacy sysfs interface, which is asynchronous. Since users control the liveness of the aggregator device and might be editing configurations while 'live' is 0, deferred probing is both unnatural and unsafe. Cancel deferred probe for purely configfs-based aggregators when probe fails. Signed-off-by: Koichiro Den Link: https://lore.kernel.org/r/20250407043019.4105613-8-koichiro.den@canonical.com Signed-off-by: Bartosz Golaszewski (cherry picked from commit 0269c768de1b5e430c3f9a6869261606c82abe90 linux-next) Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 6f4333553733..6745692951f9 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -72,6 +72,10 @@ struct gpio_aggregator_line { enum gpio_lookup_flags flags; }; +struct gpio_aggregator_pdev_meta { + bool init_via_sysfs; +}; + static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */ static DEFINE_IDR(gpio_aggregator_idr); @@ -1127,6 +1131,7 @@ static int gpio_aggregator_parse(struct gpio_aggregator *aggr) static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, const char *buf, size_t count) { + struct gpio_aggregator_pdev_meta meta = { .init_via_sysfs = true }; char name[CONFIGFS_ITEM_NAME_LEN]; struct gpio_aggregator *aggr; struct platform_device *pdev; @@ -1177,7 +1182,7 @@ static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver, gpiod_add_lookup_table(aggr->lookups); - pdev = platform_device_register_simple(DRV_NAME, aggr->id, NULL, 0); + pdev = platform_device_register_data(NULL, DRV_NAME, aggr->id, &meta, sizeof(meta)); if (IS_ERR(pdev)) { res = PTR_ERR(pdev); goto remove_table; @@ -1270,7 +1275,9 @@ ATTRIBUTE_GROUPS(gpio_aggregator); static int gpio_aggregator_probe(struct platform_device *pdev) { + struct gpio_aggregator_pdev_meta *meta; struct device *dev = &pdev->dev; + bool init_via_sysfs = false; struct gpio_desc **descs; struct gpiochip_fwd *fwd; unsigned long features; @@ -1284,10 +1291,28 @@ static int gpio_aggregator_probe(struct platform_device *pdev) if (!descs) return -ENOMEM; + meta = dev_get_platdata(&pdev->dev); + if (meta && meta->init_via_sysfs) + init_via_sysfs = true; + for (i = 0; i < n; i++) { descs[i] = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS); - if (IS_ERR(descs[i])) + if (IS_ERR(descs[i])) { + /* + * Deferred probing is not suitable when the aggregator + * is created via configfs. They should just retry later + * whenever they like. For device creation via sysfs, + * error is propagated without overriding for backward + * compatibility. .prevent_deferred_probe is kept unset + * for other cases. + */ + if (!init_via_sysfs && !dev_of_node(dev) && + descs[i] == ERR_PTR(-EPROBE_DEFER)) { + pr_warn("Deferred probe canceled for creation via configfs.\n"); + return -ENODEV; + } return PTR_ERR(descs[i]); + } } features = (uintptr_t)device_get_match_data(dev); From patchwork Fri Apr 11 07:26:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071365 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpDN0xSGz1yHt for ; Fri, 11 Apr 2025 17:27:32 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38ng-0002oQ-Ip; Fri, 11 Apr 2025 07:27:44 +0000 Received: from smtp-relay-internal-1.internal ([10.131.114.114] helo=smtp-relay-internal-1.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38nf-0002lL-NN for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:43 +0000 Received: from mail-pj1-f72.google.com (mail-pj1-f72.google.com [209.85.216.72]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 45E2B400AF for ; Fri, 11 Apr 2025 07:27:43 +0000 (UTC) Received: by mail-pj1-f72.google.com with SMTP id 98e67ed59e1d1-3082946f829so115539a91.0 for ; Fri, 11 Apr 2025 00:27:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356461; x=1744961261; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CZ6kElinfxeAlNz/rA9L6uEGTm7s2zy36MrQb/qdn0I=; b=tJ3jqycZP8ncyDnk/HQmLQbpm6qzrARTlJdmj9Fxv8fJ0tmOEcgi/SxNAEsD2p7JjF QmatulvnQP7K1E3i+O4CvAye98gH0pblk8SvvrTLqeomMwqM6jloqE6lGme73D1SearA aCrtHpkAjq6z6h7P2tzVi28qDbLl2pQSODBJl3exrfTNsf1uLNVxqOechUZdXjhlnkoQ pUpnkZ/6/YarOV4IARgyYXC99nS/H+1v1KQKihaChboamcxm2kMFW43e5dzKnZwCfm1x 2jcVB3x2AJFvLe1GIdeGwiH/wDTuVrlC3Vbg0ahrU5XhxIFv5m0SAPTEEOr1OyqRJLLg UWUg== X-Gm-Message-State: AOJu0YzycdfBT3olH3aICOwkLgorbPpLiGF+1jsVbDqYwhEpPIc/kmKw 3vnOCGcuPGoShyBbcnaHZigitk1NCmHMEg39mHDl2AH/8UypsBgPYMoeaKXuCxQABvnu3aL2fLx JfsBloVdVguVToMyodQ18p8wVUtqfJY2iivy8EfKJjtErO+H69V36Jrmn5wiqfHkhPDpjU8Zhel i4nkG/yjFKAA== X-Gm-Gg: ASbGncvcImrHBmLNxyXtmI4CBRmqQnZmGyyPhKb2ufNWSgEzEdA216PxZbPTh3DHLFA NpGJT8zYKl39MzhXkRELJWgDt+gogrUsubiroH0otTus6B2wSCvCPeVsoOnbY3xjMp1KlBnaVeF PhwwLAjs32KVBm4AEmds33z5Ie3XW0R+Fc89jzpvVRYCfqewvbUyanqcelasmF7lHlv2YjNeGw7 MEyXNQJzaKLVnMqzwrG3Bgox9Ma2MhP9FehRiHOHol78RHw4DHjVAJroF8TcIbIapoFv7PnRhw6 zvxsLoVJEuiM/m10Hcdc7GEwA5qlxA== X-Received: by 2002:a17:90b:524f:b0:2ee:d024:e4fc with SMTP id 98e67ed59e1d1-3082367f7b5mr3348293a91.33.1744356461453; Fri, 11 Apr 2025 00:27:41 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHkS1c0c/TA5wNQ5zoC9LPL+O+d4LvVwujkAP5NKxED4p8j9nE2/QNxwOoa+1x72yli7eOhNQ== X-Received: by 2002:a17:90b:524f:b0:2ee:d024:e4fc with SMTP id 98e67ed59e1d1-3082367f7b5mr3348264a91.33.1744356460979; Fri, 11 Apr 2025 00:27:40 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.40 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:40 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 12/13] Documentation: gpio: document configfs interface for gpio-aggregator Date: Fri, 11 Apr 2025 16:26:34 +0900 Message-ID: <8d8d458c3e47b76e8797652135882540d201b20f.1744350629.git.koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 Add documentation for the newly added configfs-based interface for GPIO aggregator. Signed-off-by: Koichiro Den Link: https://lore.kernel.org/r/20250407043019.4105613-9-koichiro.den@canonical.com Signed-off-by: Bartosz Golaszewski (cherry picked from commit 10f94d092bba9ab08004c624c604e976e6e3cd22 linux-next) Signed-off-by: Koichiro Den --- .../admin-guide/gpio/gpio-aggregator.rst | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/Documentation/admin-guide/gpio/gpio-aggregator.rst b/Documentation/admin-guide/gpio/gpio-aggregator.rst index 5cd1e7221756..8374a9df9105 100644 --- a/Documentation/admin-guide/gpio/gpio-aggregator.rst +++ b/Documentation/admin-guide/gpio/gpio-aggregator.rst @@ -69,6 +69,113 @@ write-only attribute files in sysfs. $ echo gpio-aggregator.0 > delete_device +Aggregating GPIOs using Configfs +-------------------------------- + +**Group:** ``/config/gpio-aggregator`` + + This is the root directory of the gpio-aggregator configfs tree. + +**Group:** ``/config/gpio-aggregator/`` + + This directory represents a GPIO aggregator device. You can assign any + name to ```` (e.g. ``agg0``), except names starting with + ``_sysfs`` prefix, which are reserved for auto-generated configfs + entries corresponding to devices created via Sysfs. + +**Attribute:** ``/config/gpio-aggregator//live`` + + The ``live`` attribute allows to trigger the actual creation of the device + once it's fully configured. Accepted values are: + + * ``1``, ``yes``, ``true`` : enable the virtual device + * ``0``, ``no``, ``false`` : disable the virtual device + +**Attribute:** ``/config/gpio-aggregator//dev_name`` + + The read-only ``dev_name`` attribute exposes the name of the device as it + will appear in the system on the platform bus (e.g. ``gpio-aggregator.0``). + This is useful for identifying a character device for the newly created + aggregator. If it's ``gpio-aggregator.0``, + ``/sys/devices/platform/gpio-aggregator.0/gpiochipX`` path tells you that the + GPIO device id is ``X``. + +You must create subdirectories for each virtual line you want to +instantiate, named exactly as ``line0``, ``line1``, ..., ``lineY``, when +you want to instantiate ``Y+1`` (Y >= 0) lines. Configure all lines before +activating the device by setting ``live`` to 1. + +**Group:** ``/config/gpio-aggregator///`` + + This directory represents a GPIO line to include in the aggregator. + +**Attribute:** ``/config/gpio-aggregator///key`` + +**Attribute:** ``/config/gpio-aggregator///offset`` + + The default values after creating the ```` directory are: + + * ``key`` : + * ``offset`` : -1 + + ``key`` must always be explicitly configured, while ``offset`` depends. + Two configuration patterns exist for each ````: + + (a). For lookup by GPIO line name: + + * Set ``key`` to the line name. + * Ensure ``offset`` remains -1 (the default). + + (b). For lookup by GPIO chip name and the line offset within the chip: + + * Set ``key`` to the chip name. + * Set ``offset`` to the line offset (0 <= ``offset`` < 65535). + +**Attribute:** ``/config/gpio-aggregator///name`` + + The ``name`` attribute sets a custom name for lineY. If left unset, the + line will remain unnamed. + +Once the configuration is done, the ``'live'`` attribute must be set to 1 +in order to instantiate the aggregator device. It can be set back to 0 to +destroy the virtual device. The module will synchronously wait for the new +aggregator device to be successfully probed and if this doesn't happen, writing +to ``'live'`` will result in an error. This is a different behaviour from the +case when you create it using sysfs ``new_device`` interface. + +.. note:: + + For aggregators created via Sysfs, the configfs entries are + auto-generated and appear as ``/config/gpio-aggregator/_sysfs./``. You + cannot add or remove line directories with mkdir(2)/rmdir(2). To modify + lines, you must use the "delete_device" interface to tear down the + existing device and reconfigure it from scratch. However, you can still + toggle the aggregator with the ``live`` attribute and adjust the + ``key``, ``offset``, and ``name`` attributes for each line when ``live`` + is set to 0 by hand (i.e. it's not waiting for deferred probe). + +Sample configuration commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: sh + + # Create a directory for an aggregator device + $ mkdir /sys/kernel/config/gpio-aggregator/agg0 + + # Configure each line + $ mkdir /sys/kernel/config/gpio-aggregator/agg0/line0 + $ echo gpiochip0 > /sys/kernel/config/gpio-aggregator/agg0/line0/key + $ echo 6 > /sys/kernel/config/gpio-aggregator/agg0/line0/offset + $ echo test0 > /sys/kernel/config/gpio-aggregator/agg0/line0/name + $ mkdir /sys/kernel/config/gpio-aggregator/agg0/line1 + $ echo gpiochip0 > /sys/kernel/config/gpio-aggregator/agg0/line1/key + $ echo 7 > /sys/kernel/config/gpio-aggregator/agg0/line1/offset + $ echo test1 > /sys/kernel/config/gpio-aggregator/agg0/line1/name + + # Activate the aggregator device + $ echo 1 > /sys/kernel/config/gpio-aggregator/agg0/live + + Generic GPIO Driver ------------------- From patchwork Fri Apr 11 07:26:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 2071370 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4ZYpDT5d5wz1yHt for ; Fri, 11 Apr 2025 17:27:37 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1u38nl-00039F-Ev; Fri, 11 Apr 2025 07:27:49 +0000 Received: from smtp-relay-internal-1.internal ([10.131.114.114] helo=smtp-relay-internal-1.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1u38ni-0002tD-4O for kernel-team@lists.ubuntu.com; Fri, 11 Apr 2025 07:27:46 +0000 Received: from mail-pl1-f199.google.com (mail-pl1-f199.google.com [209.85.214.199]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 37912400AF for ; Fri, 11 Apr 2025 07:27:45 +0000 (UTC) Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-22403329f9eso14833995ad.3 for ; Fri, 11 Apr 2025 00:27:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744356463; x=1744961263; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=IZ/lLH1g7ZBdFIghO7vkn0UTastMX5NLJd4EZFr6sDA=; b=BQ6EMpHSLedpSNp4RMMylfSGD2YKBYfs4vEQVzfBWSrKDXQpd576f6zu5xKQqPPS2p wEBKF8zvZnBBDfxGyPencDG8dUYyL1Lnfe8b4mgZmuHy1t9cQ71qFKfCiLrCohkVKW+2 n5boIqijN6UdnKmYtoz63kn8CwfSnMY7Lh8pws3C3Vu1h+Caw45tOdbeeBdpr8CAhIFv du8Ry35ioGrx+PxJBlUcQBJU9GP1MB66NLpA23zcSQwsnOsCo2F0HCYehNL7NP3oPKbP yB7iHZC6CPXjPjt6C+P366x2/nuC0K0QhK0EBwImEx4wEFLg+NRQD2NYtpAt6dIfpAaa DrRg== X-Gm-Message-State: AOJu0YzM2md8q3JB6Y7GCDkkihpLMq1caAolaOCGVPleZL7/QU/o9kLo 3Nscjf9bbaMOAsqChSlPwa4DWtOJ9lPJuFdqqB8/L3yhPCHbjSfJCVEmA30tIWPNQQLB5v/07/k xGuRzhzgLORvtVsbad0tjMbvMJ8BPKj2MpioGoO1jN5NkzVlKYEvwRefvcHqV27mIYYzimmEmVp /736beUsDLTA== X-Gm-Gg: ASbGncuU6jg18hDwK6IfSg1tK6lBIYzduhu2KGt5TDfTqOFNUGc9+Bfe1B/9rZFqAHz 4O9cRyeYJD8yVljZmIhG9l7WWb35JimhXR7EjHU3o9ZAGPQetzYZFbKrXM1Q8cySIBr6B10bj5c TNkxITm3bDFyh2+qqIyW7/kBItqpEGarWnYoVCDewMfDuFXi2j+TFXLv5Xs/ikgkUJhavFrjwXk dsJmmaGl/toy7fHmAeVEAXq5dkC9Th2zDAQus2Uxp7kvBYJQ4VE9EQFL7ptZDvk1EJzm2uUAfwy sHxtdBpRs9OnzhDkXQrWJgG8Q8ClDw== X-Received: by 2002:a17:903:228f:b0:220:bcc5:2845 with SMTP id d9443c01a7336-22bea49548fmr23000655ad.7.1744356463272; Fri, 11 Apr 2025 00:27:43 -0700 (PDT) X-Google-Smtp-Source: AGHT+IExCuZAS4GhIb0ksIk0mYTUD7ZA8CyT331SYW1NBB8oXturC2iZ+ZdXR9hY77qkC1YrzEyZ+w== X-Received: by 2002:a17:903:228f:b0:220:bcc5:2845 with SMTP id d9443c01a7336-22bea49548fmr23000295ad.7.1744356462317; Fri, 11 Apr 2025 00:27:42 -0700 (PDT) Received: from localhost.localdomain ([240f:74:7be:1:f99c:bbee:3855:787c]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cda517sm42421105ad.250.2025.04.11.00.27.41 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 00:27:41 -0700 (PDT) From: Koichiro Den To: kernel-team@lists.ubuntu.com Subject: [SRU][O][PATCH 13/13] selftests: gpio: add test cases for gpio-aggregator Date: Fri, 11 Apr 2025 16:26:35 +0900 Message-ID: <7185d95109608a32fd27f45fb157d2f54c3f9ffd.1744350629.git.koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: <174435057828.183979.10447742120666677608@z790sl> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/2103496 Add a set of tests for gpio-aggregator module. This test covers both pre-existing new_device/delete_device interface and new configfs-based interface. Signed-off-by: Koichiro Den Link: https://lore.kernel.org/r/20250407043019.4105613-10-koichiro.den@canonical.com Signed-off-by: Bartosz Golaszewski (cherry picked from commit 6d7f0c1103ef3935eb3f302d09af4ef9e85212a3 linux-next) Signed-off-by: Koichiro Den --- tools/testing/selftests/gpio/Makefile | 2 +- tools/testing/selftests/gpio/config | 1 + .../testing/selftests/gpio/gpio-aggregator.sh | 723 ++++++++++++++++++ 3 files changed, 725 insertions(+), 1 deletion(-) create mode 100755 tools/testing/selftests/gpio/gpio-aggregator.sh diff --git a/tools/testing/selftests/gpio/Makefile b/tools/testing/selftests/gpio/Makefile index e0884390447d..7bfe315f7001 100644 --- a/tools/testing/selftests/gpio/Makefile +++ b/tools/testing/selftests/gpio/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -TEST_PROGS := gpio-mockup.sh gpio-sim.sh +TEST_PROGS := gpio-mockup.sh gpio-sim.sh gpio-aggregator.sh TEST_FILES := gpio-mockup-sysfs.sh TEST_GEN_PROGS_EXTENDED := gpio-mockup-cdev gpio-chip-info gpio-line-name CFLAGS += -O2 -g -Wall $(KHDR_INCLUDES) diff --git a/tools/testing/selftests/gpio/config b/tools/testing/selftests/gpio/config index 409a8532facc..1287abeaac7e 100644 --- a/tools/testing/selftests/gpio/config +++ b/tools/testing/selftests/gpio/config @@ -2,3 +2,4 @@ CONFIG_GPIOLIB=y CONFIG_GPIO_CDEV=y CONFIG_GPIO_MOCKUP=m CONFIG_GPIO_SIM=m +CONFIG_GPIO_AGGREGATOR=m diff --git a/tools/testing/selftests/gpio/gpio-aggregator.sh b/tools/testing/selftests/gpio/gpio-aggregator.sh new file mode 100755 index 000000000000..f1bab62c4cd2 --- /dev/null +++ b/tools/testing/selftests/gpio/gpio-aggregator.sh @@ -0,0 +1,723 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2025 Bartosz Golaszewski +# Copyright (C) 2025 Koichiro Den + +BASE_DIR=$(dirname "$0") +CONFIGFS_SIM_DIR="/sys/kernel/config/gpio-sim" +CONFIGFS_AGG_DIR="/sys/kernel/config/gpio-aggregator" +SYSFS_AGG_DIR="/sys/bus/platform/drivers/gpio-aggregator" +MODULE="gpio-aggregator" + +fail() { + echo "$*" >&2 + echo "GPIO $MODULE test FAIL" + exit 1 +} + +skip() { + echo "$*" >&2 + echo "GPIO $MODULE test SKIP" + exit 4 +} + +# gpio-sim +sim_enable_chip() { + local CHIP=$1 + + echo 1 > "$CONFIGFS_SIM_DIR/$CHIP/live" || fail "Unable to enable the chip" +} + +sim_disable_chip() { + local CHIP=$1 + + echo 0 > "$CONFIGFS_SIM_DIR/$CHIP/live" || fail "Unable to disable the chip" +} + +sim_configfs_cleanup() { + local NOCHECK=${1:-0} + + for CHIP_DIR in "$CONFIGFS_SIM_DIR"/*; do + [ -d "$CHIP_DIR" ] || continue + echo 0 > "$CHIP_DIR/live" + find "$CHIP_DIR" -depth -type d -exec rmdir {} \; + done + [ "$NOCHECK" -eq 1 ] && return; + remaining=$(find "$CONFIGFS_SIM_DIR" -mindepth 1 -type d 2> /dev/null) + if [ -n "$remaining" ]; then + fail "Directories remain in $CONFIGFS_SIM_DIR: $remaining" + fi +} + +sim_get_chip_label() { + local CHIP=$1 + local BANK=$2 + local CHIP_NAME=$(cat "$CONFIGFS_SIM_DIR/$CHIP/$BANK/chip_name" 2> /dev/null) || \ + fail "Unable to read the chip name from configfs" + + $BASE_DIR/gpio-chip-info "/dev/$CHIP_NAME" label || \ + fail "Unable to read the chip label from the character device" +} + +# gpio-aggregator +agg_create_chip() { + local CHIP=$1 + + mkdir "$CONFIGFS_AGG_DIR/$CHIP" +} + +agg_remove_chip() { + local CHIP=$1 + + find "$CONFIGFS_AGG_DIR/$CHIP/" -depth -type d -exec rmdir {} \; || \ + fail "Unable to remove $CONFIGFS_AGG_DIR/$CHIP" +} + +agg_create_line() { + local CHIP=$1 + local LINE=$2 + + mkdir "$CONFIGFS_AGG_DIR/$CHIP/$LINE" +} + +agg_remove_line() { + local CHIP=$1 + local LINE=$2 + + rmdir "$CONFIGFS_AGG_DIR/$CHIP/$LINE" +} + +agg_set_key() { + local CHIP=$1 + local LINE=$2 + local KEY=$3 + + echo "$KEY" > "$CONFIGFS_AGG_DIR/$CHIP/$LINE/key" || fail "Unable to set the lookup key" +} + +agg_set_offset() { + local CHIP=$1 + local LINE=$2 + local OFFSET=$3 + + echo "$OFFSET" > "$CONFIGFS_AGG_DIR/$CHIP/$LINE/offset" || \ + fail "Unable to set the lookup offset" +} + +agg_set_line_name() { + local CHIP=$1 + local LINE=$2 + local NAME=$3 + + echo "$NAME" > "$CONFIGFS_AGG_DIR/$CHIP/$LINE/name" || fail "Unable to set the line name" +} + +agg_enable_chip() { + local CHIP=$1 + + echo 1 > "$CONFIGFS_AGG_DIR/$CHIP/live" || fail "Unable to enable the chip" +} + +agg_disable_chip() { + local CHIP=$1 + + echo 0 > "$CONFIGFS_AGG_DIR/$CHIP/live" || fail "Unable to disable the chip" +} + +agg_configfs_cleanup() { + local NOCHECK=${1:-0} + + for CHIP_DIR in "$CONFIGFS_AGG_DIR"/*; do + [ -d "$CHIP_DIR" ] || continue + echo 0 > "$CHIP_DIR/live" 2> /dev/null + find "$CHIP_DIR" -depth -type d -exec rmdir {} \; + done + [ "$NOCHECK" -eq 1 ] && return; + remaining=$(find "$CONFIGFS_AGG_DIR" -mindepth 1 -type d 2> /dev/null) + if [ -n "$remaining" ]; then + fail "Directories remain in $CONFIGFS_AGG_DIR: $remaining" + fi +} + +agg_configfs_dev_name() { + local CHIP=$1 + + cat "$CONFIGFS_AGG_DIR/$CHIP/dev_name" 2> /dev/null || \ + fail "Unable to read the device name from configfs" +} + +agg_configfs_chip_name() { + local CHIP=$1 + local DEV_NAME=$(agg_configfs_dev_name "$CHIP") + local CHIP_LIST=$(find "/sys/devices/platform/$DEV_NAME" \ + -maxdepth 1 -type d -name "gpiochip[0-9]*" 2> /dev/null) + local CHIP_COUNT=$(echo "$CHIP_LIST" | wc -l) + + if [ -z "$CHIP_LIST" ]; then + fail "No gpiochip in /sys/devices/platform/$DEV_NAME/" + elif [ "$CHIP_COUNT" -ne 1 ]; then + fail "Multiple gpiochips unexpectedly found: $CHIP_LIST" + fi + basename "$CHIP_LIST" +} + +agg_get_chip_num_lines() { + local CHIP=$1 + local N_DIR=$(ls -d $CONFIGFS_AGG_DIR/$CHIP/line[0-9]* 2> /dev/null | wc -l) + local N_LINES + + if [ "$(cat $CONFIGFS_AGG_DIR/$CHIP/live)" = 0 ]; then + echo "$N_DIR" + else + N_LINES=$( + $BASE_DIR/gpio-chip-info \ + "/dev/$(agg_configfs_chip_name "$CHIP")" num-lines + ) || fail "Unable to read the number of lines from the character device" + if [ $N_DIR != $N_LINES ]; then + fail "Discrepancy between two sources for the number of lines" + fi + echo "$N_LINES" + fi +} + +agg_get_chip_label() { + local CHIP=$1 + + $BASE_DIR/gpio-chip-info "/dev/$(agg_configfs_chip_name "$CHIP")" label || \ + fail "Unable to read the chip label from the character device" +} + +agg_get_line_name() { + local CHIP=$1 + local OFFSET=$2 + local NAME_CONFIGFS=$(cat "$CONFIGFS_AGG_DIR/$CHIP/line${OFFSET}/name") + local NAME_CDEV + + if [ "$(cat "$CONFIGFS_AGG_DIR/$CHIP/live")" = 0 ]; then + echo "$NAME_CONFIGFS" + else + NAME_CDEV=$( + $BASE_DIR/gpio-line-name \ + "/dev/$(agg_configfs_chip_name "$CHIP")" "$OFFSET" + ) || fail "Unable to read the line name from the character device" + if [ "$NAME_CONFIGFS" != "$NAME_CDEV" ]; then + fail "Discrepancy between two sources for the name of line" + fi + echo "$NAME_CDEV" + fi +} + + +# Load the modules. This will pull in configfs if needed too. +modprobe gpio-sim || skip "unable to load the gpio-sim module" +modprobe gpio-aggregator || skip "unable to load the gpio-aggregator module" + +# Make sure configfs is mounted at /sys/kernel/config. Wait a bit if needed. +for IDX in $(seq 5); do + if [ "$IDX" -eq "5" ]; then + skip "configfs not mounted at /sys/kernel/config" + fi + + mountpoint -q /sys/kernel/config && break + sleep 0.1 +done + +# If the module was already loaded: remove all previous chips +agg_configfs_cleanup +sim_configfs_cleanup + +trap "exit 1" SIGTERM SIGINT +trap "agg_configfs_cleanup 1; sim_configfs_cleanup 1" EXIT + +# Use gpio-sim chips as the test backend +for CHIP in $(seq -f "chip%g" 0 1); do + mkdir $CONFIGFS_SIM_DIR/$CHIP + for BANK in $(seq -f "bank%g" 0 1); do + mkdir -p "$CONFIGFS_SIM_DIR/$CHIP/$BANK" + echo "${CHIP}_${BANK}" > "$CONFIGFS_SIM_DIR/$CHIP/$BANK/label" || \ + fail "unable to set the chip label" + echo 16 > "$CONFIGFS_SIM_DIR/$CHIP/$BANK/num_lines" || \ + fail "unable to set the number of lines" + for IDX in $(seq 0 15); do + LINE_NAME="${CHIP}${BANK}_${IDX}" + LINE_DIR="$CONFIGFS_SIM_DIR/$CHIP/$BANK/line$IDX" + mkdir -p $LINE_DIR + echo "$LINE_NAME" > "$LINE_DIR/name" || fail "unable to set the line name" + done + done + sim_enable_chip "$CHIP" +done + +echo "1. GPIO aggregator creation/deletion" + +echo "1.1. Creation/deletion via configfs" + +echo "1.1.1. Minimum creation/deletion" +agg_create_chip agg0 +agg_create_line agg0 line0 +agg_set_key agg0 line0 "$(sim_get_chip_label chip0 bank0)" +agg_set_offset agg0 line0 5 +agg_set_line_name agg0 line0 test0 +agg_enable_chip agg0 +test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 1 || fail "chip unexpectedly dead" +test "$(agg_get_chip_label agg0)" = "$(agg_configfs_dev_name agg0)" || \ + fail "label is inconsistent" +test "$(agg_get_chip_num_lines agg0)" = "1" || fail "number of lines is not 1" +test "$(agg_get_line_name agg0 0)" = "test0" || fail "line name is unset" +agg_disable_chip agg0 +agg_remove_line agg0 line0 +agg_remove_chip agg0 + +echo "1.1.2. Complex creation/deletion" +agg_create_chip agg0 +agg_create_line agg0 line0 +agg_create_line agg0 line1 +agg_create_line agg0 line2 +agg_create_line agg0 line3 +agg_set_key agg0 line0 "$(sim_get_chip_label chip0 bank0)" +agg_set_key agg0 line1 "$(sim_get_chip_label chip0 bank1)" +agg_set_key agg0 line2 "$(sim_get_chip_label chip1 bank0)" +agg_set_key agg0 line3 "$(sim_get_chip_label chip1 bank1)" +agg_set_offset agg0 line0 1 +agg_set_offset agg0 line1 3 +agg_set_offset agg0 line2 5 +agg_set_offset agg0 line3 7 +agg_set_line_name agg0 line0 test0 +agg_set_line_name agg0 line1 test1 +agg_set_line_name agg0 line2 test2 +agg_set_line_name agg0 line3 test3 +agg_enable_chip agg0 +test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 1 || fail "chip unexpectedly dead" +test "$(agg_get_chip_label agg0)" = "$(agg_configfs_dev_name agg0)" || \ + fail "label is inconsistent" +test "$(agg_get_chip_num_lines agg0)" = "4" || fail "number of lines is not 1" +test "$(agg_get_line_name agg0 0)" = "test0" || fail "line name is unset" +test "$(agg_get_line_name agg0 1)" = "test1" || fail "line name is unset" +test "$(agg_get_line_name agg0 2)" = "test2" || fail "line name is unset" +test "$(agg_get_line_name agg0 3)" = "test3" || fail "line name is unset" +agg_disable_chip agg0 +agg_remove_line agg0 line0 +agg_remove_line agg0 line1 +agg_remove_line agg0 line2 +agg_remove_line agg0 line3 +agg_remove_chip agg0 + +echo "1.1.3. Can't instantiate a chip without any line" +agg_create_chip agg0 +echo 1 > "$CONFIGFS_AGG_DIR/agg0/live" 2> /dev/null && fail "chip unexpectedly enabled" +test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 0 || fail "chip unexpectedly alive" +agg_remove_chip agg0 + +echo "1.1.4. Can't instantiate a chip with invalid configuration" +agg_create_chip agg0 +agg_create_line agg0 line0 +agg_set_key agg0 line0 "chipX_bankX" +agg_set_offset agg0 line0 99 +agg_set_line_name agg0 line0 test0 +echo 1 > "$CONFIGFS_AGG_DIR/agg0/live" 2> /dev/null && fail "chip unexpectedly enabled" +test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 0 || fail "chip unexpectedly alive" +agg_remove_line agg0 line0 +agg_remove_chip agg0 + +echo "1.1.5. Can't instantiate a chip asynchronously via deferred probe" +agg_create_chip agg0 +agg_create_line agg0 line0 +agg_set_key agg0 line0 "chip0_bank0" +agg_set_offset agg0 line0 5 +agg_set_line_name agg0 line0 test0 +sim_disable_chip chip0 +echo 1 > "$CONFIGFS_AGG_DIR/agg0/live" 2> /dev/null && fail "chip unexpectedly enabled" +test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 0 || fail "chip unexpectedly alive" +sim_enable_chip chip0 +sleep 1 +test "$(cat "$CONFIGFS_AGG_DIR/agg0/live")" = 0 || \ + fail "chip unexpectedly transitioned to 'live' state" +agg_remove_line agg0 line0 +agg_remove_chip agg0 + +echo "1.2. Creation/deletion via sysfs" + +echo "1.2.1. Minimum creation/deletion" +echo "chip0_bank0 0" > "$SYSFS_AGG_DIR/new_device" +CHIPNAME=$(agg_configfs_chip_name _sysfs.0) +test "$(cat "$CONFIGFS_AGG_DIR/_sysfs.0/live")" = 1 || fail "chip unexpectedly dead" +test "$(agg_get_chip_label _sysfs.0)" = "$(agg_configfs_dev_name _sysfs.0)" || \ + fail "label is inconsistent" +test "$(agg_get_chip_num_lines _sysfs.0)" = "1" || fail "number of lines is not 1" +test "$(agg_get_line_name _sysfs.0 0)" = "" || fail "line name is unset" +echo "$(agg_configfs_dev_name _sysfs.0)" > "$SYSFS_AGG_DIR/delete_device" +test -d $CONFIGFS_AGG_DIR/_sysfs.0 && fail "_sysfs.0 unexpectedly remains" +test -d /dev/${CHIPNAME} && fail "/dev/${CHIPNAME} unexpectedly remains" + +echo "1.2.2. Complex creation/deletion" +echo "chip0bank0_0 chip1_bank1 10-11" > "$SYSFS_AGG_DIR/new_device" +CHIPNAME=$(agg_configfs_chip_name _sysfs.0) +test "$(cat "$CONFIGFS_AGG_DIR/_sysfs.0/live")" = 1 || fail "chip unexpectedly dead" +test "$(agg_get_chip_label _sysfs.0)" = "$(agg_configfs_dev_name _sysfs.0)" || \ + fail "label is inconsistent" +test "$(agg_get_chip_num_lines _sysfs.0)" = "3" || fail "number of lines is not 3" +test "$(agg_get_line_name _sysfs.0 0)" = "" || fail "line name is unset" +test "$(agg_get_line_name _sysfs.0 1)" = "" || fail "line name is unset" +test "$(agg_get_line_name _sysfs.0 2)" = "" || fail "line name is unset" +echo "$(agg_configfs_dev_name _sysfs.0)" > "$SYSFS_AGG_DIR/delete_device" +test -d $CONFIGFS_AGG_DIR/_sysfs.0 && fail "_sysfs.0 unexpectedly remains" +test -d /dev/${CHIPNAME} && fail "/dev/${CHIPNAME} unexpectedly remains" + +echo "1.2.3. Asynchronous creation with deferred probe" +sim_disable_chip chip0 +echo 'chip0_bank0 0' > $SYSFS_AGG_DIR/new_device +sleep 1 +test "$(cat "$CONFIGFS_AGG_DIR/_sysfs.0/live")" = 0 || fail "chip unexpectedly alive" +sim_enable_chip chip0 +sleep 1 +CHIPNAME=$(agg_configfs_chip_name _sysfs.0) +test "$(cat "$CONFIGFS_AGG_DIR/_sysfs.0/live")" = 1 || fail "chip unexpectedly remains dead" +test "$(agg_get_chip_label _sysfs.0)" = "$(agg_configfs_dev_name _sysfs.0)" || \ + fail "label is inconsistent" +test "$(agg_get_chip_num_lines _sysfs.0)" = "1" || fail "number of lines is not 1" +test "$(agg_get_line_name _sysfs.0 0)" = "" || fail "line name unexpectedly set" +echo "$(agg_configfs_dev_name _sysfs.0)" > "$SYSFS_AGG_DIR/delete_device" +test -d $CONFIGFS_AGG_DIR/_sysfs.0 && fail "_sysfs.0 unexpectedly remains" +test -d /dev/${CHIPNAME} && fail "/dev/${CHIPNAME} unexpectedly remains" + +echo "1.2.4. Can't instantiate a chip with invalid configuration" +echo "xyz 0" > "$SYSFS_AGG_DIR/new_device" +test "$(cat $CONFIGFS_AGG_DIR/_sysfs.0/live)" = 0 || fail "chip unexpectedly alive" +echo "$(agg_configfs_dev_name _sysfs.0)" > "$SYSFS_AGG_DIR/delete_device" + +echo "2. GPIO aggregator configuration" + +echo "2.1. Configuring aggregators instantiated via configfs" +setup_2_1() { + agg_create_chip agg0 + agg_create_line agg0 line0 + agg_create_line agg0 line1 + agg_set_key agg0 line0 "$(sim_get_chip_label chip0 bank0)" + agg_set_key agg0 line1 "$(sim_get_chip_label chip1 bank0)" + agg_set_offset agg0 line0 1 + agg_set_offset agg0 line1 3 + agg_set_line_name agg0 line0 test0 + agg_set_line_name agg0 line1 test1 + agg_enable_chip agg0 +} +teardown_2_1() { + agg_configfs_cleanup +} + +echo "2.1.1. While offline" + +echo "2.1.1.1. Line can be added/removed" +setup_2_1 +agg_disable_chip agg0 +agg_create_line agg0 line2 +agg_set_key agg0 line2 "$(sim_get_chip_label chip0 bank1)" +agg_set_offset agg0 line2 5 +agg_enable_chip agg0 +test "$(agg_get_chip_num_lines agg0)" = "3" || fail "number of lines is not 1" +teardown_2_1 + +echo "2.1.1.2. Line key can be modified" +setup_2_1 +agg_disable_chip agg0 +agg_set_key agg0 line0 "$(sim_get_chip_label chip0 bank1)" +agg_set_key agg0 line1 "$(sim_get_chip_label chip1 bank1)" +agg_enable_chip agg0 +teardown_2_1 + +echo "2.1.1.3. Line name can be modified" +setup_2_1 +agg_disable_chip agg0 +agg_set_line_name agg0 line0 new0 +agg_set_line_name agg0 line1 new1 +agg_enable_chip agg0 +test "$(agg_get_line_name agg0 0)" = "new0" || fail "line name is unset" +test "$(agg_get_line_name agg0 1)" = "new1" || fail "line name is unset" +teardown_2_1 + +echo "2.1.1.4. Line offset can be modified" +setup_2_1 +agg_disable_chip agg0 +agg_set_offset agg0 line0 5 +agg_set_offset agg0 line1 7 +agg_enable_chip agg0 +teardown_2_1 + +echo "2.1.1.5. Can re-enable a chip after valid reconfiguration" +setup_2_1 +agg_disable_chip agg0 +agg_set_key agg0 line0 "$(sim_get_chip_label chip1 bank1)" +agg_set_offset agg0 line0 15 +agg_set_key agg0 line1 "$(sim_get_chip_label chip0 bank1)" +agg_set_offset agg0 line0 14 +agg_create_line agg0 line2 +agg_set_key agg0 line2 "$(sim_get_chip_label chip0 bank1)" +agg_set_offset agg0 line2 13 +agg_enable_chip agg0 +test "$(agg_get_chip_num_lines agg0)" = "3" || fail "number of lines is not 1" +teardown_2_1 + +echo "2.1.1.7. Can't re-enable a chip with invalid reconfiguration" +setup_2_1 +agg_disable_chip agg0 +agg_set_key agg0 line0 invalidkey +echo 1 > "$CONFIGFS_AGG_DIR/agg0/live" 2> /dev/null && fail "chip unexpectedly enabled" +teardown_2_1 +setup_2_1 +agg_disable_chip agg0 +agg_set_offset agg0 line0 99 +echo 1 > "$CONFIGFS_AGG_DIR/agg0/live" 2> /dev/null && fail "chip unexpectedly enabled" +teardown_2_1 + +echo "2.1.2. While online" + +echo "2.1.2.1. Can't add/remove line" +setup_2_1 +mkdir "$CONFIGFS_AGG_DIR/agg0/line2" 2> /dev/null && fail "line unexpectedly added" +rmdir "$CONFIGFS_AGG_DIR/agg0/line1" 2> /dev/null && fail "line unexpectedly removed" +teardown_2_1 + +echo "2.1.2.2. Can't modify line key" +setup_2_1 +echo "chip1_bank1" > "$CONFIGFS_AGG_DIR/agg0/line0/key" 2> /dev/null && \ + fail "lookup key unexpectedly updated" +teardown_2_1 + +echo "2.1.2.3. Can't modify line name" +setup_2_1 +echo "new0" > "$CONFIGFS_AGG_DIR/agg0/line0/name" 2> /dev/null && \ + fail "name unexpectedly updated" +teardown_2_1 + +echo "2.1.2.4. Can't modify line offset" +setup_2_1 +echo "5" > "$CONFIGFS_AGG_DIR/agg0/line0/offset" 2> /dev/null && \ + fail "offset unexpectedly updated" +teardown_2_1 + +echo "2.2. Configuring aggregators instantiated via sysfs" +setup_2_2() { + echo "chip0_bank0 1 chip1_bank0 3" > "$SYSFS_AGG_DIR/new_device" +} +teardown_2_2() { + echo "$(agg_configfs_dev_name _sysfs.0)" > "$SYSFS_AGG_DIR/delete_device" +} + +echo "2.2.1. While online" + +echo "2.2.1.1. Can toggle live" +setup_2_2 +agg_disable_chip _sysfs.0 +agg_enable_chip _sysfs.0 +teardown_2_2 + +echo "2.2.1.2. Can't add/remove line" +setup_2_2 +mkdir "$CONFIGFS_AGG_DIR/_sysfs.0/line2" 2> /dev/null && fail "line unexpectedly added" +rmdir "$CONFIGFS_AGG_DIR/_sysfs.0/line1" 2> /dev/null && fail "line unexpectedly removed" +teardown_2_2 + +echo "2.2.1.3. Can't modify line key" +setup_2_2 +echo "chip1_bank1" > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/key" 2> /dev/null && \ + fail "lookup key unexpectedly updated" +teardown_2_2 + +echo "2.2.1.4. Can't modify line name" +setup_2_2 +echo "new0" > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/name" 2> /dev/null && \ + fail "name unexpectedly updated" +teardown_2_2 + +echo "2.2.1.5. Can't modify line offset" +setup_2_2 +echo "5" > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/offset" 2> /dev/null && \ + fail "offset unexpectedly updated" +teardown_2_2 + +echo "2.2.2. While waiting for deferred probe" + +echo "2.2.2.1. Can't add/remove line despite live = 0" +sim_disable_chip chip0 +setup_2_2 +mkdir "$CONFIGFS_AGG_DIR/_sysfs.0/line2" 2> /dev/null && fail "line unexpectedly added" +rmdir "$CONFIGFS_AGG_DIR/_sysfs.0/line1" 2> /dev/null && fail "line unexpectedly removed" +teardown_2_2 +sim_enable_chip chip0 + +echo "2.2.2.2. Can't modify line key" +sim_disable_chip chip0 +setup_2_2 +echo "chip1_bank1" > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/key" 2> /dev/null && \ + fail "lookup key unexpectedly updated" +teardown_2_2 +sim_enable_chip chip0 + +echo "2.2.2.3. Can't modify line name" +sim_disable_chip chip0 +setup_2_2 +echo "new0" > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/name" 2> /dev/null && \ + fail "name unexpectedly updated" +teardown_2_2 +sim_enable_chip chip0 + +echo "2.2.2.4. Can't modify line offset" +sim_disable_chip chip0 +setup_2_2 +echo 5 > "$CONFIGFS_AGG_DIR/_sysfs.0/line0/offset" 2> /dev/null && \ + fail "offset unexpectedly updated" +teardown_2_2 +sim_enable_chip chip0 + +echo "2.2.2.5. Can't toggle live" +sim_disable_chip chip0 +setup_2_2 +test "$(cat "$CONFIGFS_AGG_DIR/_sysfs.0/live")" = 0 || fail "chip unexpectedly alive" +echo 1 > "$CONFIGFS_AGG_DIR/_sysfs.0/live" 2> /dev/null && fail "chip unexpectedly enabled" +teardown_2_2 +sim_enable_chip chip0 + +echo "2.2.3. While offline" + +echo "2.2.3.1. Can't add/remove line despite live = 0" +setup_2_2 +agg_disable_chip _sysfs.0 +mkdir "$CONFIGFS_AGG_DIR/_sysfs.0/line2" 2> /dev/null && fail "line unexpectedly added" +rmdir "$CONFIGFS_AGG_DIR/_sysfs.0/line1" 2> /dev/null && fail "line unexpectedly removed" +teardown_2_2 + +echo "2.2.3.2. Line key can be modified" +setup_2_2 +agg_disable_chip _sysfs.0 +agg_set_key _sysfs.0 line0 "$(sim_get_chip_label chip0 bank1)" +agg_set_key _sysfs.0 line1 "$(sim_get_chip_label chip1 bank1)" +agg_enable_chip _sysfs.0 +teardown_2_2 + +echo "2.2.3.3. Line name can be modified" +setup_2_2 +agg_disable_chip _sysfs.0 +agg_set_line_name _sysfs.0 line0 new0 +agg_set_line_name _sysfs.0 line1 new1 +agg_enable_chip _sysfs.0 +test "$(agg_get_line_name _sysfs.0 0)" = "new0" || fail "line name is unset" +test "$(agg_get_line_name _sysfs.0 1)" = "new1" || fail "line name is unset" +teardown_2_2 + +echo "2.2.3.4. Line offset can be modified" +setup_2_2 +agg_disable_chip _sysfs.0 +agg_set_offset _sysfs.0 line0 5 +agg_set_offset _sysfs.0 line1 7 +agg_enable_chip _sysfs.0 +teardown_2_2 + +echo "2.2.3.5. Can re-enable a chip with valid reconfiguration" +setup_2_2 +agg_disable_chip _sysfs.0 +agg_set_key _sysfs.0 line0 "$(sim_get_chip_label chip1 bank1)" +agg_set_offset _sysfs.0 line0 15 +agg_set_key _sysfs.0 line1 "$(sim_get_chip_label chip0 bank1)" +agg_set_offset _sysfs.0 line0 14 +agg_enable_chip _sysfs.0 +teardown_2_2 + +echo "2.2.3.6. Can't re-enable a chip with invalid reconfiguration" +setup_2_2 +agg_disable_chip _sysfs.0 +agg_set_key _sysfs.0 line0 invalidkey +echo 1 > "$CONFIGFS_AGG_DIR/_sysfs.0/live" 2> /dev/null && fail "chip unexpectedly enabled" +teardown_2_2 +setup_2_2 +agg_disable_chip _sysfs.0 +agg_set_offset _sysfs.0 line0 99 +echo 1 > "$CONFIGFS_AGG_DIR/_sysfs.0/live" 2> /dev/null && fail "chip unexpectedly enabled" +teardown_2_2 + +echo "3. Module unload" + +echo "3.1. Can't unload module if there is at least one device created via configfs" +agg_create_chip agg0 +modprobe -r gpio-aggregator 2> /dev/null +test -d /sys/module/gpio_aggregator || fail "module unexpectedly unloaded" +agg_remove_chip agg0 + +echo "3.2. Can unload module if there is no device created via configfs" +echo "chip0_bank0 1 chip1_bank0 3" > "$SYSFS_AGG_DIR/new_device" +modprobe -r gpio-aggregator 2> /dev/null +test -d /sys/module/gpio_aggregator && fail "module unexpectedly remains to be loaded" +modprobe gpio-aggregator 2> /dev/null + +echo "4. GPIO forwarder functional" +SETTINGS="chip0:bank0:2 chip0:bank1:4 chip1:bank0:6 chip1:bank1:8" +setup_4() { + local OFFSET=0 + agg_create_chip agg0 + for SETTING in $SETTINGS; do + CHIP=$(echo "$SETTING" | cut -d: -f1) + BANK=$(echo "$SETTING" | cut -d: -f2) + LINE=$(echo "$SETTING" | cut -d: -f3) + agg_create_line agg0 "line${OFFSET}" + agg_set_key agg0 "line${OFFSET}" "$(sim_get_chip_label "$CHIP" "$BANK")" + agg_set_offset agg0 "line${OFFSET}" "$LINE" + OFFSET=$(expr $OFFSET + 1) + done + agg_enable_chip agg0 +} +teardown_4() { + agg_configfs_cleanup +} + +echo "4.1. Forwarding set values" +setup_4 +OFFSET=0 +for SETTING in $SETTINGS; do + CHIP=$(echo "$SETTING" | cut -d: -f1) + BANK=$(echo "$SETTING" | cut -d: -f2) + LINE=$(echo "$SETTING" | cut -d: -f3) + DEVNAME=$(cat "$CONFIGFS_SIM_DIR/$CHIP/dev_name") + CHIPNAME=$(cat "$CONFIGFS_SIM_DIR/$CHIP/$BANK/chip_name") + VAL_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio${LINE}/value" + test $(cat $VAL_PATH) = "0" || fail "incorrect value read from sysfs" + $BASE_DIR/gpio-mockup-cdev -s 1 "/dev/$(agg_configfs_chip_name agg0)" "$OFFSET" & + mock_pid=$! + sleep 0.1 # FIXME Any better way? + test "$(cat $VAL_PATH)" = "1" || fail "incorrect value read from sysfs" + kill "$mock_pid" + OFFSET=$(expr $OFFSET + 1) +done +teardown_4 + +echo "4.2. Forwarding set config" +setup_4 +OFFSET=0 +for SETTING in $SETTINGS; do + CHIP=$(echo "$SETTING" | cut -d: -f1) + BANK=$(echo "$SETTING" | cut -d: -f2) + LINE=$(echo "$SETTING" | cut -d: -f3) + DEVNAME=$(cat "$CONFIGFS_SIM_DIR/$CHIP/dev_name") + CHIPNAME=$(cat "$CONFIGFS_SIM_DIR/$CHIP/$BANK/chip_name") + VAL_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio${LINE}/value" + $BASE_DIR/gpio-mockup-cdev -b pull-up "/dev/$(agg_configfs_chip_name agg0)" "$OFFSET" + test $(cat "$VAL_PATH") = "1" || fail "incorrect value read from sysfs" + OFFSET=$(expr $OFFSET + 1) +done +teardown_4 + +echo "5. Race condition verification" + +echo "5.1. Stress test of new_device/delete_device and module load/unload" +for _ in $(seq 1000); do + { + echo "dummy 0" > "$SYSFS_AGG_DIR/new_device" + cat "$CONFIGFS_AGG_DIR/_sysfs.0/dev_name" > "$SYSFS_AGG_DIR/delete_device" + } 2> /dev/null +done & +writer_pid=$! +while kill -0 "$writer_pid" 2> /dev/null; do + { + modprobe gpio-aggregator + modprobe -r gpio-aggregator + } 2> /dev/null +done + +echo "GPIO $MODULE test PASS"