From nobody Fri Dec 19 13:52:02 2025 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 1A88F223300 for ; Mon, 17 Feb 2025 14:36:03 +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=1739802965; cv=none; b=c2h70d3TDzTKvTyd9zDopwhAbuhQlY0ymu9VHC88wqlF8osIbatLus6XPBTxmpVlA2Nt7mWb6bEEkWVcxnMGvHVGGTaIqyiJlSAD4ksqnGOt+vF/rUCoc3zENS6eG7RN/4eTT4WFwbTYGNBljIinCgxCwqWKzUvvjGvSJboCV8Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739802965; c=relaxed/simple; bh=d0seFRCbsm6obDyggndTpMQD/bofnkskpXmGDrRtX50=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gwroJVhm34dsimuHA7V3XCk765hrcRlzXxB159iNcRhQcSUJQzvbqNhRi3oqysUW8Cxgisxfs7FLOlA5W/8qwF9LC1zJM2+K+2LCJlHsuBq5PneOB10b75KWjs11osQkVBuYeO8xpvHmiMMdxt1hk/63PLzb7hGJIFs6s+71wkk= 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=MV+UwdEA; 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="MV+UwdEA" Received: from mail-pj1-f71.google.com (mail-pj1-f71.google.com [209.85.216.71]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 3D1453F880 for ; Mon, 17 Feb 2025 14:36:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739802962; bh=DFCOc2ChWOWoHT2jvhggwm0YHMFaUQk1iMuzmg5CkXY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MV+UwdEAiO67a51qlUkN7QYMJgyHKuzChZWAdhkEYM6yVLyGiqI5dEbB48M2rinLV /57QSdCJ6VKHwT/PPESt0XcLeUMdlFUWekRQViKsc6zwO7bECwaXflCfu6aQYk/PUa wcvgZ91ax2CjxBmjqnYAg+tqSs1QnGRH1JeMos9OAwL0RJA9BzqRA8jmr4ju6cA8/D HkmdNnhrEQDT9Uju5eo5mtfpnz5Tey+zRZoUmfgDLE3IkCHfN13ZM/binJqusT2RKw 80ZXzXOktE7CVQHYEmVGwHLkP0nTOkJh9iTpqgpyrVXWp1/PmPVGdmNJXsPJGJXW4s vb/o8laqICLYw== Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-2fbff6426f5so9065812a91.3 for ; Mon, 17 Feb 2025 06:36:02 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739802961; x=1740407761; 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=DFCOc2ChWOWoHT2jvhggwm0YHMFaUQk1iMuzmg5CkXY=; b=gI9Y0AIui3YtWxgU3Ae6rwpYr3WxXlsK139Ql/BRPxPte7S51hESXHUOcP6NxVL79c MMyYbbfapWmDtBLr8X+PBtnDALUDjIbZ2cuf71QUxFFxBxEUlv43G8gOACWYNST6ZVB7 hk3QxqPUFV0FkndJPfcqYo8tzt3xTJyvnnZwXgr7rrukr+QouqNmQLXiqkdRPSre4PaT jmb5wLmE05z5qekuzaz3MvJa4S4NnEduD8dD76Ky+ljRRyQEfozaAGtIX3WmiZ1yW+MC q2oOMfdHCap3VY1q5zkrA5i41BELqzHlL8G51SySntTOdb8nDZEKtGv9YagHmE7eM2Pm Twnw== X-Forwarded-Encrypted: i=1; AJvYcCVrwGRFCw2R05q25RZGaDS3cHSTrsr66FaKygUfVNgvOgrYcM0Y8mCLPYki3H+auZ31Vqv+Xwn1eS4R9rQ=@vger.kernel.org X-Gm-Message-State: AOJu0Yx1KNv3piTyX1WISwi688UdmUNLCklm74iAn0cuQfwKMe3cyoCw dGIU6i0FU7oQhStOKn/Z/1mg2Zp7VmPi484LLZLjHi5Q5TRi0Q59yeFmu3LOjiHtayss7VFu3qM rT7Q0+mqtJSr6mBu96CyYF7dMyEO4m4N12UqzCz0tQzAW8XSW0sWS4kocQXK02Ogf8pAgfc2URW Htbw== X-Gm-Gg: ASbGncsg1mvY0zVtHAqYG50XE82tntMJ0cN67UIO/TvvoIw6VR58Su68xalEguNIjBq X3inOehBschsBEMOOxvHVooOGjYBhlDYe5u/3LL8kqfpcRZ4YG2T92oBn3JIJpfh1RSU2nN6TPm GRfBp+vJIg6Qqo5qBeoHmxFwXJBsIb8SzhAfGomStj/QdN3siVFUEJj0DQyhqRGXY9M0x2ZHYYE E/cp1nV9FAhDdfwGGGcOE5EGCdmSU1Atu+GjSJXRhvhV4uf9JC7uw6+f7KTnGOaa12DQOsOb2Ln 0fraKyq0ZOG1Ju84fkjkwV0= X-Received: by 2002:a17:90b:2f86:b0:2ee:e518:c1cb with SMTP id 98e67ed59e1d1-2fc40d14c6emr16850260a91.7.1739802960774; Mon, 17 Feb 2025 06:36:00 -0800 (PST) X-Google-Smtp-Source: AGHT+IEWwPHNmmXaHJ5chrpk4ksWCsVxcXmVulahEqAC+Tsa1D6AEEkUl9TS6Xitb3nCoTWjymM1cQ== X-Received: by 2002:a17:90b:2f86:b0:2ee:e518:c1cb with SMTP id 98e67ed59e1d1-2fc40d14c6emr16850227a91.7.1739802960423; Mon, 17 Feb 2025 06:36:00 -0800 (PST) Received: from localhost.localdomain ([240f:74:7be:1:a6da:1fd8:6ba3:4cf3]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2fbf98b3305sm10057757a91.6.2025.02.17.06.35.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Feb 2025 06:36:00 -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 v4 1/9] gpio: aggregator: protect driver attr handlers against module unload Date: Mon, 17 Feb 2025 23:35:23 +0900 Message-ID: <20250217143531.541185-2-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250217143531.541185-1-koichiro.den@canonical.com> References: <20250217143531.541185-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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_devi= ce 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 (dead00000000= 0100) WARNING: CPU: 1 PID: 1327 at lib/list_debug.c:56 __list_del_entry_valid_o= r_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 65f41cc3eafc..d668ddb2e81d 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -119,10 +119,15 @@ static ssize_t new_device_store(struct device_driver = *driver, const char *buf, struct platform_device *pdev; int res, id; =20 + if (!try_module_get(THIS_MODULE)) + return -ENOENT; + /* kernfs guarantees string termination, so count + 1 is safe */ aggr =3D kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); - if (!aggr) - return -ENOMEM; + if (!aggr) { + res =3D -ENOMEM; + goto put_module; + } =20 memcpy(aggr->args, buf, count + 1); =20 @@ -161,6 +166,7 @@ static ssize_t new_device_store(struct device_driver *d= river, const char *buf, } =20 aggr->pdev =3D pdev; + module_put(THIS_MODULE); return count; =20 remove_table: @@ -175,6 +181,8 @@ static ssize_t new_device_store(struct device_driver *d= river, const char *buf, kfree(aggr->lookups); free_ga: kfree(aggr); +put_module: + module_put(THIS_MODULE); return res; } =20 @@ -203,13 +211,19 @@ static ssize_t delete_device_store(struct device_driv= er *driver, if (error) return error; =20 + if (!try_module_get(THIS_MODULE)) + return -ENOENT; + mutex_lock(&gpio_aggregator_lock); aggr =3D idr_remove(&gpio_aggregator_idr, id); mutex_unlock(&gpio_aggregator_lock); - if (!aggr) + if (!aggr) { + module_put(THIS_MODULE); return -ENOENT; + } =20 gpio_aggregator_free(aggr); + module_put(THIS_MODULE); return count; } static DRIVER_ATTR_WO(delete_device); --=20 2.45.2 From nobody Fri Dec 19 13:52:02 2025 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 6C5FC22333C for ; Mon, 17 Feb 2025 14:36:06 +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=1739802968; cv=none; b=C2mmJgTfTeCfZJuGRZ6NhB+Wv+pWahCVZKRU2x4vWoD/M6tHWzULTpuNjfxZmaaqnX0jWGokS6WIw6WqKHbyU6wkDwYmmkrO1RYF0o0oJvghMQu/tnj6D6y0xX9AwhPUK5Jk3Rj+crGvOx8ZHZK++s7kVW8q8xJFTnztOM6B0kc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739802968; c=relaxed/simple; bh=t3zTiX5sHGMNY70DRwaiaym4vc9V90iUU2jCySp7s2A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SdfH3YnV3lQLVU2fmoGZ/WW56YuNmqIpMGcjsm8zPOifHMFro0AWidb8abZMCykwx5aVITTrDP4Se5+9sq291isZYsOvS67DCg7dCIritoMs28Sld0TSfPpeUAE7f48hh5kinLkoWh+5V20A+XFV3saQQJo7RtfefJp4jHlJNYE= 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=iJCOKkcL; 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="iJCOKkcL" Received: from mail-pj1-f71.google.com (mail-pj1-f71.google.com [209.85.216.71]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id BFD5F3F84C for ; Mon, 17 Feb 2025 14:36:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739802964; bh=/Zis01mTN9hfdwdw4CsGVb5gEILpfxFjWK2yfeVkHJw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iJCOKkcL1ITp3UZTfGErPjchuM36PyEtbtpRGKcfiGAD8Xy/mIUXZYcXNklcv5bFQ FSUKkYOJAnHQD8jR/X0+YOZK3ev5oMekfrsArC8u0vVA5mJbdzaAuHt8JogOdW2oRO Wp1Jgvy7lPRdc0b4aj7nzvi8+pl3NUloaWYMFqIeAasQZo2zVwoTxn+NcyoMvD+k5g KJN3vqctjdBpYvpAQOLJV2lD2+FLkm+7n2i0cvH1/X6D2bqBmOkIC8W8Bbu7iSByGf C+6LGG9XV4sG2Xc993Rvl8sWILspOsWzN2O1LK4tbNyHEjcLKLd38UIfgK7XBSDn6B fmvqvhhrOYsxg== Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-2fc1a70935fso8177672a91.1 for ; Mon, 17 Feb 2025 06:36:04 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739802963; x=1740407763; 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=/Zis01mTN9hfdwdw4CsGVb5gEILpfxFjWK2yfeVkHJw=; b=s3gcNuUB2HVs0ynrXcf9H56eho/vIcwryUQObwFtixmUm5Flfxqy1tCBHGX0XO0x/3 /2EvB7qVfq4ZxIms0ieD9ADBZNhSrv9ESNe2skmU/FmVYnxkZeMvfRTDaHqxKA/BSmVX ZOsdyA+ZCEGdaxGhPZIrxOyxJ/CkHXoz4OcHTzXcCUqG5dobUHr9piWRyX8yV5TTlZfF hicbElrDqbxEwFWNXWUY7Hi7BLk0uaFTFo4tnopRG7ftKd3kAopiXtJM66y5/YljmqVM Gim50HHAYy2cizwWCXzRsu0oVQBqDycSurX4auI9eLcL3NcoW0xVFXJgHAQ0n2Pm41cC JawQ== X-Forwarded-Encrypted: i=1; AJvYcCVFfiGFWSsEfmvaupP00vWgrRKGE2cm+xdySBJq3l13rnG89L1H3jq5jR9uUb+3Ydli0ucBiYi+dczVhcI=@vger.kernel.org X-Gm-Message-State: AOJu0YxcB3zAbx642HkLhMZuCHy4C0EUdnmrFxCu8I/aBbyGHLtRH6xv 4NI0YVdY+LbKlUR+G9QtNilLg0ZjKawekVUBneLVwbxz5/gJsc6QL7gu5cj5PPtl813f8YdfimH udx9mbh8FkVQ45fo+urGg90tMpMDlfeyJ2uz6BNAHKcpHl4o7pQ5DKWfx9N7vama6ZxqXMgq0pn M/4g== X-Gm-Gg: ASbGnctV0PDqET6YO2XUGnOLnqrS60k6noTj9IomCKPAArhB56FAettR2Mbr4gUUvBr HUoIz0URWi3Tw5mB2PV8q2v16ag4UTPw9qy/KQ7NRfii4hg8g1AUF/X4QQuzlW2OhRFEoDrvAZn nPHCByeNT7QJtVSihz0JW9QvXMa4RtYLCfC3Wnzz0kimegzsAB3qAFhds4pLrfYMl6B7QCLrrAE An300nVhmbyU9duGr/QA/MIFzVFpTAbYhW0LcF5TWZgx4eBMdX3lo19R0O0YZrKA3Wb+o6hLoM+ VAnAeTB9gJKVB+OG1uXebDo= X-Received: by 2002:a17:90a:ec0c:b0:2f5:747:cbd with SMTP id 98e67ed59e1d1-2fc40f22ddfmr17907935a91.18.1739802963262; Mon, 17 Feb 2025 06:36:03 -0800 (PST) X-Google-Smtp-Source: AGHT+IEzxNF3YLnu68x/9EtesEb2iHJ0ZbypUX0sGFPDmm/E+P7hhRiN4XhIVcdNojYQSEUAl86cHw== X-Received: by 2002:a17:90a:ec0c:b0:2f5:747:cbd with SMTP id 98e67ed59e1d1-2fc40f22ddfmr17907900a91.18.1739802962909; Mon, 17 Feb 2025 06:36:02 -0800 (PST) Received: from localhost.localdomain ([240f:74:7be:1:a6da:1fd8:6ba3:4cf3]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2fbf98b3305sm10057757a91.6.2025.02.17.06.36.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Feb 2025 06:36: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 v4 2/9] gpio: aggregator: reorder functions to prepare for configfs introduction Date: Mon, 17 Feb 2025 23:35:24 +0900 Message-ID: <20250217143531.541185-3-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250217143531.541185-1-koichiro.den@canonical.com> References: <20250217143531.541185-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Reorder functions in drivers/gpio/gpio-aggregator.c to prepare for the configfs-based interface additions in subsequent commits. Arrange the code so that the configfs implementations will appear above the existing sysfs-specific code, since the latter will partly depend on the configfs interface implementations when it starts to expose the settings to configfs. The order in drivers/gpio/gpio-aggregator.c will be as follows: * Basic gpio_aggregator/gpio_aggregator_line representations * Common utility functions * GPIO Forwarder implementations * Configfs interface implementations * Sysfs interface implementations * Platform device implementations * Module init/exit implementations This separate commit ensures a clean diff for the subsequent commits. No functional change. Reviewed-by: Geert Uytterhoeven Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 380 +++++++++++++++++---------------- 1 file changed, 192 insertions(+), 188 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index d668ddb2e81d..893cd56de867 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -61,194 +61,6 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, = const char *key, return 0; } =20 -static int aggr_parse(struct gpio_aggregator *aggr) -{ - char *args =3D skip_spaces(aggr->args); - char *name, *offsets, *p; - unsigned int i, n =3D 0; - int error =3D 0; - - unsigned long *bitmap __free(bitmap) =3D - bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL); - if (!bitmap) - return -ENOMEM; - - args =3D next_arg(args, &name, &p); - while (*args) { - args =3D next_arg(args, &offsets, &p); - - p =3D get_options(offsets, 0, &error); - if (error =3D=3D 0 || *p) { - /* Named GPIO line */ - error =3D aggr_add_gpio(aggr, name, U16_MAX, &n); - if (error) - return error; - - name =3D offsets; - continue; - } - - /* GPIO chip + offset(s) */ - error =3D 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 =3D aggr_add_gpio(aggr, name, i, &n); - if (error) - return error; - } - - args =3D next_arg(args, &name, &p); - } - - if (!n) { - pr_err("No GPIOs specified\n"); - return -EINVAL; - } - - return 0; -} - -static ssize_t new_device_store(struct device_driver *driver, const char *= buf, - size_t count) -{ - struct gpio_aggregator *aggr; - struct platform_device *pdev; - int res, id; - - if (!try_module_get(THIS_MODULE)) - return -ENOENT; - - /* kernfs guarantees string termination, so count + 1 is safe */ - aggr =3D kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); - if (!aggr) { - res =3D -ENOMEM; - goto put_module; - } - - memcpy(aggr->args, buf, count + 1); - - aggr->lookups =3D kzalloc(struct_size(aggr->lookups, table, 1), - GFP_KERNEL); - if (!aggr->lookups) { - res =3D -ENOMEM; - goto free_ga; - } - - mutex_lock(&gpio_aggregator_lock); - id =3D idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL); - mutex_unlock(&gpio_aggregator_lock); - - if (id < 0) { - res =3D id; - goto free_table; - } - - aggr->lookups->dev_id =3D kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id); - if (!aggr->lookups->dev_id) { - res =3D -ENOMEM; - goto remove_idr; - } - - res =3D aggr_parse(aggr); - if (res) - goto free_dev_id; - - gpiod_add_lookup_table(aggr->lookups); - - pdev =3D platform_device_register_simple(DRV_NAME, id, NULL, 0); - if (IS_ERR(pdev)) { - res =3D PTR_ERR(pdev); - goto remove_table; - } - - aggr->pdev =3D pdev; - module_put(THIS_MODULE); - return count; - -remove_table: - gpiod_remove_lookup_table(aggr->lookups); -free_dev_id: - kfree(aggr->lookups->dev_id); -remove_idr: - mutex_lock(&gpio_aggregator_lock); - idr_remove(&gpio_aggregator_idr, id); - mutex_unlock(&gpio_aggregator_lock); -free_table: - kfree(aggr->lookups); -free_ga: - kfree(aggr); -put_module: - module_put(THIS_MODULE); - return res; -} - -static DRIVER_ATTR_WO(new_device); - -static void gpio_aggregator_free(struct gpio_aggregator *aggr) -{ - platform_device_unregister(aggr->pdev); - gpiod_remove_lookup_table(aggr->lookups); - kfree(aggr->lookups->dev_id); - kfree(aggr->lookups); - kfree(aggr); -} - -static ssize_t delete_device_store(struct device_driver *driver, - const char *buf, size_t count) -{ - struct gpio_aggregator *aggr; - unsigned int id; - int error; - - if (!str_has_prefix(buf, DRV_NAME ".")) - return -EINVAL; - - error =3D kstrtouint(buf + strlen(DRV_NAME "."), 10, &id); - if (error) - return error; - - if (!try_module_get(THIS_MODULE)) - return -ENOENT; - - mutex_lock(&gpio_aggregator_lock); - aggr =3D idr_remove(&gpio_aggregator_idr, id); - mutex_unlock(&gpio_aggregator_lock); - if (!aggr) { - module_put(THIS_MODULE); - return -ENOENT; - } - - gpio_aggregator_free(aggr); - module_put(THIS_MODULE); - return count; -} -static DRIVER_ATTR_WO(delete_device); - -static struct attribute *gpio_aggregator_attrs[] =3D { - &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); -} - =20 /* * GPIO Forwarder @@ -573,6 +385,184 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struc= t device *dev, } =20 =20 +/* + * Sysfs interface + */ +static int aggr_parse(struct gpio_aggregator *aggr) +{ + char *args =3D skip_spaces(aggr->args); + char *name, *offsets, *p; + unsigned int i, n =3D 0; + int error =3D 0; + + unsigned long *bitmap __free(bitmap) =3D + bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL); + if (!bitmap) + return -ENOMEM; + + args =3D next_arg(args, &name, &p); + while (*args) { + args =3D next_arg(args, &offsets, &p); + + p =3D get_options(offsets, 0, &error); + if (error =3D=3D 0 || *p) { + /* Named GPIO line */ + error =3D aggr_add_gpio(aggr, name, U16_MAX, &n); + if (error) + return error; + + name =3D offsets; + continue; + } + + /* GPIO chip + offset(s) */ + error =3D 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 =3D aggr_add_gpio(aggr, name, i, &n); + if (error) + return error; + } + + args =3D next_arg(args, &name, &p); + } + + if (!n) { + pr_err("No GPIOs specified\n"); + return -EINVAL; + } + + return 0; +} + +static ssize_t new_device_store(struct device_driver *driver, const char *= buf, + size_t count) +{ + struct gpio_aggregator *aggr; + struct platform_device *pdev; + int res, id; + + if (!try_module_get(THIS_MODULE)) + return -ENOENT; + + /* kernfs guarantees string termination, so count + 1 is safe */ + aggr =3D kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); + if (!aggr) { + res =3D -ENOMEM; + goto put_module; + } + + memcpy(aggr->args, buf, count + 1); + + aggr->lookups =3D kzalloc(struct_size(aggr->lookups, table, 1), + GFP_KERNEL); + if (!aggr->lookups) { + res =3D -ENOMEM; + goto free_ga; + } + + mutex_lock(&gpio_aggregator_lock); + id =3D idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL); + mutex_unlock(&gpio_aggregator_lock); + + if (id < 0) { + res =3D id; + goto free_table; + } + + aggr->lookups->dev_id =3D kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id); + if (!aggr->lookups->dev_id) { + res =3D -ENOMEM; + goto remove_idr; + } + + res =3D aggr_parse(aggr); + if (res) + goto free_dev_id; + + gpiod_add_lookup_table(aggr->lookups); + + pdev =3D platform_device_register_simple(DRV_NAME, id, NULL, 0); + if (IS_ERR(pdev)) { + res =3D PTR_ERR(pdev); + goto remove_table; + } + + aggr->pdev =3D pdev; + module_put(THIS_MODULE); + return count; + +remove_table: + gpiod_remove_lookup_table(aggr->lookups); +free_dev_id: + kfree(aggr->lookups->dev_id); +remove_idr: + mutex_lock(&gpio_aggregator_lock); + idr_remove(&gpio_aggregator_idr, id); + mutex_unlock(&gpio_aggregator_lock); +free_table: + kfree(aggr->lookups); +free_ga: + kfree(aggr); +put_module: + module_put(THIS_MODULE); + return res; +} + +static DRIVER_ATTR_WO(new_device); + +static void gpio_aggregator_free(struct gpio_aggregator *aggr) +{ + platform_device_unregister(aggr->pdev); + gpiod_remove_lookup_table(aggr->lookups); + kfree(aggr->lookups->dev_id); + kfree(aggr->lookups); + kfree(aggr); +} + +static ssize_t delete_device_store(struct device_driver *driver, + const char *buf, size_t count) +{ + struct gpio_aggregator *aggr; + unsigned int id; + int error; + + if (!str_has_prefix(buf, DRV_NAME ".")) + return -EINVAL; + + error =3D kstrtouint(buf + strlen(DRV_NAME "."), 10, &id); + if (error) + return error; + + if (!try_module_get(THIS_MODULE)) + return -ENOENT; + + mutex_lock(&gpio_aggregator_lock); + aggr =3D idr_remove(&gpio_aggregator_idr, id); + mutex_unlock(&gpio_aggregator_lock); + if (!aggr) { + module_put(THIS_MODULE); + return -ENOENT; + } + + gpio_aggregator_free(aggr); + module_put(THIS_MODULE); + return count; +} +static DRIVER_ATTR_WO(delete_device); + +static struct attribute *gpio_aggregator_attrs[] =3D { + &driver_attr_new_device.attr, + &driver_attr_delete_device.attr, + NULL +}; +ATTRIBUTE_GROUPS(gpio_aggregator); + + /* * GPIO Aggregator platform device */ @@ -630,6 +620,20 @@ static struct platform_driver gpio_aggregator_driver = =3D { }, }; =20 +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); --=20 2.45.2 From nobody Fri Dec 19 13:52:02 2025 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 37C222248A5 for ; Mon, 17 Feb 2025 14:36:09 +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=1739802970; cv=none; b=kEjCFICGvDYDzIid2DQmdxWqm8kx1NS71kzivscdo83+QfqttXxCRB/MwqhE2oWv11wzfPLsXipG2eIY6IqOK3bOPuAALLmRUeSbBCRJc+WFbg36qD47rq6BNYvAB9y/sn2firYZs2MbR6DLAvm/ifmaVudg+vlpfutniXiM7Sg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739802970; c=relaxed/simple; bh=aLA3ZVDhrDy3RNwYW++kaJn2SQ84AkvFmu6stXF9mto=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dPetsZHKLWz8N6nzuEVQ/H7v7qbqk/Fa+iw4BFGDnft0OSMOw29NQvE0Dba44C3WGUqUIkIraJVYsp6rGCiILU6m0xi0rrINn8hgCjAUpKqsYUaVEN0M55sEAKZJfclW3DuO7GHiXPH/n5YpqC8itF/gmW8VKmu5jj7YUxndnqA= 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=dwtv0Giy; 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="dwtv0Giy" Received: from mail-pl1-f200.google.com (mail-pl1-f200.google.com [209.85.214.200]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id C417F3F31E for ; Mon, 17 Feb 2025 14:36:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739802967; bh=gXHg3uCoBKmQSJJ70+DeTAJMIxaEY0B5wJevniOwqIM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dwtv0GiyNsc/tsL6hc3qJT1uU/XMRJv/68dd1mEA1//N6T9WqGrTkgCDtaBF79oc9 RIuecyayTjC4bwBhylQ1G4UFte5xNzrerda/bHtud73Fr5VNw7mCOhbWfuf0j+59CI Kd5Va9gZNhpsLJ0X/U/ZpnRP2E9g1i7dEWw4fLr+72leLzoDvGPz0K069Yy561E8qv Ul87dTGoXGMRzUTrGikjf8gwrvBt8GjhLqop4zKouGWqfDEpG+EOKneYsQtK6QLqW1 ATkBCRKtSlvOk+bJt9DNSoC40i4bOlzjPf2b25kKWFNkFW18GRSdIEkGt5KQZV++sk 12OM+xRXNApCA== Received: by mail-pl1-f200.google.com with SMTP id d9443c01a7336-220e62c4f27so100409685ad.0 for ; Mon, 17 Feb 2025 06:36:07 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739802966; x=1740407766; 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=gXHg3uCoBKmQSJJ70+DeTAJMIxaEY0B5wJevniOwqIM=; b=njdGevJMqWooTENRN31FHJ+Uu3KUt+XcgBSz7NVbD6LSuo2EX5eSx0O8pgkvNbVApX PaJLV8mxhY5X3rN3iIr3Fe1SBqdBLPLbns67wKBujueIiRD7JP+fHnv6zuQAR00y8qzs xgQvQb/gPyhkghY0M1CqvdDv9vhQY8ZitBKBIcfxUDlRTywoz8mSYaSHs8rUtYAUgrYu X8EzX7wY3rQdrITEqdBghyHTYV4zEODugWVCrusbmfKlsapBscoWyGFsahAaPC2fA45y 5rlGK2MUWKqS/6EDoLZY8ETXGMoLgXpIrBCkgbnCxGWBrFRRzAYMgbWHGbARS2ONjxxf NX0Q== X-Forwarded-Encrypted: i=1; AJvYcCWhrtT/C3i0UrzhWHOUFvIDCbpzygXwoeqibCZl5DEcvUaOpKnJlux8zlRzCVQe/ST1xd0bZCBzGpavEYY=@vger.kernel.org X-Gm-Message-State: AOJu0YxqZjS1cVjxh07xc0iR2cHppF1qP76kQsbiqjGqgm9TOxVRMkfX 8M30Fdh3aTUkhkYTv511i30Aj78YrEcrXArbDtOQ9FekeE3jZLsgFZJ9gHbd+7HYACNfOWyVgWO jY7xK0T181XDqdeA4JclzdNFVRG7vsw0rWQK/d/RyG+0eW1eTOylnFBPR/x2kHS86hT9P6+T7ws Vqxw== X-Gm-Gg: ASbGncvXoJFcS6Jke+ilb3NpXRfCrrByIR78Sgpn1B4muzRJU5HkSb9olq44lPPBTM5 lONzL3T7E3QbJUBdulr306NZ60gAq/8sVnI60ZSZZO4cHO2Z+i0rGstTT7jBYM6fGcwhzX+lq5p hajIM0zwXTgC2yRPryJ8Zc25j6MP9Pqh8mQZUJI6EGHOvFsm+lUfMY5li7arUc5KKU6Os6kYmIP dsBPy/MnOmpjgz7D8+mh5PjRS86YkJhTIrt6Zem/FnUbNvR6sAuCxRTtVoC6bWtIHpPinQth9xn Re/PKl0X7rs+hRVtH1QPqIo= X-Received: by 2002:a17:902:d542:b0:215:f1c2:fcc4 with SMTP id d9443c01a7336-221040bc31bmr169176285ad.41.1739802965885; Mon, 17 Feb 2025 06:36:05 -0800 (PST) X-Google-Smtp-Source: AGHT+IHCZIJuJa6JJ2WId5wv4vsQnYCm/8htK948V0rYbd/ALkX5nVYWeDQNlPKzKTrGrQrpSd6IAw== X-Received: by 2002:a17:902:d542:b0:215:f1c2:fcc4 with SMTP id d9443c01a7336-221040bc31bmr169175965ad.41.1739802965628; Mon, 17 Feb 2025 06:36:05 -0800 (PST) Received: from localhost.localdomain ([240f:74:7be:1:a6da:1fd8:6ba3:4cf3]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2fbf98b3305sm10057757a91.6.2025.02.17.06.36.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Feb 2025 06:36:05 -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 v4 3/9] gpio: aggregator: add aggr_alloc()/aggr_free() Date: Mon, 17 Feb 2025 23:35:25 +0900 Message-ID: <20250217143531.541185-4-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250217143531.541185-1-koichiro.den@canonical.com> References: <20250217143531.541185-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Prepare for the upcoming configfs interface. These functions will be used by both the existing sysfs interface and the new configfs interface, reducing code duplication. No functional change. Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 58 +++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 893cd56de867..a93b7d3de929 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -36,12 +36,41 @@ struct gpio_aggregator { struct gpiod_lookup_table *lookups; struct platform_device *pdev; + int id; char args[]; }; =20 static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */ static DEFINE_IDR(gpio_aggregator_idr); =20 +static int aggr_alloc(struct gpio_aggregator **aggr, size_t arg_size) +{ + struct gpio_aggregator *new __free(kfree) =3D NULL; + int ret; + + new =3D kzalloc(sizeof(*new) + arg_size, GFP_KERNEL); + if (!new) + return -ENOMEM; + + mutex_lock(&gpio_aggregator_lock); + ret =3D idr_alloc(&gpio_aggregator_idr, new, 0, 0, GFP_KERNEL); + mutex_unlock(&gpio_aggregator_lock); + if (ret < 0) + return ret; + + new->id =3D ret; + *aggr =3D no_free_ptr(new); + return 0; +} + +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); + kfree(aggr); +} + static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key, int hwnum, unsigned int *n) { @@ -444,17 +473,15 @@ static ssize_t new_device_store(struct device_driver = *driver, const char *buf, { struct gpio_aggregator *aggr; struct platform_device *pdev; - int res, id; + int res; =20 if (!try_module_get(THIS_MODULE)) return -ENOENT; =20 /* kernfs guarantees string termination, so count + 1 is safe */ - aggr =3D kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); - if (!aggr) { - res =3D -ENOMEM; + res =3D aggr_alloc(&aggr, count + 1); + if (res) goto put_module; - } =20 memcpy(aggr->args, buf, count + 1); =20 @@ -465,19 +492,10 @@ static ssize_t new_device_store(struct device_driver = *driver, const char *buf, goto free_ga; } =20 - mutex_lock(&gpio_aggregator_lock); - id =3D idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL); - mutex_unlock(&gpio_aggregator_lock); - - if (id < 0) { - res =3D id; - goto free_table; - } - - aggr->lookups->dev_id =3D kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id); + aggr->lookups->dev_id =3D kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, aggr->= id); if (!aggr->lookups->dev_id) { res =3D -ENOMEM; - goto remove_idr; + goto free_table; } =20 res =3D aggr_parse(aggr); @@ -486,7 +504,7 @@ static ssize_t new_device_store(struct device_driver *d= river, const char *buf, =20 gpiod_add_lookup_table(aggr->lookups); =20 - pdev =3D platform_device_register_simple(DRV_NAME, id, NULL, 0); + pdev =3D platform_device_register_simple(DRV_NAME, aggr->id, NULL, 0); if (IS_ERR(pdev)) { res =3D PTR_ERR(pdev); goto remove_table; @@ -500,14 +518,10 @@ static ssize_t new_device_store(struct device_driver = *driver, const char *buf, 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); + aggr_free(aggr); put_module: module_put(THIS_MODULE); return res; --=20 2.45.2 From nobody Fri Dec 19 13:52:02 2025 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 596DA224AE6 for ; Mon, 17 Feb 2025 14:36:12 +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=1739802974; cv=none; b=nZIStQaZi7bY97OxuI2876am6FLmT9bVVgHt0Hyakc7zXBtDlUmAlgSas87L9tjXvJ/cC7dnfvXkqzW3NLJU4P36qfnwxe1ajGBaGJVa1VC4VdX/IVmvrskSFE3bHozlC4lT8hp0mQQdjc9kYXudMvEHi5zDjZA84V8oQKGuYM4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739802974; c=relaxed/simple; bh=NJOhhLM9jagdTTN67NRrlRQGIjAkkuvzOzST0beJO9M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=vDGkpYKZd/2XR8eBjKsszpCVWo9KMWzOIiI0mbPEYmSIFvUSAw9rfz+cejzlTReXxz8VPnFCyZKvMsNQj/NCx9nsUAQHQwv+UtNwCXKEopIjh6famj6X0V4rPggwYkcLrttq5l/kRy/uJ8PJ2ywu1iPUOv8mrgWVXdxo2lmexAA= 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=TfyjByHG; 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="TfyjByHG" Received: from mail-pj1-f71.google.com (mail-pj1-f71.google.com [209.85.216.71]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 75AC33FE6E for ; Mon, 17 Feb 2025 14:36:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739802970; bh=Df80Zzm0kWEKoUngHLT3TkabwBuP0/F6cq+enevcDvE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TfyjByHGy/jl8LbSyCjBOp17zT/+EcbficGE/p/k2KFqruhb7L2A8oCQsGmhcQ5qg csuqVHjOxlufncU8JaXPy4f4fgVw/xjAj3R45EVXx+tw26qwIPQx0InkIx21jhw00o LLnA4xcAwKgkTp0Dq/U3wdbN8cBH6tU7GNxcD2eg5GzXDnV25UB3IpGmovvbg8R5/m CsPyLVVlYOQ7+IYAc9OeqJNCu2xstDYe4rjmsq+xeDU2/KqOn9cfGwVS6cFit3HyVF IV0HFFQQ1cdWocDQQClhtTGkIWfKgpgy2HHEqAH8HCfb3ayMYbuhKFmhiXbC8BkKM6 B6dmfxlSL9JCQ== Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-2fc17c3eeb5so8041005a91.1 for ; Mon, 17 Feb 2025 06:36:10 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739802969; x=1740407769; 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=Df80Zzm0kWEKoUngHLT3TkabwBuP0/F6cq+enevcDvE=; b=KsqtdjFbsONUIJONeA0Ilq9MK7L8qnRdJBHx/jUhC3zxAud29V1MW0QJ6yAwVQm/0A 5LybsRtL+ehQw/HtFjqhDzOJbCPhUXw7ULcM+MhO1+7IuPiPQ7mf5xLpTledYI7FBOwr wkShOQrK+VMCM7uTuMQbC1OISFu1XCT8mo7dNkSMFlh/mkXvvXVp3Hd7pDIBi9BBB7mt E2NdvdhRFqrjoGRJtctWf18QqTLbXkAttB7cMFdkGJ0SJPNYZC+xzrSPU1nEWpXfcDu9 ocK481MT4J7sCdFEqxowcNJ5u885SC6LR5PqJ2tSpDfjgTyaqyIObnJtpPdWh7xRGfaF 32sQ== X-Forwarded-Encrypted: i=1; AJvYcCUHb+bfG7YZ0C76u2SDeeO3u8J5YkL2zEXxLYHEDa+DzS4prWuYTUDAyIHJtjEl9FMsc6Zvz0Lj0OLfKq4=@vger.kernel.org X-Gm-Message-State: AOJu0YymPeV3syFNdCHJc02ZfJktWZUXcd7VbMUv5q0lweQ/Fxg5ujev EiWvFoWQ/sj1aaAlgu2IGrOzyFjFfer76mm08of4SCaUfe2Og3/3FwJihffMogr4vkCufk17E0x Q/CF9Ar0FIq4PAoyQ5Wde3fX2aSOlPm69tK+n+tjC7KHgw8uSslqeuoCRrNvtD5xw3sVTFTdZ3u 7iRQ== X-Gm-Gg: ASbGncs2hKCwDmKmiiU5OEyXdks2v6FiBCbNfzZkKx/sN84frs5KZH7Z56vEbS+nImM MLeix1iBHgP+4ikIeEwNPIF7sYuMcs1JSuXff74Z2jXp/DAB7PZKGWlKeXG0POPzQwqK3uOs8Kj EJsX/6vpZj0yd6stxYb7K01iFDTpyHp5CCEo9rGpVgkvxsYVd0MHpMdr02Z32reyitColWIXUXM pVVZY+K6uYGQGw65wiMPaAr8T1ENHYg3EeZWLgtfDNTQnFYEjB0L4+iaO7twtZlQMi+mr1xu420 y8wMS1U4iIPevhlg7UWZPE8= X-Received: by 2002:a17:90b:1e46:b0:2fa:157e:c790 with SMTP id 98e67ed59e1d1-2fc40d14e35mr14720588a91.5.1739802968718; Mon, 17 Feb 2025 06:36:08 -0800 (PST) X-Google-Smtp-Source: AGHT+IHOlOx2UpXCGlKx/OugLik7O241OJG1jR7d+OkOyOXlwVsrTKouk/mybnFP1KKUQ/ZXBq4Ryg== X-Received: by 2002:a17:90b:1e46:b0:2fa:157e:c790 with SMTP id 98e67ed59e1d1-2fc40d14e35mr14720548a91.5.1739802968229; Mon, 17 Feb 2025 06:36:08 -0800 (PST) Received: from localhost.localdomain ([240f:74:7be:1:a6da:1fd8:6ba3:4cf3]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2fbf98b3305sm10057757a91.6.2025.02.17.06.36.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Feb 2025 06:36:07 -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 v4 4/9] gpio: aggregator: introduce basic configfs interface Date: Mon, 17 Feb 2025 23:35:26 +0900 Message-ID: <20250217143531.541185-5-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250217143531.541185-1-koichiro.den@canonical.com> References: <20250217143531.541185-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 >=3D 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 | 2 + drivers/gpio/gpio-aggregator.c | 546 ++++++++++++++++++++++++++++++++- 2 files changed, 538 insertions(+), 10 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d8fede07149f..591244e6cd4e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1871,6 +1871,8 @@ menu "Virtual GPIO drivers" =20 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 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 a93b7d3de929..ec102453817b 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -9,10 +9,13 @@ =20 #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -27,6 +30,8 @@ #include #include =20 +#include "gpio-pseudo.h" + #define AGGREGATOR_MAX_GPIOS 512 =20 /* @@ -34,12 +39,36 @@ */ =20 struct gpio_aggregator { + struct pseudo_gpio_common common; + struct config_group group; struct gpiod_lookup_table *lookups; - struct platform_device *pdev; + struct mutex lock; int id; + + /* List of gpio_aggregator_line. Always added in order */ + struct list_head list_head; + + /* used by legacy sysfs interface only */ + bool init_via_sysfs; char args[]; }; =20 +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); =20 @@ -59,6 +88,8 @@ static int aggr_alloc(struct gpio_aggregator **aggr, size= _t arg_size) return ret; =20 new->id =3D ret; + INIT_LIST_HEAD(&new->list_head); + mutex_init(&new->lock); *aggr =3D no_free_ptr(new); return 0; } @@ -68,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); } =20 @@ -90,6 +122,70 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, = const char *key, return 0; } =20 +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 =3D kzalloc(sizeof(*line), GFP_KERNEL); + if (!line) + return ERR_PTR(-ENOMEM); + + if (key) { + line->key =3D kstrdup(key, GFP_KERNEL); + if (!line->key) { + kfree(line); + return ERR_PTR(-ENOMEM); + } + } + + line->flags =3D GPIO_LOOKUP_FLAGS_DEFAULT; + line->parent =3D parent; + line->idx =3D idx; + line->offset =3D 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); +} + =20 /* * GPIO Forwarder @@ -414,6 +510,400 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struc= t device *dev, } =20 =20 +/* + * Configfs interface + */ + +static struct gpio_aggregator * +to_gpio_aggregator(struct config_item *item) +{ + struct config_group *group =3D 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 =3D 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 =3D 0; + int ret =3D 0; + + if (aggr_count_lines(aggr) =3D=3D 0) + return -EINVAL; + + aggr->lookups =3D kzalloc(struct_size(aggr->lookups, table, 1), + GFP_KERNEL); + if (!aggr->lookups) + return -ENOMEM; + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo.name =3D DRV_NAME; + pdevinfo.id =3D 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 !=3D n) { + ret =3D -EINVAL; + goto err_remove_lookups; + } + + if (line->offset < 0) + ret =3D aggr_add_gpio(aggr, line->key, U16_MAX, &n); + else + ret =3D aggr_add_gpio(aggr, line->key, line->offset, &n); + if (ret) + goto err_remove_lookups; + } + + aggr->lookups->dev_id =3D kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, aggr->= id); + if (!aggr->lookups->dev_id) { + ret =3D -ENOMEM; + goto err_remove_lookups; + } + + gpiod_add_lookup_table(aggr->lookups); + + ret =3D 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 =3D 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 =3D to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr =3D 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 =3D to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr =3D line->parent; + + char *key __free(kfree) =3D 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 =3D 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 =3D to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr =3D line->parent; + unsigned int offset; + + scoped_guard(mutex, &aggr->lock) + offset =3D 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 =3D to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr =3D line->parent; + int offset, ret; + + ret =3D kstrtoint(page, 0, &offset); + if (ret) + return ret; + + /* + * When offset =3D=3D -1, 'key' represents a line name to lookup. + * When 0 <=3D 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 =3D offset; + + return count; +} +CONFIGFS_ATTR(gpio_aggr_line_, offset); + +static struct configfs_attribute *gpio_aggr_line_attrs[] =3D { + &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 =3D to_gpio_aggregator(item); + struct platform_device *pdev; + + guard(mutex)(&aggr->lock); + + pdev =3D 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 =3D to_gpio_aggregator(item); + bool active; + + scoped_guard(mutex, &aggr->lock) + active =3D 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 =3D to_gpio_aggregator(item); + int ret =3D 0; + bool live; + + ret =3D 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 =3D=3D aggr_is_active(aggr)) + ret =3D -EPERM; + else if (live) + ret =3D aggr_activate(aggr); + else + aggr_deactivate(aggr); + } + + /* + * Undepend is required only if device disablement (live =3D=3D 0) + * succeeds or if device enablement (live =3D=3D 1) fails. + */ + if (live =3D=3D !!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[] =3D { + &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 =3D to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr =3D 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 =3D { + .release =3D gpio_aggr_line_release, +}; + +static const struct config_item_type gpio_aggr_line_type =3D { + .ct_item_ops =3D &gpio_aggr_line_item_ops, + .ct_attrs =3D gpio_aggr_line_attrs, + .ct_owner =3D THIS_MODULE, +}; + +static void gpio_aggr_device_release(struct config_item *item) +{ + struct gpio_aggregator *aggr =3D 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 =3D { + .release =3D gpio_aggr_device_release, +}; + +static struct config_group * +gpio_aggr_device_make_group(struct config_group *group, const char *name) +{ + struct gpio_aggregator *aggr =3D to_gpio_aggregator(&group->cg_item); + struct gpio_aggregator_line *line; + unsigned int idx; + int ret, nchar; + + ret =3D sscanf(name, "line%u%n", &idx, &nchar); + if (ret !=3D 1 || nchar !=3D 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 =3D=3D idx) + return ERR_PTR(-EINVAL); + + line =3D 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 =3D { + .make_group =3D gpio_aggr_device_make_group, +}; + +static const struct config_item_type gpio_aggr_device_type =3D { + .ct_group_ops =3D &gpio_aggr_device_group_ops, + .ct_item_ops =3D &gpio_aggr_device_item_ops, + .ct_attrs =3D gpio_aggr_device_attrs, + .ct_owner =3D 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 =3D 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 =3D { + .make_group =3D gpio_aggr_make_group, +}; + +static const struct config_item_type gpio_aggr_type =3D { + .ct_group_ops =3D &gpio_aggr_group_ops, + .ct_owner =3D THIS_MODULE, +}; + +static struct configfs_subsystem gpio_aggr_subsys =3D { + .su_group =3D { + .cg_item =3D { + .ci_namebuf =3D DRV_NAME, + .ci_type =3D &gpio_aggr_type, + }, + }, +}; + + /* * Sysfs interface */ @@ -485,6 +975,7 @@ static ssize_t new_device_store(struct device_driver *d= river, const char *buf, =20 memcpy(aggr->args, buf, count + 1); =20 + aggr->init_via_sysfs =3D true; aggr->lookups =3D kzalloc(struct_size(aggr->lookups, table, 1), GFP_KERNEL); if (!aggr->lookups) { @@ -510,7 +1001,7 @@ static ssize_t new_device_store(struct device_driver *= driver, const char *buf, goto remove_table; } =20 - aggr->pdev =3D pdev; + aggr->common.pdev =3D pdev; module_put(THIS_MODULE); return count; =20 @@ -531,10 +1022,7 @@ static DRIVER_ATTR_WO(new_device); =20 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); + aggr_deactivate(aggr); kfree(aggr); } =20 @@ -556,12 +1044,19 @@ static ssize_t delete_device_store(struct device_dri= ver *driver, return -ENOENT; =20 mutex_lock(&gpio_aggregator_lock); - aggr =3D idr_remove(&gpio_aggregator_idr, id); - mutex_unlock(&gpio_aggregator_lock); - if (!aggr) { + aggr =3D 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); =20 gpio_aggregator_free(aggr); module_put(THIS_MODULE); @@ -636,6 +1131,10 @@ static struct platform_driver gpio_aggregator_driver = =3D { =20 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; } @@ -650,7 +1149,33 @@ static void __exit gpio_aggregator_remove_all(void) =20 static int __init gpio_aggregator_init(void) { - return platform_driver_register(&gpio_aggregator_driver); + int ret =3D 0; + + config_group_init(&gpio_aggr_subsys.su_group); + mutex_init(&gpio_aggr_subsys.su_mutex); + ret =3D 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 =3D 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); =20 @@ -658,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); =20 --=20 2.45.2 From nobody Fri Dec 19 13:52:02 2025 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 43913223328 for ; Mon, 17 Feb 2025 14:36:17 +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=1739802978; cv=none; b=DCEDkdpE7nnE5i5L1iWarz9Ua4GRKHJN/fpOGcT6OxECi3JhehB3NEGi6HlFmIC/Ohanbpo0LnvJ0Tjx6kP/dKO/xDaK/tX2SmT5fmr8OHRkAsf1581+eu+6QhgZNGOG6wRKGOvcdX4u7mQ2qjKkkg34ygM9STpdvuJIcfkGF1Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739802978; c=relaxed/simple; bh=uxdDc8NwSSoU/KhYSVoLNE3SLLqdDtG3WoHdkVTCuPk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GiJAz+ruTx5OnHTx3qMOmKO6nRMOKM1r5uUC698GAPLinpXhdIQknhO+aF+nFPj/uJsXNdyL4WZo+MulVNgIioq7HzhUaYJKzVj+MLPmQ0+VUEy5Sx6GfxDBL6sfA6JCDoMHxRw8TeOmk08XpK/FVjITGhhQKYdm++wl5Z4D+Fg= 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=iW53sRBC; 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="iW53sRBC" Received: from mail-pj1-f69.google.com (mail-pj1-f69.google.com [209.85.216.69]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 15BA23F868 for ; Mon, 17 Feb 2025 14:36:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739802976; bh=v4sbOHRoeQS1MOSALsPLtSJ65COLeoaPvTmtbuEu58k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iW53sRBCxn/x+uWVN/Z7nGx4C3N5Pkan+e7ljLY5/5uJPSQZ7PrnBCAg/JvnIQlJ2 R1t1dKLuBr7DItopTUgKUJBwR3ayoopJRjDNHXmR+1xUIUeEH4mAl253+1NIDi966I 9y/12PVLCaibVP01q1DGDpeMlsjgwCkZDaPdECfTRmEDsl/cI9CIXNVBJC/icQuSdH OTef9lQUkMTxYkucZHx8HBQBBUiX07f16o2FlHkb41sva4SDoV31WG93KiampZhBME asek/xcBW94sN5awZvNPVcUDsT0Jm2gyDZ3DNRAJflCBAKmsgWhBShSlrUloyjPksZ 0gIqQtKpT2baQ== Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-2fbfa786a1aso14003479a91.3 for ; Mon, 17 Feb 2025 06:36:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739802974; x=1740407774; 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=dAaYweoA1AB1ck/hdbzgQhDFOACmEUtSK8Uo7oo2Iij8SrvThAVdSrC2Q6i4rT95XV JbBLLUDeyPpF7W6jigoa5scRcRJnABXFXc9NhiiJlHIfg+FrJoqUws26BfPqFlZbaDKS P4z+WP3VSe5RTiw9f4diagQRuQbN2ceYu7632bfvDhv/d6WYa+0JDe11f0lVxZrsTt3J nQcuSc1tjE6S1vyPp4A7+LHNURWwZn1qHZDaHXADBwqp8jIjxKNQPng6MepdWGeZTmEy uvRCOAokslyBqW8UIBPjRJFvKfecKZ/Z3KaORnvv5bNw35jpUreaBkesh8qAcaSCYGML mNvQ== X-Forwarded-Encrypted: i=1; AJvYcCX3225KNeycI+TcIneUaqSiHcbN2Jua0B/kXPmVoYGfjzP1xMnBaMYYmGwnRGzYpXB3Leg2tc2W55FR4yI=@vger.kernel.org X-Gm-Message-State: AOJu0YznMpa5I5+v+VaNzzK6mlZAk5pDwIVPyJ6IFO9uge+SAuqA8Gzv MWx+07iVnjJAD1gVL6RqFlUgYtnsniC3NFZ6mqbEGcY8kJqdOe3rvnooX8lrSpM2qSnP9xtXELf DzN91fT/5zOmqBHNQ4/fOrfW/npzMM/3R14mmN8QmPq437QWTFZlhlDnaNAdwUjEZm4sWpxq9SR lxaw== X-Gm-Gg: ASbGncuD8YrED86P+yPmO+PAMvD0GpBY+ZV+VPLY3pcmqq5iDoH8yvZNi5oEX29ovMB /0rxGdsvKPpI1fDXlKBRzld+CER6ae/aFw5LXu2h5Sm9NFKdFMstF4Y/ArLaLQUZ/E8vbBYG5VL ofXDAHzCy9R2D5ZuN9RP3CwY1nWapBiSZqyXfqCNhK3b7DBScNwvA/jgPKw26ZMSTqo5tLaGE4c oFcTHq9Mmp4wtcHHqQ7XB0y/x9UgRgprEJ4MGgFmTJcSq5DBi7IZVnIcEB8F//VzYyCKYRVmZYd 0tsBFpzjs94VMGpAdmnCf4Y= X-Received: by 2002:a17:90b:2fc3:b0:2ea:b564:4b31 with SMTP id 98e67ed59e1d1-2fc40f21c49mr14264468a91.19.1739802973317; Mon, 17 Feb 2025 06:36:13 -0800 (PST) X-Google-Smtp-Source: AGHT+IG/i6ZhPeP35hWJ24mm/LIhcXbBPRykLdefs72sMWFjgXDC7lFQiPxRDAVbpwrRAEzufAxZDw== X-Received: by 2002:a17:90b:2fc3:b0:2ea:b564:4b31 with SMTP id 98e67ed59e1d1-2fc40f21c49mr14264311a91.19.1739802971508; Mon, 17 Feb 2025 06:36:11 -0800 (PST) Received: from localhost.localdomain ([240f:74:7be:1:a6da:1fd8:6ba3:4cf3]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2fbf98b3305sm10057757a91.6.2025.02.17.06.36.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Feb 2025 06:36:11 -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 v4 5/9] gpio: aggregator: add 'name' attribute for custom GPIO line names Date: Mon, 17 Feb 2025 23:35:27 +0900 Message-ID: <20250217143531.541185-6-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250217143531.541185-1-koichiro.den@canonical.com> References: <20250217143531.541185-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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; =20 + /* 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); } =20 +static struct fwnode_handle *aggr_make_device_swnode(struct gpio_aggregato= r *aggr) +{ + const char **line_names __free(kfree) =3D NULL; + struct property_entry properties[2]; + struct gpio_aggregator_line *line; + size_t num_lines; + int n =3D 0; + + memset(properties, 0, sizeof(properties)); + + num_lines =3D aggr_count_lines(aggr); + if (num_lines =3D=3D 0) + return NULL; + + line_names =3D 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++] =3D line->name ?: ""; + + properties[0] =3D 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 =3D 0; int ret =3D 0; =20 @@ -545,9 +577,14 @@ static int aggr_activate(struct gpio_aggregator *aggr) if (!aggr->lookups) return -ENOMEM; =20 + swnode =3D aggr_make_device_swnode(aggr); + if (IS_ERR(swnode)) + goto err_remove_lookups; + memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.name =3D DRV_NAME; pdevinfo.id =3D aggr->id; + pdevinfo.fwnode =3D swnode; =20 /* 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 !=3D n) { ret =3D -EINVAL; - goto err_remove_lookups; + goto err_remove_swnode; } =20 if (line->offset < 0) @@ -567,13 +604,13 @@ static int aggr_activate(struct gpio_aggregator *aggr) else ret =3D aggr_add_gpio(aggr, line->key, line->offset, &n); if (ret) - goto err_remove_lookups; + goto err_remove_swnode; } =20 aggr->lookups->dev_id =3D kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, aggr->= id); if (!aggr->lookups->dev_id) { ret =3D -ENOMEM; - goto err_remove_lookups; + goto err_remove_swnode; } =20 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); =20 @@ -658,6 +697,43 @@ gpio_aggr_line_key_store(struct config_item *item, con= st char *page, } CONFIGFS_ATTR(gpio_aggr_line_, key); =20 +static ssize_t +gpio_aggr_line_name_show(struct config_item *item, char *page) +{ + struct gpio_aggregator_line *line =3D to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr =3D 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 =3D to_gpio_aggregator_line(item); + struct gpio_aggregator *aggr =3D line->parent; + + char *name __free(kfree) =3D 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 =3D 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); =20 static struct configfs_attribute *gpio_aggr_line_attrs[] =3D { &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) =20 aggr_line_del(aggr, line); kfree(line->key); + kfree(line->name); kfree(line); } =20 --=20 2.45.2 From nobody Fri Dec 19 13:52:02 2025 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 1DA99223330 for ; Mon, 17 Feb 2025 14:36:17 +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=1739802979; cv=none; b=oahoVpeuE3jwtRer3m1mnz3kImxyZ28jlBkIGTq7SMIoXfAXgaUgh2YteEyr5g1FgUKTcomJORHRXhdViJV6vzke8ACYR0hUX6Y2VLlUToVSLaHBFTOXMGj57X2PjeT6UKfSH3RwyXqF0oT04OTeO0SC3s2H51a0lBMD1tcWT4Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739802979; c=relaxed/simple; bh=iH8P3Qo2jiFyP4RGsTFt/HsQ3VlXvEit9tWzKXSKuck=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=adVkDgXZWwkPJ3kaWd1tUeZrrK4U+BtE9QUmNKgK0CrpImWr354tkknLOO2viTgqk5xOD95/YSweO/3Rg5jZBw8sIvZqci93hWmZoFu00m2bv1e0tz+ZPbEqem4e/xdqi+y+R4CUpfeQnfQvE780JfM8RcOKakNc2zi80K2sPbY= 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=u3i9lFTn; 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="u3i9lFTn" Received: from mail-pj1-f69.google.com (mail-pj1-f69.google.com [209.85.216.69]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id C57114012C for ; Mon, 17 Feb 2025 14:36:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739802976; bh=FjdYUqaie9BiRKi7ISU7HN1qGBGl47EuEmlrMDzrJcg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=u3i9lFTn29dtnRj+nr8uk/jjB+ebZgPXh3m8SibRXu3Uu5mp6D7CqIjgcFEaYAweF KoVUL95j8e/mYKmSIb4D/hYzEdEBWUqEiyAqyLEBT/mrXE0kr0Cagz/+zdWJZIsjTc ZjEgUkYRTLq0GPf30E8u+4LIA+hVBAqhPLltfL546K36oX+ETpqb3889xo/PvyRs8P 1E8W0TbVlbEfyIkT/MLTDmsEjiMY0+trneur6LSuvFZ5dMzYmmoOyojsUwPEeV8pGr Nk/H6Fs1LTloJvH5N82wzYYRZmC6uKdcnjn6gpKM7ws8ExfZ9ve5JSc/TpBMT7x20J SzNHbsOqBg8jw== Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-2fc1eabf4f7so7724901a91.1 for ; Mon, 17 Feb 2025 06:36:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739802975; x=1740407775; 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=FjdYUqaie9BiRKi7ISU7HN1qGBGl47EuEmlrMDzrJcg=; b=edmJaS10e5ASR+t3hqBCiKPi8xViVSxZbvjdjvwfVPbbB076n/YS1yAecK5ZInFcL8 HgkK/fvp4PTKtsMltxXQ9kAQ9Z57Ptj+EmRVEwBE/8SfvH5OwMx51xeulxLVUNHqLp4P gLhZsPVzR4uju0O1t03H1OCOwwlnB3Q2CRdV/pzGm9+4NOvDrnoeC/oxXpE5u+7gcY1a /SSs4NjNM57nX2jmiWqcM7zCjNMKYJJ3nfONjpPhAPyI9VhwzrW+//28xIvHbkO0d3oR Wr9SoKaHJwQpAC/ujTWliulEZR3hqJDrWmK+1pHsnonrJAcS++KVI7bctpaezablU/9X vsgA== X-Forwarded-Encrypted: i=1; AJvYcCXx09m0xdhNYQ5ZMAnwn6H38bjd438arwQw7pJzyzqaTasML5tSfQOew7c+hkLhLf9ooucTrrASvkvZaIA=@vger.kernel.org X-Gm-Message-State: AOJu0YwDjX+jq8v4UazY7exdAu+rl7Gbc7lawI9NmiXnBtMN1X0tvmK7 +2ZJJTWFWh3UTnKBv5NMeyWmjPbfeA5/dU24M8+eWV9eEQ4NF2g2q89lDhmKZLsh31zO4+1GhKu PiDIjXrpCxPEEjvRp37d/iQcGab2McX1pPRf8J/OLmMTgDyRrrArUBvFuf4iEZ256+sdD8ZhZir ZCpA== X-Gm-Gg: ASbGncsOh6XepxafBTptz3oX8fSUvhGuVi0n9SIf9wb5J1D+wY8H5uPb2bwDnK2fo3f NSRzQ6DlPcO2/MjrUcuJeNDmxVjm4dlOqwhrD/A7Wo7POXsJqAtPlXaTHHCuIsEL9Ws8avClT9C vKg8jy4/fdU3Cn0uri01tPujscdjdabjJbH5s6/BWO9PGsfy3DA4c0qYlIBqxnnLA6ok5D96JWZ /aBTvYtxI58xJkTBl6Krj53tMZaJh9mv9HPxfiFYm3e54N7022jWhfuAXKEKEyHHj/FH9KM0XmW bnOJmr+kQLnLUa150BaXp2E= X-Received: by 2002:a17:90b:3812:b0:2f4:423a:8fb2 with SMTP id 98e67ed59e1d1-2fc40f21df3mr15661126a91.20.1739802975188; Mon, 17 Feb 2025 06:36:15 -0800 (PST) X-Google-Smtp-Source: AGHT+IEZKsGQGj5NNzfd+iZhP7H4YbLKGbz+dWsQlDfkLsBVAGiKwA+5hq+mhIdi3+Xkw1F8OltQCQ== X-Received: by 2002:a17:90b:3812:b0:2f4:423a:8fb2 with SMTP id 98e67ed59e1d1-2fc40f21df3mr15661097a91.20.1739802974889; Mon, 17 Feb 2025 06:36:14 -0800 (PST) Received: from localhost.localdomain ([240f:74:7be:1:a6da:1fd8:6ba3:4cf3]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2fbf98b3305sm10057757a91.6.2025.02.17.06.36.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Feb 2025 06:36:14 -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 v4 6/9] gpio: aggregator: rename 'name' to 'key' in aggr_parse() Date: Mon, 17 Feb 2025 23:35:28 +0900 Message-ID: <20250217143531.541185-7-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250217143531.541185-1-koichiro.den@canonical.com> References: <20250217143531.541185-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Rename the local variable 'name' in aggr_parse() to 'key' because struct gpio_aggregator_line now uses the 'name' field for the custom line name and the local variable actually represents a 'key'. This change prepares for the next but one commit. No functional change. Reviewed-by: Geert Uytterhoeven Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 692d90246674..2e993c9a7ce5 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -988,7 +988,7 @@ static struct configfs_subsystem gpio_aggr_subsys =3D { static int aggr_parse(struct gpio_aggregator *aggr) { char *args =3D skip_spaces(aggr->args); - char *name, *offsets, *p; + char *key, *offsets, *p; unsigned int i, n =3D 0; int error =3D 0; =20 @@ -997,18 +997,18 @@ static int aggr_parse(struct gpio_aggregator *aggr) if (!bitmap) return -ENOMEM; =20 - args =3D next_arg(args, &name, &p); + args =3D next_arg(args, &key, &p); while (*args) { args =3D next_arg(args, &offsets, &p); =20 p =3D get_options(offsets, 0, &error); if (error =3D=3D 0 || *p) { /* Named GPIO line */ - error =3D aggr_add_gpio(aggr, name, U16_MAX, &n); + error =3D aggr_add_gpio(aggr, key, U16_MAX, &n); if (error) return error; =20 - name =3D offsets; + key =3D offsets; continue; } =20 @@ -1020,12 +1020,12 @@ static int aggr_parse(struct gpio_aggregator *aggr) } =20 for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { - error =3D aggr_add_gpio(aggr, name, i, &n); + error =3D aggr_add_gpio(aggr, key, i, &n); if (error) return error; } =20 - args =3D next_arg(args, &name, &p); + args =3D next_arg(args, &key, &p); } =20 if (!n) { --=20 2.45.2 From nobody Fri Dec 19 13:52:02 2025 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 092E42253E3 for ; Mon, 17 Feb 2025 14:36:21 +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=1739802983; cv=none; b=hFHhx1c+uIjA7ESTVYn9XKEwZrHArWqUmnqKDN9GdYz0ehS+YQAmlWxL5+2c23lVJfH2TzX2q3rWXLX2NZu8NVEeDwIChGU1U6C5NdzvGHPux5cLsidRCVi0h0cvBhtMa0p+dNHYbRHVA/GT0bnIqHAaQvukFnUIxFloRpQVjEc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739802983; c=relaxed/simple; bh=lWi8cSb8BfWbLOPOp2GNgU6ysUye4CsGO9grvCFpPc8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WqXzTKtmz6knS22UqQ+85LMggXcQwY1fQYrbIbSiCokyHiosSbrF4RYDlUlpdDrulATf3Cjsp6FrwWlXw6Almq1P1oz8qx7spJQwBO08tf27MJWKSsGGTvSnPQzfVP4ZUKypraONUtNqTajpJvpV5c6YnKqXTIFZvke7Vy8XgVk= 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=VKOsOmp9; 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="VKOsOmp9" Received: from mail-pl1-f198.google.com (mail-pl1-f198.google.com [209.85.214.198]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id D085F3F31E for ; Mon, 17 Feb 2025 14:36:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739802979; bh=xsxLQ8/cIyaXlfRbTYcIHh/jf9fjXDEfeDZdjuEqzxg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VKOsOmp99GL2A36mKiww5HmHiK2L9xhFgssgFFUvUTpLsV1cOcPLdERRUJ25vE77X QD4l/HVpO/UplHeN1WGBp3wMU4LEoHSRaX6TbJPLYnZESbokOBmYiL4/KZrMxKxEF4 Zgo3llnGMTyH4vElR/lCKOdkLHTkSL+XSSAfv3+CxX8cOnmbLEzTHcJ/kfX/btmQ3b ULAkLApuuI5/pmYLb1+IK9sN4J8Yp5WhaIlSpIh8TngFKVDEIIJlcgDePehfGhQcac qgODKfeQ7Bhp0OEXrGqXQl3kn4QRKytl21ok6RBx80NFC+9rCDnq4kqB1eAdFEqBc7 DUyZDujKtKNBA== Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-220cd43c75aso152633525ad.3 for ; Mon, 17 Feb 2025 06:36:19 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739802978; x=1740407778; 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=NVLRorwPrWwFIK26XCT0cF3afMm5mmQPVx9LEhkuJC2QwdsZr2tsUdde0QKf37sRJ1 oBm3zm9zgBB5yfEwTISP8vdtHjwy4fKWMzjI5HwcqDRWOBVAk8d2lbQkbK15hCiYl6eo 0N3PVYFYf7KqYfbO/u0Jh1EAd2GXQ04j23S5dxwWXPpKfz71xA5ZKUz8JAdQ3B0/eCY3 5miS1Sdp88mwuEWs4esSdzdvr0vGEEsEepROQr+dR2pB+jR9JLMIGgmNe49JqqFiqDgz ufpGPfBua7dA/fKDDla0xWAYHMztE4zbDvpMlVDF+siJZsFIkTY65Fo81/ut7O4tZjjb 2K4Q== X-Forwarded-Encrypted: i=1; AJvYcCXpTAXnMqImZ68YHvU6MxLn1Q8tAUBIto+XqHs3LOa3pkQZX7Y7kRCPCmq3RX4qOpC6yMxZ0KAsSvpX5ug=@vger.kernel.org X-Gm-Message-State: AOJu0Yzt2ei5kFw3TGnxpRP6nHRDAghC7XTf2P2LiUfyuwb+ZWb0kkWd u8I2TNCPAsX7/QTFrMoxwvvLGSP3FR5Pm8+fGZUvPz6TZNu/nRFm31BwdcbKCQaqw0volukGWZY GjvJ0zDrc7pfIYXNLd7IT47OQ/aVI9uNtaa2aBn46+N+gREZ0X+bDktBilzNxzzm00zZp5jZ43D ZvMQ== X-Gm-Gg: ASbGncuYnfJfK9CiNLWa/ULUIQRjA3y1Nl03lTUXH7vef6kXXy0bPNHav5ixgubQOcV AjwGOTLwMQ28fOT6upkM3y/kY62WzQrDVqUvPyvaa/EAwIRxcTliWhOw1oOnRiRyEr52ybqfFFq QO1d9uzM2fzCb+FcedSEP03oGk9B08Mw/aWE9+KJxhOqIjk6v1Vn/diuQBuH0PaKLDw/qJrigS6 hfBiJ1gfUqwacJNPGttbDuQ3K5IY4zrOo4KhbPrzs2ob/zG4L9SL+h6Hu9O+UALcF9qh7r4nCJN W1A38nKfRIGN3G2MHr+ZVuY= X-Received: by 2002:a17:902:ec8f:b0:215:b45a:6a5e with SMTP id d9443c01a7336-2210403e825mr139126405ad.18.1739802978283; Mon, 17 Feb 2025 06:36:18 -0800 (PST) X-Google-Smtp-Source: AGHT+IFVcMLmivClQAJruBnXTV2Ja0RMzvZqDr0OO4NPzbiX3VFfWVAnPO/hN3pCcPbQIndpCBTwgw== X-Received: by 2002:a17:902:ec8f:b0:215:b45a:6a5e with SMTP id d9443c01a7336-2210403e825mr139125975ad.18.1739802977690; Mon, 17 Feb 2025 06:36:17 -0800 (PST) Received: from localhost.localdomain ([240f:74:7be:1:a6da:1fd8:6ba3:4cf3]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2fbf98b3305sm10057757a91.6.2025.02.17.06.36.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Feb 2025 06:36:17 -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 v4 7/9] gpio: aggregator: expose aggregator created via legacy sysfs to configfs Date: Mon, 17 Feb 2025 23:35:29 +0900 Message-ID: <20250217143531.541185-8-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250217143531.541185-1-koichiro.den@canonical.com> References: <20250217143531.541185-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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" =20 #define AGGREGATOR_MAX_GPIOS 512 +#define AGGREGATOR_LEGACY_PREFIX "_sysfs" =20 /* * GPIO Aggregator sysfs interface @@ -131,6 +132,14 @@ static bool aggr_is_active(struct gpio_aggregator *agg= r) return aggr->common.pdev && platform_get_drvdata(aggr->common.pdev); } =20 +/* 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); } =20 +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); + } +} + =20 /* * GPIO Forwarder @@ -687,7 +708,7 @@ gpio_aggr_line_key_store(struct config_item *item, cons= t char *page, =20 guard(mutex)(&aggr->lock); =20 - if (aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || aggr_is_active(aggr)) return -EBUSY; =20 kfree(line->key); @@ -724,7 +745,7 @@ gpio_aggr_line_name_store(struct config_item *item, con= st char *page, =20 guard(mutex)(&aggr->lock); =20 - if (aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || aggr_is_active(aggr)) return -EBUSY; =20 kfree(line->name); @@ -772,7 +793,7 @@ gpio_aggr_line_offset_store(struct config_item *item, c= onst char *page, =20 guard(mutex)(&aggr->lock); =20 - if (aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || aggr_is_active(aggr)) return -EBUSY; =20 line->offset =3D 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; =20 - if (live) + if (live && !aggr->init_via_sysfs) aggr_lockup_configfs(aggr, true); =20 scoped_guard(mutex, &aggr->lock) { - if (live =3D=3D aggr_is_active(aggr)) + if (aggr_is_activating(aggr) || + (live =3D=3D aggr_is_active(aggr))) ret =3D -EPERM; else if (live) ret =3D aggr_activate(aggr); @@ -847,7 +869,7 @@ gpio_aggr_device_live_store(struct config_item *item, c= onst char *page, * Undepend is required only if device disablement (live =3D=3D 0) * succeeds or if device enablement (live =3D=3D 1) fails. */ - if (live =3D=3D !!ret) + if (live =3D=3D !!ret && !aggr->init_via_sysfs) aggr_lockup_configfs(aggr, false); =20 module_put(THIS_MODULE); @@ -893,7 +915,7 @@ static void gpio_aggr_device_release(struct config_item= *item) guard(mutex)(&aggr->lock); =20 /* - * 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 !=3D 1 || nchar !=3D strlen(name)) return ERR_PTR(-EINVAL); =20 + 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); =20 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; =20 + /* + * "_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)) =3D=3D 0) + return ERR_PTR(-EINVAL); + /* arg space is unneeded */ ret =3D aggr_alloc(&aggr, 0); if (ret) @@ -988,6 +1027,8 @@ static struct configfs_subsystem gpio_aggr_subsys =3D { static int aggr_parse(struct gpio_aggregator *aggr) { char *args =3D skip_spaces(aggr->args); + struct gpio_aggregator_line *line; + char name[CONFIGFS_ITEM_NAME_LEN]; char *key, *offsets, *p; unsigned int i, n =3D 0; int error =3D 0; @@ -999,14 +1040,29 @@ static int aggr_parse(struct gpio_aggregator *aggr) =20 args =3D next_arg(args, &key, &p); while (*args) { + scnprintf(name, sizeof(name), "line%u", n); + args =3D next_arg(args, &offsets, &p); =20 p =3D get_options(offsets, 0, &error); if (error =3D=3D 0 || *p) { /* Named GPIO line */ + line =3D aggr_line_alloc(aggr, n, key, -1); + if (!line) { + error =3D -ENOMEM; + goto err; + } + config_group_init_type_name(&line->group, name, + &gpio_aggr_line_type); + error =3D configfs_register_group(&aggr->group, + &line->group); + if (error) + goto err; + aggr_line_add(aggr, line); + error =3D aggr_add_gpio(aggr, key, U16_MAX, &n); if (error) - return error; + goto err; =20 key =3D offsets; continue; @@ -1020,9 +1076,22 @@ static int aggr_parse(struct gpio_aggregator *aggr) } =20 for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { + line =3D aggr_line_alloc(aggr, n, key, i); + if (!line) { + error =3D -ENOMEM; + goto err; + } + config_group_init_type_name(&line->group, name, + &gpio_aggr_line_type); + error =3D configfs_register_group(&aggr->group, + &line->group); + if (error) + goto err; + aggr_line_add(aggr, line); + error =3D aggr_add_gpio(aggr, key, i, &n); if (error) - return error; + goto err; } =20 args =3D next_arg(args, &key, &p); @@ -1030,15 +1099,20 @@ static int aggr_parse(struct gpio_aggregator *aggr) =20 if (!n) { pr_err("No GPIOs specified\n"); - return -EINVAL; + goto err; } =20 return 0; + +err: + aggr_free_lines(aggr); + return error; } =20 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_drive= r *driver, const char *buf, goto free_table; } =20 - res =3D 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 =3D configfs_register_group(&gpio_aggr_subsys.su_group, &aggr->group); if (res) goto free_dev_id; =20 + res =3D aggr_parse(aggr); + if (res) + goto unregister_group; + gpiod_add_lookup_table(aggr->lookups); =20 pdev =3D 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, =20 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); =20 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); } =20 --=20 2.45.2 From nobody Fri Dec 19 13:52:02 2025 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 05C6822371E for ; Mon, 17 Feb 2025 14:36:27 +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=1739802989; cv=none; b=gk+t1l81lYZoEtfxr9/13RbRzjtj9b3msDxgqrRuwquV7BusvfDHvErNEPfK47jaWnrSo3W4Ce/uqt43Ws99rh6BhIAIAjO+NHQVEpPaaBN+43PGk0K4KE/abljvwOOafVHdhFN0aOwMDkscOofm2YPSYxdtrvgUSITmsRFi+7Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739802989; c=relaxed/simple; bh=uvDPPe/zh18N6hlSUI3RGzfNlPtrpvVYWv/tx+FGhgY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KTXI0IleKGi4JJbPY+N0aA/1nHcJe5iyG0AW8Mr1qvRLyScz5Nd2y6t1PHOyR/anoFQX6hwsg2KAEqkAgRhjEtfj1hRwryl7taJ5EyiiCdZ3aoQqz51NZnpiQrrSHXA/K/gddr4r4/wmyv5AHMMlJQBqxJvZxQhWmEU+6a2rCwo= 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=DHji9EP7; 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="DHji9EP7" 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 F0D813FA53 for ; Mon, 17 Feb 2025 14:36:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739802984; bh=dSs/jDBsvmuiaXfkwHoPbsWqaGsAOzbJ2wNat8FrzKA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DHji9EP7tXZ1ZlupkAq2X12FuUZpogOM9X3KkW1D+TwhMnKFFiFrN/eoHDcypitOw VaxIECDTF+2U9xHpOewWa13WBv0/awCF0mVtPn4bAyA7PHWoQNtriOvNF4V7RNA1t2 8CFJQaVId28GrdnTY9IRKCSQ9dYPDGiqScu3GQ13K9QTf/0UBB/ypVF3dxE0DaIGGF zdxs1Cla8MDV8zdm/MWbfciyK66AgrpmoJUcB3jWC2TcaaojtT5sY1J/mzVAuGWuyo n/zb2YpXuLkiXpPcAruvuPWrRYnULqxtM9s1jofoP9UPVfVfeQPgIEnQbAiYQ6iq1D f/qzjWinxnlJQ== Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-2fc318bd470so6107406a91.0 for ; Mon, 17 Feb 2025 06:36:24 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739802981; x=1740407781; 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=dSs/jDBsvmuiaXfkwHoPbsWqaGsAOzbJ2wNat8FrzKA=; b=kRKd9MNEs2yWgLldOpZwXYbbGTHywr4OhV7PEg4N//h8XfSPokRqCjkLHKGxl6PNqL 7AO7OJPhD90Y/0aFOkTisQxUCIpa20jIoCsv56wgF80terwRz7OSV3IpDhHnW1ZJRLhG Z00IrQn8RyRTJvLOt0wk0YqqoMRUWbdLynOlIkwFu+zxtuB4K41NSDZHiJoWHsCp08II I1vmROpO/t9KjatxvIaCPWp8zr4UN/Eqiogo0DFqjBmpBVnEM4BoCf3skF4W4L5t0lZ8 m7f7EKF8BfQN2toST8ZFgdNjwmRwHwajAeup8u+7stke4eesoNQTWl0VhKT44SuQ1E7X 13yA== X-Forwarded-Encrypted: i=1; AJvYcCUANDAzIHivXzm9x2ZZI4xgyA/xt+OyL6GyIWyE5WLqe+ln206g7FmO1NLHFSt9ZdIwQtuShx7/y8HWkfY=@vger.kernel.org X-Gm-Message-State: AOJu0YyrHO35iYn4wHJ5EdrbuUdOzDSKkYOX6psb3nYFQ2m+qIihXvk3 NPKogVBwwofC5bpKFJR8uCdheGddSPfonVYnFnBTFy5M/8vFoh6JgCc7gg/PsQlcHfi4NLCC8B1 esQmlRW4MO66JkC4w7nkomfX5qNMTcUWHKMWHTr+j+FWxej5MDGZOoCyLilyUZA63z3DIRhtMEH oG5w== X-Gm-Gg: ASbGncsGgE4bJEm+scSroJYrfMI8URAO9Uh1Wiavtvzhk22z5u6epigHa1YPDNLTRAJ dAJxLBPUxLt++KAa7k0Zw5/AFj+fqf9jCHVYVgN/e1Q6uSYlP0pmU8r6wyAeeYIy6y7qcEjgkeU j+HQVJ1O2eaFwaXa0m4DfKEuxjsFzi4f5aASsTxZYIKz3AoRNRCBxjOdmZ/ZzXpBjoThBk9S6Lh +PgBMT4iux1PLJ1W5liC9U1nwar6AgliRMHKkdCqu7cAOuD9oKUCfqqrgtiYzO58cJdcZscZ7GR hgl0q07neGRzw091dp7kDPg= X-Received: by 2002:a17:90b:4d87:b0:2fa:1e3e:9be7 with SMTP id 98e67ed59e1d1-2fc40d131d9mr14472029a91.5.1739802980711; Mon, 17 Feb 2025 06:36:20 -0800 (PST) X-Google-Smtp-Source: AGHT+IFw+izIBre53WvTTJHTp6m7C6QdXU/8idflMKHMYSzPd2m/IGL+jZNFSFLKI+SWsJNHweAuOQ== X-Received: by 2002:a17:90b:4d87:b0:2fa:1e3e:9be7 with SMTP id 98e67ed59e1d1-2fc40d131d9mr14471996a91.5.1739802980395; Mon, 17 Feb 2025 06:36:20 -0800 (PST) Received: from localhost.localdomain ([240f:74:7be:1:a6da:1fd8:6ba3:4cf3]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2fbf98b3305sm10057757a91.6.2025.02.17.06.36.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Feb 2025 06:36:20 -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 v4 8/9] gpio: aggregator: cancel deferred probe for devices created via configfs Date: Mon, 17 Feb 2025 23:35:30 +0900 Message-ID: <20250217143531.541185-9-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250217143531.541185-1-koichiro.den@canonical.com> References: <20250217143531.541185-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" For aggregators initialized via configfs, write 1 to 'live' waits for probe completion and returns an error if the probe fails, unlike the legacy sysfs interface, which is asynchronous. Since users control the liveness of the aggregator device and might be editing configurations while 'live' is 0, deferred probing is both unnatural and unsafe. Cancel deferred probe for purely configfs-based aggregators when probe fails. Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 8f8793f27211..f6beb9f41b9a 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -72,6 +72,10 @@ struct gpio_aggregator_line { enum gpio_lookup_flags flags; }; =20 +struct gpio_aggregator_pdev_meta { + bool init_via_sysfs; +}; + static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */ static DEFINE_IDR(gpio_aggregator_idr); =20 @@ -1112,6 +1116,7 @@ static int aggr_parse(struct gpio_aggregator *aggr) static ssize_t new_device_store(struct device_driver *driver, const char *= buf, size_t count) { + struct gpio_aggregator_pdev_meta meta =3D { .init_via_sysfs =3D true }; char name[CONFIGFS_ITEM_NAME_LEN]; struct gpio_aggregator *aggr; struct platform_device *pdev; @@ -1161,7 +1166,7 @@ static ssize_t new_device_store(struct device_driver = *driver, const char *buf, =20 gpiod_add_lookup_table(aggr->lookups); =20 - pdev =3D platform_device_register_simple(DRV_NAME, aggr->id, NULL, 0); + pdev =3D platform_device_register_data(NULL, DRV_NAME, aggr->id, &meta, s= izeof(meta)); if (IS_ERR(pdev)) { res =3D PTR_ERR(pdev); goto remove_table; @@ -1242,14 +1247,15 @@ static struct attribute *gpio_aggregator_attrs[] = =3D { }; ATTRIBUTE_GROUPS(gpio_aggregator); =20 - /* * GPIO Aggregator platform device */ =20 static int gpio_aggregator_probe(struct platform_device *pdev) { + struct gpio_aggregator_pdev_meta *meta; struct device *dev =3D &pdev->dev; + bool init_via_sysfs =3D false; struct gpio_desc **descs; struct gpiochip_fwd *fwd; unsigned long features; @@ -1263,10 +1269,28 @@ static int gpio_aggregator_probe(struct platform_de= vice *pdev) if (!descs) return -ENOMEM; =20 + meta =3D dev_get_platdata(&pdev->dev); + if (meta && meta->init_via_sysfs) + init_via_sysfs =3D true; + for (i =3D 0; i < n; i++) { descs[i] =3D devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS); - if (IS_ERR(descs[i])) + if (IS_ERR(descs[i])) { + /* + * Deferred probing is not suitable when the aggregator + * is created via configfs. They should just retry later + * whenever they like. For device creation via sysfs, + * error is propagated without overriding for backward + * compatibility. .prevent_deferred_probe is kept unset + * for other cases. + */ + if (!init_via_sysfs && !dev_of_node(dev) && + descs[i] =3D=3D ERR_PTR(-EPROBE_DEFER)) { + pr_warn("Deferred probe canceled for creation via configfs.\n"); + return -ENODEV; + } return PTR_ERR(descs[i]); + } } =20 features =3D (uintptr_t)device_get_match_data(dev); --=20 2.45.2 From nobody Fri Dec 19 13:52:02 2025 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 1198B225779 for ; Mon, 17 Feb 2025 14:36:28 +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=1739802990; cv=none; b=FUWOjrOnxk52r4+nVLyarPdeMV38Hv1nUR5Dqc+lU15TAbn7BlHXzrybO+Cfhs1oAp7Z5+G/q8R+PPiYcXsjdDuK3qRiWiX/HmoPblr5sVvFCBQeXb1ee8iNWMOt3cTnq5bdURohROjedx/20+Humj0a/kIIRIQzFoc6G0iCMqA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739802990; c=relaxed/simple; bh=5z75klJulPBK3euVFo5jCw9QXY35/qZ4NCunDCR/9Jo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UsgHUzFniYcov5qYWgjGdjQHaGMFjRBIAKA26KWU56/Zekk/XeoJCIUxWsRm9aQ1N2C722jM3EuUTYaExDFAVRnkkmOEEZks3ifrWiQl9QJvMoew6wbPgnTCiTF9Hmg4qe1PJLieBiwpu3qzLOX2uk1wy/mLCgtbpHs46P23m+s= 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=OWnYaXgV; 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="OWnYaXgV" Received: from mail-pj1-f72.google.com (mail-pj1-f72.google.com [209.85.216.72]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id EBAF03F868 for ; Mon, 17 Feb 2025 14:36:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1739802986; bh=VbN0B6Oenuw6+py3+N6wdefqtqSm9CuUWAW6b8DJ97M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OWnYaXgVeWzJsUGpq8OiHdHL99+5lGb5APfiR1EcOtj4oe/ZO/5T2nOlT28eBjTsO cYOTsflXHVDWZITJbAg43+PbYRy32EhDV080skuMFVJUvyJ5saa4QLsQjkiwfVSXWi 9W1x2ai1fW0KZE1bmBzW7OZ4CFLQ13vxkoqLVy2HRrhJ3Ze94t2hWMWUr8sQb0gcU1 GAiWRqb3zlyvsNkFiNisA1er8Es7RgcNjdVF4Fls6IAH7hy++fhMtpUko1MLd+c/MK LtYS/qLgeKcTGFlKcJTtK54dmn7lBImUJXz2N0926pmOS7X5zC/43nxbPfFcnJkrcN giUZ3sLadqO+Q== Received: by mail-pj1-f72.google.com with SMTP id 98e67ed59e1d1-2fc1e7efe00so7672093a91.2 for ; Mon, 17 Feb 2025 06:36:26 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739802983; x=1740407783; 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=HT/J9eIryWYmgpsGqBMt5VqQBkYGl+Zgdc+5zY03//FhWAf8pFDARfItM4i7WNn3nm z1Un25jiWGw1WzDdRae6MY3LZ+7QkDaAPiwJ9JTs2/NXQv8OiNDwZpkc+pncx57bL9kU aOx6rcscEKJlCAMZeXA5gYEv45RRCmeRvPoZZIZHrG0BWFvYB5kAFRezJKxGvY2EUfLB tT+4VHCcVfPf1WSmFhC8VvMIEIx6ZXy9S15adLtzA6kpEApyYnmwb94tunnCxRk7txfn 5KNTxbDKSKuzX1x43tzlC7X+tR4cMutQRaNBSzjqnsq0x6/1cYzvI7LeMPlEfNestWjc R/DQ== X-Forwarded-Encrypted: i=1; AJvYcCU0yduaup65321v8ERY5nuLzZ6OIY9jzrovtSui26m6IQBsnqEX7gZ0AgEZM890C9igEkAdKnD06X/gP6w=@vger.kernel.org X-Gm-Message-State: AOJu0YwlvVeSX7hMFZZRKLL0ljdAlfA8C+hvKqy6cwuJ1cE6FiKFd8YK 38o25GVE4bWRDCty4ryZM2hPAVO+QeqyNA9AbpFoa6pFmzCQdBKUDCQGGyXDEvVQPxP1hU4fgD1 yd4HOq9NUZdk5Bg5xHgMujAS5cwLUBZwJ2weZ8iLvRq5F9drw7YtRFYThdWoOBB2EaOi+XNY3YM C0DdHDfT1ASQ== X-Gm-Gg: ASbGncunNKajC7Pr9TWVyHTfXuUOODhyk/uYWPW0ZOwZ6Py2/+jDbKsi5sBo2qwDEG5 GpQo4Ku+tGgxwYKEE1eTEjgXMgnn7950KfSWDfxCEJb2TZGKD5FIOFV2qnRSCzeT6uX9j0oAAcm OC5wa2EOuSVQH11AMjQAXv34r4wyn3d50YvPQUxpUfRxtoC4iFuzD+Nl4prDb9y3qW0C+RkWC1H qmANpLm5Oz8n+K+HT19OIUmj61SpTnbhK7fSQN40Ef4krpCeTY18ZFqMJ0fFNB310lc1J0t/y2B j6iZVuOgYsZf9jnvMtGcDX0= X-Received: by 2002:a17:90b:1651:b0:2ea:a9ac:eee1 with SMTP id 98e67ed59e1d1-2fc40f10402mr15930226a91.10.1739802983294; Mon, 17 Feb 2025 06:36:23 -0800 (PST) X-Google-Smtp-Source: AGHT+IGn8ODnVz5U27ivcZIXnDcIe3tj3Acy3nD1kW2qRgArMBY75CRJbzFbMz5F3/bth1Q+uY2Mow== X-Received: by 2002:a17:90b:1651:b0:2ea:a9ac:eee1 with SMTP id 98e67ed59e1d1-2fc40f10402mr15930181a91.10.1739802982871; Mon, 17 Feb 2025 06:36:22 -0800 (PST) Received: from localhost.localdomain ([240f:74:7be:1:a6da:1fd8:6ba3:4cf3]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2fbf98b3305sm10057757a91.6.2025.02.17.06.36.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Feb 2025 06:36:22 -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 v4 9/9] Documentation: gpio: document configfs interface for gpio-aggregator Date: Mon, 17 Feb 2025 23:35:31 +0900 Message-ID: <20250217143531.541185-10-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250217143531.541185-1-koichiro.den@canonical.com> References: <20250217143531.541185-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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/Documenta= tion/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 =20 =20 +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 de= vice + 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 t= hat 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 >=3D 0) lines. Configure all lines bef= ore +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 <=3D ``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, wr= iting +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./``. Y= ou + 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 ------------------- =20 --=20 2.45.2