From: Mika Westerberg <mika.westerberg@linux.intel.com>
To: linux-usb@vger.kernel.org
Cc: Yehezkel Bernat <YehezkelShB@gmail.com>,
Lukas Wunner <lukas@wunner.de>,
Andreas Noever <andreas.noever@gmail.com>,
Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
netdev@vger.kernel.org,
Mika Westerberg <mika.westerberg@linux.intel.com>
Subject: [PATCH 3/9] thunderbolt: Allow service drivers to specify their own properties
Date: Tue, 28 Apr 2026 09:22:03 +0200 [thread overview]
Message-ID: <20260428072209.3084930-4-mika.westerberg@linux.intel.com> (raw)
In-Reply-To: <20260428072209.3084930-1-mika.westerberg@linux.intel.com>
The XDomain properties can be useful for service drivers, for example to
implement a registry for the services they expose. So far there has been
no need for service drivers to specify these but with the USB4STREAM
driver that we are going to use them.
This adds remote and local side properties that the service drivers have
access to. Remote side is read-only but the local side can be changed by
a service driver. Also provide a mechanism to notify the remote side
that there are changes.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/xdomain.c | 95 ++++++++++++++++++++++++++++++-----
include/linux/thunderbolt.h | 12 +++++
2 files changed, 94 insertions(+), 13 deletions(-)
diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
index 6e83f93eee83..781d88d06b93 100644
--- a/drivers/thunderbolt/xdomain.c
+++ b/drivers/thunderbolt/xdomain.c
@@ -640,6 +640,32 @@ void tb_unregister_protocol_handler(struct tb_protocol_handler *handler)
}
EXPORT_SYMBOL_GPL(tb_unregister_protocol_handler);
+static int update_service_properties(struct device *dev, void *data)
+{
+ struct tb_property_dir *root = data;
+ struct tb_service *svc;
+ struct tb_property *p;
+
+ svc = tb_to_service(dev);
+ if (!svc)
+ return 0;
+
+ guard(mutex)(&svc->lock);
+
+ /*
+ * Replace the static service properties with the dynamic one.
+ * Typically this is the same but service drivers can add their
+ * own dynamic properties here too.
+ */
+ p = tb_property_find(root, svc->key, TB_PROPERTY_TYPE_DIRECTORY);
+ if (!p)
+ return 0;
+ if (svc->local_properties)
+ return tb_property_merge_dir(p->value.dir,
+ svc->local_properties, false);
+ return 0;
+}
+
static void update_property_block(struct tb_xdomain *xd)
{
mutex_lock(&xdomain_lock);
@@ -664,6 +690,9 @@ static void update_property_block(struct tb_xdomain *xd)
tb_property_add_text(dir, "deviceid", utsname()->nodename);
tb_property_add_immediate(dir, "maxhopid", xd->local_max_hopid);
+ /* Add service specific dynamic properties */
+ device_for_each_child(&xd->dev, dir, update_service_properties);
+
ret = tb_property_format_dir(dir, NULL, 0);
if (ret < 0) {
dev_warn(&xd->dev, "local property block creation failed\n");
@@ -936,6 +965,40 @@ void tb_unregister_service_driver(struct tb_service_driver *drv)
}
EXPORT_SYMBOL_GPL(tb_unregister_service_driver);
+static int update_xdomain(struct device *dev, void *data)
+{
+ struct tb_xdomain *xd;
+
+ xd = tb_to_xdomain(dev);
+ if (xd) {
+ queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
+ msecs_to_jiffies(50));
+ }
+
+ return 0;
+}
+
+/**
+ * tb_service_properties_changed() - Notify the other host about changes
+ * @svc: Service whose properties changed
+ *
+ * Notifies the other host that service properties may have been
+ * changed. This should be called whenever @svc->local_properties is
+ * updated.
+ */
+void tb_service_properties_changed(struct tb_service *svc)
+{
+ struct tb_xdomain *xd = tb_service_parent(svc);
+
+ if (xd->is_unplugged)
+ return;
+
+ scoped_guard(mutex, &xdomain_lock)
+ xdomain_property_block_gen++;
+ update_xdomain(&xd->dev, NULL);
+}
+EXPORT_SYMBOL_GPL(tb_service_properties_changed);
+
static ssize_t key_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1035,6 +1098,7 @@ static void tb_service_release(struct device *dev)
struct tb_service *svc = container_of(dev, struct tb_service, dev);
struct tb_xdomain *xd = tb_service_parent(svc);
+ tb_property_free_dir(svc->remote_properties);
ida_free(&xd->service_ids, svc->id);
kfree(svc->key);
kfree(svc);
@@ -1049,6 +1113,16 @@ const struct device_type tb_service_type = {
};
EXPORT_SYMBOL_GPL(tb_service_type);
+static void update_service(struct tb_service *svc, struct tb_property *property)
+{
+ struct tb_property_dir *dir = property->value.dir;
+
+ guard(mutex)(&svc->lock);
+ tb_property_free_dir(svc->remote_properties);
+ svc->remote_properties = tb_property_copy_dir(dir);
+ kobject_uevent(&svc->dev.kobj, KOBJ_CHANGE);
+}
+
static void __unregister_service(struct device *dev)
{
struct tb_service *svc = tb_to_service(dev);
@@ -1109,6 +1183,12 @@ static int populate_service(struct tb_service *svc,
if (!svc->key)
return -ENOMEM;
+ svc->remote_properties = tb_property_copy_dir(dir);
+ if (!svc->remote_properties) {
+ kfree(svc->key);
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -1133,6 +1213,7 @@ static void enumerate_services(struct tb_xdomain *xd)
/* If the service exists already we are fine */
dev = device_find_child(&xd->dev, p, find_service);
if (dev) {
+ update_service(tb_to_service(dev), p);
put_device(dev);
continue;
}
@@ -1156,6 +1237,7 @@ static void enumerate_services(struct tb_xdomain *xd)
svc->dev.bus = &tb_bus_type;
svc->dev.type = &tb_service_type;
svc->dev.parent = get_device(&xd->dev);
+ mutex_init(&svc->lock);
dev_set_name(&svc->dev, "%s.%d", dev_name(&xd->dev), svc->id);
tb_service_debugfs_init(svc);
@@ -2549,19 +2631,6 @@ bool tb_xdomain_handle_request(struct tb *tb, enum tb_cfg_pkg_type type,
return ret > 0;
}
-static int update_xdomain(struct device *dev, void *data)
-{
- struct tb_xdomain *xd;
-
- xd = tb_to_xdomain(dev);
- if (xd) {
- queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
- msecs_to_jiffies(50));
- }
-
- return 0;
-}
-
static void update_all_xdomains(void)
{
bus_for_each_dev(&tb_bus_type, NULL, NULL, update_xdomain);
diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h
index e98d569779f9..f60e3a1aecae 100644
--- a/include/linux/thunderbolt.h
+++ b/include/linux/thunderbolt.h
@@ -397,6 +397,10 @@ void tb_unregister_protocol_handler(struct tb_protocol_handler *handler);
* @prtcvers: Protocol version from the properties directory
* @prtcrevs: Protocol software revision from the properties directory
* @prtcstns: Protocol settings mask from the properties directory
+ * @lock: Protects this structure
+ * @local_properties: Properties owned by the service driver
+ * @remote_properties: Properties read from the remote service. These
+ * are read-only.
* @debugfs_dir: Pointer to the service debugfs directory. Always created
* when debugfs is enabled. Can be used by service drivers to
* add their own entries under the service.
@@ -404,6 +408,9 @@ void tb_unregister_protocol_handler(struct tb_protocol_handler *handler);
* Each domain exposes set of services it supports as collection of
* properties. For each service there will be one corresponding
* &struct tb_service. Service drivers are bound to these.
+ *
+ * Service drivers can add their own dynamic properties to
+ * @local_properties but whenever they do so @lock must be held.
*/
struct tb_service {
struct device dev;
@@ -413,6 +420,9 @@ struct tb_service {
u32 prtcvers;
u32 prtcrevs;
u32 prtcstns;
+ struct mutex lock;
+ struct tb_property_dir *local_properties;
+ struct tb_property_dir *remote_properties;
struct dentry *debugfs_dir;
};
@@ -481,6 +491,8 @@ static inline struct tb_xdomain *tb_service_parent(struct tb_service *svc)
return tb_to_xdomain(svc->dev.parent);
}
+void tb_service_properties_changed(struct tb_service *svc);
+
/**
* struct tb_nhi - thunderbolt native host interface
* @lock: Must be held during ring creation/destruction. Is acquired by
--
2.50.1
next prev parent reply other threads:[~2026-04-28 7:22 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-28 7:22 [PATCH 0/9] thunderbolt: Introduce USB4STREAM Mika Westerberg
2026-04-28 7:22 ` [PATCH 1/9] thunderbolt: Add tb_property_merge_dir() Mika Westerberg
2026-04-28 7:22 ` [PATCH 2/9] thunderbolt: Add KUnit test for tb_property_merge_dir() Mika Westerberg
2026-04-28 7:22 ` Mika Westerberg [this message]
2026-04-28 7:22 ` [PATCH 4/9] thunderbolt / net: Move ring_frame_size() to thunderbolt.h Mika Westerberg
2026-04-28 7:22 ` [PATCH 5/9] thunderbolt / net: Let the service drivers configure interrupt throttling Mika Westerberg
2026-04-28 14:59 ` Andrew Lunn
2026-04-28 7:22 ` [PATCH 6/9] thunderbolt: Add helper to figure size of the ring Mika Westerberg
2026-04-28 7:22 ` [PATCH 7/9] thunderbolt: Add tb_ring_flush() Mika Westerberg
2026-04-28 7:22 ` [PATCH 8/9] thunderbolt: Add support for ConfigFS Mika Westerberg
2026-04-28 7:22 ` [PATCH 9/9] thunderbolt: Add support for USB4STREAM Mika Westerberg
2026-04-28 11:57 ` Greg KH
2026-04-28 12:03 ` Mika Westerberg
2026-04-28 13:54 ` Greg KH
2026-04-28 14:11 ` Mika Westerberg
2026-04-28 15:08 ` Andrew Lunn
2026-04-28 15:13 ` Mika Westerberg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260428072209.3084930-4-mika.westerberg@linux.intel.com \
--to=mika.westerberg@linux.intel.com \
--cc=YehezkelShB@gmail.com \
--cc=alan.borzeszkowski@linux.intel.com \
--cc=andreas.noever@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=lukas@wunner.de \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox