From nobody Thu Dec 18 22:16:19 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 48E1C1624F3 for ; Mon, 24 Feb 2025 14:40:05 +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=1740408006; cv=none; b=Dw8KEIH/4DeauBHLLY+YjsPEwsROAxuQk4KY/XefQ3wwDraOMtiGGda29A0cWDLYrOnoAzaCSm1eESHDhPK4+mQZJDeSlC4YItrP7CqagOQ5pyQDHrtthTtPw8KyuGluD9HVQ1FRkRDCvrOnQUWBib1pUZZkV7pKMzT297iP6pQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740408006; c=relaxed/simple; bh=d0seFRCbsm6obDyggndTpMQD/bofnkskpXmGDrRtX50=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ndg78AJqmRPT7cPsPMs9ckiqolYTRGJKXrWFb8se/EBXuGM6qtyXlSk/JbMDb4eLinYEinwTb0s/mGrYa3XmvOnP3uWdn0uuW0ZZSsHZ9l1QMfEJX5dvwOpwN1l07CsLr2NKOO5UeqKwnOF0Io6yELUwNWz+X/+dRcmsH2QxF5Q= 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=H9wS+l2g; 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="H9wS+l2g" Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 978EE3F735 for ; Mon, 24 Feb 2025 14:31:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1740407506; bh=DFCOc2ChWOWoHT2jvhggwm0YHMFaUQk1iMuzmg5CkXY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=H9wS+l2gCjVX2c1wmzWycoO/usRKeST/u4Bny0tia2Bkz8umW3lCyrSp4hmYO4/mV seF48UkbefCNpxPK9fe3ggRurmN5SpZAO+8Q3+yLwiOkMnCqtnWq2xi0WZmYE3y4NR /e0N5sLWelG15uDrv2KzM8WmZtsuaZRBeh4UqdpPWgjc7fpkExCkxcCu06EF57rK0K rPku9DESToJ3aAN/L8bgOu3S7iz3/Ex8uXeVIjm0/bdwIze7CYo4VUh8sU6iRq7c40 wHbeqn0CKtqpiDIC1XbOWQgflmHmbM0GrO/bLdqetTwXuvN+SOom6VZwavtHLI7LCZ hCE9FCcIid/ag== Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-220e1593b85so85692005ad.3 for ; Mon, 24 Feb 2025 06:31:46 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740407504; x=1741012304; 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=Jn0zhC5bKRkjxX+3IY5C8lOhVv0LOki3xyWbNxoxk35P1mfosz+j78YcngNRGuQMHp 7+9PveFV3BpYkdJJXsvblNBD8fo0RuEfVUih+pdox8g+AFQYyzXR7hhnX4OVT1/Ft5z3 uasgYBV3INvt/be2mjB8KI8ZHOoFcnt8rx/GzixEfbly9idjnAtQPdRuRr1+A7WluRc2 LyzcV0rn7976Af+kbJNyDIBhhlPrOnOloBnH4uJz4Q0/U9xzGpdlUr2X/42HI/wM4w5v r+Pk0T5z4LyYkN8/M1sH2qeI80YBnihhzy7thfkh6C4T2mgsHPTzKV/Mk1pgdV2RMeCP NK0Q== X-Forwarded-Encrypted: i=1; AJvYcCWUZhJCRGK3IMwv1OR+Psp3IiMSzEzEjEmztmi4BnEvxKHNqBnXL6HZPiSkrgB4VEbHxaJ74YEAcNyufIg=@vger.kernel.org X-Gm-Message-State: AOJu0Yw/MfjFQsD/T/EY9xGKgMSSNAsH+O/k8TXBMT6GMi3LhWPEdJva VcOB2y28Ds14pdAn9riyevlNsFncMgusHVsdqFO9OzpvwU+KVepkrfezjVsKDqZseIn1cEJLdlC 9G8k/LbeTswfeY/lFj80GY1au1IWjOIgc30OI4nUFu9oOb2SKoglg8fVPWihDd+EtOw5alVD1Y4 2LzA== X-Gm-Gg: ASbGncvC4bveYVayU2u+NThKBEEd5z+7SUwTpW/Vg7BN9uN2NI3PgsA9p2CthuipvYb Cnm9fqdXAjOXKZUcpUcrfFJYm5XW3SKThk1zDhIjR6OlgaYkRnETGnzAXWK3eSnDvGqgbp8K5ZK /fBy79+5gzps/XGSMciNbWlJCgd+3caJ8Hh5X5r9b3BBQ8L2poVVxx1USW+nLBwMCgnkwXEp531 52EwOvVGHOjuJ+I6hYkzq4TyiSDUKeRe8ZPD7RR4qcOM7xB5p6ALWxgfZn/87lxVLnu/3groAH7 672vFZRborwxTUvN X-Received: by 2002:a17:902:fc48:b0:21f:61a5:67a5 with SMTP id d9443c01a7336-2219ffdde5fmr233722265ad.42.1740407504525; Mon, 24 Feb 2025 06:31:44 -0800 (PST) X-Google-Smtp-Source: AGHT+IEVvBJFcEolR1dcNIqGBCvi0trfSSSLEJ+FOzuCFIVoYboEgvcnU6lXykfPq61XLxr8UBX64A== X-Received: by 2002:a17:902:fc48:b0:21f:61a5:67a5 with SMTP id d9443c01a7336-2219ffdde5fmr233721845ad.42.1740407504118; Mon, 24 Feb 2025 06:31:44 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:de7b:58db:ab85:24ee]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-220d545d067sm177613895ad.109.2025.02.24.06.31.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2025 06:31:43 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v5 1/9] gpio: aggregator: protect driver attr handlers against module unload Date: Mon, 24 Feb 2025 23:31:26 +0900 Message-ID: <20250224143134.3024598-2-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250224143134.3024598-1-koichiro.den@canonical.com> References: <20250224143134.3024598-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 Thu Dec 18 22:16:19 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 0E9D62A8D0 for ; Mon, 24 Feb 2025 14:40:04 +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=1740408007; cv=none; b=qDY/7bbkKhoTyMrti0GNizAyxWg/Si6+eDNk4CDjsWzT+OY1wXP5yhiAKSYPvd3JxzOr+r2CEiib5AEXmrTtvm79ceGFN/8F6q2Ll7+dhzJwiV6R5UFcEvkii8iJQzh9WnnFFdYcxPpZKFBQoxNTpZTu+d3ELjvOCWKM5PLX1qk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740408007; c=relaxed/simple; bh=t3zTiX5sHGMNY70DRwaiaym4vc9V90iUU2jCySp7s2A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qa/aHd6S1R6m7kY9s7LHE0iUONfp6vxacI1tKVuChXEaN3oS/YkmNCpR5FGx8SQMMvulgO4Tw2q9PIpHKzpmw1gX10QHty0LOUFSQ2E+SL758ddDgaAkYq0vpQJUaR0Z6O9yMkaJ2QBAL2QNj6kEfvOkDQfHjatOW675IdoFa3Q= 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=JtrYADiA; 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="JtrYADiA" Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 5E1253F84C for ; Mon, 24 Feb 2025 14:31:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1740407509; bh=/Zis01mTN9hfdwdw4CsGVb5gEILpfxFjWK2yfeVkHJw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JtrYADiALa/QXCBXUSE+JzItMmz11+GSniUT8ERpk/XCgChl0ep5QqL44qmIP/uIG eonRA0kbeoWKFgQcRLDtM6kOYSzEBYrdHFUf2V/5xlJj4kwDASfiKN6mjCl7gk7EUZ WVZrS09FKAeilj6r8N+pWs+984lzkzTq8/+eCf4qXufZoUS6lpqRq06dNPqEpLWh8m GAiq55k4ntaU4JfLojmdfg+Opv1VJRlJXYl/8rnOsS45hj05M049p0WNd0M0gmk8AV li04V1Arvc0T9SKqHYyScQ9cxiiHvaAWWQF/RXVed/BOEuZyujSqBRlDqPcgDYfLYD xHPvDeiLVhiwg== Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-22101351b1dso88447735ad.3 for ; Mon, 24 Feb 2025 06:31:49 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740407507; x=1741012307; 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=xHGnUW8fonbF2GDpSP3P9pTk3jmpJDfiMh9ZMI9njpE7tAlQc/xTXROheZBe3SPd5n mK1Nyzf2QOifF6vCTEzU4sqqkiK5dAZ+natp2beW4KNtgiS8CkcB2aVyUa+282da5N0z w2rHPZiEWvUl/44TT32kn6PMeofxa42e5I8GABRH3tBUpPrOTUIYypfVyReX9NZM3p0t 45AV+s7eKC6rgWk1kEgtEY8zc5PBIanJeBUH1sQAx/BdBWzRCMK5OwI9f1r+1B+UH3T/ iXk0M2S6eqLKEqsxu7FSNY24bsKGwc8R8HgJlFu/8xxe7fNQGVHPZj40iHMJaBzBEFS1 MNVQ== X-Forwarded-Encrypted: i=1; AJvYcCVAX73DD4YqZbbrCa2rCKIfx9t7iqSPzdrRh8YavHQ+oeJGrPGvWFYLgMbmLW1hPImN4TwlNUhkh4YWQ0s=@vger.kernel.org X-Gm-Message-State: AOJu0YwizlTKVttOCo368xvEYkkBfyoA2OvdZkK4c5atXdP6CsynuOsi +uAJNTpX80B7EJixhQoQJJS1za//SBA8xME6+ZIin68yRyZ/X00+pOcSzlfrfhCp8jGfc09zqnz Pxtr9HBLEKU5INODDa9sQusyQ4jXrk/LeNj8JhBA8tNuTVl9FmTFVwRasI/CrChHQZd7P/uwy7a ghPg== X-Gm-Gg: ASbGnctD97elJQCgKYltZDwu0hTtb3wpW1db0hTUROtsWPnLwIRBshpkrJ8pinIp7ab iP0d21veZOyysEvY+Sg5casVZLAmubYjQsAe88k26KOcK363CehBHFRcZylsQsRxZPMaHxLR67C oI/H2Ylzn8U2wfK4yagRpgI/mCo8FsRsdIkodbdwExtr45KYBC6ZXyHJRvvuG/JZiZnkBkKaP1E mgNtELr/L93+JSoW6/p+pDYiFpEaQWJC/zqgN+vXqohJ/hNiibuQMYIDKIIZCDE/+BJDb2gfcLv UomGJTHddBiirx1m X-Received: by 2002:a17:902:e88d:b0:220:f91a:4650 with SMTP id d9443c01a7336-2219ff55febmr194362675ad.19.1740407507536; Mon, 24 Feb 2025 06:31:47 -0800 (PST) X-Google-Smtp-Source: AGHT+IGphQ/PZnVMBQrukUNH4LwkASfNLpLh+p59bv080yBc+b6gas1SufycE7np8ybd/zi8TU36Yg== X-Received: by 2002:a17:902:e88d:b0:220:f91a:4650 with SMTP id d9443c01a7336-2219ff55febmr194362345ad.19.1740407507138; Mon, 24 Feb 2025 06:31:47 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:de7b:58db:ab85:24ee]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-220d545d067sm177613895ad.109.2025.02.24.06.31.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2025 06:31:46 -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 v5 2/9] gpio: aggregator: reorder functions to prepare for configfs introduction Date: Mon, 24 Feb 2025 23:31:27 +0900 Message-ID: <20250224143134.3024598-3-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250224143134.3024598-1-koichiro.den@canonical.com> References: <20250224143134.3024598-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 Thu Dec 18 22:16:19 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 AFC4C18A95E for ; Mon, 24 Feb 2025 14:31:55 +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=1740407518; cv=none; b=REuagIGYaYGN+6gGvnx11CAgw4tbLH35cBwX4wxZykS6bKnoNLyU+rG/wsm/e5jl/VeU5jwORDvrkOVw22rY/X8E/YNUHP73Vjp6LAmg32+H1b9NZkdN/stVhy7b8xC1rjIZEWe3evbJYMfaLXvB3ULP2+wnEZqrT4osFpQdFo0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740407518; c=relaxed/simple; bh=aLA3ZVDhrDy3RNwYW++kaJn2SQ84AkvFmu6stXF9mto=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aFCXz8D1b11yoT85vnYNgMBY0MhenENHG1OkYFXz4a4nZaRWljKhfGiOQ+UPBVIpcJJV2HjG8LYAEvCesBXrb4lnDbmf1myNzt4gTcJUoAf6D0r+1geVXH/IQXvAEHmB224XquJBzBWFSCgEyJ4vsflZGrZaV4tf26iKvKnTbpk= 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=TFPa3352; 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="TFPa3352" Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 02BC341972 for ; Mon, 24 Feb 2025 14:31:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1740407512; bh=gXHg3uCoBKmQSJJ70+DeTAJMIxaEY0B5wJevniOwqIM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TFPa3352Beils+vU8/s62hp7Cs/ocmbndUBewyoi7asMI+9EhFSMCOumcpEedLLDF X49fohYaCd0w5VreFTwXgGiljS7Q4Zuexq82YZx/KyeNnhdHkq682liyryDlZOxRsc UPHjQJyNqpBUjbCvqn56Btwovxo5cLbiiy/bVTd27bd04bc8SNzrhtaUfxUbSSaHtE 2iSPTFHf5ytlDtpj/S9kLjKQvYQU1mhZ/7LJWM9cpkz9bW0NeRih7UxPDwuyzW9oqZ bDtRjGgCHae/r8i+wK4mwpMRHAgJWcMjdR/LafEcWakiEc1+cxjMmWgjQqjA1K/i1o MvkSoMzKFe/PQ== Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-220fff23644so15082125ad.0 for ; Mon, 24 Feb 2025 06:31:51 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740407510; x=1741012310; 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=wIf72TWjbV3vNvkeKYdoGkcpdiD+cKYz9nPGGWxBbFQdq+1LW/wm8fIJ4/ZACE2jfA 25k46u8dz/UHeM0GBsPUHFYC60YkI/Crg99xBGwQbuJXGUthC3tnYLYAzXnPNDnMIPIh CZXlI0kFEwQc86pB3iQaf7232LMzEv8/3Uys3dgty89XI8LqZ4yaolxN3FxpHenpeTDu yxFKEPirIe15vumpJDCQTjaEc6Xnj0nbq68SLORM9LrWJwa6jxQ04YBLpbJDHLOkTSw6 H391E2aub3WCOWR2PxqHgJQkVYoYnCxo5wap2Q+d5vfg44I/5kCWilsL0ZWbVBzpvQQM FE7g== X-Forwarded-Encrypted: i=1; AJvYcCW8AmriDrR9tS7MRHyiDvDebko4SnGIRLbfd9xkK7IJOx7dr1nnFSyTeqv2Gj0sM54ne8mFdI4ngSh/59Q=@vger.kernel.org X-Gm-Message-State: AOJu0YxyTYUaAsGvyTYhFDYGLpQNbbxEqjc8udMArtIilIuWMZcQOSVj MlfgksT+xcmcZgoywRjdKsKWkYIGTZWiqs3y8UFoens1zKVahspNRckeawsR+nPHWmACO9A9jZX ogO7XVTS96FL+wE+/0dc5OKOd8WGg53LYFLJXAQGiKrwmUKEseLe3jdIGIODnWdo8aCoAH9O4bQ jz7w== X-Gm-Gg: ASbGncu3iTmO+Ky1jl01QGV0RQ/USWq53x42/kQI6Sj1md5QDLodPoDhPAjplxCwoCc ROG3VYtYAy6ILkywE+kcVxCyKGFgPnzj8OO0q2MFFHESKg2Msiqdsoi8Lda96IVF8ZEajikzH2I wiWGmKK8w00RS3Y5n+VkjqIqrvu7HTUICmdtRmTnUTS179G1NfCwf+XN/z5/Ieiyd4FJJtdejx7 tl45/mo143dvwKfLPQxkd6Q5dIJ+Fmr9DNI/8sEp6slceNplm+9QUuEW0HIC9ipQiAt/RpSPdPd 3pWMOy31oU/8KzkL X-Received: by 2002:a17:902:f548:b0:20c:6399:d637 with SMTP id d9443c01a7336-2219ffb5ccdmr233011365ad.40.1740407510334; Mon, 24 Feb 2025 06:31:50 -0800 (PST) X-Google-Smtp-Source: AGHT+IF1Jc0Yqwa4HwDO+K5r64/4KHjkg5DCcC3jCiIDfEPZrnBsn9cR2KGuGUfwAomXtnQycccupA== X-Received: by 2002:a17:902:f548:b0:20c:6399:d637 with SMTP id d9443c01a7336-2219ffb5ccdmr233011105ad.40.1740407510064; Mon, 24 Feb 2025 06:31:50 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:de7b:58db:ab85:24ee]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-220d545d067sm177613895ad.109.2025.02.24.06.31.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2025 06:31:49 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v5 3/9] gpio: aggregator: add aggr_alloc()/aggr_free() Date: Mon, 24 Feb 2025 23:31:28 +0900 Message-ID: <20250224143134.3024598-4-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250224143134.3024598-1-koichiro.den@canonical.com> References: <20250224143134.3024598-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 Thu Dec 18 22:16:19 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 08642253341 for ; Mon, 24 Feb 2025 14:31:58 +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=1740407521; cv=none; b=Z4W+VQM+68Gvi0PIhFSAFaGUT+124N383jYfC9O1NTchvJjQ6U20/Oj2fLkBpKJarHR0kLmrzCNZng+dqW7uwrWZzKrL3gVfdQEX02VeLJ5dd23g+zoBXxPje6vewtOYAY1HQ7vXLI9ib0JyA/FY38xndXXlE2Od1dGgy9VZ7YQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740407521; c=relaxed/simple; bh=5wB8XUqEcTyTWfIQU1/p4iXtm7LsMkGMca+2elJFbY4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uxrkPudzDIjprsS3T8iCAOF9BAgn+81rYC3qDmHEed7q/4djHTKhQc9SApx5G1CdyoYu+P2k7NDogMNs9KEIC5ufPX49/vv8mD4nYB2xc7bE252rtNmcuOL/baASWMwqqinZx8CH1A786Bo7I2qIFNJ6cnnEFj9ho9EvUMKgeH0= 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=Js212Qg6; 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="Js212Qg6" Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 3BA653F869 for ; Mon, 24 Feb 2025 14:31:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1740407516; bh=tF5BS5LoKu6A/yNHnMH7StJiB3yxQnpEHCtgJkgpdKc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Js212Qg6hO29kNVimrVnPz3aFRuUUzcxjh4fvP+4fJEgdycapCMyjh1mqrErsMfto tYrdVxRaYvQKs5PLYGbtoLvD/PjJ/ty7CyWOlZbylxNurDJ0lZ0Np0+G5h10fY8GRI 0Y7x+jzS1lK6JpEoCqBojYzAozs0fQZbWxczgM26nY89meg3FSb8eYF0GvfP6vYmAt Ohuxd/ukeKHmxmKmC2oEtom0yPGELi7hzCjLnQb+WtKtUrOPe1/C/R1dXltVF4ZN0x 3vldviwGbMYIlAqwIdLJlA1dqIeQY6FlhUQAzOOfGzlRoVhSc7kbFfiQ2U2Gy/smTg ShCTxpk/6KcYA== Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-220e04e67e2so125832675ad.2 for ; Mon, 24 Feb 2025 06:31:56 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740407513; x=1741012313; 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=tF5BS5LoKu6A/yNHnMH7StJiB3yxQnpEHCtgJkgpdKc=; b=oHRl0DVFRBAlORvMmVA1KR66n9MAM/f0kmNGy+h8pdQ4AKbaVvtIDsOK53DYXN7aQl oUzSGMNi6sSAUIed0dANsDDMCueqr4m5AWx73rUox3E/vyWe1xI/x9ySOgeyfD9oipk7 8HRVp1xuvnpBdHJfWw5PRO36b8LT7eGF5sByBAJhsFb3WcKbjbcY3pCibiVxRX8Ki0rJ bYnCu8cHlBgIXHTi6yx+LAutJnsUup5jY28rA0LiJUZc6g5Tzueb/vvUbbATh5YKgxhi /TC2ykuczeIujDIAuT/Qghv+5HPNo+qydzz8dx4SmHLDVA2YdLiRsxzHRvJmeVfyxYCz wjFw== X-Forwarded-Encrypted: i=1; AJvYcCUwJhxHqfAxSOJxiDjmjKoHz7n9S77zkOVBHF8LtGwjUFpmu0L5rk9IcwuSFF13UxmTQFNFH6W0XkQQy8M=@vger.kernel.org X-Gm-Message-State: AOJu0YyS1RMKeOreRJn4IMZyRFs30GU8DRF/0TCYCGZKqPGN6woMifG6 h3c8MjvkF8cNIfGXnnSsU2hlB20fLlwLwmRDVNopVpyqak0ilrYR/dPpvJu4GSEmUblEI+jEOwL OycPNuVjdKBTdsbYItNomh87daJbP2jQD8S6iBK5VEe1DMFvWa0v5O2AbAuq9O0fNH8Bxac6IwX jZdg== X-Gm-Gg: ASbGncuT4ToOe3oXqDOYpcGZW4IgY7S6SGKWl6vKo+WTiYz54d73137sUTmTeEMzcJ2 37xFtafkzIxdMCIWcDAlOK1G+5sHn/YVCRqnAGuhPGAJtfRjGHBvGQTGy2qs5x53seYurqXYpkp pJ2fKFgbvRaiFoNb6GkACIugth3UZQ3Mixv0VFXiUUqrIUCrmDU59veVFG/iNj3cd55wzk62S1w JhQIkxAfjIxSsxf5aN4p1kIk+giZJI5rM6D/1aLVNZGMfF1T4LdmPLQkZkDXH8OdNzxVPk7KdpX YNRjGkyiq6uy0RpX X-Received: by 2002:a17:903:41d0:b0:221:337:4862 with SMTP id d9443c01a7336-2219ff50e97mr210739555ad.15.1740407513259; Mon, 24 Feb 2025 06:31:53 -0800 (PST) X-Google-Smtp-Source: AGHT+IF8JlcI9L0RNXyy4s/cx3oV9itiUXXsPURPUbw+FLUKy+E/TkNe15mP2uW0vnBkFkht+HcodA== X-Received: by 2002:a17:903:41d0:b0:221:337:4862 with SMTP id d9443c01a7336-2219ff50e97mr210739065ad.15.1740407512827; Mon, 24 Feb 2025 06:31:52 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:de7b:58db:ab85:24ee]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-220d545d067sm177613895ad.109.2025.02.24.06.31.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2025 06:31:52 -0800 (PST) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v5 4/9] gpio: aggregator: introduce basic configfs interface Date: Mon, 24 Feb 2025 23:31:29 +0900 Message-ID: <20250224143134.3024598-5-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250224143134.3024598-1-koichiro.den@canonical.com> References: <20250224143134.3024598-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 06cc9b826483..4c157266b428 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1868,6 +1868,8 @@ menu "Virtual GPIO drivers" =20 config GPIO_AGGREGATOR tristate "GPIO Aggregator" + select CONFIGFS_FS + select DEV_SYNC_PROBE help Say yes here to enable the GPIO Aggregator, which provides a way to aggregate existing GPIO lines into a new virtual GPIO chip. diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index a93b7d3de929..0edb177bd816 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 "dev-sync-probe.h" + #define AGGREGATOR_MAX_GPIOS 512 =20 /* @@ -34,12 +39,36 @@ */ =20 struct gpio_aggregator { + struct dev_sync_probe_data probe_data; + struct config_group group; struct gpiod_lookup_table *lookups; - struct platform_device *pdev; + struct mutex lock; int id; + + /* List of gpio_aggregator_line. Always added in order */ + struct list_head list_head; + + /* used by legacy sysfs interface only */ + bool init_via_sysfs; char args[]; }; =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->probe_data.pdev && platform_get_drvdata(aggr->probe_data.pde= v); +} + +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 dev_sync_probe_register(&aggr->probe_data, &pdevinfo); + if (ret) + goto err_remove_lookup_table; + + return 0; + +err_remove_lookup_table: + kfree(aggr->lookups->dev_id); + gpiod_remove_lookup_table(aggr->lookups); +err_remove_lookups: + kfree(aggr->lookups); + + return ret; +} + +static void aggr_deactivate(struct gpio_aggregator *aggr) +{ + dev_sync_probe_unregister(&aggr->probe_data); + gpiod_remove_lookup_table(aggr->lookups); + kfree(aggr->lookups->dev_id); + kfree(aggr->lookups); +} + +static void 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->probe_data.pdev; + if (pdev) + return sysfs_emit(page, "%s\n", dev_name(&pdev->dev)); + + return sysfs_emit(page, "%s.%d\n", DRV_NAME, aggr->id); +} +CONFIGFS_ATTR_RO(gpio_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); + dev_sync_probe_init(&aggr->probe_data); + + 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->probe_data.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 Thu Dec 18 22:16:19 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 3BD7225484B for ; Mon, 24 Feb 2025 14:32:02 +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=1740407524; cv=none; b=UdckR67m16DvqHTYCKpndvvakWMlKzNNFUsZ3VJ2a+koFgkPxTgKAOqj+6U0ymOpBKk94Muqo7Bq3XpuvOiKzXfZd3fP3vqO6MQNofwtGOIy6oTnIbXn+8lW2z/PKygOC32TJAmpKEOnhRKTxtaB0ONyYFo375ymWD3yUoqAVkU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740407524; c=relaxed/simple; bh=6Gyl110JbYdihAYM2SUbMgymN9mBHUq84cqx4t8+pc8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=n0PWC4sHliUom5whPZpOsu27wQJu6T+dwy+g4xsrcCXGwJ+/nPhrC3fpy4LihQDW7XFnp34q3mxXymBDl3FYNZaC62Q6GeaBr0k4tifO/ScnWMAiI9FGQrAehjPDCmUHltPl+0CD0dyjztTOVXDpHCkADSY2aToJeYluJK/fIo4= 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=a2N0wkjA; 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="a2N0wkjA" 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-0.canonical.com (Postfix) with ESMTPS id CAD523F6B8 for ; Mon, 24 Feb 2025 14:31:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1740407518; bh=LdY3nx85rePW3A+dk/au845fHolTzm+G2Y4AdyKBUzA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=a2N0wkjA5CQMxxaL3Pk2HJzIhIKmlkkps7i5sJXDQQgqpR8ylQAKUAQg89Xo8GriN 0nHbwvAsEzh1WCkRmXxR3oaYu5l8Nd1/xL7kf2uqXtUJH3PQ1ysfVCaqNAs4cCEfyA M2SwmGs/M4YNNUkHy3K9ybwxFI9KE7/Uxjax2mlz1nNEMLrZV3xUj6YvuCp0Pr/V3M tmUTNT/vyBVEZQXnJCoh4SwHd1kYJYmxJLKyOHq6EUhXBNUtPd7GyXM7y6pku0ps4I Vwfwv4CVUVm8NzR6I72q0Hhcfy3sco5ruVJgrgAsStNGXmdcX4xU34Ih5xz59iNEjw hyyzSDmMdNg6w== Received: by mail-pl1-f200.google.com with SMTP id d9443c01a7336-220c86e46ebso72239735ad.0 for ; Mon, 24 Feb 2025 06:31:58 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740407516; x=1741012316; 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=LdY3nx85rePW3A+dk/au845fHolTzm+G2Y4AdyKBUzA=; b=CUGbZn3JXMECBw+31qh2xfQU/ciG5cWLwJT5R9lefwZ/B1RrE9C0JsqiSJsCSn4j/X MjmcKnt9lIUXLTDbtw6KL38ekl7m1Bf/+gCFw9uqlah2xp/TVXzBpjAchJ2k3FIYQE66 Z/GjFhoJeHb03ckAKG+Z9y2Pbz319w5uH6tdO9RnnWbTQoMh7HyZsfu0Xd8scDdoilf+ 9IEtqbEXp54mymY3tux/AujTDCJMvjw4vPS91ASqvyZBMKgl6Uz1TkEa8GhJwIfVxf+R Fa0X6T4yS9nS974SUv9CJ3jelw6ECfFT4X2KA+px1crsckidwnXzO2DdueeVGUdQxNDM 61ig== X-Forwarded-Encrypted: i=1; AJvYcCXQi9xKQJrCmC0E9iFXzteHWwlMrny0uYr+tYjfhhmLRce0eKhKnmoX8ywGNO6R+7hYElbrmDXT+4Yee+E=@vger.kernel.org X-Gm-Message-State: AOJu0Yw8I0L+SZrYLmY3+YQX+MB8HZb+vUzA0WQh+lrqLzSFqM9NV08D +Kl5J8TgCMp5aToM7aBDcGuWrIzNjO+AEutKAsmOyiQGocy5sZCHLGi5x4UgtC6oftTvZGfAm9p rjDXd5F+Eh15h561z82eLopOvuvdjsWV7HW4LnawWiRRik8R6yDnINeozK4OBT2lOfnFPicyMnQ mcxb/GFdF0Lw== X-Gm-Gg: ASbGncvLf0LIo0ppAWAQUF+dzoh+Vbm0nA6tk65OnGt00rkQiIrHR1+pqE8ynK3Cnzm uNaxUgnf6DTVPOfooZSKmzX/lX2Lz3qO+x8TESEZx3FA/fnGgvLt1sS5DfCazMCH5OKXUfrR3J0 /mxS3gghX29+M+AHq4G1/KlhRON5xN8aIVUiy+/nuGaISNZ0bwR9ep+e5ma6/JH96RMNUgbuMz9 gAPqYdp3K7JWSmOlVMqs0wpkuNS0Q9eAgUukRSqYMDg/vUjT9k41SlE54iMSABJX5SKqGYTd8jE dxfxqOod9Ckii8ac X-Received: by 2002:a17:902:cf08:b0:216:2259:a4bd with SMTP id d9443c01a7336-221a11d9943mr202075985ad.52.1740407515976; Mon, 24 Feb 2025 06:31:55 -0800 (PST) X-Google-Smtp-Source: AGHT+IGDrnpjPTVLJ/YSrOknLqoJmom5nEs79o3mBqMphBn5r+iJdJuZqgc4D6vTNMJ+DUW+6HFKrQ== X-Received: by 2002:a17:902:cf08:b0:216:2259:a4bd with SMTP id d9443c01a7336-221a11d9943mr202075685ad.52.1740407515545; Mon, 24 Feb 2025 06:31:55 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:de7b:58db:ab85:24ee]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-220d545d067sm177613895ad.109.2025.02.24.06.31.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2025 06:31:55 -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 v5 5/9] gpio: aggregator: add 'name' attribute for custom GPIO line names Date: Mon, 24 Feb 2025 23:31:30 +0900 Message-ID: <20250224143134.3024598-6-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250224143134.3024598-1-koichiro.den@canonical.com> References: <20250224143134.3024598-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 0edb177bd816..e6d455089a27 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 Thu Dec 18 22:16:19 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 0154F254867 for ; Mon, 24 Feb 2025 14:32:03 +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=1740407525; cv=none; b=Bu0IOEQ1QKProRGUNPGoPt7BtFjs1eFuia8/jlHiclrHkyqn8J/9t6GAqmaocKfPW6ik3Pf3VjZHCd+8MsAKERPsCT3ubat0N+yDlIAppmWbAuwY9LZzcJQ1+i4lCsK8t5mOedPFFNHOMWi9EDEmt+9R9oo0ggJXg2HB0V9Nxs4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740407525; c=relaxed/simple; bh=mIMrKN5xcM7tpm8rlo5k3zlkRBdN923WRx56grA2Qdw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LmAOv5xoEeIp3KGeYfy4gLDqyolkA8vx2qHxCQV3nNoQ+dk5Taovx/0cau1Ss52yy9UgeOz0F0fPu8tLMT/Cdy6iDBR+EkX1hPNUtcE2IV0ce+fOFYAqeZh8h3w8yuY4gHofs0d2v1Ma+VKzRpu2nz4SXbc99v23+b8Z7AP4Zgo= 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=Hq76Hsb4; 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="Hq76Hsb4" 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 9417041231 for ; Mon, 24 Feb 2025 14:32:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1740407521; bh=DjlFi9V4c7FKst+EVjkMgygpaoK69o8x/prjnL49xtM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Hq76Hsb4XzHKxsg5CFq7XxqWf2fz9LeR35/YER6bBqG/+OeGEeqrscODnz7HaJi4n yYGx/6DCKDCdLCVHrwYSU4fds3UfH8jtoGAqKZccJmImfPNelib9KsjNFQ3R6wvcE2 NhEFDHd4i3DwBAfhUGlJ/VtSJ90ygk/+R09PCBMCoGHi9ER7Qrfj8Z3WrNnVt0J5JL 5Ij5V/YlfMffKagmzs+hMDNHOscW3shNWWBOHmF2uYlo9kvPi+1ChQYoWtO9mZuX/m IiufKhclew+6s8J3FcDm9e8t0AFhdrTM5pGRPHS8MlU7xqtOmWqEdrVeA6fiZL3EFa ivt1iU7LXkoOw== Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-21f6cb3097bso118068995ad.3 for ; Mon, 24 Feb 2025 06:32:01 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740407518; x=1741012318; 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=DjlFi9V4c7FKst+EVjkMgygpaoK69o8x/prjnL49xtM=; b=l/k/Hv6sKddYlMUallpKaGrC6ZBJJ8l3SnOtaw3GCuNUVac+77Vz2CBwAXekI2WS5f Z+MaO+f1GxQ94MOswb6V8DubbB7ozuOnKvlTsDCNsK5tV/G3WK2grWrIGoQBPXisfx2j eCeb1Qg+iWQJ5cOayAgGAMfVkbpT8riwqhhuL8Jqt8XX1bQyyMBw4BmetoY1/3nEHNQV 7wgWleKhDl+pDCjwxXCS698joDitzs7o2Tp+hQYEvWcN5WtIhAxlitUcLp9iWygokvpj VSRXO+Et5V1swfZ6D9towR8/X+BVbR0pCtLNfvJQmfbcq5dY9hYGVzqS4Pp6ruifuKKx tSTw== X-Forwarded-Encrypted: i=1; AJvYcCW46975cLeTBwL0MW+na4LUDw0YS0xoPiJTkSUleCDZ5/GgTpKQqA+IUrYwFAKmD12xhN28jJ96xB0azGc=@vger.kernel.org X-Gm-Message-State: AOJu0Yzu6jQGPhIT0067SyZAICkG1OH8/VN8Fb5oga7RxtajCMNqX3u8 PaIgS4coXu1b3/3saND9ASzRE6NjjMU78roGg7JjPSpq0Uuy5VlyA6lwiZGYbDe9TRK57OZ0buH uOKXqXoyROKHOHhgePcArvx8UKaLyO8jP+0Tz7NBOckA5Mo9BJY3iGNzCRuQD8QaLTXL+1w61ES I4WA== X-Gm-Gg: ASbGncufTdMICRvFBxNoBzOcgrqj4u+w66vPPr2NxEaOZmcdTu3m54kfl1l+AT3UPPI UJ/Sq4QKm0EgaMkZIUgWCuKRgbPPygjFosOCqSbdKfmiXr+uolXCqCvi9iETmr0q6bpTzMBz0mp MLHUastn+++2Il/U40jscllUJzNZokPyo5ZsP7Shulty1/OYEXIFMa4RdfrTMPUCAU5hWhXEa7i Vn+/2ktsKZE784tBPBB/25+fTCrjwe+C5W0TLEO/h8zJkhvDC4wVxcWDsnPAtVtxXKNP5dn6bx1 QSqryHCdU5y1kwRe X-Received: by 2002:a17:902:b205:b0:220:ff3f:6cbc with SMTP id d9443c01a7336-221a1148e8emr166230325ad.34.1740407518593; Mon, 24 Feb 2025 06:31:58 -0800 (PST) X-Google-Smtp-Source: AGHT+IEz9BZWNkOBscqruU/pzCAxXMyOaiitRO4f6iCRddeVjQzMWCXFfzbSgjTM0tjnPfmZXCi17A== X-Received: by 2002:a17:902:b205:b0:220:ff3f:6cbc with SMTP id d9443c01a7336-221a1148e8emr166230025ad.34.1740407518240; Mon, 24 Feb 2025 06:31:58 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:de7b:58db:ab85:24ee]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-220d545d067sm177613895ad.109.2025.02.24.06.31.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2025 06:31:58 -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 v5 6/9] gpio: aggregator: rename 'name' to 'key' in aggr_parse() Date: Mon, 24 Feb 2025 23:31:31 +0900 Message-ID: <20250224143134.3024598-7-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250224143134.3024598-1-koichiro.den@canonical.com> References: <20250224143134.3024598-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 e6d455089a27..0c30153ce9ab 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 Thu Dec 18 22:16:19 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 F3D6F2561A3 for ; Mon, 24 Feb 2025 14:32:05 +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=1740407528; cv=none; b=K8X8zmXJU0MN9nCW59BRkcPVfSjfvPNokZwsmmLjn6mSlpl26S2dfZZW9v1LMrnWa0uaRRUZMzbOEM0PidKg1qgYwpsn97uZIKTI0FnaDyNSVsmqzpt3Ro9ghQ8RlHtZEY5Rt2U8j7GriVfmnop31DzsMlRCMG3Caql01+6fVEo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740407528; c=relaxed/simple; bh=4s+EGUr1VD7j68xpApegchInpDypgfcVa8lQczlc0W8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mKq/yE6aH/Vr6zZbNKJCPC4fPh09tIsfNX1z7UXI4MfHDGCTsU7b9GA+G5ryPnvNapYI0BjJJX//T8t9lihmAg3mKRdvhkbDulnIzfQ724Kh4OEQaNVIs/GdKu1OXDgDbuePS7ug5t0fv7NrupdfFH1/Vx1B4WQOL+SxznH4edk= 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=LDLAWPrI; 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="LDLAWPrI" 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 6FEF841962 for ; Mon, 24 Feb 2025 14:32:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1740407523; bh=dCqB03ZRHWaC4arbzPu/PsCG9rGmiexjce2IhlWSXfM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LDLAWPrIc4boPraQEI+ZG0vmoC1twVE3cIs+06B5Agi1GFqfv4zVDs0/py8lg0lGA nZkbDyOUN/95uJCh+ZaZ5gRSLq0vVfdBor6FdGQV2SX+CCfblRyFc02QbS3SC9pMSE vszrW6lttjcuYokVApN3oSXN0Orj6PwKY+NqpCkwCJClIppj8AKJwZGJWLkIbcOekI 4SvJMsJXemf364jpE16eVkzkEScAvT/qjeS58I9Ip+XbvlFfWIaECAvI7ADWdf8+nU bbK0k/K443C3UYQtF8dkybV4IBhpv5MTqYNuOgn5idYGbPD5LnnYNwtamCw6ZCjS5e GEQ4mbrURLlCQ== Received: by mail-pl1-f200.google.com with SMTP id d9443c01a7336-220caea15ccso143079485ad.2 for ; Mon, 24 Feb 2025 06:32:03 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740407521; x=1741012321; 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=dCqB03ZRHWaC4arbzPu/PsCG9rGmiexjce2IhlWSXfM=; b=Ri6um3BQaC8isZyj31ZqmMcCRQCbLzkCa7tAfriDiSGP2yUi4ChDJwGWGhhAkpGHNk JNeZPU8PT/vZ0CUe/SFPPmh/vg+K/iSylTHV6DG1kf72Fy9+8AcpyOW1j+XiIxqfB++G KISccX1ypqNxZXabi6JFVZ/d3CVWw87CPNWu/r8/z/fShIx2RK3elzUVE7k1CI3udlCn /cyO7K/Yc6dTHxj31eAG1uUPFI+RUSLpj5/S9emdH+OYk4y1Yn3+2D+KstqJCL4iIhcu nrp5lHiHP124V4n86JxbUeEBQ/RIIEvLXnNB+LtRelcHLV6hkzUvQbuthM7zNGwd3VL0 cVTg== X-Forwarded-Encrypted: i=1; AJvYcCX3505H/PN8wsMpbp77yq5dskIf/Yyc8jQmtOr3H4Pa+I/9jSoGXbDYVYQEa24jh+zNOuGZmvQNMSopYx8=@vger.kernel.org X-Gm-Message-State: AOJu0YxSbvE+YUZv4lvwWDugHbXNho+7nZ3UyqM7lswClZkmgz5o5kLa fgV+Rbt3yaTUbUL+HWUIPILXupsq5FE0WRkb9gJ/dMzsi8WBh/BWMA+BYMqGaZ9aBxwP0BenRA5 iUZkNW0pxU10y2/wYL9d985UqF98HEq26MvMMtNq0o4J2eI/BCivSqEaPOGYW+uUmwPnx7nqYB+ vkZw== X-Gm-Gg: ASbGnctXJ/Mc3JC6Ald4ngZNJX5FL4MM6KHKlbek8ZYciC1YUK3tFoX46gV2mAIJoT2 akG7E38XoBVEAM8Z0hReMiSQHYJPtN2Y+hHVakRCA4ow6lw3ADa9pSpLxUMAz8HA2GiCNZ/Hppj U+/xZ9k4xoIBya17IIKMNBHcOjdFCdJGq/4ImtdpV5JfazDrU1SZl3sHep6zITmloJGPRYhx1cv Ms5n3Xa/NRjeOq5Zi3D7g62LHQ48uBxN9zLNlcVd5XbFc44vDSL0SXLUG5nLVQ5lGLotM6udVHg zHdaG0FUEJIXOXgQ X-Received: by 2002:a17:903:22cc:b0:21f:35fd:1b7b with SMTP id d9443c01a7336-221a1195022mr196437195ad.50.1740407521273; Mon, 24 Feb 2025 06:32:01 -0800 (PST) X-Google-Smtp-Source: AGHT+IHzmmDIpDz01ZcZkwYhJ6KIm6ze5u/aIDvurrAZl++4KbI6uYsymKW0myqu6x9oVMuYI0yX5A== X-Received: by 2002:a17:903:22cc:b0:21f:35fd:1b7b with SMTP id d9443c01a7336-221a1195022mr196436875ad.50.1740407520844; Mon, 24 Feb 2025 06:32:00 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:de7b:58db:ab85:24ee]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-220d545d067sm177613895ad.109.2025.02.24.06.31.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2025 06:32: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 v5 7/9] gpio: aggregator: expose aggregator created via legacy sysfs to configfs Date: Mon, 24 Feb 2025 23:31:32 +0900 Message-ID: <20250224143134.3024598-8-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250224143134.3024598-1-koichiro.den@canonical.com> References: <20250224143134.3024598-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 0c30153ce9ab..6b0e42774b86 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -33,6 +33,7 @@ #include "dev-sync-probe.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->probe_data.pdev && platform_get_drvdata(aggr->probe_data.pde= v); } =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->probe_data.pdev && !platform_get_drvdata(aggr->probe_data.pd= ev); +} + 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. + */ + dev_sync_probe_init(&aggr->probe_data); + + /* 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 Thu Dec 18 22:16:19 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 295EF2561D9 for ; Mon, 24 Feb 2025 14:32:08 +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=1740407530; cv=none; b=V2qbFpSPqRGmDHacOxI/d2iIg6M5biKpSzkE3rK9bepz1uRJ1Z0bzsIjzgarKkqXjlbYqnG3WC5P8trX+achxjpE1wiHacaHKwQmC5DCrnP/hUKj56d416Q6zkBImpmWU3a0rWhU9cyRWbl526lCBYtYwlv5OrukF+Q1F3wiXno= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740407530; c=relaxed/simple; bh=I9lP76yFPs8lG+vM/++5W8TxmjrOGCD202JeuHQOcIA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XhiIt89UH4po0BvXj4rIhcg1KLt+XKQeBTT4TwzMRKo0FlZ29H4z6iIQWXzxsodZEG5BmRUtaIP92CUNleN4H25Lv40dXNWrsbayB3tMRpeynK7lfxUYTPwvWI/XT2xo81mqXiUHDCOxLvA7f3bM7+P4dhrVf3F7tls0wziJA5Q= 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=aTQ8DUha; 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="aTQ8DUha" Received: from mail-pl1-f199.google.com (mail-pl1-f199.google.com [209.85.214.199]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 8A3883F18A for ; Mon, 24 Feb 2025 14:32:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1740407526; bh=EeWm4eF7hu13oz72eC95zGuOMvWxCgDdPfM+4c66iwM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aTQ8DUha0yYo7YqSQlfvtFF1mKQh4mJoscLnn6HOGy+nafhpm0f6IUrxj2oSigeLP 25yiAGBVhfwg1ipYtl8GrJz6x/2sO/AjtLN3tJWHRsHmwpUB0XwA03ohPT4CE1hEgf IybE0rXM0Hv/jlHpsYKaZqmw8WoM/Nw0S6FMsX5yEPyhPWgecuB3LCIHnEajRW70bt fB5jU0VOUiZamJA+0YULW01sZyx7aCZH51Q5BBTu5rNNGfpJuFg3QegKixHSSd16oL PQq69nY5UtF/hbvvhuelAbAFPoqR2i7NpDb84Yk2Lroyh4ioynmnZlZCVC4EAyZHcH KlxBDqbP8wmUw== Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-220bf94cb40so66428505ad.0 for ; Mon, 24 Feb 2025 06:32:06 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740407523; x=1741012323; 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=EeWm4eF7hu13oz72eC95zGuOMvWxCgDdPfM+4c66iwM=; b=lkMyfQ0aN3/kahp3rIUp1x5BvKF6crg78KIYl7JotZNNbmV1kxzL1Z/lrMncQM6ZP5 WcahjIhdRUPcZK/AEuxhoMpNbY+2YNdwXSge/HWMJAAh1MQsQx2631nXRbGUajubtrej 7NpopIOifsTwjOjTlKP0wdjrK3p5203qLAbsh/lFiR0CYByE2ciNh9Zaj6fXSIxWr4b5 YdlsjOjokQeF7IrkZ/k/8mHj5ydUcvqNFKnvqZTY3OyM5UrOHaGxE3DwTu2fN9TFMwXR +WaeEpwoGI4RMqucUTUI/K0D8P0sYuQ2RWr+zoI8zNaqAroVxHljQ8c1qq77JKon3CId vKjw== X-Forwarded-Encrypted: i=1; AJvYcCWZKlzORAVdhqMxMm7qvoAogkfD5KBDfdmi6K2C97opCn/YNpSCO/0VFFPdu8V5JLQq5IqfB9fkY+mG2hg=@vger.kernel.org X-Gm-Message-State: AOJu0YzISRePLyNIvvhAQ8udiV3QpeL0ITczCbrCELXhNeZM4r9LaWne xkUJIhf7lTMNLlx6JGADpW1tKHANqqDyCPSyt9gCy38zPtEbl2HykDA/IwiE+TdomJOkbvUapND 6jRwXtNWlHVOJe5Cqt4ir6tAcaHPzKBBkaqlvioNbgF0v/rIgBVIe8deMglOL/cr58KoTJjNC2B v/dQ== X-Gm-Gg: ASbGncs1RN4ElS5mqee2fNIGXMX+yVrQBmu9iKHdnrow/dd9RGQIFr9PzXKbsGwZrqt qksJqP2QsOvWYeNvf+yKDb2DppX93SGXvGzk9v146//F9jJZpD/mYiThptTFUJqhQkXJcJryUTY poW20axsli6mYnnh7norkgfPXVZ6fQsla/VFOObQKMX4Vw3cKucm5sjLtXjNUzRRJFYKqGkfcwT TRg9o+Kmt1+oIM1RPRnblQapEVRh7WHLLX/ndSX9WdRKpT+okBq++z3yCFJZKdIEjA+RGAtCIgI tLyKbd0Nl/uqAxuQ X-Received: by 2002:a17:902:ea06:b0:215:acb3:3786 with SMTP id d9443c01a7336-2219ff4eccbmr218819765ad.19.1740407523616; Mon, 24 Feb 2025 06:32:03 -0800 (PST) X-Google-Smtp-Source: AGHT+IGYBdUZGjKrDW9Lsq6u2A2A+A32rloyxDv3flD3BcouC0SJNqzemHrcMLYanlXTC9x3Jnqqdg== X-Received: by 2002:a17:902:ea06:b0:215:acb3:3786 with SMTP id d9443c01a7336-2219ff4eccbmr218819425ad.19.1740407523301; Mon, 24 Feb 2025 06:32:03 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:de7b:58db:ab85:24ee]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-220d545d067sm177613895ad.109.2025.02.24.06.32.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2025 06:32:03 -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 v5 8/9] gpio: aggregator: cancel deferred probe for devices created via configfs Date: Mon, 24 Feb 2025 23:31:33 +0900 Message-ID: <20250224143134.3024598-9-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250224143134.3024598-1-koichiro.den@canonical.com> References: <20250224143134.3024598-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 6b0e42774b86..137b5d032427 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 Thu Dec 18 22:16:19 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 76AF925C6E7 for ; Mon, 24 Feb 2025 14:32:11 +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=1740407533; cv=none; b=OQFg1s0iH8YSkFquH/irUrVfMIQC9IfAiO3J3RAnPE99tfvVCzQ0vgPb2yGalvzvtrxblEw7bb/PgAmugcUw4XnRUp3HCB6XIYBIvFsU2eZrj0r16mOV0tq8TN4we0FuDMZbk5eQbsDxIfEfdpgNSs8nzuzp87d04XC6gzTTPpU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740407533; c=relaxed/simple; bh=5z75klJulPBK3euVFo5jCw9QXY35/qZ4NCunDCR/9Jo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TAyPjtj7VoHvY6bLdssUxCO74MaLjUZ/43vRE2DB+Sk00t45CPCAyj+aJHl2RRrgNeqEesqXEtHsSRLQ1hf/4ztnoRFY3BEEM4t4s08Da/LPkjzFzoM8DX1SGsYUfRzf+MM9o3LudP1bcL/eiOZYG4e9aoiKsFOXxHh6kUvthLU= 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=X5sk5TFm; 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="X5sk5TFm" Received: from mail-pl1-f199.google.com (mail-pl1-f199.google.com [209.85.214.199]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 21FA43F869 for ; Mon, 24 Feb 2025 14:32:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1740407528; bh=VbN0B6Oenuw6+py3+N6wdefqtqSm9CuUWAW6b8DJ97M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=X5sk5TFmTopWRUURxS3AisP1L4ZqBngZoeRafiP9zjRzKwMtLaRZvZN3WxkRkVuNV UpGE+LQ8DUuPA4nBPSno+/+ucCujOjI3US2Xs1l1F/buxiNPpTkvxrocEzAozPexbo 4xvr/RlNcPGIsEeIoIS8gYf+eEyMb2SFTgO37gARWjR0tg9IIXnD/mm7eeK/GvzAp6 vfQTrnEzQQatpHCAT5zmsQQ2P5U8JkXWs8btEp/rNseH1fUFNUMkYl9qHXcslCQCr9 jLGFHI8MygER0aQ3G8BEck26GKlBmyY06zGnvW6fScwZflsom0LVyrIljvt+tWmOkw +36A/b1dqrGsQ== Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-220c86e46ebso72242195ad.0 for ; Mon, 24 Feb 2025 06:32:08 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740407527; x=1741012327; 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=jJstnJXocB42ETd3ySOX4PwAZYPsjgvXZbek/qclLaBtBpQDxKZZnzygzPSHuOwZGy NfrkOroTmYY5TedN36AU5axEcq2yCV1SyoWlAu/wXejzJD+WF1aQUjSOtX5/SBNtNrKH K2FW/1COnFpAR2UCxbVZrsrxcWoExrPvIZYUmv/IgtGqVl1hMvU4DrgAzLaUcAKkgPwb n/siPff6qNMcTb+MAbqMnpbsEVoazh9MunRpqGAVJ7xvrnMqYfao8sx8KyDvSV5UZvQA /ebwWzL73OByLryi9xSaIYXlMIfcnPPBeioht8uINUKKYygONqr86R3op/u3g/uzIhdV jADA== X-Forwarded-Encrypted: i=1; AJvYcCVizln9ewiq6IdS3rVC+jG5hwf59JAy97bnAdmFqykc7aTVGUqrpfT0KcQ1SE6XNnCOHBGBUQxQe2vM6HM=@vger.kernel.org X-Gm-Message-State: AOJu0YxMJC8kY6LGAYwO7eu6X7RdC1NVJ+B96v1I3Co5Y9zFhSiKpZhw F8bJdVFfdccbKyVYNgdExFmLy/hGeAWwtFSEjX7We6tN1cLslYvtv0fNdu/baXAzhqTmgNaGU0W SPuNmgRMjmotB7AyXxG28B6SvjB59BzcOTQUveLvv3+C5LXmVaESTRkXPJqmChHrUffyyH+EE57 bs6A== X-Gm-Gg: ASbGncuip9C0xafijycBnldjAjp2UFRpek4dfbuBhSjTDamrJrg4+RdRSTGeItOo6KD cq6eZj2fw6ECH0bmuM8EE/MkhqPKWaz4YgU8yigHxwAoFr1CwCHT7AUxchISSDkNqLZPW2Bz9zh UwMrYGYZMEQaVwNk60unyNRc7+hNOglfgf5D2FdLAI2ep2lql/510Yj+vvzZXcUHTqlQV8IJZxA qZnsu1e1pNa2A3UciXC9+gLcqncTLMm0UvAJbxcK6CadDWaDXNuwPD7rxaFGYchK2woklYkqtWg AztQrREECYpG5SAy X-Received: by 2002:a17:902:ce8c:b0:21f:522b:690f with SMTP id d9443c01a7336-221a11b9bfdmr221006845ad.46.1740407526684; Mon, 24 Feb 2025 06:32:06 -0800 (PST) X-Google-Smtp-Source: AGHT+IHSZQwlljMmmYRCC7Y9lX6+uL/BcL5sVp/WVmnDYsqhnw8DVA1aShXde+2Ht/xNGnXwOQ2afA== X-Received: by 2002:a17:902:ce8c:b0:21f:522b:690f with SMTP id d9443c01a7336-221a11b9bfdmr221006465ad.46.1740407526306; Mon, 24 Feb 2025 06:32:06 -0800 (PST) Received: from z790sl.. ([240f:74:7be:1:de7b:58db:ab85:24ee]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-220d545d067sm177613895ad.109.2025.02.24.06.32.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2025 06:32:06 -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 v5 9/9] Documentation: gpio: document configfs interface for gpio-aggregator Date: Mon, 24 Feb 2025 23:31:34 +0900 Message-ID: <20250224143134.3024598-10-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250224143134.3024598-1-koichiro.den@canonical.com> References: <20250224143134.3024598-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