From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-oi1-f177.google.com (mail-oi1-f177.google.com [209.85.167.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 11D664192F8 for ; Tue, 11 Aug 2026 08:27:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.177 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786436869; cv=none; b=iH4d/bL8msnNgTbHKSfWeBTw3taG5QV+6rOcy0PT/n4rEzQ5RNnipaN8tqMXbnde6i/6bR6mFWDgqV9C/rVzTVwtj9PD6pBBxA73cgGj80ZYLl41owBQBhfsFSNmOzLNTQKmUL09hJfhrxnmDRr9yh7xdXeuRamD8C1p+Aa06ug= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786436869; c=relaxed/simple; bh=IzRlEU23yfQQ6x4BYmQXGZqejxD9TteX1wiEO5R8YME=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JPAn70OLIq/yT9CNDHONLbazpmGj4QRI/wLVOu1UEtk6M8/djlaVYOf8jJI4UxBh/jOu2iitUIT7wUR0AAmAuz9UK0eA+hbfnuiAGoKZ36dPkRAfG27XUjv30FFKQfwD3cWtEPaDt98MmF7vzci13e9Qhq3yGYEgQN1lOIl00N8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=EtdVI2b/; arc=none smtp.client-ip=209.85.167.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="EtdVI2b/" Received: by mail-oi1-f177.google.com with SMTP id 5614622812f47-4af173320f9so1470275b6e.2 for ; Tue, 11 Aug 2026 01:27:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786436867; x=1787041667; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=gyzPxN0hN+8W2JU9IAdx12pcVnDBJDk0tQrb35djIKE=; b=EtdVI2b/D3bDM3lFQnz5p2POUYPO36ver9oYtWmCUsd28/gYM2LYR4wPynBeDZfFic VfEz1PQiOleHeI+T5RIOcY1V/rR1PDDpF6iY9gr07NDdBXK0IqC5PjiHnBWPpwD6pGW1 jiNT9hLwOri7RYr/7hZRdoygTZEZOYZ7Mo9nuNCj4mk4tj161O2fzV2aewYjRH75jGbs c0d57uSkhlA7YtK/aWz4boEF9WIFsDF3W4eodKs0tzLhkBrIfb7+niVQXmOpdtK5FdrV nXAjUJKSSs8yalfrl9gFY+bJzQ8PHyU+SgMW+OYgrhjLowBt4CUGzAS/cSCQ4YTXscra DCIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786436867; x=1787041667; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=gyzPxN0hN+8W2JU9IAdx12pcVnDBJDk0tQrb35djIKE=; b=UkRadokPACqlVTELT5JUzHwKsxlfQBXG8rgZ9wKPmdc6QJ9eAckEXyiralTE7qWxcK 8SIn7iGL2lUytqQ/E28zBNGuB31MU9GgqH3oZCkhw6VdJHf4kzv+K6Q/GNCkddDoKa6h a5FLEMxqc0T9qe2x0VHfCpAse7Fz8KtG/hZ88hv84RCXn1eB7m9O4Uuohfyh1jVO9ScL sk5xbu5TnsA4PJyT/HpAcE8OkKSRvh+Valh3lHYZ+tuuO3msT1OXzUS008Q31eVkJVqM gkBRbOrQ68OrON5E0/MW+xZbV0CnGsC6Q1OE9bbD8j+8WDpY55xpRBp4W6q+i2TvG/2x L9/g== X-Forwarded-Encrypted: i=1; AHgh+RrqJ9FjX6kR/MPIpEN+pWH7y39qC9wVPqDV9US7MU6gx76cdy/YjL+EnDtFVfKO90KbObKaYXTSWjhEgcI=@vger.kernel.org X-Gm-Message-State: AOJu0YxDJp6E39iZgk2IWJ5QtOVZF6xF96dSfNc91I5a78WZ8E4wjpqO p+aUVCesBiSe34O7YqEkDQ7SaGvxc6Jz5wElYR1KxzHvdSwJN0kFsFNH X-Gm-Gg: AR+sD126hydaHI+HxOywFVfzYRVDEYk4VV7Oi+MHnvEZLK0vWZ2VOHjc7c3qAr6pB63 SyXXYhHAriP8xOZ1G4/FVRtx8Pd3G1gBmkVzbd0XQy5PboPPGKW0dsncQ3XfEyWsE1hoVB4E2kG CAenM5wvVkbgEkzVPb6jQtEp3zjjPkCK9/EIu3/wqndGoYP0QYof4/Ruh/+aJY6j88zszY/XUl7 BqEEfgCe8UYdd+4P31u2HQTgFDkZqoAttgpp0zCGMQVhJiMWrxqvhB1BKlAmvIBi/BKq7KS2rGs si13arLryBxBXU9rCdzY3arTPIeJBAE5JAELkPciWORB04x7NPN2JT7hhmczll9A/cNE2iq4s+w R433UUu2H5M4WqSUqsS4W26vLztNBdJ6dd1mfX+HIDMXsUHmqHrxHCMrQD4y0E6iS4hzxshz223 QJtqyPhHQi4ZysERomfY9BacjAEeYZFsRBrHbDQCeqTdEO+AFuuwbF3kYccEPBAKdFYhd8IoZG2 x9lXDQn+SCrGeur6y/0ZxQXBhXyPKPCAmKAI/hipstI8J3I8h+TL+oX5djap7V0xr8G5mn3M7/w hCiJz/W06wTbwHsE3bWPRACGyM3pphaZMt533Ag2rtQ8xCx3GBflrkEYsSL6mbEJLplU0sJdDi8 NahT1JacBHuK/RqUx X-Received: by 2002:a05:6808:bc6:b0:495:da3c:1aa with SMTP id 5614622812f47-4b1fd9af94amr998551b6e.16.1786436866871; Tue, 11 Aug 2026 01:27:46 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4b1fff55fdcsm318095b6e.6.2026.08.11.01.27.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 11 Aug 2026 01:27:45 -0700 (PDT) From: James Hilliard Date: Tue, 11 Aug 2026 02:27:24 -0600 Subject: [PATCH v6 2/3] mfd: syscon: Add managed registration for external regmaps Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260811-submit-ac200-mfd-v6-2-c5b1292c8498@gmail.com> References: <20260811-submit-ac200-mfd-v6-0-c5b1292c8498@gmail.com> In-Reply-To: <20260811-submit-ac200-mfd-v6-0-c5b1292c8498@gmail.com> To: Lee Jones , Arnd Bergmann , Rob Herring , Krzysztof Kozlowski , Conor Dooley , James Hilliard Cc: mfd@lists.linux.dev, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15.2 of_syscon_register_regmap() publishes an externally owned regmap in the global syscon list, but provides no way for a removable driver to withdraw it. Registering a devm-managed regmap from such a driver would therefore leave a stale pointer after unbind. Factor external registration through an internal helper and add devm_of_syscon_register_regmap(). The managed action removes the entry under the syscon list lock before later devres actions release the regmap. Hold a device-node reference for the lifetime of every externally registered entry so its lookup key also remains valid. Consumers of a removable provider remain responsible for ordering teardown, for example with a managed device link. Signed-off-by: James Hilliard --- drivers/mfd/syscon.c | 87 ++++++++++++++++++++++++++++++++++------------ include/linux/mfd/syscon.h | 12 +++++++ 2 files changed, 77 insertions(+), 22 deletions(-) diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 21a7fcdd2737..448422fe4f21 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -193,53 +194,95 @@ static struct regmap *device_node_get_regmap(struct device_node *np, return syscon->regmap; } -/** - * of_syscon_register_regmap() - Register regmap for specified device node - * @np: Device tree node - * @regmap: Pointer to regmap object - * - * Register an externally created regmap object with syscon for the specified - * device tree node. This regmap will then be returned to client drivers using - * the syscon_regmap_lookup_by_phandle() API. - * - * Return: 0 on success, negative error code on failure. - */ -int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap) +static struct syscon * +of_syscon_register_regmap_internal(struct device_node *np, + struct regmap *regmap) { struct syscon *entry, *syscon = NULL; - int ret; if (!np || !regmap) - return -EINVAL; + return ERR_PTR(-EINVAL); syscon = kzalloc_obj(*syscon); if (!syscon) - return -ENOMEM; + return ERR_PTR(-ENOMEM); /* check if syscon entry already exists */ mutex_lock(&syscon_list_lock); list_for_each_entry(entry, &syscon_list, list) if (entry->np == np) { - ret = -EEXIST; - goto err_unlock; + mutex_unlock(&syscon_list_lock); + kfree(syscon); + return ERR_PTR(-EEXIST); } syscon->regmap = regmap; - syscon->np = np; + syscon->np = of_node_get(np); /* register the regmap in syscon list */ list_add_tail(&syscon->list, &syscon_list); mutex_unlock(&syscon_list_lock); - return 0; + return syscon; +} + +/** + * of_syscon_register_regmap() - Register regmap for specified device node + * @np: Device tree node + * @regmap: Pointer to regmap object + * + * Register an externally created regmap object with syscon for the specified + * device tree node. This regmap will then be returned to client drivers using + * the syscon_regmap_lookup_by_phandle() API. + * + * Return: 0 on success, negative error code on failure. + */ +int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap) +{ + return PTR_ERR_OR_ZERO(of_syscon_register_regmap_internal(np, regmap)); +} +EXPORT_SYMBOL_GPL(of_syscon_register_regmap); + +static void devm_of_syscon_register_regmap_release(void *data) +{ + struct syscon *syscon = data; -err_unlock: + mutex_lock(&syscon_list_lock); + list_del(&syscon->list); mutex_unlock(&syscon_list_lock); + + of_node_put(syscon->np); kfree(syscon); - return ret; } -EXPORT_SYMBOL_GPL(of_syscon_register_regmap); + +/** + * devm_of_syscon_register_regmap() - Register a managed external syscon regmap + * @dev: Device that owns the regmap + * @np: Device tree node associated with the regmap + * @regmap: Pointer to the externally created regmap + * + * Register an externally created regmap object with syscon and remove it when + * @dev is unbound. Consumers must stop using the regmap before the provider is + * unbound, for example by establishing a managed device link to @dev. + * + * Return: 0 on success, negative error code on failure. + */ +int devm_of_syscon_register_regmap(struct device *dev, + struct device_node *np, + struct regmap *regmap) +{ + struct syscon *syscon; + + syscon = of_syscon_register_regmap_internal(np, regmap); + if (IS_ERR(syscon)) + return PTR_ERR(syscon); + + return devm_add_action_or_reset(dev, + devm_of_syscon_register_regmap_release, + syscon); +} +EXPORT_SYMBOL_GPL(devm_of_syscon_register_regmap); /** * device_node_to_regmap() - Get or create a regmap for specified device node diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h index aad9c6b50463..3e804fc1b03e 100644 --- a/include/linux/mfd/syscon.h +++ b/include/linux/mfd/syscon.h @@ -15,6 +15,7 @@ #include struct device_node; +struct device; #ifdef CONFIG_MFD_SYSCON struct regmap *device_node_to_regmap(struct device_node *np); @@ -30,6 +31,9 @@ struct regmap *syscon_regmap_lookup_by_phandle_optional(struct device_node *np, const char *property); int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap); +int devm_of_syscon_register_regmap(struct device *dev, + struct device_node *np, + struct regmap *regmap); #else static inline struct regmap *device_node_to_regmap(struct device_node *np) { @@ -75,6 +79,14 @@ static inline int of_syscon_register_regmap(struct device_node *np, return -EOPNOTSUPP; } +static inline int +devm_of_syscon_register_regmap(struct device *dev, + struct device_node *np, + struct regmap *regmap) +{ + return -EOPNOTSUPP; +} + #endif #endif /* __LINUX_MFD_SYSCON_H__ */ -- 2.53.0