* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Alan Stern @ 2026-06-28 19:21 UTC (permalink / raw)
To: Nikhil Solanke
Cc: linux-usb, gregkh, linux-kernel, michal.pecio, stable, corbet,
skhan, linux-doc
In-Reply-To: <CAFgddh+dEgtJf=3rL_48x5aQx7q3FH20CAw-50J32JOJCYdtMQ@mail.gmail.com>
On Sun, Jun 28, 2026 at 10:01:32PM +0530, Nikhil Solanke wrote:
> On Sun, 28 Jun 2026 at 19:25, Alan Stern <stern@rowland.harvard.edu> wrote:
> >
> > On Sun, Jun 28, 2026 at 11:53:09AM +0530, Nikhil Solanke wrote:
> > > I need some help with the USB_QUIRK_DELAY_INIT part. I can't figure
> > > out how to make it properly work with my patch because of the
> > > following reasons:
> > >
> > > 1. I don't want to move it to the top because, from my pov, there must
> > > have been some reason for placing that quirk where it is now. so i
> > > don't want to mess with it.
> > >
> > > 2. Regarding my idea of adding a condition — so that it doesn't change
> > > the behavior when the quirk isn't set — if the full configuration set
> > > exceeds 255 bytes, we would have to issue a 2nd request. In this case
> > > the existing behavior would be more justified.
> > >
> > > So, I'm a bit confused about how to implement this properly. Adding
> > > yet another condition to fix the second case doesn't feel right to me.
> > > It would look unnecessarily complicated. I would appreciate a bit of
> > > help and advice.
> >
> > If the 255-byte quirk flag isn't set, do the delay before the second
> > transfer just as it is now.
> >
> > If the 255-byte quirk flag is set, do the delay before the first
> > transfer. If a second transfer is needed, you can do a second delay
> > before it or not -- I suspect it doesn't matter. If you want to be
> > safe, add the second delay.
> >
> > Alan Stern
>
> Ok thanks! Just to make sure, because the change I will introduce
> won't affect any existing behavior, these changes (relating to
> DELAY_INIT quirk) won't belong in a new patch, right?
Maybe the best thing to do at this point is to assume that both quirk
flags will never be set for the same device. Under that assumption
there's no need to change the delay code in any way. Just add a comment
mentioning this assumption to avoid confusing people in the future.
Alan Stern
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Alan Stern @ 2026-06-28 19:18 UTC (permalink / raw)
To: Michal Pecio
Cc: Nikhil Solanke, linux-usb, gregkh, linux-kernel, stable, corbet,
skhan, linux-doc
In-Reply-To: <20260628190201.00afdccf.michal.pecio@gmail.com>
On Sun, Jun 28, 2026 at 07:02:01PM +0200, Michal Pecio wrote:
> On Sun, 28 Jun 2026 11:48:36 -0400, Alan Stern wrote:
> > > How about "keep unrelated changes out of a stable patch", i.e. always
> > > do the delay (if any) after the first request, regardless of size?
> >
> > This is not an unrelated change. Rather, it's deciding on how to behave
> > in an entirely new control pathway -- the one where the 255-byte quirk
> > flag is set. The old pathway is completely unaffected.
> >
> > I suspect no devices will have both this quirk flag and the DELAY_INIT
> > flag set, which means the location of any delays in the new pathway
> > won't matter at all since they will never be used.
>
> If no devices will have both quirks then new delay added before the
> first configuration request will never execute.
Correct.
> If such devices will exist, then it probably won't matter whether the
> delay comes after or before the first request. Purpose isn't known,
> but it appears to be rate limiting configuration descriptor requests
> or delaying other requests after this function returns.
In fact, the commit that talks about the Logitech webcams does describe
their buggy behavior to some extent. It says that they seem to reply
with stale video data instead of the real config information, and from
there it's a short guess that adding a delay gives time for the video
pipeline to drain or time out.
In addition, the fact that the delay is needed after the first request
but before the second suggests that the data corruption only affects
transfers longer than 9 bytes -- which the new first request would be.
Therefore it would be appropriate to have the delay before the new first
request. Whether another delay would be needed before the second
request (if there is one) is unknown.
> Either way, no known need exists to add another delay before the first
> request or alter the existing delay (or its conditions) in any way.
See the reasoning above.
> In general, I always object to code which serves no purpose because
> such code is easy to add but very hard to remove when it gets in the
> way. There are no known users, no test cases, only paranoia.
>
> So I would keep the delay code completely unchaged.
At this point it's entirely theoretical anyway, since the devices that
would get the new 255-byte quirk flag don't also have the DELAY_INIT
quirk.
> And skip other random changes like error string nitpicking. Reliable
> and up to date information about how many bytes are requested,
> "expected" (what does it even mean, to somebody reading dmesg?),
> received or verified to exist can be gained from source and usbmon.
Good point. But I dislike messages that actively produce wrong
information. Nikhil could get rid of the parts of the log messages you
don't like, but he shouldn't leave them as they are. He could even do
that in a second patch, separate from this one.
> A stable patch is supposedly supposed to be 100 lines with context ;)
Nonsense. An excellent stable patch is 7 lines, including context. :-)
> I really think it could (and should) be a simple patch.
>
> This is what I wrote a few weeks ago. It's an unconditional change
> for all devices, but it would be easy to turn it into a quirk.
>
>
> --- a/drivers/usb/core/config.c
> +++ b/drivers/usb/core/config.c
> @@ -938,15 +938,14 @@ int usb_get_configuration(struct usb_device *dev)
> if (!dev->rawdescriptors)
> return -ENOMEM;
>
> - desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
> + desc = kmalloc(255, GFP_KERNEL);
> if (!desc)
> return -ENOMEM;
>
> for (cfgno = 0; cfgno < ncfg; cfgno++) {
> - /* We grab just the first descriptor so we know how long
> - * the whole configuration is */
> + /* Try 255 bytes first because that's what Windows does */
> result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
> - desc, USB_DT_CONFIG_SIZE);
> + desc, 255);
> if (result < 0) {
> dev_err(ddev, "unable to read config index %d "
> "descriptor/%s: %d\n", cfgno, "start", result);
> @@ -975,8 +974,12 @@ int usb_get_configuration(struct usb_device *dev)
> if (dev->quirks & USB_QUIRK_DELAY_INIT)
> msleep(200);
>
> - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
> - bigbuffer, length);
> + /* Don't bother if we already have it all */
> + if (length <= result)
> + memcpy(bigbuffer, desc, length);
> + else
> + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
> + bigbuffer, length);
> if (result < 0) {
> dev_err(ddev, "unable to read config index %d "
> "descriptor/%s\n", cfgno, "all");
Making this depend on a quirk flag instead of being unconditional would
yield a patch very similar to what Nikhil has already posted.
Alan Stern
^ permalink raw reply
* [PATCH RFC v6 5/5] iio: osf: add UART IIO driver
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
In-Reply-To: <20260628191337.937-1-kimjinseob88@gmail.com>
Add the Open Sensor Fusion serdev transport, driver core, and IIO
registration path as one complete driver patch.
The driver enables the required vcc regulator, receives OSF frames over
UART, registers IIO devices from capability reports, supports direct raw
reads from the latest sample cache, and pushes buffered samples into
software kfifo buffers.
Use final Kconfig and Makefile contents from the start, claim IIO buffer
mode while pushing samples, and use zeroed scan storage with explicit
timestamp alignment so the driver does not depend on IIO core
bounce-buffer padding behavior.
Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>
---
MAINTAINERS | 5 +
drivers/iio/Kconfig | 1 +
drivers/iio/Makefile | 1 +
drivers/iio/opensensorfusion/Kconfig | 16 ++
drivers/iio/opensensorfusion/Makefile | 6 +
drivers/iio/opensensorfusion/osf_core.c | 291 ++++++++++++++++++++
drivers/iio/opensensorfusion/osf_core.h | 70 +++++
drivers/iio/opensensorfusion/osf_iio.c | 308 ++++++++++++++++++++++
drivers/iio/opensensorfusion/osf_iio.h | 22 ++
drivers/iio/opensensorfusion/osf_serdev.c | 114 ++++++++
10 files changed, 834 insertions(+)
create mode 100644 drivers/iio/opensensorfusion/Kconfig
create mode 100644 drivers/iio/opensensorfusion/Makefile
create mode 100644 drivers/iio/opensensorfusion/osf_core.c
create mode 100644 drivers/iio/opensensorfusion/osf_core.h
create mode 100644 drivers/iio/opensensorfusion/osf_iio.c
create mode 100644 drivers/iio/opensensorfusion/osf_iio.h
create mode 100644 drivers/iio/opensensorfusion/osf_serdev.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 3d4199d9e..6ce18ad92 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20016,7 +20016,12 @@ M: Jinseob Kim <kimjinseob88@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
F: Documentation/iio/open-sensor-fusion.rst
+F: drivers/iio/opensensorfusion/Kconfig
+F: drivers/iio/opensensorfusion/Makefile
+F: drivers/iio/opensensorfusion/osf_core.*
+F: drivers/iio/opensensorfusion/osf_iio.*
F: drivers/iio/opensensorfusion/osf_protocol.*
+F: drivers/iio/opensensorfusion/osf_serdev.c
F: drivers/iio/opensensorfusion/osf_stream.*
K: opensensorfusion
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 661127aed..939f6c546 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -101,6 +101,7 @@ source "drivers/iio/light/Kconfig"
source "drivers/iio/magnetometer/Kconfig"
source "drivers/iio/multiplexer/Kconfig"
source "drivers/iio/orientation/Kconfig"
+source "drivers/iio/opensensorfusion/Kconfig"
source "drivers/iio/test/Kconfig"
if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index cb80ef837..d864fe17b 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -37,6 +37,7 @@ obj-y += light/
obj-y += magnetometer/
obj-y += multiplexer/
obj-y += orientation/
+obj-y += opensensorfusion/
obj-y += position/
obj-y += potentiometer/
obj-y += potentiostat/
diff --git a/drivers/iio/opensensorfusion/Kconfig b/drivers/iio/opensensorfusion/Kconfig
new file mode 100644
index 000000000..6da44f91c
--- /dev/null
+++ b/drivers/iio/opensensorfusion/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config OPEN_SENSOR_FUSION
+ tristate "Open Sensor Fusion UART IIO driver"
+ depends on IIO
+ depends on SERIAL_DEV_BUS
+ select CRC32
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ help
+ Build the Open Sensor Fusion UART IIO driver.
+
+ The driver receives OSF protocol frames over a serdev UART and
+ registers IIO devices for supported capability entries. It exposes
+ accelerometer, gyroscope, magnetometer, and temperature samples
+ through IIO direct reads and software buffers.
diff --git a/drivers/iio/opensensorfusion/Makefile b/drivers/iio/opensensorfusion/Makefile
new file mode 100644
index 000000000..b4e03b80c
--- /dev/null
+++ b/drivers/iio/opensensorfusion/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_OPEN_SENSOR_FUSION) += open-sensor-fusion.o
+
+open-sensor-fusion-y := osf_core.o osf_iio.o osf_protocol.o osf_serdev.o \
+ osf_stream.o
diff --git a/drivers/iio/opensensorfusion/osf_core.c b/drivers/iio/opensensorfusion/osf_core.c
new file mode 100644
index 000000000..207de03db
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_core.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/cleanup.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include "osf_core.h"
+#include "osf_iio.h"
+
+#define OSF_RESERVED_MSG_FIRST 0x7f00
+#define OSF_RESERVED_MSG_LAST 0x7fff
+#define OSF_VENDOR_PRIVATE_FIRST 0x8000
+
+void osf_core_init(struct osf_device *osf, struct device *dev)
+{
+ *osf = (struct osf_device) {
+ .dev = dev,
+ };
+ mutex_init(&osf->latest_lock);
+}
+
+void osf_core_unregister_iio(struct osf_device *osf)
+{
+ for (unsigned int i = 0; i < osf->iio_dev_count; i++)
+ osf_iio_unregister_sensor(osf->iio_devs[i].indio_dev);
+
+ osf->iio_dev_count = 0;
+}
+
+static struct iio_dev *osf_core_find_iio_dev(struct osf_device *osf,
+ u16 sensor_type, u16 sensor_index)
+{
+ const struct osf_iio_binding *binding;
+
+ for (unsigned int i = 0; i < osf->iio_dev_count; i++) {
+ binding = &osf->iio_devs[i];
+ if (binding->sensor_type == sensor_type &&
+ binding->sensor_index == sensor_index)
+ return binding->indio_dev;
+ }
+
+ return NULL;
+}
+
+static struct osf_latest_sample *
+osf_core_find_latest_sample(struct osf_device *osf, u16 sensor_type,
+ u16 sensor_index)
+{
+ struct osf_latest_sample *latest;
+
+ for (unsigned int i = 0; i < osf->latest_sample_count; i++) {
+ latest = &osf->latest_samples[i];
+ if (latest->sensor_type == sensor_type &&
+ latest->sensor_index == sensor_index)
+ return latest;
+ }
+
+ if (osf->latest_sample_count >= OSF_MAX_CAPABILITIES)
+ return NULL;
+
+ return &osf->latest_samples[osf->latest_sample_count++];
+}
+
+static bool osf_core_capability_is_duplicate(const struct osf_capability_cache *cache,
+ u16 index)
+{
+ const struct osf_capability_entry *entry = &cache->entries[index];
+
+ for (u16 i = 0; i < index; i++) {
+ if (!osf_iio_sensor_supported(cache->entries[i].sensor_type,
+ cache->entries[i].channel_count))
+ continue;
+
+ if (cache->entries[i].sensor_type == entry->sensor_type &&
+ cache->entries[i].sensor_index == entry->sensor_index)
+ return true;
+ }
+
+ return false;
+}
+
+static int osf_core_register_capabilities(struct osf_device *osf,
+ const struct osf_capability_cache *cache)
+{
+ struct iio_dev *indio_dev;
+ int ret;
+
+ if (osf->capability_cache.valid)
+ return 0;
+
+ for (u16 i = 0; i < cache->capability_count; i++) {
+ if (!osf_iio_sensor_supported(cache->entries[i].sensor_type,
+ cache->entries[i].channel_count))
+ continue;
+
+ if (osf_core_capability_is_duplicate(cache, i))
+ return -EEXIST;
+ }
+
+ for (u16 i = 0; i < cache->capability_count; i++) {
+ if (!osf_iio_sensor_supported(cache->entries[i].sensor_type,
+ cache->entries[i].channel_count))
+ continue;
+
+ ret = osf_iio_register_sensor(osf->dev, &cache->entries[i],
+ osf, &indio_dev);
+ if (ret)
+ goto err_unregister;
+
+ osf->iio_devs[osf->iio_dev_count++] = (struct osf_iio_binding) {
+ .sensor_type = cache->entries[i].sensor_type,
+ .sensor_index = cache->entries[i].sensor_index,
+ .indio_dev = indio_dev,
+ };
+ }
+
+ return 0;
+
+err_unregister:
+ osf_core_unregister_iio(osf);
+
+ return ret;
+}
+
+static int osf_core_handle_sensor_sample(struct osf_device *osf,
+ const struct osf_frame *frame)
+{
+ struct osf_latest_sample *latest;
+ struct osf_sensor_sample sample;
+ struct iio_dev *indio_dev;
+ s32 values[OSF_MAX_SAMPLE_CHANNELS] = { };
+ int ret;
+
+ ret = osf_protocol_decode_sensor_sample(frame, &sample);
+ if (ret)
+ return ret;
+
+ if (sample.channel_count > OSF_MAX_SAMPLE_CHANNELS)
+ return -E2BIG;
+
+ for (u16 i = 0; i < sample.channel_count; i++) {
+ ret = osf_protocol_sensor_sample_value(&sample, i, &values[i]);
+ if (ret)
+ return ret;
+ }
+
+ scoped_guard(mutex, &osf->latest_lock) {
+ latest = osf_core_find_latest_sample(osf, sample.sensor_type,
+ sample.sensor_index);
+ if (!latest)
+ return -E2BIG;
+
+ memcpy(latest->values, values, sizeof(values));
+ latest->sensor_type = sample.sensor_type;
+ latest->sensor_index = sample.sensor_index;
+ latest->channel_count = sample.channel_count;
+ latest->sample_format = sample.sample_format;
+ latest->scale_nano = sample.scale_nano;
+ latest->sequence = frame->sequence;
+ latest->timestamp_us = frame->timestamp_us;
+ latest->valid = true;
+ osf->last_sequence = frame->sequence;
+ }
+
+ indio_dev = osf_core_find_iio_dev(osf, sample.sensor_type,
+ sample.sensor_index);
+ if (!indio_dev)
+ return 0;
+
+ return osf_iio_push_sample(indio_dev, values, sample.channel_count);
+}
+
+static int osf_core_handle_device_status(struct osf_device *osf,
+ const struct osf_frame *frame)
+{
+ struct osf_device_status status;
+ int ret;
+
+ ret = osf_protocol_decode_device_status(frame, &status);
+ if (ret)
+ return ret;
+
+ osf->status_cache = (struct osf_status_cache) {
+ .uptime_s = status.uptime_s,
+ .status_flags = status.status_flags,
+ .error_flags = status.error_flags,
+ .dropped_frames = status.dropped_frames,
+ .sequence = frame->sequence,
+ .valid = true,
+ };
+ osf->last_sequence = frame->sequence;
+
+ return 0;
+}
+
+static int osf_core_handle_capability_report(struct osf_device *osf,
+ const struct osf_frame *frame)
+{
+ struct osf_capability_cache cache = { };
+ struct osf_capability_report report;
+ int ret;
+
+ ret = osf_protocol_decode_capability_report(frame, &report);
+ if (ret)
+ return ret;
+
+ if (report.capability_count > OSF_MAX_CAPABILITIES)
+ return -E2BIG;
+
+ if (osf->capability_cache.valid) {
+ osf->last_sequence = frame->sequence;
+ return 0;
+ }
+
+ for (u16 i = 0; i < report.capability_count; i++) {
+ ret = osf_protocol_decode_capability_entry(&report, i,
+ &cache.entries[i]);
+ if (ret)
+ return ret;
+ }
+
+ cache.capability_count = report.capability_count;
+ cache.sequence = frame->sequence;
+ cache.valid = true;
+
+ ret = osf_core_register_capabilities(osf, &cache);
+ if (ret)
+ return ret;
+
+ osf->capability_cache = cache;
+ osf->last_sequence = frame->sequence;
+
+ return 0;
+}
+
+int osf_core_receive_frame(struct osf_device *osf, const u8 *buf, size_t len)
+{
+ struct osf_frame frame;
+ size_t frame_len;
+ int ret;
+
+ ret = osf_protocol_decode_frame(buf, len, &frame, &frame_len);
+ if (ret)
+ return ret;
+
+ if (frame_len != len)
+ return -EMSGSIZE;
+
+ switch (frame.message_type) {
+ case OSF_MSG_SENSOR_SAMPLE:
+ return osf_core_handle_sensor_sample(osf, &frame);
+ case OSF_MSG_DEVICE_STATUS:
+ return osf_core_handle_device_status(osf, &frame);
+ case OSF_MSG_CAPABILITY_REPORT:
+ return osf_core_handle_capability_report(osf, &frame);
+ default:
+ if (frame.message_type >= OSF_RESERVED_MSG_FIRST &&
+ frame.message_type <= OSF_RESERVED_MSG_LAST)
+ return 0;
+ if (frame.message_type >= OSF_VENDOR_PRIVATE_FIRST)
+ return 0;
+ return -EOPNOTSUPP;
+ }
+}
+
+int osf_core_read_latest_sample(struct osf_device *osf, u16 sensor_type,
+ u16 sensor_index, u16 channel,
+ s32 *value)
+{
+ const struct osf_latest_sample *latest;
+
+ if (!osf || !value)
+ return -EINVAL;
+
+ guard(mutex)(&osf->latest_lock);
+ for (unsigned int i = 0; i < osf->latest_sample_count; i++) {
+ latest = &osf->latest_samples[i];
+ if (latest->sensor_type != sensor_type ||
+ latest->sensor_index != sensor_index)
+ continue;
+
+ if (!latest->valid || channel >= latest->channel_count)
+ break;
+
+ *value = latest->values[channel];
+ return 0;
+ }
+
+ return -ENODATA;
+}
diff --git a/drivers/iio/opensensorfusion/osf_core.h b/drivers/iio/opensensorfusion/osf_core.h
new file mode 100644
index 000000000..5744a39cf
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_core.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _OSF_CORE_H
+#define _OSF_CORE_H
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#include "osf_protocol.h"
+
+#define OSF_MAX_SAMPLE_CHANNELS 3
+#define OSF_MAX_CAPABILITIES 16
+
+struct device;
+struct iio_dev;
+
+struct osf_latest_sample {
+ u16 sensor_type;
+ u16 sensor_index;
+ u16 channel_count;
+ u16 sample_format;
+ u32 scale_nano;
+ s32 values[OSF_MAX_SAMPLE_CHANNELS];
+ u64 sequence;
+ u64 timestamp_us;
+ bool valid;
+};
+
+struct osf_capability_cache {
+ u16 capability_count;
+ struct osf_capability_entry entries[OSF_MAX_CAPABILITIES];
+ u64 sequence;
+ bool valid;
+};
+
+struct osf_status_cache {
+ u32 uptime_s;
+ u32 status_flags;
+ u32 error_flags;
+ u32 dropped_frames;
+ u64 sequence;
+ bool valid;
+};
+
+struct osf_iio_binding {
+ u16 sensor_type;
+ u16 sensor_index;
+ struct iio_dev *indio_dev;
+};
+
+struct osf_device {
+ struct device *dev;
+ /* Protects latest_samples and latest_sample_count. */
+ struct mutex latest_lock;
+ struct osf_latest_sample latest_samples[OSF_MAX_CAPABILITIES];
+ unsigned int latest_sample_count;
+ struct osf_capability_cache capability_cache;
+ struct osf_status_cache status_cache;
+ struct osf_iio_binding iio_devs[OSF_MAX_CAPABILITIES];
+ unsigned int iio_dev_count;
+ u64 last_sequence;
+};
+
+void osf_core_init(struct osf_device *osf, struct device *dev);
+void osf_core_unregister_iio(struct osf_device *osf);
+int osf_core_receive_frame(struct osf_device *osf, const u8 *buf, size_t len);
+int osf_core_read_latest_sample(struct osf_device *osf, u16 sensor_type,
+ u16 sensor_index, u16 channel,
+ s32 *value);
+
+#endif
diff --git a/drivers/iio/opensensorfusion/osf_iio.c b/drivers/iio/opensensorfusion/osf_iio.c
new file mode 100644
index 000000000..91afcf3b8
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_iio.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include "osf_core.h"
+#include "osf_iio.h"
+
+struct osf_iio_sensor_spec {
+ u16 sensor_type;
+ u16 channel_count;
+ const char *name;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ const unsigned long *available_scan_masks;
+};
+
+struct osf_iio_state {
+ const struct osf_iio_sensor_spec *spec;
+ struct iio_buffer *buffer;
+ u32 scale_nano;
+ u16 sensor_index;
+ struct osf_device *osf;
+};
+
+struct osf_iio_scan_3axis {
+ s32 values[3];
+ aligned_s64 timestamp;
+};
+
+struct osf_iio_scan_1axis {
+ s32 value;
+ aligned_s64 timestamp;
+};
+
+#define OSF_SCAN_TYPE_S32 \
+ { \
+ .sign = 's', \
+ .realbits = 32, \
+ .storagebits = 32, \
+ .endianness = IIO_CPU, \
+ }
+
+#define OSF_MOD_CHAN(_type, _mod, _idx) \
+ { \
+ .type = (_type), \
+ .modified = 1, \
+ .channel2 = (_mod), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = (_idx), \
+ .scan_type = OSF_SCAN_TYPE_S32, \
+ }
+
+#define OSF_CHAN(_type, _idx) \
+ { \
+ .type = (_type), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = (_idx), \
+ .scan_type = OSF_SCAN_TYPE_S32, \
+ }
+
+static const struct iio_chan_spec osf_accel_channels[] = {
+ OSF_MOD_CHAN(IIO_ACCEL, IIO_MOD_X, 0),
+ OSF_MOD_CHAN(IIO_ACCEL, IIO_MOD_Y, 1),
+ OSF_MOD_CHAN(IIO_ACCEL, IIO_MOD_Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec osf_gyro_channels[] = {
+ OSF_MOD_CHAN(IIO_ANGL_VEL, IIO_MOD_X, 0),
+ OSF_MOD_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, 1),
+ OSF_MOD_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec osf_mag_channels[] = {
+ OSF_MOD_CHAN(IIO_MAGN, IIO_MOD_X, 0),
+ OSF_MOD_CHAN(IIO_MAGN, IIO_MOD_Y, 1),
+ OSF_MOD_CHAN(IIO_MAGN, IIO_MOD_Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec osf_temp_channels[] = {
+ OSF_CHAN(IIO_TEMP, 0),
+ IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const unsigned long osf_3axis_available_scan_masks[] = {
+ GENMASK(2, 0),
+ 0
+};
+
+static const struct osf_iio_sensor_spec osf_iio_sensor_specs[] = {
+ {
+ .sensor_type = OSF_SENSOR_ACCELEROMETER,
+ .channel_count = 3,
+ .name = "osf-accel",
+ .channels = osf_accel_channels,
+ .num_channels = ARRAY_SIZE(osf_accel_channels),
+ .available_scan_masks = osf_3axis_available_scan_masks,
+ },
+ {
+ .sensor_type = OSF_SENSOR_GYROSCOPE,
+ .channel_count = 3,
+ .name = "osf-gyro",
+ .channels = osf_gyro_channels,
+ .num_channels = ARRAY_SIZE(osf_gyro_channels),
+ .available_scan_masks = osf_3axis_available_scan_masks,
+ },
+ {
+ .sensor_type = OSF_SENSOR_MAGNETOMETER,
+ .channel_count = 3,
+ .name = "osf-magn",
+ .channels = osf_mag_channels,
+ .num_channels = ARRAY_SIZE(osf_mag_channels),
+ .available_scan_masks = osf_3axis_available_scan_masks,
+ },
+ {
+ .sensor_type = OSF_SENSOR_TEMPERATURE,
+ .channel_count = 1,
+ .name = "osf-temp",
+ .channels = osf_temp_channels,
+ .num_channels = ARRAY_SIZE(osf_temp_channels),
+ },
+};
+
+static const struct osf_iio_sensor_spec *
+osf_iio_find_sensor_spec(u16 sensor_type, u16 channel_count)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(osf_iio_sensor_specs); i++) {
+ if (osf_iio_sensor_specs[i].sensor_type == sensor_type &&
+ osf_iio_sensor_specs[i].channel_count == channel_count)
+ return &osf_iio_sensor_specs[i];
+ }
+
+ return NULL;
+}
+
+bool osf_iio_sensor_supported(u16 sensor_type, u16 channel_count)
+{
+ if (osf_iio_find_sensor_spec(sensor_type, channel_count))
+ return true;
+
+ return false;
+}
+
+const char *osf_iio_sensor_name(u16 sensor_type)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(osf_iio_sensor_specs); i++) {
+ if (osf_iio_sensor_specs[i].sensor_type == sensor_type)
+ return osf_iio_sensor_specs[i].name;
+ }
+
+ return NULL;
+}
+
+static int osf_iio_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *val,
+ int *val2, long mask)
+{
+ struct osf_iio_state *state = iio_priv(indio_dev);
+ s32 raw;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = osf_core_read_latest_sample(state->osf,
+ state->spec->sensor_type,
+ state->sensor_index,
+ chan->scan_index, &raw);
+ if (ret)
+ return ret;
+
+ *val = raw;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = state->scale_nano / NANO;
+ *val2 = state->scale_nano % NANO;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info osf_iio_info = {
+ .read_raw = osf_iio_read_raw,
+};
+
+int osf_iio_register_sensor(struct device *dev,
+ const struct osf_capability_entry *entry,
+ struct osf_device *osf, struct iio_dev **indio_dev)
+{
+ const struct osf_iio_sensor_spec *spec;
+ struct osf_iio_state *state;
+ struct iio_dev *iio_dev;
+ int ret;
+
+ spec = osf_iio_find_sensor_spec(entry->sensor_type,
+ entry->channel_count);
+ if (!spec)
+ return -EOPNOTSUPP;
+
+ if (entry->sample_format != OSF_SAMPLE_FORMAT_S32)
+ return -EOPNOTSUPP;
+
+ iio_dev = iio_device_alloc(dev, sizeof(*state));
+ if (!iio_dev)
+ return -ENOMEM;
+
+ state = iio_priv(iio_dev);
+ state->spec = spec;
+ state->scale_nano = entry->scale_nano;
+ state->sensor_index = entry->sensor_index;
+ state->osf = osf;
+
+ iio_dev->name = spec->name;
+ iio_dev->info = &osf_iio_info;
+ iio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+ iio_dev->channels = spec->channels;
+ iio_dev->num_channels = spec->num_channels;
+ iio_dev->available_scan_masks = spec->available_scan_masks;
+
+ state->buffer = iio_kfifo_allocate();
+ if (!state->buffer) {
+ ret = -ENOMEM;
+ goto err_free_iio;
+ }
+
+ ret = iio_device_attach_buffer(iio_dev, state->buffer);
+ if (ret)
+ goto err_free_buffer;
+
+ ret = iio_device_register(iio_dev);
+ if (ret)
+ goto err_free_buffer;
+
+ *indio_dev = iio_dev;
+
+ return 0;
+
+err_free_buffer:
+ iio_kfifo_free(state->buffer);
+err_free_iio:
+ iio_device_free(iio_dev);
+
+ return ret;
+}
+
+void osf_iio_unregister_sensor(struct iio_dev *indio_dev)
+{
+ struct osf_iio_state *state = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_kfifo_free(state->buffer);
+ iio_device_free(indio_dev);
+}
+
+int osf_iio_push_sample(struct iio_dev *indio_dev, const s32 *values,
+ u16 channel_count)
+{
+ struct osf_iio_state *state = iio_priv(indio_dev);
+ s64 timestamp;
+ int ret;
+
+ if (channel_count != state->spec->channel_count)
+ return -EPROTO;
+
+ if (!iio_device_try_claim_buffer_mode(indio_dev))
+ return 0;
+
+ timestamp = iio_get_time_ns(indio_dev);
+
+ switch (channel_count) {
+ case 1: {
+ struct osf_iio_scan_1axis scan = { };
+
+ scan.value = values[0];
+ ret = iio_push_to_buffers_with_ts(indio_dev, &scan,
+ sizeof(scan), timestamp);
+ break;
+ }
+ case 3: {
+ struct osf_iio_scan_3axis scan = { };
+
+ scan.values[0] = values[0];
+ scan.values[1] = values[1];
+ scan.values[2] = values[2];
+ ret = iio_push_to_buffers_with_ts(indio_dev, &scan,
+ sizeof(scan), timestamp);
+ break;
+ }
+ default:
+ ret = -EPROTO;
+ break;
+ }
+
+ iio_device_release_buffer_mode(indio_dev);
+
+ return ret;
+}
diff --git a/drivers/iio/opensensorfusion/osf_iio.h b/drivers/iio/opensensorfusion/osf_iio.h
new file mode 100644
index 000000000..d0745167f
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_iio.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _OSF_IIO_H
+#define _OSF_IIO_H
+
+#include <linux/types.h>
+
+#include "osf_protocol.h"
+
+struct device;
+struct iio_dev;
+struct osf_device;
+
+int osf_iio_register_sensor(struct device *dev,
+ const struct osf_capability_entry *entry,
+ struct osf_device *osf, struct iio_dev **indio_dev);
+void osf_iio_unregister_sensor(struct iio_dev *indio_dev);
+int osf_iio_push_sample(struct iio_dev *indio_dev, const s32 *values,
+ u16 channel_count);
+bool osf_iio_sensor_supported(u16 sensor_type, u16 channel_count);
+const char *osf_iio_sensor_name(u16 sensor_type);
+
+#endif
diff --git a/drivers/iio/opensensorfusion/osf_serdev.c b/drivers/iio/opensensorfusion/osf_serdev.c
new file mode 100644
index 000000000..474fa251f
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_serdev.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/serdev.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "osf_core.h"
+#include "osf_stream.h"
+
+#define OSF_SERDEV_BAUD 115200
+
+struct osf_serdev {
+ struct serdev_device *serdev;
+ struct osf_device osf;
+ struct osf_stream stream;
+};
+
+static size_t osf_serdev_receive_buf(struct serdev_device *serdev,
+ const u8 *buf, size_t count)
+{
+ struct osf_serdev *osf_uart = serdev_device_get_drvdata(serdev);
+ const struct osf_stream_stats *stats;
+ u64 valid_before;
+ int ret;
+
+ valid_before = osf_uart->stream.stats.valid_frames;
+ ret = osf_stream_receive_bytes(&osf_uart->stream, buf, count);
+ stats = &osf_uart->stream.stats;
+
+ if (ret || stats->valid_frames != valid_before)
+ dev_dbg_ratelimited(&serdev->dev,
+ "rx count=%zu valid=%llu bad_magic=%llu bad_crc=%llu partial=%llu dropped=%llu ret=%d\n",
+ count, stats->valid_frames,
+ stats->bad_magic_resyncs,
+ stats->bad_crc_frames, stats->partial_frames,
+ stats->dropped_bytes, ret);
+
+ return count;
+}
+
+static const struct serdev_device_ops osf_serdev_ops = {
+ .receive_buf = osf_serdev_receive_buf,
+};
+
+static int osf_serdev_probe(struct serdev_device *serdev)
+{
+ struct device *dev = &serdev->dev;
+ struct osf_serdev *osf_uart;
+ unsigned int baudrate;
+ int ret;
+
+ osf_uart = devm_kzalloc(dev, sizeof(*osf_uart), GFP_KERNEL);
+ if (!osf_uart)
+ return -ENOMEM;
+
+ osf_uart->serdev = serdev;
+ osf_core_init(&osf_uart->osf, dev);
+ osf_stream_init(&osf_uart->stream, &osf_uart->osf);
+
+ serdev_device_set_drvdata(serdev, osf_uart);
+ serdev_device_set_client_ops(serdev, &osf_serdev_ops);
+
+ ret = devm_regulator_get_enable(dev, "vcc");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to enable vcc regulator\n");
+
+ ret = serdev_device_open(serdev);
+ if (ret)
+ return ret;
+
+ baudrate = serdev_device_set_baudrate(serdev, OSF_SERDEV_BAUD);
+ if (baudrate != OSF_SERDEV_BAUD)
+ dev_warn(dev, "requested %u baud, controller set %u\n",
+ OSF_SERDEV_BAUD, baudrate);
+
+ serdev_device_set_flow_control(serdev, false);
+
+ return 0;
+}
+
+static void osf_serdev_remove(struct serdev_device *serdev)
+{
+ struct osf_serdev *osf_uart = serdev_device_get_drvdata(serdev);
+
+ /* Stop the RX producer before unregistering IIO consumers. */
+ serdev_device_close(serdev);
+ osf_stream_reset(&osf_uart->stream);
+ osf_core_unregister_iio(&osf_uart->osf);
+}
+
+static const struct of_device_id osf_serdev_of_match[] = {
+ { .compatible = "opensensorfusion,osf" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, osf_serdev_of_match);
+
+static struct serdev_device_driver osf_serdev_driver = {
+ .probe = osf_serdev_probe,
+ .remove = osf_serdev_remove,
+ .driver = {
+ .name = "open-sensor-fusion-uart",
+ .of_match_table = osf_serdev_of_match,
+ },
+};
+module_serdev_device_driver(osf_serdev_driver);
+
+MODULE_DESCRIPTION("Open Sensor Fusion IIO driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v6 4/5] iio: osf: add authenticated stream parser
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
In-Reply-To: <20260628191337.937-1-kimjinseob88@gmail.com>
Add a UART byte-stream parser for Open Sensor Fusion frames.
The parser searches for the OSF0 wire magic, keeps partial frames
buffered, checks header length and payload bounds, and passes complete
candidate frames to the core decoder.
Rejected candidate frames drop only the current head byte before
resynchronizing, so a corrupted unauthenticated payload length cannot
make the parser skip later valid frames.
Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>
---
MAINTAINERS | 1 +
drivers/iio/opensensorfusion/osf_stream.c | 189 ++++++++++++++++++++++
drivers/iio/opensensorfusion/osf_stream.h | 31 ++++
3 files changed, 221 insertions(+)
create mode 100644 drivers/iio/opensensorfusion/osf_stream.c
create mode 100644 drivers/iio/opensensorfusion/osf_stream.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 32d3e7674..3d4199d9e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20017,6 +20017,7 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
F: Documentation/iio/open-sensor-fusion.rst
F: drivers/iio/opensensorfusion/osf_protocol.*
+F: drivers/iio/opensensorfusion/osf_stream.*
K: opensensorfusion
OPENCOMPUTE PTP CLOCK DRIVER
diff --git a/drivers/iio/opensensorfusion/osf_stream.c b/drivers/iio/opensensorfusion/osf_stream.c
new file mode 100644
index 000000000..470b4ec1f
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_stream.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#include "osf_core.h"
+#include "osf_protocol.h"
+#include "osf_stream.h"
+
+#define OSF_STREAM_MAGIC_LEN 4
+#define OSF_STREAM_MAX_PAYLOAD_LEN \
+ (OSF_STREAM_MAX_FRAME_LEN - OSF_FRAME_HEADER_LEN - OSF_FRAME_CRC_LEN)
+
+static const u8 osf_stream_magic[OSF_STREAM_MAGIC_LEN] = {
+ 'O', 'S', 'F', '0',
+};
+
+static void osf_stream_discard(struct osf_stream *stream, size_t count)
+{
+ if (count >= stream->len) {
+ stream->len = 0;
+ return;
+ }
+
+ memmove(stream->buf, stream->buf + count, stream->len - count);
+ stream->len -= count;
+}
+
+static void osf_stream_drop_invalid_head(struct osf_stream *stream)
+{
+ osf_stream_discard(stream, 1);
+}
+
+static bool osf_stream_magic_match(const u8 *buf, size_t len)
+{
+ return !memcmp(buf, osf_stream_magic, len);
+}
+
+static size_t osf_stream_discard_to_magic(struct osf_stream *stream)
+{
+ size_t old_len = stream->len;
+ size_t match_len;
+ size_t i;
+
+ for (i = 0; i < stream->len; i++) {
+ match_len = stream->len - i;
+ if (match_len > OSF_STREAM_MAGIC_LEN)
+ match_len = OSF_STREAM_MAGIC_LEN;
+
+ if (osf_stream_magic_match(stream->buf + i, match_len)) {
+ if (i)
+ osf_stream_discard(stream, i);
+ return i;
+ }
+ }
+
+ stream->len = 0;
+ return old_len;
+}
+
+static int osf_stream_process(struct osf_stream *stream)
+{
+ size_t discarded;
+ size_t frame_len;
+ u32 payload_len;
+ int first_err = 0;
+ int ret;
+
+ while (stream->len) {
+ discarded = osf_stream_discard_to_magic(stream);
+ if (discarded) {
+ stream->stats.bad_magic_resyncs++;
+ stream->stats.dropped_bytes += discarded;
+ if (!first_err)
+ first_err = -EPROTO;
+ }
+
+ if (!stream->len)
+ break;
+
+ if (stream->len < OSF_FRAME_HEADER_LEN)
+ break;
+
+ if (get_unaligned_le16(stream->buf + 6) !=
+ OSF_FRAME_HEADER_LEN) {
+ stream->stats.dropped_bytes++;
+ osf_stream_drop_invalid_head(stream);
+ if (!first_err)
+ first_err = -EPROTO;
+ continue;
+ }
+
+ payload_len = get_unaligned_le32(stream->buf + 10);
+ if (payload_len > OSF_STREAM_MAX_PAYLOAD_LEN) {
+ stream->stats.dropped_bytes++;
+ osf_stream_drop_invalid_head(stream);
+ if (!first_err)
+ first_err = -EMSGSIZE;
+ continue;
+ }
+
+ frame_len = OSF_FRAME_HEADER_LEN + payload_len + OSF_FRAME_CRC_LEN;
+ if (stream->len < frame_len)
+ break;
+
+ ret = osf_core_receive_frame(stream->osf, stream->buf, frame_len);
+ if (ret) {
+ if (ret == -EBADMSG)
+ stream->stats.bad_crc_frames++;
+
+ /*
+ * Until the decoder accepts the frame, payload_len is
+ * untrusted. Drop only the current head and resynchronize.
+ */
+ stream->stats.dropped_bytes++;
+ osf_stream_drop_invalid_head(stream);
+ if (!first_err)
+ first_err = ret;
+ continue;
+ }
+
+ stream->stats.valid_frames++;
+ osf_stream_discard(stream, frame_len);
+ }
+
+ return first_err;
+}
+
+void osf_stream_init(struct osf_stream *stream, struct osf_device *osf)
+{
+ if (!stream)
+ return;
+
+ stream->osf = osf;
+ stream->len = 0;
+ memset(&stream->stats, 0, sizeof(stream->stats));
+}
+
+void osf_stream_reset(struct osf_stream *stream)
+{
+ if (stream) {
+ stream->len = 0;
+ memset(&stream->stats, 0, sizeof(stream->stats));
+ }
+}
+
+int osf_stream_receive_bytes(struct osf_stream *stream, const u8 *buf,
+ size_t len)
+{
+ size_t copy_len;
+ size_t space;
+ int first_err = 0;
+ int ret;
+
+ if (!stream || !stream->osf || (!buf && len))
+ return -EINVAL;
+
+ if (!len) {
+ ret = osf_stream_process(stream);
+ if (ret && !first_err)
+ first_err = ret;
+ return first_err;
+ }
+
+ while (len) {
+ space = OSF_STREAM_MAX_FRAME_LEN - stream->len;
+ if (!space) {
+ stream->stats.dropped_bytes++;
+ osf_stream_discard(stream, 1);
+ if (!first_err)
+ first_err = -EMSGSIZE;
+ continue;
+ }
+
+ copy_len = len < space ? len : space;
+ memcpy(stream->buf + stream->len, buf, copy_len);
+ stream->len += copy_len;
+ buf += copy_len;
+ len -= copy_len;
+
+ ret = osf_stream_process(stream);
+ if (ret && !first_err)
+ first_err = ret;
+ }
+
+ return first_err;
+}
diff --git a/drivers/iio/opensensorfusion/osf_stream.h b/drivers/iio/opensensorfusion/osf_stream.h
new file mode 100644
index 000000000..f7f9477fe
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_stream.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _OSF_STREAM_H
+#define _OSF_STREAM_H
+
+#include <linux/types.h>
+
+#define OSF_STREAM_MAX_FRAME_LEN 4096
+
+struct osf_device;
+
+struct osf_stream_stats {
+ u64 valid_frames;
+ u64 bad_magic_resyncs;
+ u64 bad_crc_frames;
+ u64 partial_frames;
+ u64 dropped_bytes;
+};
+
+struct osf_stream {
+ struct osf_device *osf;
+ u8 buf[OSF_STREAM_MAX_FRAME_LEN];
+ size_t len;
+ struct osf_stream_stats stats;
+};
+
+void osf_stream_init(struct osf_stream *stream, struct osf_device *osf);
+void osf_stream_reset(struct osf_stream *stream);
+int osf_stream_receive_bytes(struct osf_stream *stream, const u8 *buf,
+ size_t len);
+
+#endif
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v6 3/5] iio: osf: add protocol decoding
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
In-Reply-To: <20260628191337.937-1-kimjinseob88@gmail.com>
Add helpers for decoding Open Sensor Fusion frame headers and supported
message payloads.
The decoder validates the OSF0 wire magic, protocol major version,
header length, payload bounds, reserved fields and CRC before exposing
decoded frame contents to the rest of the driver.
Use explicit little-endian wire storage sizes and designated
initializers for decoded output structures.
Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>
---
MAINTAINERS | 1 +
drivers/iio/opensensorfusion/osf_protocol.c | 258 ++++++++++++++++++++
drivers/iio/opensensorfusion/osf_protocol.h | 97 ++++++++
3 files changed, 356 insertions(+)
create mode 100644 drivers/iio/opensensorfusion/osf_protocol.c
create mode 100644 drivers/iio/opensensorfusion/osf_protocol.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 17c80b55b..32d3e7674 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20016,6 +20016,7 @@ M: Jinseob Kim <kimjinseob88@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
F: Documentation/iio/open-sensor-fusion.rst
+F: drivers/iio/opensensorfusion/osf_protocol.*
K: opensensorfusion
OPENCOMPUTE PTP CLOCK DRIVER
diff --git a/drivers/iio/opensensorfusion/osf_protocol.c b/drivers/iio/opensensorfusion/osf_protocol.c
new file mode 100644
index 000000000..7e27ce3b0
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_protocol.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bits.h>
+#include <linux/crc32.h>
+#include <linux/errno.h>
+#include <linux/limits.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#include "osf_protocol.h"
+
+#define OSF_CRC32_INIT GENMASK(31, 0)
+#define OSF_CRC32_XOROUT GENMASK(31, 0)
+#define OSF_FRAME_MAGIC 0x3046534f /* "OSF0" little-endian */
+
+static bool osf_sensor_type_valid(u16 sensor_type)
+{
+ return sensor_type >= OSF_SENSOR_ACCELEROMETER &&
+ sensor_type <= OSF_SENSOR_PROXIMITY;
+}
+
+static u32 osf_crc32_ieee(const u8 *buf, size_t len)
+{
+ return crc32_le(OSF_CRC32_INIT, buf, len) ^ OSF_CRC32_XOROUT;
+}
+
+int osf_protocol_decode_frame(const u8 *buf, size_t len,
+ struct osf_frame *frame, size_t *frame_len)
+{
+ u32 expected_crc;
+ u32 actual_crc;
+ u32 payload_len;
+ size_t total_len;
+ u8 major;
+
+ if (!buf || !frame || !frame_len)
+ return -EINVAL;
+
+ if (len < OSF_FRAME_MIN_LEN)
+ return -EMSGSIZE;
+
+ if (get_unaligned_le32(buf) != OSF_FRAME_MAGIC)
+ return -EPROTO;
+
+ major = buf[4];
+ if (major != OSF_PROTOCOL_MAJOR)
+ return -EPROTO;
+
+ if (get_unaligned_le16(buf + 6) != OSF_FRAME_HEADER_LEN)
+ return -EPROTO;
+
+ payload_len = get_unaligned_le32(buf + 10);
+ if (payload_len > len - OSF_FRAME_MIN_LEN)
+ return -EMSGSIZE;
+
+ if (get_unaligned_le32(buf + 34))
+ return -EPROTO;
+
+ total_len = OSF_FRAME_HEADER_LEN + payload_len + OSF_FRAME_CRC_LEN;
+ expected_crc = osf_crc32_ieee(buf, OSF_FRAME_HEADER_LEN + payload_len);
+ actual_crc = get_unaligned_le32(buf + OSF_FRAME_HEADER_LEN + payload_len);
+
+ if (actual_crc != expected_crc)
+ return -EBADMSG;
+
+ frame->protocol_minor = buf[5];
+ frame->message_type = get_unaligned_le16(buf + 8);
+ frame->payload_len = payload_len;
+ frame->sequence = get_unaligned_le64(buf + 14);
+ frame->timestamp_us = get_unaligned_le64(buf + 22);
+ frame->flags = get_unaligned_le32(buf + 30);
+ frame->payload = buf + OSF_FRAME_HEADER_LEN;
+ frame->crc = actual_crc;
+ *frame_len = total_len;
+
+ return 0;
+}
+
+int osf_protocol_decode_sensor_sample(const struct osf_frame *frame,
+ struct osf_sensor_sample *sample)
+{
+ u16 channel_count;
+ u16 sample_format;
+ u16 sensor_type;
+ size_t expected_len;
+ const u8 *payload;
+
+ if (!frame || !sample || !frame->payload)
+ return -EINVAL;
+
+ if (frame->message_type != OSF_MSG_SENSOR_SAMPLE)
+ return -EPROTO;
+
+ if (frame->payload_len < OSF_SENSOR_SAMPLE_BASE_LEN)
+ return -EMSGSIZE;
+
+ payload = frame->payload;
+ sensor_type = get_unaligned_le16(payload);
+ channel_count = get_unaligned_le16(payload + 4);
+ sample_format = get_unaligned_le16(payload + 6);
+
+ if (!osf_sensor_type_valid(sensor_type))
+ return -EPROTO;
+
+ if (!channel_count)
+ return -EPROTO;
+
+ if (sample_format != OSF_SAMPLE_FORMAT_S32)
+ return -EPROTO;
+
+ if (get_unaligned_le32(payload + 12))
+ return -EPROTO;
+
+ if (channel_count > (SIZE_MAX - OSF_SENSOR_SAMPLE_BASE_LEN) /
+ sizeof(__le32))
+ return -EOVERFLOW;
+
+ expected_len = OSF_SENSOR_SAMPLE_BASE_LEN + channel_count * sizeof(__le32);
+ if (frame->payload_len != expected_len)
+ return -EMSGSIZE;
+
+ *sample = (struct osf_sensor_sample) {
+ .sensor_type = sensor_type,
+ .sensor_index = get_unaligned_le16(payload + 2),
+ .channel_count = channel_count,
+ .sample_format = sample_format,
+ .scale_nano = get_unaligned_le32(payload + 8),
+ .samples = payload + OSF_SENSOR_SAMPLE_BASE_LEN,
+ };
+
+ return 0;
+}
+
+int osf_protocol_sensor_sample_value(const struct osf_sensor_sample *sample,
+ u16 index, s32 *value)
+{
+ if (!sample || !sample->samples || !value)
+ return -EINVAL;
+
+ if (index >= sample->channel_count)
+ return -ERANGE;
+
+ /* Samples are little-endian two's-complement signed values. */
+ *value = get_unaligned_le32(sample->samples + index * sizeof(__le32));
+
+ return 0;
+}
+
+int osf_protocol_decode_device_status(const struct osf_frame *frame,
+ struct osf_device_status *status)
+{
+ const u8 *payload;
+
+ if (!frame || !status || !frame->payload)
+ return -EINVAL;
+
+ if (frame->message_type != OSF_MSG_DEVICE_STATUS)
+ return -EPROTO;
+
+ if (frame->payload_len != OSF_DEVICE_STATUS_LEN)
+ return -EMSGSIZE;
+
+ payload = frame->payload;
+ if (get_unaligned_le32(payload + 16))
+ return -EPROTO;
+
+ *status = (struct osf_device_status) {
+ .uptime_s = get_unaligned_le32(payload),
+ .status_flags = get_unaligned_le32(payload + 4),
+ .error_flags = get_unaligned_le32(payload + 8),
+ .dropped_frames = get_unaligned_le32(payload + 12),
+ };
+
+ return 0;
+}
+
+int osf_protocol_decode_capability_report(const struct osf_frame *frame,
+ struct osf_capability_report *report)
+{
+ u16 capability_count;
+ size_t expected_len;
+ const u8 *payload;
+
+ if (!frame || !report || !frame->payload)
+ return -EINVAL;
+
+ if (frame->message_type != OSF_MSG_CAPABILITY_REPORT)
+ return -EPROTO;
+
+ if (frame->payload_len < OSF_CAP_REPORT_BASE_LEN)
+ return -EMSGSIZE;
+
+ payload = frame->payload;
+ capability_count = get_unaligned_le16(payload);
+
+ if (get_unaligned_le16(payload + 2))
+ return -EPROTO;
+
+ if (capability_count > (SIZE_MAX - OSF_CAP_REPORT_BASE_LEN) /
+ OSF_CAP_SENSOR_ENTRY_LEN)
+ return -EOVERFLOW;
+
+ expected_len = OSF_CAP_REPORT_BASE_LEN +
+ capability_count * OSF_CAP_SENSOR_ENTRY_LEN;
+ if (frame->payload_len != expected_len)
+ return -EMSGSIZE;
+
+ *report = (struct osf_capability_report) {
+ .capability_count = capability_count,
+ .entries = payload + OSF_CAP_REPORT_BASE_LEN,
+ };
+
+ return 0;
+}
+
+int osf_protocol_decode_capability_entry(const struct osf_capability_report
+ *report, u16 index,
+ struct osf_capability_entry *entry)
+{
+ u16 sample_format;
+ u16 sensor_type;
+ u32 flags;
+ const u8 *payload;
+
+ if (!report || !report->entries || !entry)
+ return -EINVAL;
+
+ if (index >= report->capability_count)
+ return -ERANGE;
+
+ payload = report->entries + index * OSF_CAP_SENSOR_ENTRY_LEN;
+ sensor_type = get_unaligned_le16(payload);
+ sample_format = get_unaligned_le16(payload + 6);
+ flags = get_unaligned_le32(payload + 12);
+
+ if (!osf_sensor_type_valid(sensor_type))
+ return -EPROTO;
+
+ if (sample_format != OSF_SAMPLE_FORMAT_S32)
+ return -EPROTO;
+
+ if (flags & ~OSF_CAPABILITY_FLAGS_MASK)
+ return -EPROTO;
+
+ if (get_unaligned_le32(payload + 16))
+ return -EPROTO;
+
+ *entry = (struct osf_capability_entry) {
+ .sensor_type = sensor_type,
+ .sensor_index = get_unaligned_le16(payload + 2),
+ .channel_count = get_unaligned_le16(payload + 4),
+ .sample_format = sample_format,
+ .scale_nano = get_unaligned_le32(payload + 8),
+ .flags = flags,
+ };
+
+ return 0;
+}
diff --git a/drivers/iio/opensensorfusion/osf_protocol.h b/drivers/iio/opensensorfusion/osf_protocol.h
new file mode 100644
index 000000000..479cb07af
--- /dev/null
+++ b/drivers/iio/opensensorfusion/osf_protocol.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _OSF_PROTOCOL_H
+#define _OSF_PROTOCOL_H
+
+#include <linux/bits.h>
+#include <linux/types.h>
+
+#define OSF_PROTOCOL_MAJOR 0
+#define OSF_PROTOCOL_MINOR 0
+#define OSF_FRAME_HEADER_LEN 38
+#define OSF_FRAME_CRC_LEN 4
+#define OSF_FRAME_MIN_LEN (OSF_FRAME_HEADER_LEN + OSF_FRAME_CRC_LEN)
+
+#define OSF_SENSOR_SAMPLE_BASE_LEN 16
+#define OSF_DEVICE_STATUS_LEN 20
+#define OSF_CAP_REPORT_BASE_LEN 4
+#define OSF_CAP_SENSOR_ENTRY_LEN 20
+#define OSF_CAPABILITY_FLAGS_MASK GENMASK(1, 0)
+
+enum osf_message_type {
+ OSF_MSG_SENSOR_SAMPLE = 0x0001,
+ OSF_MSG_DEVICE_STATUS = 0x0002,
+ OSF_MSG_CAPABILITY_REPORT = 0x0003,
+};
+
+enum osf_sensor_type {
+ OSF_SENSOR_ACCELEROMETER = 0x0001,
+ OSF_SENSOR_GYROSCOPE = 0x0002,
+ OSF_SENSOR_MAGNETOMETER = 0x0003,
+ OSF_SENSOR_BAROMETER = 0x0004,
+ OSF_SENSOR_TEMPERATURE = 0x0005,
+ OSF_SENSOR_HUMIDITY = 0x0006,
+ OSF_SENSOR_AMBIENT_LIGHT = 0x0007,
+ OSF_SENSOR_PROXIMITY = 0x0008,
+};
+
+enum osf_sample_format {
+ OSF_SAMPLE_FORMAT_S32 = 0x0001,
+};
+
+struct osf_frame {
+ u8 protocol_minor;
+ u16 message_type;
+ u32 payload_len;
+ u64 sequence;
+ u64 timestamp_us;
+ u32 flags;
+ /* payload points into the caller-owned frame buffer. */
+ const u8 *payload;
+ u32 crc;
+};
+
+struct osf_sensor_sample {
+ u16 sensor_type;
+ u16 sensor_index;
+ u16 channel_count;
+ u16 sample_format;
+ u32 scale_nano;
+ const u8 *samples;
+};
+
+struct osf_device_status {
+ u32 uptime_s;
+ u32 status_flags;
+ u32 error_flags;
+ u32 dropped_frames;
+};
+
+struct osf_capability_report {
+ u16 capability_count;
+ const u8 *entries;
+};
+
+struct osf_capability_entry {
+ u16 sensor_type;
+ u16 sensor_index;
+ u16 channel_count;
+ u16 sample_format;
+ u32 scale_nano;
+ u32 flags;
+};
+
+int osf_protocol_decode_frame(const u8 *buf, size_t len,
+ struct osf_frame *frame, size_t *frame_len);
+int osf_protocol_decode_sensor_sample(const struct osf_frame *frame,
+ struct osf_sensor_sample *sample);
+int osf_protocol_decode_device_status(const struct osf_frame *frame,
+ struct osf_device_status *status);
+int osf_protocol_decode_capability_report(const struct osf_frame *frame,
+ struct osf_capability_report *report);
+int osf_protocol_decode_capability_entry(const struct osf_capability_report
+ *report, u16 index,
+ struct osf_capability_entry *entry);
+int osf_protocol_sensor_sample_value(const struct osf_sensor_sample *sample,
+ u16 index, s32 *value);
+
+#endif
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v6 2/5] Documentation: iio: add Open Sensor Fusion driver overview
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
In-Reply-To: <20260628191337.937-1-kimjinseob88@gmail.com>
Document the Linux IIO mapping for Open Sensor Fusion devices.
The overview explains that sensor channels are discovered at runtime
from mandatory capability reports. It also documents that OSF0 is a
wire-format detail and that protocol_major and protocol_minor carry
protocol compatibility information.
Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>
---
Documentation/iio/index.rst | 1 +
Documentation/iio/open-sensor-fusion.rst | 72 ++++++++++++++++++++++++
MAINTAINERS | 1 +
3 files changed, 74 insertions(+)
create mode 100644 Documentation/iio/open-sensor-fusion.rst
diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst
index ba3e609c6..2713ec5e0 100644
--- a/Documentation/iio/index.rst
+++ b/Documentation/iio/index.rst
@@ -38,4 +38,5 @@ Industrial I/O Kernel Drivers
adxl345
bno055
ep93xx_adc
+ open-sensor-fusion
opt4060
diff --git a/Documentation/iio/open-sensor-fusion.rst b/Documentation/iio/open-sensor-fusion.rst
new file mode 100644
index 000000000..832901f5e
--- /dev/null
+++ b/Documentation/iio/open-sensor-fusion.rst
@@ -0,0 +1,72 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+Open Sensor Fusion
+==================
+
+Open Sensor Fusion is a sensor aggregation hub interface. The Linux IIO driver
+receives OSF protocol frames from an attached device and registers matching IIO
+devices for the sensor classes supported by the driver. The actual sensor
+channels are discovered at runtime from mandatory OSF capability reports.
+
+This document is a driver-facing overview for the Linux IIO mapping. The full
+wire protocol, firmware behavior, and hardware model details belong in the Open
+Sensor Fusion project documentation.
+
+Device Model
+------------
+
+An OSF device sends binary frames from the device to the host. Devices using the
+``opensensorfusion,osf`` compatible are expected to provide
+``CAPABILITY_REPORT`` messages so the host can discover which sensor streams are
+available. Device Tree describes the attached OSF sensor aggregation hub; it does
+not enumerate the individual sensors discovered at runtime.
+
+The currently supported Linux subset exposes:
+
+* accelerometer samples as ``IIO_ACCEL`` X/Y/Z channels,
+* gyroscope samples as ``IIO_ANGL_VEL`` X/Y/Z channels,
+* magnetometer samples as ``IIO_MAGN`` X/Y/Z channels, and
+* temperature samples as ``IIO_TEMP``.
+
+Protocol Scope
+---------------
+
+The driver supports OSF protocol major version 0 for the initial IIO receive
+path. The current wire magic is ``OSF0``; that string is a wire-format detail and
+is not the Linux driver identity. Device Tree keeps the generic
+``opensensorfusion,osf`` compatible rather than naming a product such as OSF
+GREEN or a wire magic value.
+
+Protocol versioning is carried by the ``protocol_major`` and ``protocol_minor``
+fields at fixed offsets in the OSF frame header. The driver currently
+supports ``protocol_major`` 0. ``protocol_minor`` changes within major version
+0 are intended to remain backward-compatible within the fixed header layout.
+Incompatible wire-format changes require a new ``protocol_major``. A future
+device that cannot expose compatible version discovery through that fixed
+header layout would need a different Device Tree compatible.
+
+The initial Linux driver handles device-to-host frames for:
+
+* ``SENSOR_SAMPLE`` buffered and direct-mode sample data,
+* ``CAPABILITY_REPORT`` based IIO device registration, and
+* ``DEVICE_STATUS`` cache updates.
+
+Vendor-private message types are ignored. Command transport, calibration
+control ABI, fusion output ABI, and runtime capability removal are outside the
+initial Linux IIO receive path.
+
+Timestamps
+----------
+
+OSF frames include a device-side ``timestamp_us`` field. Buffered IIO samples use
+an IIO timestamp captured on the host when samples are pushed to IIO buffers.
+The initial driver does not correlate the device timestamp with the host IIO
+clock.
+
+Compatibility Notes
+-------------------
+
+The project protocol documentation should define the compatibility rules for
+reserved fields, optional flags, and trailing extension data. Until those rules
+are finalized, the Linux decoder keeps conservative bounds checks around the
+currently supported message layouts.
diff --git a/MAINTAINERS b/MAINTAINERS
index e4df9d8dc..17c80b55b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20015,6 +20015,7 @@ OPEN SENSOR FUSION
M: Jinseob Kim <kimjinseob88@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
+F: Documentation/iio/open-sensor-fusion.rst
K: opensensorfusion
OPENCOMPUTE PTP CLOCK DRIVER
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v6 1/5] dt-bindings: iio: add Open Sensor Fusion device
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
In-Reply-To: <20260628191337.937-1-kimjinseob88@gmail.com>
Add a binding for the generic Open Sensor Fusion host interface.
Open Sensor Fusion devices report capabilities and samples over an OSF
protocol stream. Sensor channels are discovered at runtime from
capability reports instead of being described individually in Device
Tree.
The protocol version is discovered at runtime from the OSF frame header.
OSF GREEN is a product identity, and OSF0 is a wire-format magic value,
so neither is used as the Linux compatible string.
Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>
---
.../bindings/iio/opensensorfusion,osf.yaml | 54 +++++++++++++++++++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
MAINTAINERS | 6 +++
3 files changed, 62 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
diff --git a/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml b/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
new file mode 100644
index 000000000..8016d582f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/opensensorfusion,osf.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Open Sensor Fusion Sensor Aggregation Hub
+
+maintainers:
+ - Jinseob Kim <kimjinseob88@gmail.com>
+
+description: |
+ This binding documents the generic Open Sensor Fusion host interface. Open
+ Sensor Fusion is a sensor aggregation hub. The hub exposes an OSF protocol
+ data stream over its host interface and reports capabilities and samples for
+ multiple sensor classes. The actual sensor channels are discovered at runtime
+ from OSF capability reports instead of describing them in Device Tree. The
+ protocol version is discovered at runtime.
+
+ Public project documentation is available at:
+
+ https://github.com/opensensorfusion
+
+ The compatible describes the generic Open Sensor Fusion host interface. It
+ is not an OSF GREEN board identity, and it does not encode the OSF0 wire
+ magic. OSF0, protocol_major, and protocol_minor are wire-protocol details
+ exchanged in OSF frames.
+
+allOf:
+ - $ref: /schemas/serial/serial-peripheral-props.yaml#
+
+properties:
+ compatible:
+ const: opensensorfusion,osf
+
+ vcc-supply:
+ description:
+ Regulator supplying power to the Open Sensor Fusion device.
+
+required:
+ - compatible
+ - vcc-supply
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ serial {
+ sensor {
+ compatible = "opensensorfusion,osf";
+ vcc-supply = <&vcc_sensor>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 28784d66a..88172d4a4 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1237,6 +1237,8 @@ patternProperties:
description: OpenPandora GmbH
"^openrisc,.*":
description: OpenRISC.io
+ "^opensensorfusion,.*":
+ description: Open Sensor Fusion
"^openwrt,.*":
description: OpenWrt
"^option,.*":
diff --git a/MAINTAINERS b/MAINTAINERS
index c2c6d7927..e4df9d8dc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20011,6 +20011,12 @@ F: Documentation/devicetree/
F: arch/*/boot/dts/
F: include/dt-bindings/
+OPEN SENSOR FUSION
+M: Jinseob Kim <kimjinseob88@gmail.com>
+S: Maintained
+F: Documentation/devicetree/bindings/iio/opensensorfusion,osf.yaml
+K: opensensorfusion
+
OPENCOMPUTE PTP CLOCK DRIVER
M: Vadim Fedorenko <vadim.fedorenko@linux.dev>
L: netdev@vger.kernel.org
--
2.43.0
^ permalink raw reply related
* [PATCH RFC v6 0/5] iio: add Open Sensor Fusion IIO driver
From: Jinseob Kim @ 2026-06-28 19:13 UTC (permalink / raw)
To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Jonathan Corbet,
Shuah Khan, Jinseob Kim, linux-iio, devicetree, linux-doc,
linux-kernel
Open Sensor Fusion (OSF) devices expose a UART/serdev host interface
for a sensor aggregation hub. This RFC adds a Linux IIO driver that
parses OSF frames and creates IIO devices at runtime from capability
reports provided by the device firmware.
When the corresponding capabilities are reported, the driver exposes
accelerometer, gyroscope, magnetometer, and temperature data as IIO
devices named osf-accel, osf-gyro, osf-magn, and osf-temp.
This remains RFC while the binding, protocol subset, runtime discovery
model, and driver-facing ABI are reviewed.
Changes in v6:
- Reworked the series as a 5-patch standalone RFC.
- Folded the previous transport and IIO registration split into one
final driver patch to avoid Kconfig and Makefile churn.
- Addressed binding feedback with generic host interface wording,
mandatory capability reporting, runtime discovery wording, no
Linux-specific binding language, and no fixed regulator provider in
the example.
- Added progressive MAINTAINERS coverage as files are introduced.
- Removed patch-split wording from Kconfig and introduced Kconfig and
Makefile entries in final form.
- Applied style cleanups including loop-local variables, unused include
cleanup, and a probe-local device pointer.
- Used designated initializers and guard/scoped_guard where useful.
- Kept the stream parser from discarding unauthenticated frame_len on
failed decode.
- Synchronized IIO buffer pushes with
iio_device_try_claim_buffer_mode() and release.
- Replaced iio_push_to_buffers_with_ts_unaligned() with local zeroed
scan storage and iio_push_to_buffers_with_ts().
Validation summary:
- git diff --check: pass.
- checkpatch --strict: pass, 0 errors, 0 warnings, 0 checks.
- dt_binding_check: pass with dtschema 2026.4.
- make KBUILD_MODPOST_WARN=1 W=1 M=drivers/iio/opensensorfusion:
pass, no compiler warnings.
- Local stream parser corruption/resync harness: pass.
- Static IIO scan layout and padding checks: pass.
- Raspberry Pi hardware/runtime smoke testing is pending for this v6
candidate.
Jinseob Kim (5):
dt-bindings: iio: add Open Sensor Fusion device
Documentation: iio: add Open Sensor Fusion driver overview
iio: osf: add protocol decoding
iio: osf: add authenticated stream parser
iio: osf: add UART IIO driver
.../bindings/iio/opensensorfusion,osf.yaml | 54 +++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
Documentation/iio/index.rst | 1 +
Documentation/iio/open-sensor-fusion.rst | 72 ++++
MAINTAINERS | 14 +
drivers/iio/Kconfig | 1 +
drivers/iio/Makefile | 1 +
drivers/iio/opensensorfusion/Kconfig | 16 +
drivers/iio/opensensorfusion/Makefile | 6 +
drivers/iio/opensensorfusion/osf_core.c | 291 +++++++++++++++++
drivers/iio/opensensorfusion/osf_core.h | 70 ++++
drivers/iio/opensensorfusion/osf_iio.c | 308 ++++++++++++++++++
drivers/iio/opensensorfusion/osf_iio.h | 22 ++
drivers/iio/opensensorfusion/osf_protocol.c | 258 +++++++++++++++
drivers/iio/opensensorfusion/osf_protocol.h | 97 ++++++
drivers/iio/opensensorfusion/osf_serdev.c | 114 +++++++
drivers/iio/opensensorfusion/osf_stream.c | 189 +++++++++++
drivers/iio/opensensorfusion/osf_stream.h | 31 ++
18 files changed, 1547 insertions(+)
base-commit: ab5fce87a778cb780a05984a2ca448f2b41aafbf
--
2.43.0
^ permalink raw reply
* Re: [PATCH] crypto: af_alg - Add af_alg_restrict sysctl, defaulting to 1
From: Eric Biggers @ 2026-06-28 18:54 UTC (permalink / raw)
To: Demi Marie Obenour
Cc: Andy Lutomirski, linux-crypto, Herbert Xu, linux-kernel,
linux-doc, linux-bluetooth, iwd, linux-hardening, Milan Broz
In-Reply-To: <c7cb79ce-48f9-4433-ab4f-88b4c4df996c@gmail.com>
On Tue, Jun 23, 2026 at 10:09:27PM -0400, Demi Marie Obenour wrote:
> On 6/23/26 15:27, Eric Biggers wrote:
> > On Tue, Jun 23, 2026 at 12:12:24PM -0700, Andy Lutomirski wrote:
> >> On Mon, Jun 22, 2026 at 4:49 PM Eric Biggers <ebiggers@kernel.org> wrote:
> >>>
> >>> AF_ALG is a frequent source of vulnerabilities and a maintenance
> >>> nightmare. It exposes far more functionality to userspace than ever
> >>> should have been exposed, especially to unprivileged processes. Recent
> >>> exploits have targeted kernel internal implementation details like
> >>> "authencesn" that have zero use case for userspace access.
> >>>
> >>> Fortunately, AF_ALG is rarely used in practice, as userspace crypto
> >>> libraries exist. And when it is used, only some functionality is known
> >>> to be used, and many users are known to hold capabilities already.
> >>> iwd for example requires CAP_NET_ADMIN and has a known algorithm list
> >>> (https://lore.kernel.org/linux-crypto/bcbbef00-5881-421b-8892-7be6c04b832d@gmail.com/).
> >>>
> >>> Thus, let's restrict the set of allowed algorithms by default, depending
> >>> on the capabilities held.
> >>>
> >>> Add a sysctl /proc/sys/crypto/af_alg_restrict with meaning:
> >>>
> >>> 0: unrestricted
> >>> 1: limited functionality
> >>> 2: completely disabled
> >>>
> >>> Set the default value to 1, which enables an algorithm allowlist for
> >>> unprivileged processes and a slightly longer allowlist for privileged
> >>> processes.
> >>
> >> In our brave new world of containers, this is a bit awkward. The
> >> admin is sort of asking two separate questions:
> >>
> >> 1. Is the actual running distro and its privileged components capable
> >> of working without AF_ALG or with only the parts marked as being
> >> unprivileged?
> >>
> >> 2. Is the system running contains that need the unprivileged parts?
> >> (Which is maybe just sha1 for ip? I really don't know.)
> >>
> >> Should there maybe be two separate options so that all options are
> >> available? Or maybe something between 2 and 3 that means "limited
> >> functionality and privileged modes are completely disabled"?
> >
> > If we want to offer more settings we could. I could see this getting
> > quite complex pretty quickly once everyone weighs in, though. There's
> > quite a bit of value in keeping things simple, even if the offered
> > settings won't be optimal for every case.
> >
> > - Eric
>
> What about exposing both allowlists to userspace and making them
> configurable?
>
> I'm mostly concerned about systems running code (possibly
> closed-source) that uses algorithms that nobody here knows about.
> It would be better to allow a single algorithm than to turn off all
> restrictions.
> --
> Sincerely,
> Demi Marie Obenour (she/her/hers)
I think the following is what you're asking for:
sysctl crypto.algif_aead_priv_allowlist='ccm(aes)'
sysctl crypto.algif_aead_unpriv_allowlist=''
sysctl crypto.algif_hash_priv_allowlist='cmac(aes),hmac(md5),hmac(sha1),hmac(sha256),hmac(sha384),hmac(sha512),md4,md5,sha224,sha256,sha384,sha512'
sysctl crypto.algif_hash_unpriv_allowlist='sha1'
sysctl crypto.algif_skcipher_priv_allowlist='cbc(aes),cbc(des),cbc(des3_ede),ctr(aes),ecb(aes),ecb(des)'
sysctl crypto.algif_skcipher_unpriv_allowlist='adiantum(xchacha12,aes),adiantum(xchacha20,aes),hctr2(aes),xts(aes)'
sysctl crypto.algif_rng_priv_allowlist=''
sysctl crypto.algif_rng_unpriv_allowlist=''
We could do that if it's what people want. Just keep in mind that it
would be much more complex than the single tristate sysctl. And in
practice the number of people who are knowledgeable enough to create
these lists is quite small; we've seen similar things with other "Crypto
API" configuration knobs that seem to never be touched in practice.
Any thoughts?
- Eric
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Michal Pecio @ 2026-06-28 17:22 UTC (permalink / raw)
To: Alan Stern
Cc: Nikhil Solanke, linux-usb, gregkh, linux-kernel, stable, corbet,
skhan, linux-doc
In-Reply-To: <20260628190201.00afdccf.michal.pecio@gmail.com>
I really think it could (and should) be a simple patch.
This is what I wrote a few weeks ago. It's an unconditional change
for all devices, but it would be easy to turn it into a quirk.
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -938,15 +938,14 @@ int usb_get_configuration(struct usb_device *dev)
if (!dev->rawdescriptors)
return -ENOMEM;
- desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
+ desc = kmalloc(255, GFP_KERNEL);
if (!desc)
return -ENOMEM;
for (cfgno = 0; cfgno < ncfg; cfgno++) {
- /* We grab just the first descriptor so we know how long
- * the whole configuration is */
+ /* Try 255 bytes first because that's what Windows does */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
- desc, USB_DT_CONFIG_SIZE);
+ desc, 255);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s: %d\n", cfgno, "start", result);
@@ -975,8 +974,12 @@ int usb_get_configuration(struct usb_device *dev)
if (dev->quirks & USB_QUIRK_DELAY_INIT)
msleep(200);
- result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
- bigbuffer, length);
+ /* Don't bother if we already have it all */
+ if (length <= result)
+ memcpy(bigbuffer, desc, length);
+ else
+ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
+ bigbuffer, length);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s\n", cfgno, "all");
^ permalink raw reply
* Re: [PATCH iproute2-next 0/7] devlink: add per-port resource support
From: David Ahern @ 2026-06-28 17:14 UTC (permalink / raw)
To: Tariq Toukan, Stephen Hemminger, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Andrew Lunn, David S. Miller
Cc: Donald Hunter, Simon Horman, Jiri Pirko, Jonathan Corbet,
Shuah Khan, Saeed Mahameed, Leon Romanovsky, Mark Bloch,
Shuah Khan, Matthieu Baerts (NGI0), Chuck Lever, Or Har-Toov,
Carolina Jubran, Moshe Shemesh, Shay Drori, Dragos Tatulea,
Daniel Zahka, Shahar Shitrit, Jacob Keller, Cosmin Ratiu,
Parav Pandit, Kees Cook, Adithya Jayachandran, Daniel Jurgens,
netdev, linux-kernel, linux-doc, linux-rdma, linux-kselftest,
Gal Pressman, Ido Schimmel, Jiri Pirko, Petr Machata
In-Reply-To: <20260609053953.487152-1-tariqt@nvidia.com>
On 6/8/26 11:39 PM, Tariq Toukan wrote:
> Hi,
>
> Currently, devlink resource show only supports querying a specific
> device and displays device-level resources. However, some resources
> are per-port, such as the maximum number of SFs that can be created
> on a specific PF port.
>
> This series extends devlink resource show with full support for
> port-level resources, including a dump mode, per-port querying syntax,
> and scope filtering. In preparation for these features, the first two
> patches refactor how dpipe tables are handled to unblock dump support
> and ensure errors in secondary queries are non-fatal.
>
> The series is organized as follows:
>
> Patch 1 splits the dpipe tables display into a separate function.
>
> Patch 2 moves the dpipe tables query into the per-device resource show
> callback, ensuring it behaves correctly during a multi-device dump.
>
> Patch 3 fixes a pre-existing memory leak in resource_ctx_fini.
>
> Patch 4 adds dump support to resource show (no device required).
>
> Patch 5 shows port-level resources returned in a dump reply.
>
> Patch 6 adds DEV/PORT_INDEX syntax to resource show.
>
> Patch 7 adds scope filter to resource show.
>
> With this series, users can query resources at all levels:
>
> $ devlink resource show
> pci/0000:03:00.0:
> name local_max_SFs size 508 unit entry
> name external_max_SFs size 508 unit entry
> pci/0000:03:00.0/196608:
> name max_SFs size 20 unit entry
>
> $ devlink resource show scope dev
> pci/0000:03:00.0:
> name local_max_SFs size 508 unit entry
> name external_max_SFs size 508 unit entry
>
> $ devlink resource show scope port
> pci/0000:03:00.0/196608:
> name max_SFs size 20 unit entry
>
> $ devlink resource show pci/0000:03:00.0/196608
> pci/0000:03:00.0/196608:
> name max_SFs size 20 unit entry
>
> This series is the userspace counterpart to the kernel series:
> https://lore.kernel.org/all/20260407194107.148063-1-tariqt@nvidia.com/
>
> Ido Schimmel (2):
> devlink: Split dpipe tables output to a separate function
> devlink: Move dpipe tables query to resources show callback
>
> Or Har-Toov (5):
> devlink: fix memory leak in resource_ctx_fini
> devlink: add dump support for resource show
> devlink: show port resources in resource dump
> devlink: add per-port resource show support
> devlink: add scope filter to resource show
>
> bash-completion/devlink | 8 ++
> devlink/devlink.c | 202 +++++++++++++++++++++++++++---------
> man/man8/devlink-resource.8 | 34 +++++-
> 3 files changed, 192 insertions(+), 52 deletions(-)
>
>
> base-commit: 7340b539841dc739bc0b813e8e86825bc1eb5a4c
applied to iproute2-next with the fixup recommended by Claude and
confirmed by Or
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Michal Pecio @ 2026-06-28 17:02 UTC (permalink / raw)
To: Alan Stern
Cc: Nikhil Solanke, linux-usb, gregkh, linux-kernel, stable, corbet,
skhan, linux-doc
In-Reply-To: <62e1fab3-1045-41f3-bc74-4c7624011619@rowland.harvard.edu>
On Sun, 28 Jun 2026 11:48:36 -0400, Alan Stern wrote:
> > How about "keep unrelated changes out of a stable patch", i.e. always
> > do the delay (if any) after the first request, regardless of size?
>
> This is not an unrelated change. Rather, it's deciding on how to behave
> in an entirely new control pathway -- the one where the 255-byte quirk
> flag is set. The old pathway is completely unaffected.
>
> I suspect no devices will have both this quirk flag and the DELAY_INIT
> flag set, which means the location of any delays in the new pathway
> won't matter at all since they will never be used.
If no devices will have both quirks then new delay added before the
first configuration request will never execute.
If such devices will exist, then it probably won't matter whether the
delay comes after or before the first request. Purpose isn't known,
but it appears to be rate limiting configuration descriptor requests
or delaying other requests after this function returns.
Either way, no known need exists to add another delay before the first
request or alter the existing delay (or its conditions) in any way.
In general, I always object to code which serves no purpose because
such code is easy to add but very hard to remove when it gets in the
way. There are no known users, no test cases, only paranoia.
So I would keep the delay code completely unchaged.
And skip other random changes like error string nitpicking. Reliable
and up to date information about how many bytes are requested,
"expected" (what does it even mean, to somebody reading dmesg?),
received or verified to exist can be gained from source and usbmon.
A stable patch is supposedly supposed to be 100 lines with context ;)
Regards,
Michal
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Nikhil Solanke @ 2026-06-28 16:38 UTC (permalink / raw)
To: Michal Pecio
Cc: Alan Stern, linux-usb, gregkh, linux-kernel, stable, corbet,
skhan, linux-doc
In-Reply-To: <20260628165040.76fd608d.michal.pecio@gmail.com>
On Sun, 28 Jun 2026 at 20:20, Michal Pecio <michal.pecio@gmail.com> wrote:
>
> On Sun, 28 Jun 2026 09:55:07 -0400, Alan Stern wrote:
> > On Sun, Jun 28, 2026 at 11:53:09AM +0530, Nikhil Solanke wrote:
> > > I need some help with the USB_QUIRK_DELAY_INIT part. I can't figure
> > > out how to make it properly work with my patch because of the
> > > following reasons:
> > >
> > > 1. I don't want to move it to the top because, from my pov, there
> > > must have been some reason for placing that quirk where it is now.
> > > so i don't want to mess with it.
>
> git blame is your friend:
I'll keep in mind to use git blame in future. I haven't worked
extensively in a large, collaborative codebase, so using git blame
didn't occur to me in this case. Sorry about that!
Thanks,
Nikhil Solanke
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Nikhil Solanke @ 2026-06-28 16:31 UTC (permalink / raw)
To: Alan Stern
Cc: linux-usb, gregkh, linux-kernel, michal.pecio, stable, corbet,
skhan, linux-doc
In-Reply-To: <02060df3-b8c5-4a86-b3ab-3a28eea8a562@rowland.harvard.edu>
On Sun, 28 Jun 2026 at 19:25, Alan Stern <stern@rowland.harvard.edu> wrote:
>
> On Sun, Jun 28, 2026 at 11:53:09AM +0530, Nikhil Solanke wrote:
> > I need some help with the USB_QUIRK_DELAY_INIT part. I can't figure
> > out how to make it properly work with my patch because of the
> > following reasons:
> >
> > 1. I don't want to move it to the top because, from my pov, there must
> > have been some reason for placing that quirk where it is now. so i
> > don't want to mess with it.
> >
> > 2. Regarding my idea of adding a condition — so that it doesn't change
> > the behavior when the quirk isn't set — if the full configuration set
> > exceeds 255 bytes, we would have to issue a 2nd request. In this case
> > the existing behavior would be more justified.
> >
> > So, I'm a bit confused about how to implement this properly. Adding
> > yet another condition to fix the second case doesn't feel right to me.
> > It would look unnecessarily complicated. I would appreciate a bit of
> > help and advice.
>
> If the 255-byte quirk flag isn't set, do the delay before the second
> transfer just as it is now.
>
> If the 255-byte quirk flag is set, do the delay before the first
> transfer. If a second transfer is needed, you can do a second delay
> before it or not -- I suspect it doesn't matter. If you want to be
> safe, add the second delay.
>
> Alan Stern
Ok thanks! Just to make sure, because the change I will introduce
won't affect any existing behavior, these changes (relating to
DELAY_INIT quirk) won't belong in a new patch, right?
Thanks,
Nikhil Solanke
^ permalink raw reply
* Re: [PATCH] Documentation: RCU: adopt new coding style of type-aware kmalloc-family - part 2/2
From: Paul E. McKenney @ 2026-06-28 16:13 UTC (permalink / raw)
To: Manuel Ebner
Cc: Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Jonathan Corbet,
Shuah Khan, open list:DOCUMENTATION, open list, Kees Cook
In-Reply-To: <20260627090605.28955-2-manuelebner@mailbox.org>
On Sat, Jun 27, 2026 at 11:06:06AM +0200, Manuel Ebner wrote:
> Update Documentation/RCU/* to reflect new type-aware kmalloc-family
> as suggested in commit 2932ba8d9c99 ("slab: Introduce kmalloc_obj()
> and family")
>
> p = kmalloc(...);
> -> p = kmalloc_obj(...);
>
> Signed-off-by: Manuel Ebner <manuelebner@mailbox.org>
Queued for further review, thank you!!!
Thanx, Paul
> ---
> A similar patch sent by me has been applied. Back then I wasn't familiar
> enough to convert all *alloc(*. That's why this is " - part 2/2".
> Part 1: f61bf5fdf77d ("Documentation: RCU: adopt new coding style of
> type-aware kmalloc-family")
> ---
> Documentation/RCU/rcu_dereference.rst | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/RCU/rcu_dereference.rst b/Documentation/RCU/rcu_dereference.rst
> index 2524dcdadde2..5bc3785ebfc2 100644
> --- a/Documentation/RCU/rcu_dereference.rst
> +++ b/Documentation/RCU/rcu_dereference.rst
> @@ -236,7 +236,7 @@ precautions. To see this, consider the following code fragment::
> {
> struct foo *p;
>
> - p = kmalloc(...);
> + p = kmalloc_obj(*p);
> if (p == NULL)
> deal_with_it();
> p->a = 42; /* Each field in its own cache line. */
> @@ -293,7 +293,7 @@ Then one approach is to use locking, for example, as follows::
> {
> struct foo *p;
>
> - p = kmalloc(...);
> + p = kmalloc_obj(*p);
> if (p == NULL)
> deal_with_it();
> spin_lock(&p->lock);
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH v11 11/11] tracing/probes: Add a new testcase for BTF typecasts
From: Masami Hiramatsu @ 2026-06-28 16:03 UTC (permalink / raw)
To: Masami Hiramatsu (Google)
Cc: Steven Rostedt, Mathieu Desnoyers, Jonathan Corbet, Shuah Khan,
linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest
In-Reply-To: <178248336390.841606.1695444929833877704.stgit@devnote2>
This has a problem and needs some updates.
On Fri, 26 Jun 2026 23:16:04 +0900
"Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:
> diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc b/tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc
> new file mode 100644
> index 000000000000..96791e120b7d
> --- /dev/null
> +++ b/tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc
> @@ -0,0 +1,51 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +# description: BTF event with typecast and percpu access
> +# requires: dynamic_events "this_cpu_read(<fetcharg>)":README "[(structname[,field])]<argname>[->field[->field|.field...]]":README
> +
> +# Check if the sample module is loaded
> +if ! lsmod | grep -q trace_events_sample; then
> + modprobe trace-events-sample || exit_unsupported
I think this should be exit_unresolved.
> +fi
[...]
> diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/btf_typecast_accepted.tc b/tools/testing/selftests/ftrace/test.d/dynevent/btf_typecast_accepted.tc
> new file mode 100644
> index 000000000000..acf0b5a917d3
> --- /dev/null
> +++ b/tools/testing/selftests/ftrace/test.d/dynevent/btf_typecast_accepted.tc
> @@ -0,0 +1,107 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +# description: BTF typecast and percpu access syntax validation
> +# requires: dynamic_events "this_cpu_read(<fetcharg>)":README "[(structname[,field])]<argname>[->field[->field|.field...]]":README
> +
> +KPROBES=
> +FPROBES=
> +
> +if grep -qF "p[:[<group>/][<event>]] <place> [<args>]" README ; then
> + KPROBES=yes
> +fi
> +if grep -qF "f[:[<group>/][<event>]] <func-name>[%return] [<args>]" README ; then
> + FPROBES=yes
> +fi
> +
> +if [ -z "$KPROBES" -a -z "$FPROBES" ] ; then
> + exit_unsupported
> +fi
> +
> +echo 0 > events/enable
> +echo > dynamic_events
> +
> +# Load trace-events-sample module if available to have per-CPU counter structure defined
> +if ! lsmod | grep -q trace_events_sample; then
> + modprobe trace-events-sample || true
I think this must be tested, and if the module is not found,
the test must return UNRESOLVED error.
> +fi
[...]
> diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc
> index 0e65e787e426..1d6d1cf94f16 100644
> --- a/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc
> +++ b/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc
> @@ -21,8 +21,17 @@ check_error 'e:foo/^bar.1 syscalls/sys_enter_openat' # BAD_EVENT_NAME
>
> check_error 'e:foo/bar syscalls/sys_enter_openat arg=^$foo' # BAD_ATTACH_ARG
>
> +check_error 'e:foo/bar syscalls/sys_enter_openat arg=^COMM' # NO_EVENT_FIELD
> +if grep -q '\\$current' README; then
Sashiko found a problem here. Indeed. this is wrong. See below:
> diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc
> index c817158b99db..e12dc967ec76 100644
> --- a/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc
> +++ b/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc
> @@ -28,4 +28,9 @@ if grep -q ".*symstr.*" README; then
> check_error 'p /bin/sh:10 $stack0:^symstr' # BAD_TYPE
> fi
>
> +# $current is not supported by uprobe
> +if grep -q "\$current.*" README; then
This is correct check.
Let me fix those.
Thanks,
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Alan Stern @ 2026-06-28 15:48 UTC (permalink / raw)
To: Michal Pecio
Cc: Nikhil Solanke, linux-usb, gregkh, linux-kernel, stable, corbet,
skhan, linux-doc
In-Reply-To: <20260628165040.76fd608d.michal.pecio@gmail.com>
On Sun, Jun 28, 2026 at 04:50:40PM +0200, Michal Pecio wrote:
> On Sun, 28 Jun 2026 09:55:07 -0400, Alan Stern wrote:
> > On Sun, Jun 28, 2026 at 11:53:09AM +0530, Nikhil Solanke wrote:
> > > I need some help with the USB_QUIRK_DELAY_INIT part. I can't figure
> > > out how to make it properly work with my patch because of the
> > > following reasons:
> > >
> > > 1. I don't want to move it to the top because, from my pov, there
> > > must have been some reason for placing that quirk where it is now.
> > > so i don't want to mess with it.
>
> git blame is your friend:
>
> The DELAY_INIT quirk only reduces the frequency of enumeration
> failures with the Logitech HD Pro C920 and C930e webcams, but does
> not quite eliminate them. We have found that adding a delay of 100ms
> between the first and second Get Configuration request makes the
> device enumerate perfectly reliable even after several weeks of
> extensive testing. The reasons for that are anyone's guess,
>
> > >
> > > 2. Regarding my idea of adding a condition — so that it doesn't
> > > change the behavior when the quirk isn't set — if the full
> > > configuration set exceeds 255 bytes, we would have to issue a 2nd
> > > request. In this case the existing behavior would be more justified.
> > >
> > > So, I'm a bit confused about how to implement this properly. Adding
> > > yet another condition to fix the second case doesn't feel right to
> > > me. It would look unnecessarily complicated. I would appreciate a
> > > bit of help and advice.
> >
> > If the 255-byte quirk flag isn't set, do the delay before the second
> > transfer just as it is now.
> >
> > If the 255-byte quirk flag is set, do the delay before the first
> > transfer. If a second transfer is needed, you can do a second delay
> > before it or not -- I suspect it doesn't matter. If you want to be
> > safe, add the second delay.
>
> How about "keep unrelated changes out of a stable patch", i.e. always
> do the delay (if any) after the first request, regardless of size?
This is not an unrelated change. Rather, it's deciding on how to behave
in an entirely new control pathway -- the one where the 255-byte quirk
flag is set. The old pathway is completely unaffected.
I suspect no devices will have both this quirk flag and the DELAY_INIT
flag set, which means the location of any delays in the new pathway
won't matter at all since they will never be used. But even if some
such devices do turn up, adding an extra unecessary 200 ms to an
initialization that is already at least 2200 ms long won't make much
difference.
Alan Stern
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Michal Pecio @ 2026-06-28 14:50 UTC (permalink / raw)
To: Alan Stern
Cc: Nikhil Solanke, linux-usb, gregkh, linux-kernel, stable, corbet,
skhan, linux-doc
In-Reply-To: <02060df3-b8c5-4a86-b3ab-3a28eea8a562@rowland.harvard.edu>
On Sun, 28 Jun 2026 09:55:07 -0400, Alan Stern wrote:
> On Sun, Jun 28, 2026 at 11:53:09AM +0530, Nikhil Solanke wrote:
> > I need some help with the USB_QUIRK_DELAY_INIT part. I can't figure
> > out how to make it properly work with my patch because of the
> > following reasons:
> >
> > 1. I don't want to move it to the top because, from my pov, there
> > must have been some reason for placing that quirk where it is now.
> > so i don't want to mess with it.
git blame is your friend:
The DELAY_INIT quirk only reduces the frequency of enumeration
failures with the Logitech HD Pro C920 and C930e webcams, but does
not quite eliminate them. We have found that adding a delay of 100ms
between the first and second Get Configuration request makes the
device enumerate perfectly reliable even after several weeks of
extensive testing. The reasons for that are anyone's guess,
> >
> > 2. Regarding my idea of adding a condition — so that it doesn't
> > change the behavior when the quirk isn't set — if the full
> > configuration set exceeds 255 bytes, we would have to issue a 2nd
> > request. In this case the existing behavior would be more justified.
> >
> > So, I'm a bit confused about how to implement this properly. Adding
> > yet another condition to fix the second case doesn't feel right to
> > me. It would look unnecessarily complicated. I would appreciate a
> > bit of help and advice.
>
> If the 255-byte quirk flag isn't set, do the delay before the second
> transfer just as it is now.
>
> If the 255-byte quirk flag is set, do the delay before the first
> transfer. If a second transfer is needed, you can do a second delay
> before it or not -- I suspect it doesn't matter. If you want to be
> safe, add the second delay.
How about "keep unrelated changes out of a stable patch", i.e. always
do the delay (if any) after the first request, regardless of size?
Regards,
Michal
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Alan Stern @ 2026-06-28 13:55 UTC (permalink / raw)
To: Nikhil Solanke
Cc: linux-usb, gregkh, linux-kernel, michal.pecio, stable, corbet,
skhan, linux-doc
In-Reply-To: <CAFgddhLZ9SuOzG_6mW09j9aDkCp6TedpNkzJ6TUD+DnR3TDLKA@mail.gmail.com>
On Sun, Jun 28, 2026 at 11:53:09AM +0530, Nikhil Solanke wrote:
> I need some help with the USB_QUIRK_DELAY_INIT part. I can't figure
> out how to make it properly work with my patch because of the
> following reasons:
>
> 1. I don't want to move it to the top because, from my pov, there must
> have been some reason for placing that quirk where it is now. so i
> don't want to mess with it.
>
> 2. Regarding my idea of adding a condition — so that it doesn't change
> the behavior when the quirk isn't set — if the full configuration set
> exceeds 255 bytes, we would have to issue a 2nd request. In this case
> the existing behavior would be more justified.
>
> So, I'm a bit confused about how to implement this properly. Adding
> yet another condition to fix the second case doesn't feel right to me.
> It would look unnecessarily complicated. I would appreciate a bit of
> help and advice.
If the 255-byte quirk flag isn't set, do the delay before the second
transfer just as it is now.
If the 255-byte quirk flag is set, do the delay before the first
transfer. If a second transfer is needed, you can do a second delay
before it or not -- I suspect it doesn't matter. If you want to be
safe, add the second delay.
Alan Stern
^ permalink raw reply
* [RFC] Doc: ABI: add files to MAINTAINERS
From: Manuel Ebner @ 2026-06-28 11:42 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, linux-doc; +Cc: Jonathan Cameron, Manuel Ebner
Due to my last couple patches to /ABI I bumped in the issue of orphaned files.
This is my effort to improve this. My plan is to send the mail below per
subsystem. Can I add the text as is below or should I add a git-patch?
I will add more files but I wanted to clarify this before continuing.
Thanks
Manuel
---
Doc: ABI: add files to MAINTAINERS [SUBSYSTEM]
Unfortunately the get_maintainer script didn't return your e-mail-address
for following files below. Because of the output of git log I assume you
are the maintainer. Please consider adding path(s) to file(s) or directories
to your subsystem in MAINTAINERS. As suggested by Jonathan Cameron [1].
Thanks
Manuel
[1] https://lore.kernel.org/all/20260611171520.0a96ac83@jic23-huawei/#t
---
INFINIBAND SUBSYSTEM
M: Jason Gunthorpe <jgg@nvidia.com>
M: Leon Romanovsky <leonro@nvidia.com>
L: linux-rdma@vger.kernel.org
S: Supported
W: https://github.com/linux-rdma/rdma-core
Q: http://patchwork.kernel.org/project/linux-rdma/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git
F: Documentation/devicetree/bindings/infiniband/
F: Documentation/infiniband/
F: drivers/infiniband/
F: include/rdma/
F: include/trace/events/ib_mad.h
F: include/trace/events/ib_umad.h
F: include/trace/misc/rdma.h
F: include/uapi/linux/if_infiniband.h
F: include/uapi/rdma/
F: samples/bpf/ibumad_kern.c
F: samples/bpf/ibumad_user.c
F: tools/testing/selftests/rdma/
+F: Documentation/ABI/stable/sysfs-class-infiniband
DMI/SMBIOS SUPPORT
M: Jean Delvare <jdelvare@suse.com>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging.git dmi-for-
next
F: Documentation/ABI/testing/sysfs-firmware-dmi-tables
F: drivers/firmware/dmi-id.c
F: drivers/firmware/dmi_scan.c
F: include/linux/dmi.h
+F: Documentation/ABI/testing/sysfs-firmware-dmi-entries
GOOGLE FIRMWARE DRIVERS
M: Tzung-Bi Shih <tzungbi@kernel.org>
R: Brian Norris <briannorris@chromium.org>
R: Julius Werner <jwerner@chromium.org>
L: chrome-platform@lists.linux.dev
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git
F: drivers/firmware/google/
F: include/linux/coreboot.h
+F: Documentation/ABI/testing/sysfs-firmware-gsmi
DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: "Rafael J. Wysocki" <rafael@kernel.org>
M: Danilo Krummrich <dakr@kernel.org>
L: driver-core@lists.linux.dev
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git
F: Documentation/core-api/kobject.rst
F: Documentation/driver-api/driver-model/
F: drivers/base/
F: fs/debugfs/
F: fs/sysfs/
F: include/linux/device/
F: include/linux/debugfs.h
F: include/linux/device.h
F: include/linux/fwnode.h
F: include/linux/kobj*
F: include/linux/ksysfs.h
F: include/linux/property.h
F: include/linux/sysfs.h
F: kernel/ksysfs.c
F: lib/kobj*
F: rust/kernel/debugfs.rs
F: rust/kernel/debugfs/
F: rust/kernel/device.rs
F: rust/kernel/device/
F: rust/kernel/device_id.rs
F: rust/kernel/devres.rs
F: rust/kernel/driver.rs
F: rust/kernel/faux.rs
F: rust/kernel/platform.rs
F: rust/kernel/soc.rs
F: samples/rust/rust_debugfs.rs
F: samples/rust/rust_debugfs_scoped.rs
F: samples/rust/rust_driver_platform.rs
F: samples/rust/rust_driver_faux.rs
F: samples/rust/rust_soc.rs
+F: Documentation/ABI/testing/sysfs-uevent
^ permalink raw reply
* Re: [PATCH 19/19] MAINTAINERS: add Rambus CryptoManager Hub (CMH)
From: Krzysztof Kozlowski @ 2026-06-28 8:41 UTC (permalink / raw)
To: Krishnamoorthy, Saravanakrishnan
Cc: Albert Ou, Ousherovitch, Alex, Conor Dooley, David S. Miller,
Herbert Xu, Jonathan Corbet, Krzysztof Kozlowski, Palmer Dabbelt,
Paul Walmsley, Rob Herring, Shuah Khan, Alexandre Ghiti,
devicetree@vger.kernel.org, Wittenauer, Joel,
linux-api@vger.kernel.org, linux-crypto@vger.kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org, linux-riscv@lists.infradead.org,
Shuah Khan, SIPSupport, Nguyen, Thi
In-Reply-To: <SA1PR04MB985196991689AF3F3DCD349BC2EB2@SA1PR04MB9851.namprd04.prod.outlook.com>
On 26/06/2026 19:22, Krishnamoorthy, Saravanakrishnan wrote:
> Hi Krzysztof,
>
> Thanks for the review - all fair, and we'll fix them in v2:
>
> Drop L: sipsupport@rambus.com (keeping only linux-crypto).
> Drop the T: line - we don't maintain a tree; the driver will go through the crypto tree.
>
> Yes, Joel and Thi reviewed and acknowledged with the statement of oversight.
Do not top post, please.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v2 1/3] dt-bindings: watchdog: npcm: add GCR syscon property
From: Tomer Maimon @ 2026-06-28 7:01 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: andrew, wim, linux, robh, krzk+dt, conor+dt, openbmc,
linux-watchdog, linux-doc, devicetree, linux-kernel, avifishman70,
tali.perry1, venture, yuenn, benjaminfair, corbet, skhan, joel
In-Reply-To: <20260623-ochre-spoonbill-of-security-a4bc42@quoll>
Hi Krzysztof,
On Tue, 23 Jun 2026 at 11:05, Krzysztof Kozlowski <krzk@kernel.org> wrote:
>
> On Mon, Jun 22, 2026 at 11:30:44AM +0300, Tomer Maimon wrote:
> > Describe syscon property that handles general control registers (GCR) in
> > Nuvoton BMC NPCM watchdog driver.
>
> Why? Well, you try to answer by saying something about driver, but we do
> not add bindings for drivers. Instead hardware should be the reason.
>
> Anyway, why is this needed now?
It is needed for accessing the reset indication registers. I would
mention it in the commit message.
>
> >
> > Signed-off-by: Tomer Maimon <tmaimon77@gmail.com>
> > ---
> > .../devicetree/bindings/watchdog/nuvoton,npcm750-wdt.yaml | 6 ++++++
> > 1 file changed, 6 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/watchdog/nuvoton,npcm750-wdt.yaml b/Documentation/devicetree/bindings/watchdog/nuvoton,npcm750-wdt.yaml
> > index 7aa30f5b5c49..4f00f099b2d2 100644
> > --- a/Documentation/devicetree/bindings/watchdog/nuvoton,npcm750-wdt.yaml
> > +++ b/Documentation/devicetree/bindings/watchdog/nuvoton,npcm750-wdt.yaml
> > @@ -40,6 +40,12 @@ properties:
> > clock-frequency:
> > description: Frequency in Hz of the clock that drives the NPCM timer.
> >
> > + nuvoton,sysgcr:
> > + $ref: /schemas/types.yaml#/definitions/phandle
> > + description:
> > + a phandle to access GCR registers on NPCM750 and NPCM845 watchdog
> > + instances.
>
> Here you write also for what purpose.
>
>
> Best regards,
> Krzysztof
>
Thanks,
Tomer
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Nikhil Solanke @ 2026-06-28 6:23 UTC (permalink / raw)
To: Alan Stern
Cc: linux-usb, gregkh, linux-kernel, michal.pecio, stable, corbet,
skhan, linux-doc
In-Reply-To: <eb0dfd45-91c5-49ba-a297-b183dbc52c8c@rowland.harvard.edu>
I need some help with the USB_QUIRK_DELAY_INIT part. I can't figure
out how to make it properly work with my patch because of the
following reasons:
1. I don't want to move it to the top because, from my pov, there must
have been some reason for placing that quirk where it is now. so i
don't want to mess with it.
2. Regarding my idea of adding a condition — so that it doesn't change
the behavior when the quirk isn't set — if the full configuration set
exceeds 255 bytes, we would have to issue a 2nd request. In this case
the existing behavior would be more justified.
So, I'm a bit confused about how to implement this properly. Adding
yet another condition to fix the second case doesn't feel right to me.
It would look unnecessarily complicated. I would appreciate a bit of
help and advice.
Thanks,
Nikhil Solanke
^ permalink raw reply
* Re: [PATCH net-next] Documentation: networking: Add a test plan for ethtool pause validation
From: Andrew Lunn @ 2026-06-27 23:46 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Maxime Chevallier, davem, Eric Dumazet, Paolo Abeni, Simon Horman,
Russell King, Heiner Kallweit, Jonathan Corbet, Shuah Khan,
Oleksij Rempel, Vladimir Oltean, Florian Fainelli,
thomas.petazzoni, netdev, linux-kernel, linux-doc
In-Reply-To: <20260627143028.5afed23a@kernel.org>
On Sat, Jun 27, 2026 at 02:30:28PM -0700, Jakub Kicinski wrote:
> On Sat, 27 Jun 2026 07:34:31 +0200 Maxime Chevallier wrote:
> > > This is very far from what existing python tests do in netdev.
> >
> > We can probably drop the class, as it is with this discussion, it's merely a way
> > to regroup doc common to similar tests. The rest really is the usual set of
> > ksft funcs you can feed to the run function, with a set of ksft_ethtool_*
> > annotators for generic checks.
>
> The common way of checking prereqs in the tests is to call a function
> called require_xyz() which then raises a skip. At a quick glance - the
> rss_api and xdp_metadata are good tests to get a sense of the usual format.
The counter example is the ksft_disruptive() decorator.
Pythons own unittest framework makes use of decorators to skip
tests. Its the Pythonic way.
Andrew
^ permalink raw reply
* Re: [External] [PATCH v2 4/8] riscv_cbqri: Add capacity controller probe and allocation device ops
From: Drew Fustini @ 2026-06-27 22:10 UTC (permalink / raw)
To: yunhui cui
Cc: Adrien Ricciardi, Alexandre Ghiti, Atish Kumar Patra, Atish Patra,
Babu Moger, Ben Horgan, Borislav Petkov, Chen Pei, Conor Dooley,
Conor Dooley, Dave Hansen, Dave Martin, Fenghua Yu, Gong Shuai,
Gong Shuai, guo.wenjia23, James Morse, Kornel Dulęba,
Krzysztof Kozlowski, liu.qingtao2, Liu Zhiwei, Palmer Dabbelt,
Paul Walmsley, Peter Newman, Radim Krčmář,
Reinette Chatre, Rob Herring, Samuel Holland,
Sebastian Andrzej Siewior, Tony Luck, Vasudevan Srinivasan,
Ved Shanbhogue, Weiwei Li, linux-kernel, linux-riscv, x86,
devicetree, linux-rt-devel, linux-doc
In-Reply-To: <CAEEQ3w=ZVtHPdLfN0tTzG8AACu+rjhEFWY5pCg+uxvmr7ofqfA@mail.gmail.com>
On Sat, Jun 27, 2026 at 05:31:03PM +0800, yunhui cui wrote:
> Hi Drew,
>
> On Thu, Jun 25, 2026 at 9:41 AM Drew Fustini <fustini@kernel.org> wrote:
> >
> > Add support for the RISC-V CBQRI capacity controller. A platform driver
> > passes a cbqri_controller_info descriptor together with the cache level
> > to riscv_cbqri_register_cc_dt(), which probes the controller and adds it
> > to the controller list.
> >
> > Assisted-by: Claude:claude-opus-4-7
> > Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
[..]
> > diff --git a/drivers/resctrl/cbqri_devices.c b/drivers/resctrl/cbqri_devices.c
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..8ad9df404f65d5d82722cf8b78f02936c489ca6d
> > --- /dev/null
> > +++ b/drivers/resctrl/cbqri_devices.c
[..]
> > +
> > +/* Set capacity block mask (cc_block_mask) */
> > +static void cbqri_set_cbm(struct cbqri_controller *ctrl, u64 cbm)
> > +{
> > + iowrite64(cbm, ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
>
> The CBQRI spec allows naturally aligned 4-byte accesses and only guarantees
> atomicity for 4-byte accesses; 8-byte atomicity is unspecified.
>
> Would 32-bit split accesses be preferable here instead of relying on
> ioread64/iowrite64? This may also make the driver less dependent on native
> 64-bit MMIO support.
I suppose there could be systems that are RV64 but do 4-byte access for
the CBQRI registers. You are right the spec only guarantees atomicity
for naturally aligned 4-byte accesses and leaves 8-byte atomicity
unspecified.
I will switch the controller register accesses to 32-bit reads and
writes. The driver rejects ncblks > 32, so cc_block_mask only uses its
low 32 bits. For cc_alloc_ctl, the writable fields all sit in the low
word while the status and busy bits are read-only in the high word. A
read can reconstruct the value from two 32-bit reads and a write only
needs the low word.
Thanks,
Drew
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox