From patchwork Sun Feb 16 12:58:04 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 865645 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A02821925BA for ; Sun, 16 Feb 2025 12:58:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710722; cv=none; b=G5Jy4t+4MXmi2trP88M+e8VZzo+bGaI7IJ0BFszHN91DwOeOFeZ1WQWKgG7z3VSg3ahdO7WZeOadngc7B3zGJlraNgO/xIzRnd7hos5zDHwtEs1Ca43U3T4CxTwmiEm6sXE+kiR+vH5qL03XxRN4cn+7fu7jC5V9d01jIOPg2ac= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710722; c=relaxed/simple; bh=ON0ehqNkL/xvxuSncxnJd1gtNg+6gWPXLCaJXpCE84w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=b6AwkjaUdWB5QM3p7fJdw9r0TwYJMbndpqhGiY+wmJ0tJWyvvOqzV7Zn46x4QRRwQ+2Ls+uQyL3sXrI8uuphfewHBubAR9BEK6zFJ5KkQMKQB14He1Tb2PbKRsPbeXw1QO5USzh/0Q9nN4/xnIaWMAYJHAwujdW95kB51T6zl9U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=WXFkxYHt; arc=none smtp.client-ip=185.125.188.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="WXFkxYHt" Received: from mail-pj1-f70.google.com (mail-pj1-f70.google.com [209.85.216.70]) (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 C52EF3F302 for ; Sun, 16 Feb 2025 12:58:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739710712; bh=/dv1clno4vwekIxpQT8JlY6+oBRlXDyt/p4pqtLh8l4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WXFkxYHtOz9qO2L6zTzIUh3P4jSiUiKPLf4Ezf9mOKjQKzXCxBoAwzG0yeJrTPPxV tITZ9iY49e0FAWf4bn7rBKnGBBm+utUiBA0wMFLocer6biWg9OJ7/uj6luf9Ch5uTX bZk22ToV9WiJVElYSuD32BLaJRylUCnZB+42xnGMvY5hi3i2Na0JW7BUmUUHrXhs+P ga/1ExDhLB+ZDJTRobzeeDKxKWiUsqGNGxu5YZ/08A2Q316sZc6dolAqx/9iLQUgt2 L1n2CMCcMFK6BGkTih+T8lv2RyryJFgQW4tnOWDLhYkLW1Gijj0GFLbQNny0mijAbZ Oojgd+5c8A8Pw== Received: by mail-pj1-f70.google.com with SMTP id 98e67ed59e1d1-2fbfa786a1aso11007622a91.3 for ; Sun, 16 Feb 2025 04:58:32 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739710709; x=1740315509; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/dv1clno4vwekIxpQT8JlY6+oBRlXDyt/p4pqtLh8l4=; b=h4WKNX8u02TmsIm0DfGExvEGs4srpPpVrnF0JVaGDM+gH3TG+2YqA2z/BFvCAYGYRm wewoGRuKXN6QfvUBaWW8yzbi1Qgvd8AzieeYfVXgHrj0CKzFCN3I9TVobojCKgYn+BZO AhSNlymKp+4TOeH28U1YsTlDpz8a3GFiCR8XogbCDvR5I9sMbc1N5i1On/zH5W0nHfO1 lMU8f/j+SxQ2MZ8THYqe4jjWmFMSpLid9CQQ8fZZfjgjg4fklHiI4RTkFQjtWQk8ZVIv NIloSmtp0OUREqN5SUoqyJejGvYfqpT5IdTTNH2Lhq37DUG9eVhfG6ItwD675Nd0Lozx djKg== X-Gm-Message-State: AOJu0YwDW4mfkD/VGDaogap6HpfIRJs4y1P8o8Re38GNW6YYgntu9DGJ HIZM5UmjauAjdXwuwAaDYLIN2rJcYR1eglR05gmVCJ9uYkDHHAQnkpJBqKF1LRyuJCJTu/ZIFO9 7Ka0LIxwlomvBryfLaZpulouSn1GWzDDLzKcoDHvJ3is7GodXLCS8YHYJNzvolDCPHTrTgwRABQ IxSD3C9so= X-Gm-Gg: ASbGncs2I24CRRS4eNU9Zy46Vm/xDZlZUGLIcO50GAFOzPeuw5rtznd28apXe+kAtgu BeFXzLkYY5SoqU80Ep9aU/sM8ZiLD1IaJ5DPn679Vp+HzCqUH3RY28FkQZAsv37Q0heW+2u9qCN qY2cKzg0nvPIfVlxGBs0PA9PvVl5TJ/I5h/1/UhasTz4Kl57ibc2YWjIg5P55qw7Lnv7UGQdZpo tQffLQcB3rqlGT045E7l0CbtSSZwV34badUMlPyLRxDt/4iH2wngTA1wP+eFstDXvdfv4LA6beP aYXZpA== X-Received: by 2002:a05:6a00:1488:b0:731:771:38f2 with SMTP id d2e1a72fcca58-732617999fdmr11611740b3a.8.1739710709438; Sun, 16 Feb 2025 04:58:29 -0800 (PST) X-Google-Smtp-Source: AGHT+IHr0sSHEuxQ/iRTDuywgcXZzEo/SyHTpbRxRCvFg9+hwaoEIdP0tYG9nBhVnyE+pI/KYmPfFg== X-Received: by 2002:a05:6a00:1488:b0:731:771:38f2 with SMTP id d2e1a72fcca58-732617999fdmr11611706b3a.8.1739710709068; Sun, 16 Feb 2025 04:58:29 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:eaa9:d394:f21d:ee9f]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73256fb09e1sm4316545b3a.65.2025.02.16.04.58.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Feb 2025 04:58:28 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v3 01/13] gpio: aggregator: reorder functions to prepare for configfs introduction Date: Sun, 16 Feb 2025 21:58:04 +0900 Message-ID: <20250216125816.14430-2-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250216125816.14430-1-koichiro.den@canonical.com> References: <20250216125816.14430-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 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. Signed-off-by: Koichiro Den Reviewed-by: Geert Uytterhoeven --- drivers/gpio/gpio-aggregator.c | 352 +++++++++++++++++---------------- 1 file changed, 178 insertions(+), 174 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 65f41cc3eafc..570cd1ff8cc2 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -61,180 +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; - - /* kernfs guarantees string termination, so count + 1 is safe */ - aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); - if (!aggr) - return -ENOMEM; - - 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; - 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); - 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; - - mutex_lock(&gpio_aggregator_lock); - aggr = idr_remove(&gpio_aggregator_idr, id); - mutex_unlock(&gpio_aggregator_lock); - if (!aggr) - return -ENOENT; - - gpio_aggregator_free(aggr); - 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 @@ -559,6 +385,170 @@ 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; + + /* kernfs guarantees string termination, so count + 1 is safe */ + aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); + if (!aggr) + return -ENOMEM; + + 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; + 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); + 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; + + mutex_lock(&gpio_aggregator_lock); + aggr = idr_remove(&gpio_aggregator_idr, id); + mutex_unlock(&gpio_aggregator_lock); + if (!aggr) + return -ENOENT; + + gpio_aggregator_free(aggr); + 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 */ @@ -616,6 +606,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 Sun Feb 16 12:58:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 865646 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7D61918FC80 for ; Sun, 16 Feb 2025 12:58:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710718; cv=none; b=HAuaJR0Mr3prVnGqLc0PgwlE5sWAUM/O4hfXjs7mSwyE6qiJlsHZ8ouYCuhK5LkOuTkRuJpW8p4uB5H0rTuR+uJ5o7E+CFi4Vkyf+hskKYPHSbwK9QMXzwWH0Io+x/fxRfwLaCsdAAJ0WD6dLuSIQuOSX9YCd/vORarzzMMmpZE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710718; c=relaxed/simple; bh=SKtk5LGExLk6bdAki5p/BEUv1i+8IBo24wWDS1BWA5Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LNt1oTSw8lHSqazqNjor4EK8AF7XwJzK1GoOIkibgDPLJW/G7fJAppfRlNlVIe//ayp6YIHOlKHREG2VCgiB0GRahvNP8DjJo523dNY9wBf3nO9uMd/CKKePdfbT6LXPsLLadJjkg6IQaqqWqiROwCYG2PSL18Yr9CTNGo5eGD4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=L08MBtwB; arc=none smtp.client-ip=185.125.188.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="L08MBtwB" 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-1.canonical.com (Postfix) with ESMTPS id 5F2E53F2F0 for ; Sun, 16 Feb 2025 12:58:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739710714; bh=9/5pkxra7VYfBLz3YJTkR4kouC63TcrGmJ2E28pjOC0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=L08MBtwBcUL3xaLBOyN8182ozxsWUPBr338mZ/wJWdgDbgetbpkMdzx6OzyOVxY1E c/6cqrAy+DBUNOrCjBuEVrJ8gju2Iu43DOnQuleiI87TtBjXkNEQj5LwlhDvucrhjB xqTR1DVO6cfwLaxwmh4Db4HSMxSPwruqld064KnbOhaEVpr4MHamVWsINxSy7h3cbe O8c/D31vu8n6VIHuXt/TaQPHXBQYKRLXGOkrsCpYXm27P35QEtKWVLFQ4h1WTLRjmQ RyiuLEwVlNMPvWBUult560/nRgDPHoBW7eR+8Vt1qYI64Muo39rwZ6WWgCQY9wn4Zj mbD3+nGp1F6Wg== Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-2fc0bc05b36so11499714a91.3 for ; Sun, 16 Feb 2025 04:58:34 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739710712; x=1740315512; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9/5pkxra7VYfBLz3YJTkR4kouC63TcrGmJ2E28pjOC0=; b=EETNYmArOCRxiF7dAPGUZMABGoDBRGmrJmfsDiEz+ZO7rjibJOJdL0fNEMRrxSctzd ch5ceDdUoc1jaxrnbiW4LtAdnjmKK16GhCtJXcc7UKREZ9AoE2cHsNrjjFvzWgDQj/bC sP7+f8ENc8cCx8ndvR6xeLUqzgC+MjbfhsQTBRy1Bk4v1bYxJ/iIdpJTRPRg3Fp7yyZY i1ASJAFUcAf3zAw7J++g0S3h93BFsVg6MQJXMIgiZlb2HdnAQQZkeKMsxeFgJSoqV37M keuZcqdpourh2Xh3A54A9xSP1IiLOEu/Q/DSIaeJeejsK+yZlXKeWMlFMNpkh6BYGa0u LNRg== X-Gm-Message-State: AOJu0YyO0M7CUcyz2dkXKtPbBRHEGL0qtZnFwIs50rybvXVoenCJbCNP 2mpXQeFRKrwFST3+VwzHwon1NWsjJ4wIVeQ7sLw62L671r5WsrBy97HcdaxI2qNrT1FNnEHiMjr bsv5ut43sV5ma92gTH9U1ijpEEVouzBI0iloNrvb8H+8Cd9OodAaQCD2QSQR5YUgDE5eoey6t3D TRSrYzAa0= X-Gm-Gg: ASbGncuK9BPuUwB4+ScvlE7HUBJMC5TQDBePjFx3gyZO4B+3iMbtf6lSUwTiVR7432m 5LfwDJSyfWCsKWplYRuq2K42VWr14/HJjpxqhPIx3KPdKb+ouZ4xBVMUEQ86h4c1jYsC/t38Sxv P+2aXSr1xqVnIDfxYxsHXm1n8YPzgz+QikJ0aAmOL0jmOEsk3wTBHFnNJDbuAjLBUaE0mrO1QdE 66HjIZoBezZBiidkrXOx5wGZkuAgayWp3nuju3d22vmq78I8OUPXQRD2ghv86olAcEljwq2T3MP yP5lZw== X-Received: by 2002:a05:6a20:258b:b0:1ee:668f:4232 with SMTP id adf61e73a8af0-1ee8cbe8181mr9301438637.29.1739710712634; Sun, 16 Feb 2025 04:58:32 -0800 (PST) X-Google-Smtp-Source: AGHT+IEpMqivvwPm0hDtcmUrV8dkJTDpemIr76dzIdEexUvHzP0VmV3hCHaiULKqPm03NeL8sl5Ygw== X-Received: by 2002:a05:6a20:258b:b0:1ee:668f:4232 with SMTP id adf61e73a8af0-1ee8cbe8181mr9301416637.29.1739710712225; Sun, 16 Feb 2025 04:58:32 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:eaa9:d394:f21d:ee9f]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73256fb09e1sm4316545b3a.65.2025.02.16.04.58.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Feb 2025 04:58:31 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v3 02/13] gpio: aggregator: protect driver attr handlers against module unload Date: Sun, 16 Feb 2025 21:58:05 +0900 Message-ID: <20250216125816.14430-3-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250216125816.14430-1-koichiro.den@canonical.com> References: <20250216125816.14430-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 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") 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 570cd1ff8cc2..893cd56de867 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -446,10 +446,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); @@ -488,6 +493,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: @@ -502,6 +508,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; } @@ -530,13 +538,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 Sun Feb 16 12:58:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 865644 Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DEF5F194C75 for ; Sun, 16 Feb 2025 12:58:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.122 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710725; cv=none; b=CXkQKbpz3AvkfaGEcF+PqPfuQkOAujFlMQ/ZbVZ17uRJhDTNpuYT9QTA3+RgL43P/TvJkcJzeHkRCXuKEuNkQl8BKqGM8ssLQQcuN1pv0TvHxe6JvEfB9rFWyfAcEKhFANQVzRk8ns7BiiDBOeqLJzfo6x1+ZSFjrSoUOZx2N2A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710725; c=relaxed/simple; bh=QAOA908gNel3y1R7ETsRu2jzdhf2WxIWOfoFCHcP9qo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W7sZMl0kMYx4SY1OmQDjPJlaEwMZlxnQgW3CMiyQIGJhGKIBsW3sUNTrTeEmRs9e4RuPIWX6piHyQxjEeS2mTJdKUKcFTjR8Pykb8HIsuzxft480ztaBpIMhLlFcxXi8EloweDiWGdGqCosHH2ri32YBLODulA3suJMBPrs0YKE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=K/rEkbm7; arc=none smtp.client-ip=185.125.188.122 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="K/rEkbm7" 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-0.canonical.com (Postfix) with ESMTPS id 956B43F516 for ; Sun, 16 Feb 2025 12:58:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739710720; bh=N0Kj1d8MdTe6Cku6k8Y4hSRN1wAEicDaX3HkzkoJuyo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=K/rEkbm7ThcQ5Dl97ITLHjXADsoQ1zziXuk8U6tMGS3BfCK9MwThgAw2Jngnp7uqo xblJ74gCYLq2L5RNc2inH80pIi1riuKLCWEFQ0tsPITRuxlhbRG6WaruKSE9x9XspG 81BWo/xIqTUx3ZfyaaUK2uyZlh9LTvJDDUqP9JvHAfMRq0P1lC/L9j8tz1wAkZ33R1 8ELWeQwkyvxJS2l8ANeCPFGY8se2eGemm+X6t1XAPqQHBR32owc6CJkkdo2LHccnkE 1DM1UjZrR09s/SP2tz5A0qNDV86SwAc/EXHY84mCsrkA8S8sqwqHJHX4SesE+lGlTd hFCur173etkaQ== Received: by mail-pj1-f72.google.com with SMTP id 98e67ed59e1d1-2fc5a9f18afso999317a91.1 for ; Sun, 16 Feb 2025 04:58:40 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739710719; x=1740315519; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=N0Kj1d8MdTe6Cku6k8Y4hSRN1wAEicDaX3HkzkoJuyo=; b=wTVj1ItSBLfJKEDah0yrsoGTITnSmknHm52pQAn8JtTnFQJP3HMCgt1C6yH4eMVBZE 52uZ/tcrQ9LmqpNW0HNH2jBZ6Zfm/jZ2V5UFwkFhC45etaTHv70nrE+n8Wv1B6esHfdf xArpd/yqaN17M9lSQedIIr9tHkSGpKJVDOkWRMAd1MXlsQBwkcX4uUEdMaMqU8zLP4oj YJABWgeg/Ws37fqmQWiz9I5Oxdyk16lInkHw0ciBoE4Jpj7j7qnSUI6PpWnYE/LShGte 1W2ULqXvJX1ZNmqyvaAXI1gEnHnWsgQ568S84GHEn0OMmAumCxNqns9tI4CUepFwKvuX paOQ== X-Gm-Message-State: AOJu0YxdYX2DMkMKDh+erY1/AkMsQGWbOGienvBywpXi2Sg9BPfyFoQ4 0wCo1GgVxszdwOEsYZf3RSeoT0ys78Iapx8Vi7X3FOj6O2AbNnVrisEdTzimE71oVK439aR9c/j jLRRERuifAfKxYyU8OxdZA7uHVMjycPc36OMiqM4IsLd+P+MeM1koOPPly7N3A1kyl8orFxHhTW iHJ5GZZrg= X-Gm-Gg: ASbGncsYO24NbMDqkRy/MWHP7oNxkiPFZky+zBD0bskC0EL3XFOuet7P537uNvQW7is YGcUpv4wFGOn/mzqvmboj+57MQAbJG1sPR5Wou678tUBDvOzpnvobirtk5fg1+EjOq/jPdYtR4k 8susaejims/UNlcYIhV9OS5flYxb/b3j9UD1GoMwiC5iq5j5EMzRMRZRWj1r8yLub2ggXdifXZF YIB4ZhS6cr7U1/ZfBO1wABNgmLCbZ5r6YpmAhMjOoOWibgeSDBhSC/eYRX14eH8yDhd+PoQu+8H 1udN2g== X-Received: by 2002:a05:6a00:198c:b0:730:7885:d902 with SMTP id d2e1a72fcca58-7326144b262mr10956756b3a.0.1739710718761; Sun, 16 Feb 2025 04:58:38 -0800 (PST) X-Google-Smtp-Source: AGHT+IHNx31ACnol66ZluTW2jPSBmJYZlDsj5AI975Vm2nDmoYYTRm8RaHhWXg3ML7mJhrQFbFiFIA== X-Received: by 2002:a05:6a00:198c:b0:730:7885:d902 with SMTP id d2e1a72fcca58-7326144b262mr10956735b3a.0.1739710718404; Sun, 16 Feb 2025 04:58:38 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:eaa9:d394:f21d:ee9f]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73256fb09e1sm4316545b3a.65.2025.02.16.04.58.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Feb 2025 04:58:37 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v3 04/13] gpio: sim: convert to use gpio-pseudo utilities Date: Sun, 16 Feb 2025 21:58:07 +0900 Message-ID: <20250216125816.14430-5-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250216125816.14430-1-koichiro.den@canonical.com> References: <20250216125816.14430-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Update gpio-sim to use the new gpio-pseudo helper functions for synchronized platform device creation, reducing code duplication. No functional change. Signed-off-by: Koichiro Den --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-sim.c | 84 ++++++----------------------------------- 2 files changed, 13 insertions(+), 72 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 1e2c95e03a95..c482e3494bac 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1913,6 +1913,7 @@ config GPIO_SIM tristate "GPIO Simulator Module" select IRQ_SIM select CONFIGFS_FS + select GPIO_PSEUDO help This enables the GPIO simulator - a configfs-based GPIO testing driver. diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index a086087ada17..45dbf16bee12 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -37,6 +36,8 @@ #include #include +#include "gpio-pseudo.h" + #define GPIO_SIM_NGPIO_MAX 1024 #define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */ #define GPIO_SIM_NUM_ATTRS 3 /* value, pull and sentinel */ @@ -541,14 +542,9 @@ static struct platform_driver gpio_sim_driver = { }; struct gpio_sim_device { + struct pseudo_gpio_common common; struct config_group group; - /* - * If pdev is NULL, the device is 'pending' (waiting for configuration). - * Once the pointer is assigned, the device has been created and the - * item is 'live'. - */ - struct platform_device *pdev; int id; /* @@ -562,46 +558,11 @@ struct gpio_sim_device { */ struct mutex lock; - /* - * This is used to synchronously wait for the driver's probe to complete - * and notify the user-space about any errors. - */ - struct notifier_block bus_notifier; - struct completion probe_completion; - bool driver_bound; - struct gpiod_hog *hogs; struct list_head bank_list; }; -/* This is called with dev->lock already taken. */ -static int gpio_sim_bus_notifier_call(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct gpio_sim_device *simdev = container_of(nb, - struct gpio_sim_device, - bus_notifier); - struct device *dev = data; - char devname[32]; - - snprintf(devname, sizeof(devname), "gpio-sim.%u", simdev->id); - - if (!device_match_name(dev, devname)) - return NOTIFY_DONE; - - if (action == BUS_NOTIFY_BOUND_DRIVER) - simdev->driver_bound = true; - else if (action == BUS_NOTIFY_DRIVER_NOT_BOUND) - simdev->driver_bound = false; - else - return NOTIFY_DONE; - - complete(&simdev->probe_completion); - - return NOTIFY_OK; -} - static struct gpio_sim_device *to_gpio_sim_device(struct config_item *item) { struct config_group *group = to_config_group(item); @@ -708,7 +669,7 @@ static bool gpio_sim_device_is_live(struct gpio_sim_device *dev) { lockdep_assert_held(&dev->lock); - return !!dev->pdev; + return !!dev->common.pdev; } static char *gpio_sim_strdup_trimmed(const char *str, size_t count) @@ -730,7 +691,7 @@ static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item, guard(mutex)(&dev->lock); - pdev = dev->pdev; + pdev = dev->common.pdev; if (pdev) return sprintf(page, "%s\n", dev_name(&pdev->dev)); @@ -939,7 +900,6 @@ static int gpio_sim_device_activate(struct gpio_sim_device *dev) { struct platform_device_info pdevinfo; struct fwnode_handle *swnode; - struct platform_device *pdev; struct gpio_sim_bank *bank; int ret; @@ -981,31 +941,13 @@ static int gpio_sim_device_activate(struct gpio_sim_device *dev) pdevinfo.fwnode = swnode; pdevinfo.id = dev->id; - reinit_completion(&dev->probe_completion); - dev->driver_bound = false; - bus_register_notifier(&platform_bus_type, &dev->bus_notifier); - - pdev = platform_device_register_full(&pdevinfo); - if (IS_ERR(pdev)) { - bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); - gpio_sim_remove_hogs(dev); - gpio_sim_remove_swnode_recursive(swnode); - return PTR_ERR(pdev); - } - - wait_for_completion(&dev->probe_completion); - bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); - - if (!dev->driver_bound) { - /* Probe failed, check kernel log. */ - platform_device_unregister(pdev); + ret = pseudo_gpio_register(&dev->common, &pdevinfo); + if (ret) { gpio_sim_remove_hogs(dev); gpio_sim_remove_swnode_recursive(swnode); - return -ENXIO; + return ret; } - dev->pdev = pdev; - return 0; } @@ -1015,11 +957,10 @@ static void gpio_sim_device_deactivate(struct gpio_sim_device *dev) lockdep_assert_held(&dev->lock); - swnode = dev_fwnode(&dev->pdev->dev); - platform_device_unregister(dev->pdev); + swnode = dev_fwnode(&dev->common.pdev->dev); + pseudo_gpio_unregister(&dev->common); gpio_sim_remove_hogs(dev); gpio_sim_remove_swnode_recursive(swnode); - dev->pdev = NULL; } static void @@ -1117,7 +1058,7 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item, guard(mutex)(&dev->lock); if (gpio_sim_device_is_live(dev)) - return device_for_each_child(&dev->pdev->dev, &ctx, + return device_for_each_child(&dev->common.pdev->dev, &ctx, gpio_sim_emit_chip_name); return sprintf(page, "none\n"); @@ -1558,8 +1499,7 @@ gpio_sim_config_make_device_group(struct config_group *group, const char *name) mutex_init(&dev->lock); INIT_LIST_HEAD(&dev->bank_list); - dev->bus_notifier.notifier_call = gpio_sim_bus_notifier_call; - init_completion(&dev->probe_completion); + pseudo_gpio_init(&dev->common); return &no_free_ptr(dev)->group; } From patchwork Sun Feb 16 12:58:09 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 865643 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B05AD1922E0 for ; Sun, 16 Feb 2025 12:58:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710730; cv=none; b=DODeusIj98qRHn9AcmoPcohvwqg0Ly9yxSo768gODTB/nOKKxm5KmzCSILm0w/L5VxyoLbCuwYupthz3kt18biHKa57ypuBd9oNgP3BV5m0hWLONLlavFuMXqrkaNjb0MSl4SNN0iJeZxLXorw8h9CpJHdzzhJalOjw7YhYr4iU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710730; c=relaxed/simple; bh=gaGxbWoVq59TTDiq4cJd0eCsgnEJQWKB3/3FfvlvZ5M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZgBLXcxlVOqteZwcsz+5CzkgwCQxBxZU1Kn3FfYCUrRnNrOOfz5ImxoQYcLXAOke4Bwbecg0F1VU9hzf+zeMNBqtJLihIWvPtDpKx1ugR9BQoqt8Xm/C77O6B4NF9kb2zaPuxRoKh0f0nOcPmoLtN+xgjo/2Cj77mGfiscDypok= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=W7vVdxDZ; arc=none smtp.client-ip=185.125.188.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="W7vVdxDZ" 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-1.canonical.com (Postfix) with ESMTPS id 2B99E3F2BC for ; Sun, 16 Feb 2025 12:58:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739710727; bh=iZPn8FzJi1wBDhT5MKcLY0VoABjKA3JgOf2KFRB4x/o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W7vVdxDZzg/3v+FEy3Aa24IGgiaSYe96RCAxPe4+lWq2Dn8JDWsnxU8HZzHEbkfZ+ YzZS7qkWolJcA+AmXqn2qQQG1SyesQUYPTUqxQLN6IH32UGyTk18camn+b3/eHmne3 627rKwKiN5EwY9R1yK0FjzIINFArH6KCNM1l86ASxeojcGjYDt1Qsj2XOFcJfYGjAx JQUca3a0WNcc7xnYriAVbbvx6smhOt38de3xis+MVEbPF0WvcJI4uTqZPjmbJ2tO6L yTY/yK/LiE59ILn52B2o4RkwXF/uOUfb2lCd2mPSkactOYrGDqttVfDxs+YW2Xyic1 92BXRcZPmweSw== Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-2f83e54432dso11518800a91.2 for ; Sun, 16 Feb 2025 04:58:47 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739710724; x=1740315524; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=iZPn8FzJi1wBDhT5MKcLY0VoABjKA3JgOf2KFRB4x/o=; b=hXvZjn/nhroJoNjkTDb8y8R90rgSsQXtP2Xqeh76QgxXtWypcqIPayi4wEx6fSMd3V gIT+fNUSndRLJFJAKlC0Juy85R3kSYNJQTICOCpZP63nicoOMS07oFVYZoF100uWIUKQ OQLPWHusttmwI9pDxdzCp51AhZ6KJbdn8gT9chVULeyIhU4ec9m1jF7xSOKyFqa6IcfM bo0AjXUgAPi2yGJLgBovsoy7Bd1Ggh3Rc/0AYDI+28MbJs4gMWVM/TFNhm952fR6Whir 8+3e/+Jg7sAWWugMxvm1ig+WnaOAw/HL9w2mKsebCa44NaM9TJy4hU9V9WqwaLNjtRn6 hgPg== X-Gm-Message-State: AOJu0YzBilF5dAPMbGpVl35v+uEGQEz1Lnruog/sMNyz4z7tQb8gKwCa wUkBkGZH0Phu23GhdNym7ceWtANoRrfCKcaf4EMbhCT0/ENl7MGuEZ6RGO5Hm4HvGWZMDsPyUF9 OTKopa1UzytT1rzzz3FA4XovOQJ6XJKsXzMRe38xrMwYHoDfnbQEM1zGFDwcg8cDNBXisy99aPy 0a6Jw4UVs= X-Gm-Gg: ASbGnctwyfAwzTYdPYOABrMgS3qn/laGmUXWpr4uuk2vmX+enHkrQvzBXwA/6xGEz6Q cxfnh2D+flLathsvceIffG+qRAxKeyyHf552Ep178n6bhT+k1uLTcYJc1NHdOEVeCeg26aoOCz7 C7ttA9ox3dvll5im3HSQb3S9AouKgGR/nDXeJGr9e84AShb7X3eY0OPbQu3XfRN+8u7m74pi1OS VUJiEhryo6Cj4T8QI3h37qPWsyrjQZJsstDsj+nWdV143k1ggb/5bBrQSjxK1if7H6+C2gzbTzM SdEnbg== X-Received: by 2002:a05:6a21:4014:b0:1e4:8fdd:8c77 with SMTP id adf61e73a8af0-1ee8caab5bcmr12234120637.8.1739710724265; Sun, 16 Feb 2025 04:58:44 -0800 (PST) X-Google-Smtp-Source: AGHT+IHfRPYv58J7W+79MK/Q30Fi4lENg4yHxG8EDlpAXCIOHoz6Soxw8W0XJQto3mMp1Ii5Vz+npw== X-Received: by 2002:a05:6a21:4014:b0:1e4:8fdd:8c77 with SMTP id adf61e73a8af0-1ee8caab5bcmr12234095637.8.1739710724000; Sun, 16 Feb 2025 04:58:44 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:eaa9:d394:f21d:ee9f]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73256fb09e1sm4316545b3a.65.2025.02.16.04.58.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Feb 2025 04:58:43 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v3 06/13] gpio: aggregator: convert to use gpio-pseudo utilities Date: Sun, 16 Feb 2025 21:58:09 +0900 Message-ID: <20250216125816.14430-7-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250216125816.14430-1-koichiro.den@canonical.com> References: <20250216125816.14430-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Update gpio-aggregator to use the new gpio-pseudo helper functions. Note that the current sysfs interface for gpio-aggregator does not wait for probe completion when creating a platform device. This change brings no immediate benefit but prepares for a later commit introducing configfs that shares this mechanism. No functional change. Signed-off-by: Koichiro Den --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-aggregator.c | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d8fede07149f..8b9ffe17426e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1871,6 +1871,7 @@ menu "Virtual GPIO drivers" config GPIO_AGGREGATOR tristate "GPIO Aggregator" + select GPIO_PSEUDO 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 893cd56de867..b24ed963cd9a 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -27,6 +27,8 @@ #include #include +#include "gpio-pseudo.h" + #define AGGREGATOR_MAX_GPIOS 512 /* @@ -34,8 +36,8 @@ */ struct gpio_aggregator { + struct pseudo_gpio_common common; struct gpiod_lookup_table *lookups; - struct platform_device *pdev; char args[]; }; @@ -492,7 +494,7 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, goto remove_table; } - aggr->pdev = pdev; + aggr->common.pdev = pdev; module_put(THIS_MODULE); return count; @@ -517,7 +519,7 @@ static DRIVER_ATTR_WO(new_device); static void gpio_aggregator_free(struct gpio_aggregator *aggr) { - platform_device_unregister(aggr->pdev); + platform_device_unregister(aggr->common.pdev); gpiod_remove_lookup_table(aggr->lookups); kfree(aggr->lookups->dev_id); kfree(aggr->lookups); From patchwork Sun Feb 16 12:58:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 865642 Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6A21919C558 for ; Sun, 16 Feb 2025 12:58:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.122 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710735; cv=none; b=GvwzYRDaQeCRoQ1HzsLExMeclaNgMqxsms4o3sj24swRcfHoXfmgaRjwf/jFbhGaQkaaWJx6de7n2uLtA4fHr5J41CE1i8jo8SRsD3h7ToOyoft7ES4mLJWKCQalqnlW7Gg8bSfyvlz9FvhBcrWrZ2vM42wy289jXMRJpzOqkBA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710735; c=relaxed/simple; bh=iunzfnwXFZMiOJcVkULwj7dzepJGOPG5VVJaaTzqHOc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gG2mv1BafqrKH/GBTahHzvmUh9ATYQFsMmWK4Uiw7hI38hzfmeE2y2j1oU+LjK/3zfkQRjCNTLq6tGrRSu+AMa2Fc68NmwovaNL57cOPpjA/fyn3WTtoBX0BWmOH/0gZX4fGn/Pr+UgqzP3enJQBARn7uCWqZX93UoWuMm4Ba0w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=HQt1mVWQ; arc=none smtp.client-ip=185.125.188.122 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="HQt1mVWQ" 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-0.canonical.com (Postfix) with ESMTPS id 01DB33F880 for ; Sun, 16 Feb 2025 12:58:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739710732; bh=Gk/La4hkh91qCBNBtRkn7mQ3+1B82nsIS3HpG8PL1f4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HQt1mVWQ95vA5oXZ1mUecvSv/6VBuG+8/Pgu/faFfef+khQ9t56mrzbm5r/Wljfiz qxoYQ6jcpFlG6MNnz2tcYbiHISefP7hSbD9Bt89xWswRvAl0utVLUfxPSJCVpp4fSY KVVehmTCBxX+MnWAw0KgdNxdj04Pr8OtpCOozQ6FE2OkVYIlVbWWpBqqiinaG1DFv8 2aWjFpSxBHZ6V6ZH/sniWNLqcUfJ5aMgpIpptkKO+AydLoCaDYFnTLaiNeN8YKcJ43 U4f8rdgkCB87dTyf8nLiR25ykk/0UBVWjZThoYEHtL4me+tBvsFxKu0AuJKgWGG6US jvCkeJ6AQBmqw== Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-2f81a0d0a18so6924630a91.3 for ; Sun, 16 Feb 2025 04:58:51 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739710730; x=1740315530; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Gk/La4hkh91qCBNBtRkn7mQ3+1B82nsIS3HpG8PL1f4=; b=D7X38Sz/1Q1IUYrRQf7YEHsKlu4CE87wH66+9JuPy6pHwWaxv8usArn2mM3f4GTm4J BPECGHnSfYeXCUKSojh4DEu3UG7YFZD0b5fL+M+VXxZL2xLNFe03VUhjxahsu5IaBlL3 whrZJDbAN6jIDkjPhQuoXQ+xCvDKKZP7RSIhsnYyg4s0xvqKJBZHMaxQoML4AW4Po8P0 jhoUgF96E5K4TJqtjKHW2oR/s035K8H0nG6QuMU2iZ66C54I4D0ePzOWemyqqlgL5xv/ l3twspCkSMewIfZSNVND0FlqyBDtnoiHzQ99Lmz/U1dHPgOQksLRjFwHvKO6DH1BWemD fWIg== X-Gm-Message-State: AOJu0Yy5o5LswFoS16b5V/Pa+PU1IdJH+JpwrWXkOLlOid1glFICFAQD wAqa5PgiTFhselotcg7QOseqov6YGXjvk2B4Cmrz8fG/wfSDm6CmnrMGMUq19h5yl4AWd369Jr4 oQupCeNcV2c0a7AvCmxh1D7lZiRGw5fxnpz4K4b3w8pzERJa7wfGvw0PwY1WakhL7tBqJaMEALh LtEFFFzVE= X-Gm-Gg: ASbGncuXrIc19/T1qDRo9Zp+PP0pktgyzqP2LkxykEq/AA/w2t2IPU4XNA903wzeSGD 3x/sRnq5v8M7c06xgwX6QYT/mxhM6bMMOcSMr8mI4kA+RRyOMz1KF7Mg0IoZBhnv60TeN00pGiF x6bBPlw6NhCd76QbGTvmVhsHcfNuWzm8HR1mAY4Ysm28V7BLmGMH5NCUFfgBOhri3P9NDWZbt6k ngFaRXPIWk+zDCi04P9G+r2UMx9fLDH5vNoR6vTk3Ms9WT8THsaW6xr+69VXn10sPUGnTdiPOfX Zgcv4g== X-Received: by 2002:aa7:88c1:0:b0:730:91fc:f9c4 with SMTP id d2e1a72fcca58-7326190a122mr9417886b3a.24.1739710730209; Sun, 16 Feb 2025 04:58:50 -0800 (PST) X-Google-Smtp-Source: AGHT+IFXkL97gmZRuswV2wo/Hb4xAoccXkZA0zPnnNOfSFswbTD//6qwI9Ditkpzitl+ERgixr4HWw== X-Received: by 2002:aa7:88c1:0:b0:730:91fc:f9c4 with SMTP id d2e1a72fcca58-7326190a122mr9417844b3a.24.1739710729660; Sun, 16 Feb 2025 04:58:49 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:eaa9:d394:f21d:ee9f]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73256fb09e1sm4316545b3a.65.2025.02.16.04.58.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Feb 2025 04:58:49 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v3 08/13] gpio: aggregator: introduce basic configfs interface Date: Sun, 16 Feb 2025 21:58:11 +0900 Message-ID: <20250216125816.14430-9-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250216125816.14430-1-koichiro.den@canonical.com> References: <20250216125816.14430-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 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 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* Signed-off-by: Koichiro Den --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-aggregator.c | 540 ++++++++++++++++++++++++++++++++- 2 files changed, 533 insertions(+), 8 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8b9ffe17426e..591244e6cd4e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1871,6 +1871,7 @@ menu "Virtual GPIO drivers" config GPIO_AGGREGATOR tristate "GPIO Aggregator" + select CONFIGFS_FS select GPIO_PSEUDO help Say yes here to enable the GPIO Aggregator, which provides a way to diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 6252a686f805..ec102453817b 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 @@ -37,11 +40,35 @@ struct gpio_aggregator { struct pseudo_gpio_common common; + struct config_group group; struct gpiod_lookup_table *lookups; + 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; + + /* 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); @@ -61,6 +88,8 @@ static int aggr_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; } @@ -70,6 +99,7 @@ static void aggr_free(struct gpio_aggregator *aggr) mutex_lock(&gpio_aggregator_lock); idr_remove(&gpio_aggregator_idr, aggr->id); mutex_unlock(&gpio_aggregator_lock); + mutex_destroy(&aggr->lock); kfree(aggr); } @@ -92,6 +122,70 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key, return 0; } +static bool aggr_is_active(struct gpio_aggregator *aggr) +{ + lockdep_assert_held(&aggr->lock); + + return aggr->common.pdev && platform_get_drvdata(aggr->common.pdev); +} + +static size_t aggr_count_lines(struct gpio_aggregator *aggr) +{ + lockdep_assert_held(&aggr->lock); + + return list_count_nodes(&aggr->list_head); +} + +static struct gpio_aggregator_line *aggr_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 aggr_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 aggr_line_del(struct gpio_aggregator *aggr, + struct gpio_aggregator_line *line) +{ + lockdep_assert_held(&aggr->lock); + + list_del(&line->entry); +} + /* * GPIO Forwarder @@ -416,6 +510,400 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, } +/* + * 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 int aggr_activate(struct gpio_aggregator *aggr) +{ + struct platform_device_info pdevinfo; + struct gpio_aggregator_line *line; + unsigned int n = 0; + int ret = 0; + + if (aggr_count_lines(aggr) == 0) + return -EINVAL; + + aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1), + GFP_KERNEL); + if (!aggr->lookups) + return -ENOMEM; + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo.name = DRV_NAME; + pdevinfo.id = aggr->id; + + /* 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_lookups; + } + + if (line->offset < 0) + ret = aggr_add_gpio(aggr, line->key, U16_MAX, &n); + else + ret = aggr_add_gpio(aggr, line->key, line->offset, &n); + if (ret) + goto err_remove_lookups; + } + + aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, aggr->id); + if (!aggr->lookups->dev_id) { + ret = -ENOMEM; + goto err_remove_lookups; + } + + gpiod_add_lookup_table(aggr->lookups); + + ret = pseudo_gpio_register(&aggr->common, &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_lookups: + kfree(aggr->lookups); + + return ret; +} + +static void aggr_deactivate(struct gpio_aggregator *aggr) +{ + pseudo_gpio_unregister(&aggr->common); + gpiod_remove_lookup_table(aggr->lookups); + kfree(aggr->lookups->dev_id); + kfree(aggr->lookups); +} + +static void aggr_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_aggr_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_aggr_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 (aggr_is_active(aggr)) + return -EBUSY; + + kfree(line->key); + line->key = no_free_ptr(key); + + return count; +} +CONFIGFS_ATTR(gpio_aggr_line_, key); + +static ssize_t +gpio_aggr_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; + unsigned int offset; + + scoped_guard(mutex, &aggr->lock) + offset = line->offset; + + return sysfs_emit(page, "%d\n", offset); +} + +static ssize_t +gpio_aggr_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 (aggr_is_active(aggr)) + return -EBUSY; + + line->offset = offset; + + return count; +} +CONFIGFS_ATTR(gpio_aggr_line_, offset); + +static struct configfs_attribute *gpio_aggr_line_attrs[] = { + &gpio_aggr_line_attr_key, + &gpio_aggr_line_attr_offset, + NULL +}; + +static ssize_t +gpio_aggr_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->common.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_aggr_device_, dev_name); + +static ssize_t +gpio_aggr_device_live_show(struct config_item *item, char *page) +{ + struct gpio_aggregator *aggr = to_gpio_aggregator(item); + bool active; + + scoped_guard(mutex, &aggr->lock) + active = aggr_is_active(aggr); + + return sysfs_emit(page, "%c\n", active ? '1' : '0'); +} + +static ssize_t +gpio_aggr_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) + aggr_lockup_configfs(aggr, true); + + scoped_guard(mutex, &aggr->lock) { + if (live == aggr_is_active(aggr)) + ret = -EPERM; + else if (live) + ret = aggr_activate(aggr); + else + aggr_deactivate(aggr); + } + + /* + * Undepend is required only if device disablement (live == 0) + * succeeds or if device enablement (live == 1) fails. + */ + if (live == !!ret) + aggr_lockup_configfs(aggr, false); + + module_put(THIS_MODULE); + + return ret ?: count; +} +CONFIGFS_ATTR(gpio_aggr_device_, live); + +static struct configfs_attribute *gpio_aggr_device_attrs[] = { + &gpio_aggr_device_attr_dev_name, + &gpio_aggr_device_attr_live, + NULL +}; + +static void +gpio_aggr_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); + + aggr_line_del(aggr, line); + kfree(line->key); + kfree(line); +} + +static struct configfs_item_operations gpio_aggr_line_item_ops = { + .release = gpio_aggr_line_release, +}; + +static const struct config_item_type gpio_aggr_line_type = { + .ct_item_ops = &gpio_aggr_line_item_ops, + .ct_attrs = gpio_aggr_line_attrs, + .ct_owner = THIS_MODULE, +}; + +static void gpio_aggr_device_release(struct config_item *item) +{ + struct gpio_aggregator *aggr = to_gpio_aggregator(item); + + guard(mutex)(&aggr->lock); + + /* + * If the aggregator is active, this code wouldn't be reached, + * so calling aggr_deactivate() is always unnecessary. + */ + aggr_free(aggr); +} + +static struct configfs_item_operations gpio_aggr_device_item_ops = { + .release = gpio_aggr_device_release, +}; + +static struct config_group * +gpio_aggr_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 (aggr_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 = aggr_line_alloc(aggr, idx, NULL, -1); + if (!line) + return ERR_PTR(-ENOMEM); + + config_group_init_type_name(&line->group, name, &gpio_aggr_line_type); + + aggr_line_add(aggr, line); + + return &line->group; +} + +static struct configfs_group_operations gpio_aggr_device_group_ops = { + .make_group = gpio_aggr_device_make_group, +}; + +static const struct config_item_type gpio_aggr_device_type = { + .ct_group_ops = &gpio_aggr_device_group_ops, + .ct_item_ops = &gpio_aggr_device_item_ops, + .ct_attrs = gpio_aggr_device_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group * +gpio_aggr_make_group(struct config_group *group, const char *name) +{ + struct gpio_aggregator *aggr; + int ret; + + /* arg space is unneeded */ + ret = aggr_alloc(&aggr, 0); + if (ret) + return ERR_PTR(ret); + + config_group_init_type_name(&aggr->group, name, &gpio_aggr_device_type); + pseudo_gpio_init(&aggr->common); + + return &aggr->group; +} + +static struct configfs_group_operations gpio_aggr_group_ops = { + .make_group = gpio_aggr_make_group, +}; + +static const struct config_item_type gpio_aggr_type = { + .ct_group_ops = &gpio_aggr_group_ops, + .ct_owner = THIS_MODULE, +}; + +static struct configfs_subsystem gpio_aggr_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = DRV_NAME, + .ci_type = &gpio_aggr_type, + }, + }, +}; + + /* * Sysfs interface */ @@ -487,6 +975,7 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, 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) { @@ -533,10 +1022,7 @@ static DRIVER_ATTR_WO(new_device); static void gpio_aggregator_free(struct gpio_aggregator *aggr) { - platform_device_unregister(aggr->common.pdev); - gpiod_remove_lookup_table(aggr->lookups); - kfree(aggr->lookups->dev_id); - kfree(aggr->lookups); + aggr_deactivate(aggr); kfree(aggr); } @@ -558,12 +1044,19 @@ static ssize_t 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_free(aggr); module_put(THIS_MODULE); @@ -638,6 +1131,10 @@ 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_free(p); return 0; } @@ -652,7 +1149,33 @@ static void __exit gpio_aggregator_remove_all(void) static int __init gpio_aggregator_init(void) { - return platform_driver_register(&gpio_aggregator_driver); + int ret = 0; + + config_group_init(&gpio_aggr_subsys.su_group); + mutex_init(&gpio_aggr_subsys.su_mutex); + ret = configfs_register_subsystem(&gpio_aggr_subsys); + if (ret) { + pr_err("Failed to register the '%s' configfs subsystem: %d\n", + gpio_aggr_subsys.su_group.cg_item.ci_namebuf, ret); + mutex_destroy(&gpio_aggr_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_aggr_subsys.su_mutex); + configfs_unregister_subsystem(&gpio_aggr_subsys); + } + + return ret; } module_init(gpio_aggregator_init); @@ -660,6 +1183,7 @@ static void __exit gpio_aggregator_exit(void) { gpio_aggregator_remove_all(); platform_driver_unregister(&gpio_aggregator_driver); + configfs_unregister_subsystem(&gpio_aggr_subsys); } module_exit(gpio_aggregator_exit); From patchwork Sun Feb 16 12:58:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 865641 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 05C74193429 for ; Sun, 16 Feb 2025 12:58:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710738; cv=none; b=j3YtHlw6OfcnqrPoL2pz63pjl+Z1pMEwp1yrUAPzD1AuAGkuMv/85WDMNWn0zEn2PuRiAX1qkKKG5YWzZ24QwRI2xH2ESRPiELyy/RUVV38rScOmw+TRcIj1n0kBRh/kSdeAZTyOJE6t4HNGvXeJ4XHm5MYXCBmhiqpXyGeXq6Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710738; c=relaxed/simple; bh=uxdDc8NwSSoU/KhYSVoLNE3SLLqdDtG3WoHdkVTCuPk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=X7xHlvn20qhoElsQ1TNquxX5LXoDk/qSCjLmBfULy/8Z2bCx/+wxPksqH0ujrHqWZb7rDF5+0LJJp2h65eXZGL4e9k8l+4eLhrIHLLFQKFjC9WT/USKX07WF0qE3DWrr14jEt5jFS+g7cwDoY56Ke6uj9IzmyK8Ou80ZcSr9ff8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=mr5ZnzxU; arc=none smtp.client-ip=185.125.188.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="mr5ZnzxU" 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 466613F302 for ; Sun, 16 Feb 2025 12:58:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739710734; bh=v4sbOHRoeQS1MOSALsPLtSJ65COLeoaPvTmtbuEu58k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mr5ZnzxU+GxcELfh4cg+MAKjOHcpaoD8lYrtXjB4Yw9AXSywbyEry3ihuoQMD3u4B fo+4pMKTiVcu3mIFX0/vrcJ4XOsI6Qt6Mb87hfXgYNmfVShWnrieBzu1Qg+pzBdoPT yWnw58sB0oC4SDAfr2YqurBqGyek80AyCH7YGtI8j7IU/KmzuraL2DD2juRJHXXsLo 2CZOk1C1ruoP4vgDoRHp+l4roAK8L+bfSyYeUwtS2GO9p5oL77IeXbJ7m3ATLdqRpJ CJW0ppzkD8+eNqi0eTghXetjSEsGfXbkByuzVl0k43NYkkdQy7qOHNKpyuTdOAhxfx HYOWe3OfoEqTg== Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-2210305535bso47794525ad.1 for ; Sun, 16 Feb 2025 04:58:54 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739710732; x=1740315532; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=v4sbOHRoeQS1MOSALsPLtSJ65COLeoaPvTmtbuEu58k=; b=p/Q+YYBWKGx4tMKjghfN3GbkLgDCcWdCFY/bHSbRh2RPrFS4CPF+k5mO/KBz0sGNa8 /E8n0ouH8B6Tgir5udrk3mALiEbVnu/lTE2LAhRPnGjMwigkwBLpM6DXVjHQpmzW+s5h Y0SGgAQlKojRQVBu1+JIfNNWaAIKsypdkmSyEgFPREs9AJn/7iM1X5e/9XV2g2GnfeCZ wuuvvssA6RuBIQmm/J376jkza7cKwRevMhnjcRs0RtXy+tbWUy4aRYYoVnqki5Kg4s+S wNRAfg+aZ7IV1qpnxXE6c9vuKY12+UOhZCjI4pJUdFVVgtfrGiQga9m3JdL2l7BTARra SWHw== X-Gm-Message-State: AOJu0Yz4BWCGYlVVmnAcui0Lc8AYHAp9gQ1Rl4U6nxDqpLOReSfJ74d1 QWwDhCfdE7tvxNQZ9xh4WRUPna7hQanmuaB/HwJ18VGgh+sDvbZGemwlvIjR/9l/Qy8EN4uQL6t 3mJ5xD7a8LP7Rt8C3wYKlHEf2YRZRceYqXdbYU9iaHMNITyJipwn5dg7GnRWOwVEfmAaOc4GRSu 20aynswf8= X-Gm-Gg: ASbGncsf90gR7LHMI40JI2XzdNDekdlFNB/qA9Dxosl4dDUwdyWAxM3TE4e+d3FZean gqZMyxngngn1NJj/09l5rO7GDBMVpQBo5/jY1+/Q22XV+7CukpP/rcEXTibW4om1q7+lrWQvX20 D9QAthhufKMKkN+ILogzkQSuMhAu3DcsYsg7IFxLEMPXy5HZIJt+UBlWBbdkUjhuwjB/sCaZGWx PdwuDQyqqyikdGO4wuJgMhVszP0k2B6XXUMOD3Fgwn3QRala+ZOD5U22VRRnDM6yKk7aWJpZ4iU lu7zCg== X-Received: by 2002:a05:6a21:6182:b0:1ee:7714:50 with SMTP id adf61e73a8af0-1ee8cb0e872mr8693881637.5.1739710732665; Sun, 16 Feb 2025 04:58:52 -0800 (PST) X-Google-Smtp-Source: AGHT+IETzXxsVanjAhXHVIrho5GeRODi5T05ultUcs3mcWlJEertTezQ6W5MIqTT3OooQDM45eE3tQ== X-Received: by 2002:a05:6a21:6182:b0:1ee:7714:50 with SMTP id adf61e73a8af0-1ee8cb0e872mr8693857637.5.1739710732350; Sun, 16 Feb 2025 04:58:52 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:eaa9:d394:f21d:ee9f]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73256fb09e1sm4316545b3a.65.2025.02.16.04.58.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Feb 2025 04:58:52 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v3 09/13] gpio: aggregator: add 'name' attribute for custom GPIO line names Date: Sun, 16 Feb 2025 21:58:12 +0900 Message-ID: <20250216125816.14430-10-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250216125816.14430-1-koichiro.den@canonical.com> References: <20250216125816.14430-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Previously, there was no way to assign names to GPIO lines exported through the aggregator when the device was created via sysfs. Allow users to set custom line names via a 'name' attribute and expose them using swnode. Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 84 ++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index ec102453817b..692d90246674 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -61,6 +61,8 @@ struct gpio_aggregator_line { /* 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 */ @@ -530,10 +532,40 @@ to_gpio_aggregator_line(struct config_item *item) return container_of(group, struct gpio_aggregator_line, group); } +static struct fwnode_handle *aggr_make_device_swnode(struct gpio_aggregator *aggr) +{ + const char **line_names __free(kfree) = NULL; + struct property_entry properties[2]; + struct gpio_aggregator_line *line; + size_t num_lines; + int n = 0; + + memset(properties, 0, sizeof(properties)); + + num_lines = aggr_count_lines(aggr); + if (num_lines == 0) + return NULL; + + line_names = 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 aggr_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; @@ -545,9 +577,14 @@ static int aggr_activate(struct gpio_aggregator *aggr) if (!aggr->lookups) return -ENOMEM; + swnode = aggr_make_device_swnode(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) { @@ -559,7 +596,7 @@ static int aggr_activate(struct gpio_aggregator *aggr) */ if (!line->key || line->idx != n) { ret = -EINVAL; - goto err_remove_lookups; + goto err_remove_swnode; } if (line->offset < 0) @@ -567,13 +604,13 @@ static int aggr_activate(struct gpio_aggregator *aggr) else ret = aggr_add_gpio(aggr, line->key, line->offset, &n); if (ret) - goto err_remove_lookups; + 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_lookups; + goto err_remove_swnode; } gpiod_add_lookup_table(aggr->lookups); @@ -587,6 +624,8 @@ static int aggr_activate(struct gpio_aggregator *aggr) 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); @@ -658,6 +697,43 @@ gpio_aggr_line_key_store(struct config_item *item, const char *page, } CONFIGFS_ATTR(gpio_aggr_line_, key); +static ssize_t +gpio_aggr_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_aggr_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 (aggr_is_active(aggr)) + return -EBUSY; + + kfree(line->name); + line->name = no_free_ptr(name); + + return count; +} +CONFIGFS_ATTR(gpio_aggr_line_, name); + static ssize_t gpio_aggr_line_offset_show(struct config_item *item, char *page) { @@ -707,6 +783,7 @@ CONFIGFS_ATTR(gpio_aggr_line_, offset); static struct configfs_attribute *gpio_aggr_line_attrs[] = { &gpio_aggr_line_attr_key, + &gpio_aggr_line_attr_name, &gpio_aggr_line_attr_offset, NULL }; @@ -795,6 +872,7 @@ gpio_aggr_line_release(struct config_item *item) aggr_line_del(aggr, line); kfree(line->key); + kfree(line->name); kfree(line); } From patchwork Sun Feb 16 12:58:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 865640 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3B2D519D89B for ; Sun, 16 Feb 2025 12:59:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710745; cv=none; b=EhugkhQT2HH1xrkuEGheSKEF73vDSXX1VHJL9UokSBXeJ6WQZ/rmaa3ETUoXPPLtXAr7k5WhuNtIm+85jmK7Kqfavljlz2ZvBW3RnO7T0rYLaCpPaj8BvkafIS0YFt3HHkQew3KZXgR2lV/vcldnY2RqKjJrKwPfrULc4nUgvBk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710745; c=relaxed/simple; bh=lWi8cSb8BfWbLOPOp2GNgU6ysUye4CsGO9grvCFpPc8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PAZ8AmwNHLu5GzXIWQZJKhR+yX+suYYMkNfJKnxpye4q1WkelTa0gn3yFymRkw53gkP3jobKIse+0SqU1FOXadcr2aOs6LplUqy+8EnA/Qb+BxmaVI/w6n4Vu/20fKkewRuIGtWpzXV7c0FVAHDRr9WkVGzsEJXkDzY0AVRtGtA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=c2e0OV4H; arc=none smtp.client-ip=185.125.188.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="c2e0OV4H" Received: from mail-pj1-f70.google.com (mail-pj1-f70.google.com [209.85.216.70]) (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 CDF7E3F29B for ; Sun, 16 Feb 2025 12:59:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739710740; bh=xsxLQ8/cIyaXlfRbTYcIHh/jf9fjXDEfeDZdjuEqzxg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=c2e0OV4HXGRdmUELsXCXIpJC02Vng3j/jZQ1JY+3mIk4pxAT1CQ6EGtVWtVfRMZS1 rQfSxEBrOi8ybS0NSx8WIlKZXK0p/OohUHXgY42LmofbyyOlV04fzKUzXMHtEdJhir qRGy8w3lYFbVltajfjQbEAqb+pKoW3zSYLGxPGxAdb2q6EzsTBkXHnh6URNvwMHfYu 9F3pY9vjdlKh/Z+oJ+vAcGZPjGH34fET15CTJsQAWyqHoZzyh4mDwZ7YP2XBgCqS5o ObOr8kfSkp67rxwVVadq4Jj5aG6qhEuN7SiwA2ybImP3G/OzAti2xunOIqac4n5E2r 7d7WT+00itvZA== Received: by mail-pj1-f70.google.com with SMTP id 98e67ed59e1d1-2fc43be27f8so3359580a91.1 for ; Sun, 16 Feb 2025 04:59:00 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739710738; x=1740315538; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=xsxLQ8/cIyaXlfRbTYcIHh/jf9fjXDEfeDZdjuEqzxg=; b=HHaGT6Y4M4cPU38pVJzjLkKK8DXagpLrzhqasqeDZB0k2yi1yuZbgBF6//dpk6qTmf 92RLaA9EGqjb0fGVeSovSjXVJrqCFI8ooQ541alQvWBdTWCDLtGTi5zKyQ4f12gpEFb8 naCOQVmkdH2arRxPCQ9fBLVv4Fy9MtWusSdf1bYYhw1xD/d3G87yvzsFY/fVJL0w/Vke mHmQ5eEeYsuTgmNou/XYdZx1fwxpeHM9kXfTj5KQjZR37PhHgjOs5kJUvxt7yPU9txo/ odAjVkcGMbXN1draKMBdkl42E31g3gDvwvzMTZ6gVKqAJNkS4Cq8/hK9BgMKEEQi5Mhl 10Dw== X-Gm-Message-State: AOJu0YwKjVeymgsukS2416/sSbghHg42nzj+nnJpoXLDCn1AuUaBhhSG bxuGeOVcIZ3xzoTt6iLIALzMmiJI5INfBUt/C7mq15PlRyL5LlmsrBkpzvI7noz9kARyex45Ycx nYsSWTBtOFgXJm+tPfgVYSGG9qZaPzlCg7k+Ydo92rwYv5nL69BUTy5WQbXu2p2rHq4wbg8zowl 01OmXZpsE= X-Gm-Gg: ASbGncvsQXw5n3W/a7K5q4Ss/N7DvqYy1jCQ1Lu2oPekTSZRV5TTtsVRsLhWIaxNxDz 6/RQchVj6ac2yYxlxWqHjg0Ud1hc9jTYMd5lIqUVXR98cce+1qhSjeqZTtWmB17VB1M9wWx2jWr /HQEU0uu+MndsIMUKVIGU8WyU/g7J2fGLaVFUZEY3J0uGqX1qnrczInH7fT2Sc5T1xeASfOm99q gse/4Rb4tYq4gHeL9u3htdDGlVHg+q5YAoaDZsRbzteqFpf3B7cCnWhATRbituLzF2LYqyY0qaq q7fCaQ== X-Received: by 2002:a05:6a20:734c:b0:1d8:a9c0:8853 with SMTP id adf61e73a8af0-1ee8cb1738fmr10303061637.23.1739710738245; Sun, 16 Feb 2025 04:58:58 -0800 (PST) X-Google-Smtp-Source: AGHT+IGX3reIldeUK0by88Q0O41ffSGW5Iq7r2xShkOSx8hGvz+DJc6z8RJ94YczGts59TaJt2Tb7w== X-Received: by 2002:a05:6a20:734c:b0:1d8:a9c0:8853 with SMTP id adf61e73a8af0-1ee8cb1738fmr10303033637.23.1739710737827; Sun, 16 Feb 2025 04:58:57 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:eaa9:d394:f21d:ee9f]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73256fb09e1sm4316545b3a.65.2025.02.16.04.58.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Feb 2025 04:58:57 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v3 11/13] gpio: aggregator: expose aggregator created via legacy sysfs to configfs Date: Sun, 16 Feb 2025 21:58:14 +0900 Message-ID: <20250216125816.14430-12-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250216125816.14430-1-koichiro.den@canonical.com> References: <20250216125816.14430-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 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 --- drivers/gpio/gpio-aggregator.c | 117 +++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 2e993c9a7ce5..8f8793f27211 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -33,6 +33,7 @@ #include "gpio-pseudo.h" #define AGGREGATOR_MAX_GPIOS 512 +#define AGGREGATOR_LEGACY_PREFIX "_sysfs" /* * GPIO Aggregator sysfs interface @@ -131,6 +132,14 @@ static bool aggr_is_active(struct gpio_aggregator *aggr) return aggr->common.pdev && platform_get_drvdata(aggr->common.pdev); } +/* Only aggregators created via legacy sysfs can be "activating". */ +static bool aggr_is_activating(struct gpio_aggregator *aggr) +{ + lockdep_assert_held(&aggr->lock); + + return aggr->common.pdev && !platform_get_drvdata(aggr->common.pdev); +} + static size_t aggr_count_lines(struct gpio_aggregator *aggr) { lockdep_assert_held(&aggr->lock); @@ -188,6 +197,18 @@ static void aggr_line_del(struct gpio_aggregator *aggr, list_del(&line->entry); } +static void aggr_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); + aggr_line_del(aggr, line); + kfree(line->key); + kfree(line); + } +} + /* * GPIO Forwarder @@ -687,7 +708,7 @@ gpio_aggr_line_key_store(struct config_item *item, const char *page, guard(mutex)(&aggr->lock); - if (aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || aggr_is_active(aggr)) return -EBUSY; kfree(line->key); @@ -724,7 +745,7 @@ gpio_aggr_line_name_store(struct config_item *item, const char *page, guard(mutex)(&aggr->lock); - if (aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || aggr_is_active(aggr)) return -EBUSY; kfree(line->name); @@ -772,7 +793,7 @@ gpio_aggr_line_offset_store(struct config_item *item, const char *page, guard(mutex)(&aggr->lock); - if (aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || aggr_is_active(aggr)) return -EBUSY; line->offset = offset; @@ -831,11 +852,12 @@ gpio_aggr_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) aggr_lockup_configfs(aggr, true); scoped_guard(mutex, &aggr->lock) { - if (live == aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || + (live == aggr_is_active(aggr))) ret = -EPERM; else if (live) ret = aggr_activate(aggr); @@ -847,7 +869,7 @@ gpio_aggr_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) aggr_lockup_configfs(aggr, false); module_put(THIS_MODULE); @@ -893,7 +915,7 @@ static void gpio_aggr_device_release(struct config_item *item) guard(mutex)(&aggr->lock); /* - * If the aggregator is active, this code wouldn't be reached, + * At this point, aggr is neither active nor activating, * so calling aggr_deactivate() is always unnecessary. */ aggr_free(aggr); @@ -915,6 +937,15 @@ gpio_aggr_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 (aggr_is_active(aggr)) @@ -952,6 +983,14 @@ gpio_aggr_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 = aggr_alloc(&aggr, 0); if (ret) @@ -988,6 +1027,8 @@ static struct configfs_subsystem gpio_aggr_subsys = { static int aggr_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; @@ -999,14 +1040,29 @@ static int aggr_parse(struct gpio_aggregator *aggr) args = next_arg(args, &key, &p); while (*args) { + scnprintf(name, sizeof(name), "line%u", n); + args = next_arg(args, &offsets, &p); p = get_options(offsets, 0, &error); if (error == 0 || *p) { /* Named GPIO line */ + line = aggr_line_alloc(aggr, n, key, -1); + if (!line) { + error = -ENOMEM; + goto err; + } + config_group_init_type_name(&line->group, name, + &gpio_aggr_line_type); + error = configfs_register_group(&aggr->group, + &line->group); + if (error) + goto err; + aggr_line_add(aggr, line); + error = aggr_add_gpio(aggr, key, U16_MAX, &n); if (error) - return error; + goto err; key = offsets; continue; @@ -1020,9 +1076,22 @@ static int aggr_parse(struct gpio_aggregator *aggr) } for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { + line = aggr_line_alloc(aggr, n, key, i); + if (!line) { + error = -ENOMEM; + goto err; + } + config_group_init_type_name(&line->group, name, + &gpio_aggr_line_type); + error = configfs_register_group(&aggr->group, + &line->group); + if (error) + goto err; + aggr_line_add(aggr, line); + error = aggr_add_gpio(aggr, key, i, &n); if (error) - return error; + goto err; } args = next_arg(args, &key, &p); @@ -1030,15 +1099,20 @@ static int aggr_parse(struct gpio_aggregator *aggr) if (!n) { pr_err("No GPIOs specified\n"); - return -EINVAL; + goto err; } return 0; + +err: + aggr_free_lines(aggr); + return error; } static ssize_t 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; @@ -1067,10 +1141,24 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, goto free_table; } - res = aggr_parse(aggr); + scnprintf(name, sizeof(name), "%s.%d", AGGREGATOR_LEGACY_PREFIX, aggr->id); + config_group_init_type_name(&aggr->group, name, &gpio_aggr_device_type); + + /* + * Since the device created by sysfs might be toggled via configfs + * 'live' attribute later, this initialization is needed. + */ + pseudo_gpio_init(&aggr->common); + + /* Expose to configfs */ + res = configfs_register_group(&gpio_aggr_subsys.su_group, &aggr->group); if (res) goto free_dev_id; + res = aggr_parse(aggr); + if (res) + goto unregister_group; + gpiod_add_lookup_table(aggr->lookups); pdev = platform_device_register_simple(DRV_NAME, aggr->id, NULL, 0); @@ -1085,6 +1173,8 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf, 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: @@ -1100,7 +1190,10 @@ static DRIVER_ATTR_WO(new_device); static void gpio_aggregator_free(struct gpio_aggregator *aggr) { - aggr_deactivate(aggr); + if (aggr_is_activating(aggr) || aggr_is_active(aggr)) + aggr_deactivate(aggr); + aggr_free_lines(aggr); + configfs_unregister_group(&aggr->group); kfree(aggr); } From patchwork Sun Feb 16 12:58:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 865639 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 014161A0B08 for ; Sun, 16 Feb 2025 12:59:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710748; cv=none; b=gjhAIuWzGHBumfZ48DfXFMO/occdJhTNhK6BL74CPCHJbjs0mgzzneNtOrVfxcsji+hEZBDN7rpMo9ovIkdV5i/LHcYoE1OqeG+wgpP7DoyPX/GYvskmKxEQKc7COYvP+gFK3ujuDRKjCPojJOyzFv8Ce7VMsFU+DkznS4pI0lQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739710748; c=relaxed/simple; bh=5z75klJulPBK3euVFo5jCw9QXY35/qZ4NCunDCR/9Jo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=glufKjqwjLq/0S1AXjh8hC73KmxNR3qXRKwBBVf78J0ns/EwF1iIbwz+XlR9eX/XlpWt/a19wSDSnv9sEWt1v7M+9cRMebtR7w3OJbGTC6HudsDnpPoRUY3JL/OvQTZBaD6Wk1UDEWVU67G8tIqUXi/tfs1GgounfEIOh2hqOoU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=FBqhXcA7; arc=none smtp.client-ip=185.125.188.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="FBqhXcA7" 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-1.canonical.com (Postfix) with ESMTPS id A7DD63F302 for ; Sun, 16 Feb 2025 12:59:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739710745; bh=VbN0B6Oenuw6+py3+N6wdefqtqSm9CuUWAW6b8DJ97M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FBqhXcA7ki76jeo2zoKrLcuptSNJKEfvrWc9cxO4tKBfRPUbbRxEik3WwPKHZJ0Gt PGT/CKgQvyYfDrarAhGrhu2T1IllCveSfCd7YjJhZ32hzB5MzUxSR2a1hQU/LFIVSg gcrqQZP/lDiKvYHcJY4Khzv/P78PKkACozRTJG48i5+A4o/vTvFjH8dSarWJ3W4xE4 Ddg3vcfqUVOWelAzpodcFEnJ6j0XcBMAJ3iBcoUW2tSqeJe7Augl+k1rOKG07VOf2n RAHC37F+pwGWFCI/mCg7R9OgowjJzm+AQXDeHV5t3NGJGwenATm2fHL5mg0/pG4VIv mdNKlNGcicssw== Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-220c86b3ef3so78700065ad.1 for ; Sun, 16 Feb 2025 04:59:05 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739710743; x=1740315543; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=VbN0B6Oenuw6+py3+N6wdefqtqSm9CuUWAW6b8DJ97M=; b=H5D3DbdSTo5EgNT/v7jMVKlVjgO8ulcIRXS84brAq5dqvPh6nBGhbsN40CXIhT5loX m+G3uhOX4Ctm5iM6x1VaXz2jwowOXeGZ99JaTEMAxdcQ9KjytBqU5jqFlCfKnD5YMyFF oRZQqiK7znfhQnLH5JPCyUFy0rjbPPwbNkds2phC58ZavhkQnu63A9WFtTg+WiRq0pli b20TT7NUIMdGgeFJHredgdCVGCfFfaXk/MjguwqxIvdA/EKrFtO3HxI9qYmGMWtVJriS gVy2CiOxruOBlJzupDDb+e7ZyeVrqrJSERPVbkR84EZKUt/PEWRAtqJq5d94O1T5y6Hr b0ig== X-Gm-Message-State: AOJu0Ywl24v+hqxQPh8aJtxedNCkg6B7lWdlusdKh3qacFSLVQbxykfq NLsTWiEcoBcYIQJ/gxd+O/3MvKXPc1S7B9GDVk9Vjqs8SoHgHBAgA+5m0fCv+ZfIC6/CdBcTics YFMjIGlkOh8RjTPPXl1MyMV07XtUvN5fiLQRUc8muyDU9lrN9FEoZEcGCuRSkGAfisszZlsXFN+ A1rtMx2W8= X-Gm-Gg: ASbGncvlI9REmaYw+rzg0as6YX1nKOPMsewH4dE/tYfZPCyReduWUTE3hS5vSywNMlO 9HIonuVukcnnb3MAuCOXi2N2+MZbkmsEFGs0lpisi/2+VrvV1kcITSrqV0t1VOQP7+7eiuCmGHE KTGeByGuAXXCEJrxbLZjSw6LT3Jbq1IPU18KfskbsgdLD2GpwBMtHj/yR/YZvKUSqpfdCJwxMzt JxXlSmlhCkVCK1mXwe/+KyuIW1+Ug3xOfFm1EUKbC3CR9doD0pic8wjeCeYygFr1qHyzjUqKOTr UXqWBQ== X-Received: by 2002:aa7:9912:0:b0:732:5875:eb95 with SMTP id d2e1a72fcca58-7325875ee4fmr11310404b3a.4.1739710743634; Sun, 16 Feb 2025 04:59:03 -0800 (PST) X-Google-Smtp-Source: AGHT+IHo/tLeo1FafwhPWL09gZg/Vg+JGHNlMxvFuz7WLwpyGUOorkDmHNR4ArvfJ6p5/jd7rf5PvA== X-Received: by 2002:aa7:9912:0:b0:732:5875:eb95 with SMTP id d2e1a72fcca58-7325875ee4fmr11310374b3a.4.1739710743132; Sun, 16 Feb 2025 04:59:03 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:eaa9:d394:f21d:ee9f]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73256fb09e1sm4316545b3a.65.2025.02.16.04.59.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Feb 2025 04:59:02 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v3 13/13] Documentation: gpio: document configfs interface for gpio-aggregator Date: Sun, 16 Feb 2025 21:58:16 +0900 Message-ID: <20250216125816.14430-14-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250216125816.14430-1-koichiro.den@canonical.com> References: <20250216125816.14430-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add documentation for the newly added configfs-based interface for GPIO aggregator. 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 -------------------