* [PATCH 00/24] vfs/nfsd: add support for CB_NOTIFY callbacks in directory delegations
From: Jeff Layton @ 2026-04-07 13:21 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Chuck Lever,
Alexander Aring, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Jonathan Corbet, Shuah Khan, NeilBrown,
Olga Kornievskaia, Dai Ngo, Tom Talpey, Trond Myklebust,
Anna Schumaker, Amir Goldstein
Cc: Calum Mackay, linux-fsdevel, linux-kernel, linux-trace-kernel,
linux-doc, linux-nfs, Jeff Layton
This patchset builds on the directory delegation work we did a few
months ago, to add support for CB_NOTIFY callbacks for some events. In
particular, creates, unlinks and renames. The server also sends updated
directory attributes in the notifications. With this support, the client
can register interest in a directory and get notifications about changes
within it without losing its lease.
The series starts with patches to allow the vfs to ignore certain types
of events on directories. nfsd can then request these sorts of
delegations on directories, and then set up inotify watches on the
directory to trigger sending CB_NOTIFY events.
This has mainly been tested with pynfs, with some new testcases that
I'll be posting soon. They seem to work fine with those tests, but I
don't think we'll want to merge these until we have a complete
client-side implementation to test against.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
Jeff Layton (24):
filelock: add support for ignoring deleg breaks for dir change events
filelock: add a tracepoint to start of break_lease()
filelock: add an inode_lease_ignore_mask helper
nfsd: add protocol support for CB_NOTIFY
nfs_common: add new NOTIFY4_* flags proposed in RFC8881bis
nfsd: allow nfsd to get a dir lease with an ignore mask
vfs: add fsnotify_modify_mark_mask()
nfsd: update the fsnotify mark when setting or removing a dir delegation
nfsd: make nfsd4_callback_ops->prepare operation bool return
nfsd: add callback encoding and decoding linkages for CB_NOTIFY
nfsd: use RCU to protect fi_deleg_file
nfsd: add data structures for handling CB_NOTIFY
nfsd: add notification handlers for dir events
nfsd: add tracepoint to dir_event handler
nfsd: apply the notify mask to the delegation when requested
nfsd: add helper to marshal a fattr4 from completed args
nfsd: allow nfsd4_encode_fattr4_change() to work with no export
nfsd: send basic file attributes in CB_NOTIFY
nfsd: allow encoding a filehandle into fattr4 without a svc_fh
nfsd: add a fi_connectable flag to struct nfs4_file
nfsd: add the filehandle to returned attributes in CB_NOTIFY
nfsd: properly track requested child attributes
nfsd: track requested dir attributes
nfsd: add support to CB_NOTIFY for dir attribute changes
Documentation/sunrpc/xdr/nfs4_1.x | 264 ++++++++++++++-
fs/attr.c | 2 +-
fs/locks.c | 89 +++++-
fs/namei.c | 31 +-
fs/nfsd/filecache.c | 57 +++-
fs/nfsd/nfs4callback.c | 60 +++-
fs/nfsd/nfs4layouts.c | 5 +-
fs/nfsd/nfs4proc.c | 15 +
fs/nfsd/nfs4state.c | 524 ++++++++++++++++++++++++++----
fs/nfsd/nfs4xdr.c | 300 ++++++++++++++---
fs/nfsd/nfs4xdr_gen.c | 601 ++++++++++++++++++++++++++++++++++-
fs/nfsd/nfs4xdr_gen.h | 20 +-
fs/nfsd/state.h | 70 +++-
fs/nfsd/trace.h | 21 ++
fs/nfsd/xdr4.h | 5 +
fs/nfsd/xdr4cb.h | 12 +
fs/notify/mark.c | 29 ++
fs/posix_acl.c | 4 +-
fs/xattr.c | 4 +-
include/linux/filelock.h | 54 +++-
include/linux/fsnotify_backend.h | 1 +
include/linux/nfs4.h | 127 --------
include/linux/sunrpc/xdrgen/nfs4_1.h | 291 ++++++++++++++++-
include/trace/events/filelock.h | 38 ++-
include/uapi/linux/nfs4.h | 2 -
25 files changed, 2321 insertions(+), 305 deletions(-)
---
base-commit: bd5b9fd5e3d55bc412cec4bebe5a11da2151de4a
change-id: 20260325-dir-deleg-339066dd1017
Best regards,
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply
* Re: [PATCH] docs: proc: document ProtectionKey in smaps
From: Vlastimil Babka (SUSE) @ 2026-04-07 13:00 UTC (permalink / raw)
To: Kevin Brodsky, linux-doc
Cc: linux-kernel, Yury Khrustalev, Jonathan Corbet, Shuah Khan,
Dave Hansen, Andrew Morton, Lorenzo Stoakes, David Hildenbrand,
Mark Rutland, linux-fsdevel, linux-mm
In-Reply-To: <20260407125133.564182-1-kevin.brodsky@arm.com>
On 4/7/26 14:51, Kevin Brodsky wrote:
> The ProtectionKey entry was added in v4.9; back then it was
> x86-specific, but it now lives in generic code and applies to all
> architectures supporting pkeys (currently x86, power, arm64).
>
> Time to document it: add a paragraph to proc.rst about the
> ProtectionKey entry.
>
> Reported-by: Yury Khrustalev <yury.khrustalev@arm.com>
> Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
> ---
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Shuah Khan <skhan@linuxfoundation.org>
> Cc: Dave Hansen <dave.hansen@linux.intel.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Lorenzo Stoakes <ljs@kernel.org>
> Cc: Vlastimil Babka <vbabka@kernel.org>
> Cc: David Hildenbrand <david@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: linux-fsdevel@vger.kernel.org
> Cc: linux-mm@kvack.org
> ---
> Documentation/filesystems/proc.rst | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst
> index b0c0d1b45b99..d673cad7dbe4 100644
> --- a/Documentation/filesystems/proc.rst
> +++ b/Documentation/filesystems/proc.rst
> @@ -549,6 +549,10 @@ does not take into account swapped out page of underlying shmem objects.
> naturally aligned THP pages of any currently enabled size. 1 if true, 0
> otherwise.
>
> +If both the kernel and the system support protection keys (pkeys),
> +"ProtectionKey" indicates the memory protection key associated with the
> +virtual memory area.
> +
> "VmFlags" field deserves a separate description. This member represents the
> kernel flags associated with the particular virtual memory area in two letter
> encoded manner. The codes are the following:
^ permalink raw reply
* [PATCH] docs: proc: document ProtectionKey in smaps
From: Kevin Brodsky @ 2026-04-07 12:51 UTC (permalink / raw)
To: linux-doc
Cc: linux-kernel, Kevin Brodsky, Yury Khrustalev, Jonathan Corbet,
Shuah Khan, Dave Hansen, Andrew Morton, Lorenzo Stoakes,
Vlastimil Babka, David Hildenbrand, Mark Rutland, linux-fsdevel,
linux-mm
The ProtectionKey entry was added in v4.9; back then it was
x86-specific, but it now lives in generic code and applies to all
architectures supporting pkeys (currently x86, power, arm64).
Time to document it: add a paragraph to proc.rst about the
ProtectionKey entry.
Reported-by: Yury Khrustalev <yury.khrustalev@arm.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Shuah Khan <skhan@linuxfoundation.org>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-mm@kvack.org
---
Documentation/filesystems/proc.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst
index b0c0d1b45b99..d673cad7dbe4 100644
--- a/Documentation/filesystems/proc.rst
+++ b/Documentation/filesystems/proc.rst
@@ -549,6 +549,10 @@ does not take into account swapped out page of underlying shmem objects.
naturally aligned THP pages of any currently enabled size. 1 if true, 0
otherwise.
+If both the kernel and the system support protection keys (pkeys),
+"ProtectionKey" indicates the memory protection key associated with the
+virtual memory area.
+
"VmFlags" field deserves a separate description. This member represents the
kernel flags associated with the particular virtual memory area in two letter
encoded manner. The codes are the following:
--
2.51.2
^ permalink raw reply related
* RE: [PATCH v6 4/4] iio: adc: ad4691: add SPI offload support
From: Sabau, Radu bogdan @ 2026-04-07 12:38 UTC (permalink / raw)
To: David Lechner, Lars-Peter Clausen, Hennerich, Michael,
Jonathan Cameron, Sa, Nuno, Andy Shevchenko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Uwe Kleine-König,
Liam Girdwood, Mark Brown, Linus Walleij, Bartosz Golaszewski,
Philipp Zabel, Jonathan Corbet, Shuah Khan
Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org,
linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org
In-Reply-To: <420dba4a-0c31-47bc-b84a-5d29702b115e@baylibre.com>
> -----Original Message-----
> From: David Lechner <dlechner@baylibre.com>
> Sent: Monday, April 6, 2026 4:44 PM
...
> >> If we stop the PWM after an IRQ, then we don't get a consistent sample
> rate.
> >> Ideally, we would leave the PWM running and just pick a rate slow enough
> >> that
> >> there is plenty of time to read the data. Otherwise, this mode doesn't seem
> >> particularly useful.
> >
> > Should there also be a condition when setting the sampling frequency, that
> will
> > protect from setting too fast sample rates?
>
> I haven't figured out a good way to do this since the real max rate
> depends on a lot of different things and when not using offloading,
> the time it takes to do SPI xfers is non-deterministic.
>
There is another question that pops in my mind. How would osr work for the buffer
sampling frequency? Since that controls the PWM period, and if say channels 0, 1, 2
are used with osr 1, 4, 8 respectively, then it would mean the PWM "required
frequency" would be something like :
osr_avg = (osr[0] + osr[1] + osr[2]) / 3;
actual_samp_freq = samp_freq / osr_avg;
The problem here being - beside what you already stated that the xfer is non-deterministic -
that the implementation could be fragile, since buffer_sampling frequency wouldn't really
know for sure which channels are enabled and so couldn't account for osr in a safe way.
The solution I propose is letting PWM run from buffer enable to disable, the whole time,
while only disabling/enabling the irq in the handler before and after spi transfer, to also
assure they are rightly happening. This way, the PWM runs at the desired rate, the only
thing here is that if the PWM is set to a too high of a frequency, some periods will be
missed, which is normal if you think about it.
For example : if the user uses a 1MHz SPI for some reason, and wants a PWM of 500kHz,
and enables 4 channels with maximum osr and maximum per-channel samp_freq.
tPWM = 1/500kHz = 2us;
tOSR_per_channel = 32 * tOSC = 32us;
-> tPWM is already too fast, but there would be more
tOSR_total = 4 * 32 = 128us;
tSPI_per_channel = 32 * tSPI = 32us (too say the least)
tSPI_total = 128us;
tSEQ_total = 256us (again, to say the least)
so the actual sampling freq is 256us in this case, but that's non-determinstic, since this
is nothing but a best case scenario, time would vary between 256-280us to say so in
reality.
I would then say so, setting a too high buffer sampling frequency (PWM frequency) implies
by itself that samples will be missed.
So then, PWM freq should be set by the user, to the desired value without capping of the
value since that capping depends on too much run-time variables set by the same user.
^ permalink raw reply
* Re: [PATCH v7 1/2] docs: s390/pci: Improve and update PCI documentation
From: Gerd Bayer @ 2026-04-07 12:28 UTC (permalink / raw)
To: Niklas Schnelle, Bjorn Helgaas, Jonathan Corbet, Lukas Wunner,
Shuah Khan
Cc: Farhan Ali, Alexander Gordeev, Christian Borntraeger,
Gerald Schaefer, Heiko Carstens, Julian Ruess, Matthew Rosato,
Peter Oberparleiter, Ramesh Errabolu, Sven Schnelle,
Vasily Gorbik, linux-doc, linux-kernel, linux-pci, linux-s390,
Randy Dunlap, Gerd Bayer
In-Reply-To: <20260407-uid_slot-v7-1-e50f7976124e@linux.ibm.com>
On Tue, 2026-04-07 at 12:12 +0200, Niklas Schnelle wrote:
[... snip ...]
> Similarly add documentation for the fidparm attribute added by commit
> 99ad39306a62 ("s390/pci: Expose FIDPARM attribute in sysfs") and
> add a list of pft values and their names.
>
[... snip ...]
> ---
> Documentation/arch/s390/pci.rst | 144 +++++++++++++++++++++++++++-------------
> 1 file changed, 97 insertions(+), 47 deletions(-)
>
> diff --git a/Documentation/arch/s390/pci.rst b/Documentation/arch/s390/pci.rst
> index d5755484d8e75c7bf67a350e61bbe04f0452a2fa..8cb0a1e784a7cfc5df1e04a4154ba02c9ecf46cc 100644
> --- a/Documentation/arch/s390/pci.rst
> +++ b/Documentation/arch/s390/pci.rst
> @@ -6,6 +6,7 @@ S/390 PCI
>
> Authors:
> - Pierre Morel
> + - Niklas Schnelle
>
> Copyright, IBM Corp. 2020
>
> @@ -27,14 +28,16 @@ Command line parameters
> debugfs entries
> ---------------
>
> -The S/390 debug feature (s390dbf) generates views to hold various debug results in sysfs directories of the form:
> +The S/390 debug feature (s390dbf) generates views to hold various debug results
> +in sysfs directories of the form:
>
> * /sys/kernel/debug/s390dbf/pci_*/
>
> For example:
>
> - /sys/kernel/debug/s390dbf/pci_msg/sprintf
> - Holds messages from the processing of PCI events, like machine check handling
> +
> + holds messages from the processing of PCI events, like machine check handling
> and setting of global functionality, like UID checking.
>
> Change the level of logging to be more or less verbose by piping
> @@ -47,87 +50,134 @@ Sysfs entries
>
[... snip ...]
> +
> +* /sys/firmware/clp/uid_is_unique:
As much as I had loved the attribute to be named as such, or even
better /sys/firmware/clp/uids_are_unique, I find commit b043a81ce3ee
("s390/pci: Expose firmware provided UID Checking state in sysfs") has
introduced
/sys/firmware/clp/uid_checking.
Sorry, that this did slip me...
Gerd
^ permalink raw reply
* Re: [RFC net-next 15/15] Documentation: networking: add ipxlat translator guide
From: Daniel Gröber @ 2026-04-07 11:30 UTC (permalink / raw)
To: Xavier Hsinyuan
Cc: ralf, antonio, corbet, davem, edumazet, horms, kuba, linux-doc,
linux-kernel, netdev, pabeni, skhan
In-Reply-To: <TYRPR01MB12666EEA0B8007166ED446088CA5DA@TYRPR01MB12666.jpnprd01.prod.outlook.com>
On Mon, Apr 06, 2026 at 10:50:44PM +0800, Xavier Hsinyuan wrote:
> >+ $ ./tools/net/ynl/pyynl/cli.py --family ipxlat --json '{"ifindex": $IID, \
> >+ "config": {"xlat-prefix6": "'$HEX_ADDR'", "prefix-len": 96} }'
> Should this be like:
> $ python3 /extends/pyynl/cli.py --spec ipxlat.yaml --do dev-set --json \
> '{"ifindex": "'$IID'", "config": {"xlat-prefix6": \
> {"prefix":"'$ADDR_HEX'", "prefix-len": 96}}}'
Indeed, the JSON is just wrong and --do dev-set is missing. However
`--family ipxlat` works for me and looking at the code is basically the
same as specifying --spec.
Could you try this:
$ JSON='{"ifindex": '"$IID"', "config": {"xlat-prefix6": { "prefix": "'$ADDR_HEX'", "prefix-len": 96}}}'
$ ./tools/net/ynl/pyynl/cli.py --family ipxlat --do dev-set --json "$JSON"
> >+Address Translation
> >+-------------------
> >+
> >+The ipxlat address translation algorithm is stateless, per RFC-ADDR_, all
> >+possible IPv4 addressess are mapped one-to-one into the translation prefix,
> >+optionally including a non-standard "suffix". See `RFC-ADDR Section 2.2
> >+<https://datatracker.ietf.org/doc/html/rfc6052#section-2.2>`_.
> >+
> >+.. _RFC-ADDR: https://datatracker.ietf.org/doc/html/rfc6052
> >+
> >+IPv6 addressess outside this prefix are rejected with ICMPv6 errors with
> >+the notable exception of ICMPv6 errors originating from untranslatable
> >+source addressess. These are translated to be sourced from the IPv4 Dummy
> >+Address ``192.0.0.8`` (per I-D-dummy_) instead to maintain IPv4 traceroute
> >+visibility.
>
> Would it help to add a few example? For instance,
> - Interface ipxlat0 with prefix6=64:ff9b::/96.
> - A IPv6 packet with src=64:ff9b::192.0.2.1 dst=64:ff9b::198.51.100.1,
> was send to ipxlat0.
> - Then a IPv4 packet with src=192.0.2.1 dst=198.51.100.1 was received from
> ipxlat0.
I worry once we start with that we're really just re-stating what's already
extensively documented in the RFCs.
How about a reference to RFC 7915 Appendix A? This has a full bidirectional
end-to-end example of how translation operates:
https://datatracker.ietf.org/doc/html/rfc7915#appendix-A
Admittedly using a /96 prefix (which the appendix doesn't) would make it
easier to grok whats going on. Not sure that's reason enough to get into
more detailed examples here.
WDYT?
Thanks,
--Daniel
^ permalink raw reply
* Re: [PATCH] hwmon: (yogafan) various markup improvements
From: Sergio Melas @ 2026-04-07 11:04 UTC (permalink / raw)
To: Randy Dunlap
Cc: linux-kernel, Guenter Roeck, linux-hwmon, Jonathan Corbet,
Shuah Khan, linux-doc
In-Reply-To: <20260407052317.2097791-1-rdunlap@infradead.org>
Thank you, Randy.
I will incorporate these markup improvements into the next version of
the patch set.
On Tue, Apr 7, 2026 at 7:23 AM Randy Dunlap <rdunlap@infradead.org> wrote:
>
> There are several places in yogafan.rst where it appears that lines
> are meant to be presented on their own but instead they are strung
> together due to the lack of markups. Fix these issues by:
>
> - using bullets where needed
> - indenting continuation lines of bulleted items
> - using a table where appropriate
> - using a literal block where appropriate
>
> Fixes: c67c248ca406 ("hwmon: (yogafan) Add support for Lenovo Yoga/Legion fan monitoring")
> Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
> ---
> Cc: Sergio Melas <sergiomelas@gmail.com>
> Cc: Guenter Roeck <linux@roeck-us.net>
> Cc: linux-hwmon@vger.kernel.org
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Shuah Khan <skhan@linuxfoundation.org>
> Cc: linux-doc@vger.kernel.org
>
> Documentation/hwmon/yogafan.rst | 55 ++++++++++++++++--------------
> 1 file changed, 31 insertions(+), 24 deletions(-)
>
> --- linux-next-20260406.orig/Documentation/hwmon/yogafan.rst
> +++ linux-next-20260406/Documentation/hwmon/yogafan.rst
> @@ -7,8 +7,8 @@ Kernel driver yogafan
> Supported chips:
>
> * Lenovo Yoga, Legion, IdeaPad, Slim, Flex, and LOQ Embedded Controllers
> - Prefix: 'yogafan'
> - Addresses: ACPI handle (See Database Below)
> + * Prefix: 'yogafan'
> + * Addresses: ACPI handle (See Database Below)
>
> Author: Sergio Melas <sergiomelas@gmail.com>
>
> @@ -31,19 +31,21 @@ deterministically via a DMI Product Fami
> eliminating the need for runtime heuristics.
>
> 1. 8-bit EC Architecture (Multiplier: 100)
> +
> - **Families:** Yoga, IdeaPad, Slim, Flex.
> - **Technical Detail:** These models allocate a single 8-bit register for
> - tachometer data. Since 8-bit fields are limited to a value of 255, the
> - BIOS stores fan speed in units of 100 RPM (e.g., 42 = 4200 RPM).
> + tachometer data. Since 8-bit fields are limited to a value of 255, the
> + BIOS stores fan speed in units of 100 RPM (e.g., 42 = 4200 RPM).
>
> 2. 16-bit EC Architecture (Multiplier: 1)
> +
> - **Families:** Legion, LOQ.
> - **Technical Detail:** High-performance gaming models require greater
> - precision for fans exceeding 6000 RPM. These use a 16-bit word (2 bytes)
> - storing the raw RPM value directly.
> + precision for fans exceeding 6000 RPM. These use a 16-bit word (2 bytes)
> + storing the raw RPM value directly.
>
> -Filter Details:
> ----------------
> +Filter Details
> +--------------
>
> The RLLag filter is a passive discrete-time first-order lag model that ensures:
> - **Smoothing:** Low-resolution step increments are smoothed into 1-RPM increments.
> @@ -66,8 +68,11 @@ Usage
> -----
>
> The driver exposes standard hwmon sysfs attributes:
> +
> +=============== ============================
> Attribute Description
> fanX_input Filtered fan speed in RPM.
> +=============== ============================
>
>
> Note: If the hardware reports 0 RPM, the filter is bypassed and 0 is reported
> @@ -78,22 +83,24 @@ immediately to ensure the user knows the
> LENOVO FAN CONTROLLER: MASTER REFERENCE DATABASE (2026)
> ====================================================================================================
>
> -MODEL (DMI PN) | FAMILY / SERIES | EC OFFSET | FULL ACPI OBJECT PATH | WIDTH | MULTiplier
> -----------------------------------------------------------------------------------------------------
> -82N7 | Yoga 14cACN | 0x06 | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
> -80V2 / 81C3 | Yoga 710/720 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
> -83E2 / 83DN | Yoga Pro 7/9 | 0xFE | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
> -82A2 / 82A3 | Yoga Slim 7 | 0x06 | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
> -81YM / 82FG | IdeaPad 5 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
> -82JW / 82JU | Legion 5 (AMD) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS (Fan1) | 16-bit | 1
> -82JW / 82JU | Legion 5 (AMD) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FA2S (Fan2) | 16-bit | 1
> -82WQ | Legion 7i (Int) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS (Fan1) | 16-bit | 1
> -82WQ | Legion 7i (Int) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FA2S (Fan2) | 16-bit | 1
> -82XV / 83DV | LOQ 15/16 | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS /FA2S | 16-bit | 1
> -83AK | ThinkBook G6 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
> -81X1 | Flex 5 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
> -*Legacy* | Pre-2020 Models | 0x06 | \_SB.PCI0.LPC.EC.FAN0 | 8-bit | 100
> -----------------------------------------------------------------------------------------------------
> +::
> +
> + MODEL (DMI PN) | FAMILY / SERIES | EC OFFSET | FULL ACPI OBJECT PATH | WIDTH | MULTiplier
> + ----------------------------------------------------------------------------------------------------
> + 82N7 | Yoga 14cACN | 0x06 | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
> + 80V2 / 81C3 | Yoga 710/720 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
> + 83E2 / 83DN | Yoga Pro 7/9 | 0xFE | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
> + 82A2 / 82A3 | Yoga Slim 7 | 0x06 | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
> + 81YM / 82FG | IdeaPad 5 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
> + 82JW / 82JU | Legion 5 (AMD) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS (Fan1) | 16-bit | 1
> + 82JW / 82JU | Legion 5 (AMD) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FA2S (Fan2) | 16-bit | 1
> + 82WQ | Legion 7i (Int) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS (Fan1) | 16-bit | 1
> + 82WQ | Legion 7i (Int) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FA2S (Fan2) | 16-bit | 1
> + 82XV / 83DV | LOQ 15/16 | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS /FA2S | 16-bit | 1
> + 83AK | ThinkBook G6 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
> + 81X1 | Flex 5 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
> + *Legacy* | Pre-2020 Models | 0x06 | \_SB.PCI0.LPC.EC.FAN0 | 8-bit | 100
> + ----------------------------------------------------------------------------------------------------
>
> METHODOLOGY & IDENTIFICATION:
>
^ permalink raw reply
* Re: [PATCH v2] bootconfig: Apply early options from embedded config
From: Breno Leitao @ 2026-04-07 10:19 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Jonathan Corbet, Shuah Khan, linux-kernel, linux-trace-kernel,
linux-doc, oss, paulmck, rostedt, kernel-team, Kiryl Shutsemau
In-Reply-To: <20260403114519.14e326a4bba019373bf3ff09@kernel.org>
On Fri, Apr 03, 2026 at 11:45:19AM +0900, Masami Hiramatsu wrote:
> > I'm still uncertain about this approach. The goal is to identify and
> > categorize the early parameters that are parsed prior to bootconfig
> > initialization.
>
> Yes, if we support early parameters in bootconfig, we need to clarify
> which parameters are inherently unsupportable, and document it.
> Currently it is easy to say that it does not support the parameter
> defined with "early_param()". Similary, maybe we should introduce
> "arch_param()" or something like it (or support all of them).
>
> >
> > Moreover, this work could become obsolete if bootconfig's initialization
> > point shifts earlier or later in the boot sequence, necessitating
> > another comprehensive analysis.
>
> If we can init it before calling setup_arch(), yes, we don't need to
> check it. So that is another option. Do you think it is feasible to
> support all of them? (Of course, theologically we can do, but the
> question is the use case and requirements.)
I don't believe all early parameters can be supported by bootconfig.
Some are inherently incompatible as far as I understand, while others
depend on bootconfig's initialization point in the boot sequence.
Regarding documenting arch_param(), I need clarification: should we
document parameters that are currently called before bootconfig (as of
today), or those that fundamentally cannot be called by bootconfig
regardless of its location?
> > Do you have any additional recommendations if I proceed with this
> > approach?
>
> OK,
>
> First of all, even if we enable early parameter support in bootconfig,
> this is only possible if bootconfig is embedded. In that case, we can
> pass memory that has been pre-allocated at compile time to bootconfig
> as a working area. However, this will consume a lot of memory, so it
> needs to be selectable in Kconfig.
>
> If you're going to embed this, as Kiryl pointed out[1], it might be better
> to pass pre-normalized (or compiled) data and avoid using a parser.
> Compilation itself is relatively easy if you utilize the tools/bootconfig.
> (However, in this case, there doesn't seem to be much point in using
> bootconfig in the first place because we also can use embed kernel
> cmdline.)
>
> [1] https://lore.kernel.org/all/acueCFv4neO7zQGI@thinkstation/
>
> Can you clarify the main reason of requesting this feature and
> examples?
My primary objective is to enable early configuration of
`irqchip.gicv3_pseudo_nmi`, allowing the kernel to support pseudo NMI
on arm64 by default.
^ permalink raw reply
* [PATCH v7 1/2] docs: s390/pci: Improve and update PCI documentation
From: Niklas Schnelle @ 2026-04-07 10:12 UTC (permalink / raw)
To: Bjorn Helgaas, Jonathan Corbet, Lukas Wunner, Shuah Khan
Cc: Farhan Ali, Alexander Gordeev, Christian Borntraeger,
Gerald Schaefer, Gerd Bayer, Heiko Carstens, Julian Ruess,
Matthew Rosato, Peter Oberparleiter, Ramesh Errabolu,
Sven Schnelle, Vasily Gorbik, linux-doc, linux-kernel, linux-pci,
linux-s390, Niklas Schnelle, Randy Dunlap
In-Reply-To: <20260407-uid_slot-v7-0-e50f7976124e@linux.ibm.com>
Update the s390 specific PCI documentation to better reflect current
behavior and terms such as the handling of Isolated VFs via commit
25f39d3dcb48 ("s390/pci: Ignore RID for isolated VFs").
Add a descriptions for /sys/firmware/clp/uid_is_unique which was added
in commit b043a81ce3ee ("s390/pci: Expose firmware provided UID Checking
state in sysfs") but missed documentation.
Similarly add documentation for the fidparm attribute added by commit
99ad39306a62 ("s390/pci: Expose FIDPARM attribute in sysfs") and
add a list of pft values and their names.
Finally improve formatting of the different attribute descriptions by
adding a separating colon.
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Acked-by: Randy Dunlap <rdunlap@infradead.org>
Tested-by: Randy Dunlap <rdunlap@infradead.org>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
---
Documentation/arch/s390/pci.rst | 144 +++++++++++++++++++++++++++-------------
1 file changed, 97 insertions(+), 47 deletions(-)
diff --git a/Documentation/arch/s390/pci.rst b/Documentation/arch/s390/pci.rst
index d5755484d8e75c7bf67a350e61bbe04f0452a2fa..8cb0a1e784a7cfc5df1e04a4154ba02c9ecf46cc 100644
--- a/Documentation/arch/s390/pci.rst
+++ b/Documentation/arch/s390/pci.rst
@@ -6,6 +6,7 @@ S/390 PCI
Authors:
- Pierre Morel
+ - Niklas Schnelle
Copyright, IBM Corp. 2020
@@ -27,14 +28,16 @@ Command line parameters
debugfs entries
---------------
-The S/390 debug feature (s390dbf) generates views to hold various debug results in sysfs directories of the form:
+The S/390 debug feature (s390dbf) generates views to hold various debug results
+in sysfs directories of the form:
* /sys/kernel/debug/s390dbf/pci_*/
For example:
- /sys/kernel/debug/s390dbf/pci_msg/sprintf
- Holds messages from the processing of PCI events, like machine check handling
+
+ holds messages from the processing of PCI events, like machine check handling
and setting of global functionality, like UID checking.
Change the level of logging to be more or less verbose by piping
@@ -47,87 +50,134 @@ Sysfs entries
Entries specific to zPCI functions and entries that hold zPCI information.
-* /sys/bus/pci/slots/XXXXXXXX
+* /sys/bus/pci/slots/XXXXXXXX:
- The slot entries are set up using the function identifier (FID) of the
- PCI function. The format depicted as XXXXXXXX above is 8 hexadecimal digits
- with 0 padding and lower case hexadecimal digits.
+ The slot entries are set up using the function identifier (FID) of the PCI
+ function as slot name. The format depicted as XXXXXXXX above is 8 hexadecimal
+ digits with 0 padding and lower case hexadecimal digits.
- /sys/bus/pci/slots/XXXXXXXX/power
A physical function that currently supports a virtual function cannot be
powered off until all virtual functions are removed with:
- echo 0 > /sys/bus/pci/devices/XXXX:XX:XX.X/sriov_numvf
+ echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvf
-* /sys/bus/pci/devices/XXXX:XX:XX.X/
+* /sys/bus/pci/devices/DDDD:BB:dd.f/:
- - function_id
- A zPCI function identifier that uniquely identifies the function in the Z server.
+ - function_id:
+ The zPCI function identifier (FID) is a 32-bit hexadecimal value that
+ uniquely identifies the PCI function. Unless the hypervisor provides
+ a virtual FID e.g. on KVM this identifier is unique across the machine even
+ between different partitions.
- - function_handle
- Low-level identifier used for a configured PCI function.
- It might be useful for debugging.
+ - function_handle:
+ This 32-bit hexadecimal value is a low-level identifier used for a PCI
+ function. Note that the function handle may be changed and become invalid
+ on PCI events and when enabling/disabling the PCI function.
- - pchid
- Model-dependent location of the I/O adapter.
+ - pchid:
+ This 16-bit hexadecimal value encodes a model-dependent location for
+ the PCI function.
- - pfgid
- PCI function group ID, functions that share identical functionality
+ - pfgid:
+ PCI function group ID; functions that share identical functionality
use a common identifier.
A PCI group defines interrupts, IOMMU, IOTLB, and DMA specifics.
- - vfn
+ - vfn:
The virtual function number, from 1 to N for virtual functions,
0 for physical functions.
- - pft
- The PCI function type
+ - pft:
+ The PCI function type is an s390-specific type attribute. It indicates
+ a more general, usage oriented, type than PCI Specification
+ class/vendor/device identifiers. That is PCI functions with the same pft
+ value may be backed by different hardware implementations. At the same time
+ apart from unclassified functions (pft is 0x00) the same pft value
+ generally implies a similar usage model. At the same time the same
+ PCI hardware device may appear with different pft values when in a
+ different usage model. For example NETD and NETH VFs may be implemented
+ by the same PCI hardware device but in NETD the parent Physical Function
+ is user managed while with NETH it is platform managed.
- - port
- The port corresponds to the physical port the function is attached to.
- It also gives an indication of the physical function a virtual function
- is attached to.
+ Currently the following PFT values are defined:
- - uid
- The user identifier (UID) may be defined as part of the machine
- configuration or the z/VM or KVM guest configuration. If the accompanying
- uid_is_unique attribute is 1 the platform guarantees that the UID is unique
- within that instance and no devices with the same UID can be attached
- during the lifetime of the system.
+ - 0x00 (UNC): Unclassified
+ - 0x02 (ROCE): RoCE Express
+ - 0x05 (ISM): Internal Shared Memory
+ - 0x0a (ROC2): RoCE Express 2
+ - 0x0b (NVMe): NVMe
+ - 0x0c (NETH): Network Express hybrid
+ - 0x0d (CNW): Cloud Network Adapter
+ - 0x0f (NETD): Network Express direct
- - uid_is_unique
- Indicates whether the user identifier (UID) is guaranteed to be and remain
- unique within this Linux instance.
+ - port:
+ The port is a decimal value corresponding to the physical port the function
+ is attached to. Virtual Functions (VFs) share the port with their parent
+ Physical Function (PF). A value of 0 indicates that the port attribute is
+ not applicable for that PCI function type.
- - pfip/segmentX
+ - uid:
+ The user-defined identifier (UID) for a PCI function is a 32-bit
+ hexadecimal value. It is defined on a per instance basis as part of the
+ partition, KVM guest, or z/VM guest configuration. If UID Checking is
+ enabled the platform ensures that the UID is unique within that instance
+ and no two PCI functions with the same UID will be visible to the instance.
+
+ Independent of this guarantee and unlike the function ID (FID) the UID may
+ be the same in different partitions within the same machine. This allows to
+ create PCI configurations in multiple partitions to be identical in the
+ UID-namespace.
+
+ - uid_is_unique:
+ A 0 or 1 flag indicating whether the user-defined identifier (UID) is
+ guaranteed to be and remain unique within this Linux instance. This
+ platform feature is called UID Checking.
+
+ - pfip/segmentX:
The segments determine the isolation of a function.
They correspond to the physical path to the function.
The more the segments are different, the more the functions are isolated.
+ - fidparm:
+ Contains an 8-bit-per-PCI function parameter field in hexadecimal provided
+ by the platform. The meaning of this field is PCI function type specific.
+ For NETH VFs a value of 0x01 indicates that the function supports
+ promiscuous mode.
+
+* /sys/firmware/clp/uid_is_unique:
+
+ In addition to the per-device uid_is_unique attribute this presents a
+ global indication of whether UID Checking is enabled. This allows users
+ to check for UID Checking even when no PCI functions are configured.
+
Enumeration and hotplug
=======================
The PCI address consists of four parts: domain, bus, device and function,
-and is of this form: DDDD:BB:dd.f
+and is of this form: DDDD:BB:dd.f.
-* When not using multi-functions (norid is set, or the firmware does not
- support multi-functions):
+* For a PCI function for which the platform does not expose the RID, the
+ pci=norid kernel parameter is used, or a so-called isolated Virtual Function
+ which does have RID information but is used without its parent Physical
+ Function being part of the same PCI configuration:
- There is only one function per domain.
- - The domain is set from the zPCI function's UID as defined during the
- LPAR creation.
+ - The domain is set from the zPCI function's UID if UID Checking is on;
+ otherwise the domain ID is generated dynamically and is not stable
+ across reboots or hot plug.
-* When using multi-functions (norid parameter is not set),
- zPCI functions are addressed differently:
+* For a PCI function for which the platform exposes the RID and which
+ is not an Isolated Virtual Function:
- There is still only one bus per domain.
- - There can be up to 256 functions per bus.
+ - There can be up to 256 PCI functions per bus.
- - The domain part of the address of all functions for
- a multi-Function device is set from the zPCI function's UID as defined
- in the LPAR creation for the function zero.
+ - The domain part of the address of all functions within the same topology is
+ that of the configured PCI function with the lowest devfn within that
+ topology.
- - New functions will only be ready for use after the function zero
- (the function with devfn 0) has been enumerated.
+ - Virtual Functions generated by an SR-IOV capable Physical Function only
+ become visible once SR-IOV is enabled.
--
2.51.0
^ permalink raw reply related
* [PATCH v7 2/2] PCI: s390: Expose the UID as an arch specific PCI slot attribute
From: Niklas Schnelle @ 2026-04-07 10:12 UTC (permalink / raw)
To: Bjorn Helgaas, Jonathan Corbet, Lukas Wunner, Shuah Khan
Cc: Farhan Ali, Alexander Gordeev, Christian Borntraeger,
Gerald Schaefer, Gerd Bayer, Heiko Carstens, Julian Ruess,
Matthew Rosato, Peter Oberparleiter, Ramesh Errabolu,
Sven Schnelle, Vasily Gorbik, linux-doc, linux-kernel, linux-pci,
linux-s390, Niklas Schnelle
In-Reply-To: <20260407-uid_slot-v7-0-e50f7976124e@linux.ibm.com>
On s390, an individual PCI function can generally be identified by two
identifiers, the FID and the UID. Which identifier is used depends on
the scope and the platform configuration.
The first identifier, the FID, is always available and identifies a PCI
device uniquely within a machine. The FID may be virtualized by
hypervisors, but on the LPAR level, the machine scope makes it
impossible to create the same configuration based on FIDs on two
different LPARs of the same machine, and difficult to reuse across
machines.
Such matching LPAR configurations are useful, though, allowing
standardized setups and booting a Linux installation on different LPARs.
To this end the UID, or user-defined identifier, was introduced. While
it is only guaranteed to be unique within an LPAR and only if indicated
by firmware, it allows users to replicate PCI device setups.
On s390, which uses a machine hypervisor, a per PCI function hotplug
model is used. The shortcoming with the UID then is, that it is not
visible to the user without first attaching the PCI function and
accessing the "uid" device attribute. The FID, on the other hand, is
used as the slot name and is thus known even with the PCI function in
standby.
Remedy this shortcoming by providing the UID as an attribute on the slot
allowing the user to identify a PCI function based on the UID without
having to first attach it. Do this via a macro mechanism analogous to
what was introduced by commit 265baca69a07 ("s390/pci: Stop usurping
pdev->dev.groups") for the PCI device attributes.
Reviewed-by: Gerd Bayer <gbayer@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
---
Documentation/arch/s390/pci.rst | 7 +++++++
arch/s390/include/asm/pci.h | 4 ++++
arch/s390/pci/pci_sysfs.c | 20 ++++++++++++++++++++
drivers/pci/slot.c | 13 ++++++++++++-
4 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/Documentation/arch/s390/pci.rst b/Documentation/arch/s390/pci.rst
index 8cb0a1e784a7cfc5df1e04a4154ba02c9ecf46cc..a620cf694c6f6c0bbd4f77ea4768cce7cc42c963 100644
--- a/Documentation/arch/s390/pci.rst
+++ b/Documentation/arch/s390/pci.rst
@@ -58,6 +58,13 @@ Entries specific to zPCI functions and entries that hold zPCI information.
- /sys/bus/pci/slots/XXXXXXXX/power
+ In addition to using the FID as the name of the slot, the slot directory
+ also contains the following s390-specific slot attributes.
+
+ - uid:
+ The User-defined identifier (UID) of the function which may be configured
+ by this slot. See also the corresponding attribute of the device.
+
A physical function that currently supports a virtual function cannot be
powered off until all virtual functions are removed with:
echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvf
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index c0ff19dab5807c7e1aabb48a0e9436aac45ec97d..5dcf35f0f325f5f44b28109a1c8d9aef18401035 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -208,6 +208,10 @@ extern const struct attribute_group zpci_ident_attr_group;
&pfip_attr_group, \
&zpci_ident_attr_group,
+extern const struct attribute_group zpci_slot_attr_group;
+
+#define ARCH_PCI_SLOT_GROUPS (&zpci_slot_attr_group)
+
extern unsigned int s390_pci_force_floating __initdata;
extern unsigned int s390_pci_no_rid;
diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c
index c2444a23e26c4218832bb91930b5f0ffd498d28f..d98d97df792adb3c7e415a8d374cc2f3a65fbb52 100644
--- a/arch/s390/pci/pci_sysfs.c
+++ b/arch/s390/pci/pci_sysfs.c
@@ -187,6 +187,17 @@ static ssize_t index_show(struct device *dev,
}
static DEVICE_ATTR_RO(index);
+static ssize_t zpci_uid_slot_show(struct pci_slot *slot, char *buf)
+{
+ struct zpci_dev *zdev = container_of(slot->hotplug, struct zpci_dev,
+ hotplug_slot);
+
+ return sysfs_emit(buf, "0x%x\n", zdev->uid);
+}
+
+static struct pci_slot_attribute zpci_slot_attr_uid =
+ __ATTR(uid, 0444, zpci_uid_slot_show, NULL);
+
static umode_t zpci_index_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
@@ -243,6 +254,15 @@ const struct attribute_group pfip_attr_group = {
.attrs = pfip_attrs,
};
+static struct attribute *zpci_slot_attrs[] = {
+ &zpci_slot_attr_uid.attr,
+ NULL,
+};
+
+const struct attribute_group zpci_slot_attr_group = {
+ .attrs = zpci_slot_attrs,
+};
+
static struct attribute *clp_fw_attrs[] = {
&uid_checking_attr.attr,
NULL,
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index 787311614e5b6ebb39e7284f9b9f205a0a684d6d..2f8fcfbbec24e73d0bb6e40fd04c05a94f518045 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -96,7 +96,18 @@ static struct attribute *pci_slot_default_attrs[] = {
&pci_slot_attr_cur_speed.attr,
NULL,
};
-ATTRIBUTE_GROUPS(pci_slot_default);
+
+static const struct attribute_group pci_slot_default_group = {
+ .attrs = pci_slot_default_attrs,
+};
+
+static const struct attribute_group *pci_slot_default_groups[] = {
+ &pci_slot_default_group,
+#ifdef ARCH_PCI_SLOT_GROUPS
+ ARCH_PCI_SLOT_GROUPS,
+#endif
+ NULL,
+};
static const struct kobj_type pci_slot_ktype = {
.sysfs_ops = &pci_slot_sysfs_ops,
--
2.51.0
^ permalink raw reply related
* [PATCH v7 0/2] PCI: s390: Expose the UID as an arch specific PCI slot attribute
From: Niklas Schnelle @ 2026-04-07 10:12 UTC (permalink / raw)
To: Bjorn Helgaas, Jonathan Corbet, Lukas Wunner, Shuah Khan
Cc: Farhan Ali, Alexander Gordeev, Christian Borntraeger,
Gerald Schaefer, Gerd Bayer, Heiko Carstens, Julian Ruess,
Matthew Rosato, Peter Oberparleiter, Ramesh Errabolu,
Sven Schnelle, Vasily Gorbik, linux-doc, linux-kernel, linux-pci,
linux-s390, Niklas Schnelle, Randy Dunlap
Hi all,
Add a mechanism for architecture specific attributes on
PCI slots in order to add the user-defined ID (UID) as an s390 specific
PCI slot attribute. First though improve some issues with the s390 specific
documentation of PCI sysfs attributes noticed during development.
Also note, I considered adding the UID as a generic slot index attribute
analogous to the PCI device index attribute (SMBIOS index / s390 UID)
but decided against it as this seems rather s390 specific and having
it named UID makes things easier for users and aligns with the existing
separate uid device attribute.
Thanks,
Niklas
v6->v7:
- Incorporate doc suggestions from Randy Dunlap
- Add R-b, T-b and A-b
- Rebase on v7.0-rc7
- Link to v6: https://lore.kernel.org/r/20260402-uid_slot-v6-0-d5ea0a14ddb9@linux.ibm.com
v5->v6:
- Add documentation cleanup patch before adding new slot attribute
- Link to v5: https://lore.kernel.org/r/20260401-uid_slot-v5-1-e73036c74bf6@linux.ibm.com
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
---
---
---
Niklas Schnelle (2):
docs: s390/pci: Improve and update PCI documentation
PCI: s390: Expose the UID as an arch specific PCI slot attribute
Documentation/arch/s390/pci.rst | 151 +++++++++++++++++++++++++++-------------
arch/s390/include/asm/pci.h | 4 ++
arch/s390/pci/pci_sysfs.c | 20 ++++++
drivers/pci/slot.c | 13 +++-
4 files changed, 140 insertions(+), 48 deletions(-)
---
base-commit: 591cd656a1bf5ea94a222af5ef2ee76df029c1d2
change-id: 20250923-uid_slot-e3559cf5ca30
Best regards,
--
Niklas Schnelle
^ permalink raw reply
* Re: [PATCH v2] Documentation: gpio: update the preferred method for using software node lookup
From: Linus Walleij @ 2026-04-07 10:03 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Bartosz Golaszewski, Jonathan Corbet, Shuah Khan, Dmitry Torokhov,
linux-gpio, linux-doc, linux-kernel
In-Reply-To: <20260403-doc-gpio-swnodes-v2-1-c705f5897b80@oss.qualcomm.com>
On Fri, Apr 3, 2026 at 3:05 PM Bartosz Golaszewski
<bartosz.golaszewski@oss.qualcomm.com> wrote:
> In its current version, the manual for converting of board files from
> using GPIO lookup tables to software nodes recommends leaving the
> software nodes representing GPIO controllers as "free-floating", not
> attached objects and relying on the matching of their names against the
> GPIO controller's name. This is an abuse of the software node API and
> makes it impossible to create fw_devlinks between GPIO suppliers and
> consumers in this case. We want to remove this behavior from GPIOLIB and
> to this end, work on converting all existing drivers to using "attached"
> software nodes.
>
> Except for a few corner-cases where board files define consumers
> depending on GPIO controllers described in firmware - where we need to
> reference a real firmware node from a software node - which requires a
> more complex approach, most board files can easily be converted to using
> propert firmware node lookup.
>
> Update the documentation to recommend attaching the GPIO chip's software
> nodes to the actual platform devices and show how to do it.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
OK this is clearly making the kernel a better place, and I expect
the AI coding agents to pick up on it and help everyone do the right
thing soon enough as well:
Reviewed-by: Linus Walleij <linusw@kernel.org>
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH] sched_ext: Documentation: Fix scx_bpf_move_to_local kfunc name
From: fangqiurong @ 2026-04-07 9:34 UTC (permalink / raw)
To: linux-kernel, linux-doc; +Cc: tj, corbet
From: fangqiurong <fangqiurong@kylinos.com>
The correct kfunc name is scx_bpf_dsq_move_to_local(), not
scx_bpf_move_to_local(). Fix the two references in the
Scheduling Cycle section.
Signed-off-by: fangqiurong <fangqiurong@kylinos.cn>
---
Documentation/scheduler/sched-ext.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/scheduler/sched-ext.rst b/Documentation/scheduler/sched-ext.rst
index d74c2c2b9ef3..b106ccf7a0b8 100644
--- a/Documentation/scheduler/sched-ext.rst
+++ b/Documentation/scheduler/sched-ext.rst
@@ -264,9 +264,9 @@ The following briefly shows how a waking task is scheduled and executed.
rather than performing them immediately. There can be up to
``ops.dispatch_max_batch`` pending tasks.
- * ``scx_bpf_move_to_local()`` moves a task from the specified non-local
+ * ``scx_bpf_dsq_move_to_local()`` moves a task from the specified non-local
DSQ to the dispatching DSQ. This function cannot be called with any BPF
- locks held. ``scx_bpf_move_to_local()`` flushes the pending insertions
+ locks held. ``scx_bpf_dsq_move_to_local()`` flushes the pending insertions
tasks before trying to move from the specified DSQ.
4. After ``ops.dispatch()`` returns, if there are tasks in the local DSQ,
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v6 2/2] PCI: s390: Expose the UID as an arch specific PCI slot attribute
From: Niklas Schnelle @ 2026-04-07 8:51 UTC (permalink / raw)
To: Farhan Ali, Bjorn Helgaas, Jonathan Corbet, Lukas Wunner,
Shuah Khan
Cc: Alexander Gordeev, Christian Borntraeger, Gerald Schaefer,
Gerd Bayer, Heiko Carstens, Julian Ruess, Matthew Rosato,
Peter Oberparleiter, Ramesh Errabolu, Sven Schnelle,
Vasily Gorbik, linux-doc, linux-kernel, linux-pci, linux-s390
In-Reply-To: <bde50f9a-bbe1-43ba-b2f4-24951dd0cccf@linux.ibm.com>
On Fri, 2026-04-03 at 10:19 -0700, Farhan Ali wrote:
> On 4/2/2026 1:34 PM, Niklas Schnelle wrote:
> > On s390, an individual PCI function can generally be identified by two
> > identifiers, the FID and the UID. Which identifier is used depends on
> > the scope and the platform configuration.
> >
> > The first identifier, the FID, is always available and identifies a PCI
> > device uniquely within a machine. The FID may be virtualized by
> > hypervisors, but on the LPAR level, the machine scope makes it
> > impossible to create the same configuration based on FIDs on two
> > different LPARs of the same machine, and difficult to reuse across
> > machines.
> >
> > Such matching LPAR configurations are useful, though, allowing
> > standardized setups and booting a Linux installation on different LPARs.
> > To this end the UID, or user-defined identifier, was introduced. While
> > it is only guaranteed to be unique within an LPAR and only if indicated
> > by firmware, it allows users to replicate PCI device setups.
> >
> > On s390, which uses a machine hypervisor, a per PCI function hotplug
> > model is used. The shortcoming with the UID then is, that it is not
> > visible to the user without first attaching the PCI function and
> > accessing the "uid" device attribute. The FID, on the other hand, is
> > used as the slot name and is thus known even with the PCI function in
> > standby.
> >
> > Remedy this shortcoming by providing the UID as an attribute on the slot
> > allowing the user to identify a PCI function based on the UID without
> > having to first attach it. Do this via a macro mechanism analogous to
> > what was introduced by commit 265baca69a07 ("s390/pci: Stop usurping
> > pdev->dev.groups") for the PCI device attributes.
> >
> > Reviewed-by: Gerd Bayer <gbayer@linux.ibm.com>
> > Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
> > Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
> > ---
> > Documentation/arch/s390/pci.rst | 7 +++++++
> > arch/s390/include/asm/pci.h | 4 ++++
> > arch/s390/pci/pci_sysfs.c | 20 ++++++++++++++++++++
> > drivers/pci/slot.c | 13 ++++++++++++-
> > 4 files changed, 43 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/arch/s390/pci.rst b/Documentation/arch/s390/pci.rst
> > index 31c24ed5506f1fc07f89821f67a814118514f441..4c0f35c8a5588eee3cf0d596e0057f24b3ed079c 100644
> > --- a/Documentation/arch/s390/pci.rst
> > +++ b/Documentation/arch/s390/pci.rst
> > @@ -57,6 +57,13 @@ Entries specific to zPCI functions and entries that hold zPCI information.
> >
> > - /sys/bus/pci/slots/XXXXXXXX/power
> >
> > + In addition to using the FID as the name of the slot the slot directory
> > + also contains the following s390 specific slot attributes.
> > +
> > + - uid:
> > + The User-defined identifier (UID) of the function which may be configured
> > + by this slot. See also the corresponding attribute of the device.
> > +
> > A physical function that currently supports a virtual function cannot be
> > powered off until all virtual functions are removed with:
> > echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvf
> > diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
> > index c0ff19dab5807c7e1aabb48a0e9436aac45ec97d..5dcf35f0f325f5f44b28109a1c8d9aef18401035 100644
> > --- a/arch/s390/include/asm/pci.h
> > +++ b/arch/s390/include/asm/pci.h
> > @@ -208,6 +208,10 @@ extern const struct attribute_group zpci_ident_attr_group;
> > &pfip_attr_group, \
> > &zpci_ident_attr_group,
> >
> > +extern const struct attribute_group zpci_slot_attr_group;
> > +
> > +#define ARCH_PCI_SLOT_GROUPS (&zpci_slot_attr_group)
> > +
> > extern unsigned int s390_pci_force_floating __initdata;
> > extern unsigned int s390_pci_no_rid;
> >
> > diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c
> > index c2444a23e26c4218832bb91930b5f0ffd498d28f..d98d97df792adb3c7e415a8d374cc2f3a65fbb52 100644
> > --- a/arch/s390/pci/pci_sysfs.c
> > +++ b/arch/s390/pci/pci_sysfs.c
> > @@ -187,6 +187,17 @@ static ssize_t index_show(struct device *dev,
> > }
> > static DEVICE_ATTR_RO(index);
> >
> > +static ssize_t zpci_uid_slot_show(struct pci_slot *slot, char *buf)
> > +{
> > + struct zpci_dev *zdev = container_of(slot->hotplug, struct zpci_dev,
> > + hotplug_slot);
> > +
> > + return sysfs_emit(buf, "0x%x\n", zdev->uid);
> > +}
>
> I think the way we assign the same pci slot to multifunctions (PF and VF
> on the same LPAR), IIUC we could possibly display the wrong uid here. I
> am hoping my patch [1] can fix this. I am curious, is there any
> s390-tool that would use the uid? Though this would only impact the NETD
> devices on newer machines, so I don't know if we want to gate this
> behind my patch?
>
> [1] https://lore.kernel.org/all/20260330174011.1161-2-alifm@linux.ibm.com/
>
> Thanks
>
> Farhan
>
>
In my testing the UIDs for NETD VFs were correct. This is because there
is a bit of an asymmetry in the wrong slot assignment. Without your
patch pdev->slot gets set to the wrong slot but the correct slot and
hotplug slot still exist and are reachable via the sysfs kobjects or
zdev->hotplug_slot. This is also why we do have the correct
/sys/bus/pci/slots/<FID>/ directory and why the issue of wrong slot
assignment only came up via the reset mechanism not e.g. when trying to
deconfigure a PCI function.
As for tools using this attribute there is work ongoing to add PCI
support to lszdev/chzdev and these would utilize the UID in the slot
directory for listing the PCI functions as well as by generating udev
rules based on the UID. See also Ramesh's patch for adding the missing
uevent file in /sys/bus/pci/slots/*/ for cold plug[0].
Thanks,
Niklas
[0]
https://lore.kernel.org/lkml/20260401163152.632779-1-ramesh@linux.ibm.com/
^ permalink raw reply
* Re: [PATCH v2 07/33] rust: allow globally `clippy::incompatible_msrv`
From: Miguel Ojeda @ 2026-04-07 8:37 UTC (permalink / raw)
To: Tamir Duberstein
Cc: Miguel Ojeda, Nathan Chancellor, Nicolas Schier, Danilo Krummrich,
Andreas Hindborg, Catalin Marinas, Will Deacon, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Courbot, David Airlie,
Simona Vetter, Brendan Higgins, David Gow, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, Alice Ryhl, Jonathan Corbet, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Trevor Gross, rust-for-linux,
linux-kbuild, Lorenzo Stoakes, Vlastimil Babka, Liam R . Howlett,
Uladzislau Rezki, linux-block, linux-arm-kernel, Alexandre Ghiti,
linux-riscv, nouveau, dri-devel, Rae Moar, linux-kselftest,
kunit-dev, Nick Desaulniers, Bill Wendling, Justin Stitt, llvm,
linux-kernel, Shuah Khan, linux-doc
In-Reply-To: <CAJ-ks9kbHz_KYAXx02vgW1dN2pfb5MFoaSoU1HbJbJg2O8EUaw@mail.gmail.com>
On Mon, Apr 6, 2026 at 5:31 PM Tamir Duberstein <tamird@kernel.org> wrote:
>
> You're welcome! Actually it seems the lint was already improved
> upstream, starting with 1.90.0.
>
> Link: https://github.com/rust-lang/rust-clippy/commit/c0dc3b61 [0]
Indeed, I had the PR linked in
https://github.com/Rust-for-Linux/linux/issues/349, and it is nicer,
but it would still fire in a case like this patch :(
So we could conditionally enable it for Rust >= 1.90.0 now that we
have support for that (and allow locally some cases like this one when
they pop up), but it is still simpler to just ignore it (especially
since it can be quite confusing for other developers to see it
triggering).
I think we may want to eventually re-enable it when we use no unstable
language features.
Added:
[ In addition, the lint fired without taking into account the features
that have been enabled in a crate [2]. While this was improved in Rust
1.90.0 [3], it would still fire in a case like this patch. ]
Thanks!
Cheers,
Miguel
^ permalink raw reply
* [PATCH] Documentation: sysctl: document net core sysctls
From: Shubham Chakraborty @ 2026-04-07 8:32 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, linux-doc, linux-kernel; +Cc: Shubham Chakraborty
Document missing net.core and net.unix sysctl entries in admin-guide/sysctl/net.rst, and correct wording for defaults that are derived from PAGE_SIZE, HZ, or CONFIG_MAX_SKB_FRAGS.
Also clarify that the RFS and flow-limit controls are only present when CONFIG_RPS or CONFIG_NET_FLOW_LIMIT is enabled, and describe rps_sock_flow_entries the way the handler implements it: non-zero values are rounded up to the nearest power of two.
Validation: git diff --check -- Documentation/admin-guide/sysctl/net.rst
Validation: make -j1 O=/tmp/linux-docs-check SPHINXDIRS=admin-guide/sysctl htmldocs
Signed-off-by: Shubham Chakraborty <chakrabortyshubham66@gmail.com>
---
Documentation/admin-guide/sysctl/net.rst | 66 +++++++++++++++++++++++-
1 file changed, 64 insertions(+), 2 deletions(-)
diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst
index 3b2ad61995d4..05d301b8752c 100644
--- a/Documentation/admin-guide/sysctl/net.rst
+++ b/Documentation/admin-guide/sysctl/net.rst
@@ -210,7 +210,9 @@ Default: 0 (off)
mem_pcpu_rsv
------------
-Per-cpu reserved forward alloc cache size in page units. Default 1MB per CPU.
+Per-cpu reserved forward alloc cache size in page units.
+
+Default: 1MB per CPU, expressed in page units
bypass_prot_mem
---------------
@@ -238,6 +240,37 @@ rps_default_mask
The default RPS CPU mask used on newly created network devices. An empty
mask means RPS disabled by default.
+rps_sock_flow_entries
+---------------------
+
+The total number of entries in the RPS flow table. This is used by
+RFS (Receive Flow Steering) to track which CPU is currently processing
+a flow in userspace. Non-zero values are rounded up to the nearest
+power of two.
+Available only when ``CONFIG_RPS`` is enabled.
+
+Default: 0
+
+flow_limit_cpu_bitmap
+---------------------
+
+Bitmap of CPUs for which RPS flow limiting is enabled. Flow limiting
+prioritizes small flows during CPU contention by dropping packets
+from large flows slightly ahead of those from small flows.
+Available only when ``CONFIG_NET_FLOW_LIMIT`` is enabled.
+
+Default: 0 (disabled)
+
+flow_limit_table_len
+--------------------
+
+The number of buckets in the flow limit hashtable. This value is
+only consulted when a new table is allocated. Modifying it does
+not update active tables. This value should be a power of two.
+Available only when ``CONFIG_NET_FLOW_LIMIT`` is enabled.
+
+Default: 4096
+
tstamp_allow_data
-----------------
Allow processes to receive tx timestamps looped together with the original
@@ -290,6 +323,8 @@ probed in a round-robin manner. Also, a polling cycle may not exceed
netdev_budget_usecs microseconds, even if netdev_budget has not been
exhausted.
+Default: 300
+
netdev_budget_usecs
---------------------
@@ -297,12 +332,16 @@ Maximum number of microseconds in one NAPI polling cycle. Polling
will exit when either netdev_budget_usecs have elapsed during the
poll cycle or the number of packets processed reaches netdev_budget.
+Default: ``2 * USEC_PER_SEC / HZ`` (2000 when ``HZ`` is 1000)
+
netdev_max_backlog
------------------
Maximum number of packets, queued on the INPUT side, when the interface
receives packets faster than kernel can process them.
+Default: 1000
+
qdisc_max_burst
------------------
@@ -368,6 +407,15 @@ by the cpu which allocated them.
Default: 128
+max_skb_frags
+-------------
+
+The maximum number of fragments allowed per skb (socket buffer).
+This is mostly used for performance tuning of GSO (Generic
+Segmentation Offload).
+
+Default: ``CONFIG_MAX_SKB_FRAGS`` (17 if not overridden)
+
optmem_max
----------
@@ -377,6 +425,16 @@ optmem_max as a limit for its internal structures.
Default : 128 KB
+somaxconn
+---------
+
+Limit of the socket listen() backlog, known in userspace as SOMAXCONN.
+The maximum number of established sockets waiting to be accepted by
+accept(). If the backlog is greater than this value, it will be
+silently truncated to this value.
+
+Default: 4096
+
fb_tunnels_only_for_init_net
----------------------------
@@ -449,6 +507,8 @@ GRO has decided not to coalesce, it is placed on a per-NAPI list. This
list is then passed to the stack when the number of segments reaches the
gro_normal_batch limit.
+Default: 8
+
high_order_alloc_disable
------------------------
@@ -465,9 +525,11 @@ Default: 0
----------------------------------------------------------
There is only one file in this directory.
-unix_dgram_qlen limits the max number of datagrams queued in Unix domain
+max_dgram_qlen limits the max number of datagrams queued in Unix domain
socket's buffer. It will not take effect unless PF_UNIX flag is specified.
+Default: 10
+
3. /proc/sys/net/ipv4 - IPV4 settings
-------------------------------------
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v6 1/2] docs: s390/pci: Improve and update PCI documentation
From: Niklas Schnelle @ 2026-04-07 8:13 UTC (permalink / raw)
To: Randy Dunlap, Bjorn Helgaas, Jonathan Corbet, Lukas Wunner,
Shuah Khan
Cc: Farhan Ali, Alexander Gordeev, Christian Borntraeger,
Gerald Schaefer, Gerd Bayer, Heiko Carstens, Julian Ruess,
Matthew Rosato, Peter Oberparleiter, Ramesh Errabolu,
Sven Schnelle, Vasily Gorbik, linux-doc, linux-kernel, linux-pci,
linux-s390
In-Reply-To: <9e1cc48c-79ea-486a-96f4-a1d1395d7e47@infradead.org>
On Thu, 2026-04-02 at 21:01 -0700, Randy Dunlap wrote:
> Hi,
>
> On 4/2/26 1:34 PM, Niklas Schnelle wrote:
> > Update the s390 specific PCI documentation to better reflect current
> > behavior and terms such as the handling of Isolated VFs via commit
> > 25f39d3dcb48 ("s390/pci: Ignore RID for isolated VFs").
> >
> > Add a descriptions for /sys/firmware/clp/uid_is_unique which was added
> > in commit b043a81ce3ee ("s390/pci: Expose firmware provided UID Checking
> > state in sysfs") but missed documentation.
> >
> > Similarly add documentation for the fidparm attribute added by commit
> > 99ad39306a62 ("s390/pci: Expose FIDPARM attribute in sysfs") and
> > add a list of pft values and their names.
> >
> > Finally improve formatting of the different attribute descriptions by
> > adding a separating colon.
> >
> > Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
> > ---
> > Documentation/arch/s390/pci.rst | 139 +++++++++++++++++++++++++++-------------
> > 1 file changed, 94 insertions(+), 45 deletions(-)
>
>
> These changes are good, so:
> Acked-by: Randy Dunlap <rdunlap@infradead.org>
> Tested-by: Randy Dunlap <rdunlap@infradead.org>
>
>
> However, I would go a little farther and add these changes if you
> are OK with them. (Patch applies after both of your patches.)
Thank you for the feedback and the suggestions, I agree with all of
them and they will be part of v7.
Thanks,
Niklas
^ permalink raw reply
* 回复:[PATCH v10 net-next 04/11] net/nebula-matrix: channel msg value and msg struct
From: Illusion Wang @ 2026-04-07 7:22 UTC (permalink / raw)
To: Mohsin Bashir, Dimon, Alvin, Sam, netdev
Cc: andrew+netdev, corbet, kuba, linux-doc, lorenzo, pabeni, horms,
vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
hkallweit1, jani.nikula, open list
In-Reply-To: <0b0eb2e1-7aec-4913-8062-b3eff786a1ae@gmail.com>
> struct nbl_channel_mgt;
> struct nbl_adapter;
>> +enum nbl_chan_msg_type {
>> + NBL_CHAN_MSG_ACK,
>> + NBL_CHAN_MSG_ADD_MACVLAN,
>> + NBL_CHAN_MSG_DEL_MACVLAN,
>> + NBL_CHAN_MSG_ADD_MULTI_RULE,
>> + NBL_CHAN_MSG_DEL_MULTI_RULE,
>> + NBL_CHAN_MSG_SETUP_MULTI_GROUP,
>> + NBL_CHAN_MSG_REMOVE_MULTI_GROUP,
>> + NBL_CHAN_MSG_REGISTER_NET,
>> + NBL_CHAN_MSG_UNREGISTER_NET,
>> + NBL_CHAN_MSG_ALLOC_TXRX_QUEUES,
>> + NBL_CHAN_MSG_FREE_TXRX_QUEUES,
>> + NBL_CHAN_MSG_SETUP_QUEUE,
>> + NBL_CHAN_MSG_REMOVE_ALL_QUEUES,
>> + NBL_CHAN_MSG_CFG_DSCH,
>> + NBL_CHAN_MSG_SETUP_CQS,
>> + NBL_CHAN_MSG_REMOVE_CQS,
>> + NBL_CHAN_MSG_CFG_QDISC_MQPRIO,
>> + NBL_CHAN_MSG_CONFIGURE_MSIX_MAP,
>> + NBL_CHAN_MSG_DESTROY_MSIX_MAP,
>> + NBL_CHAN_MSG_MAILBOX_ENABLE_IRQ,
>> + NBL_CHAN_MSG_GET_GLOBAL_VECTOR,
>> + NBL_CHAN_MSG_GET_VSI_ID,
>> + NBL_CHAN_MSG_SET_PROSISC_MODE,
>> + NBL_CHAN_MSG_GET_FIRMWARE_VERSION,
>> + NBL_CHAN_MSG_GET_QUEUE_ERR_STATS,
>> + NBL_CHAN_MSG_GET_COALESCE,
>> + NBL_CHAN_MSG_SET_COALESCE,
>> + NBL_CHAN_MSG_SET_SPOOF_CHECK_ADDR,
>> + NBL_CHAN_MSG_SET_VF_SPOOF_CHECK,
>> + NBL_CHAN_MSG_GET_RXFH_INDIR_SIZE,
>> + NBL_CHAN_MSG_GET_RXFH_INDIR,
>> + NBL_CHAN_MSG_GET_RXFH_RSS_KEY,
>> + NBL_CHAN_MSG_GET_RXFH_RSS_ALG_SEL,
>> + NBL_CHAN_MSG_GET_HW_CAPS,
>> + NBL_CHAN_MSG_GET_HW_STATE,
>> + NBL_CHAN_MSG_REGISTER_RDMA,
>> + NBL_CHAN_MSG_UNREGISTER_RDMA,
>> + NBL_CHAN_MSG_GET_REAL_HW_ADDR,
>> + NBL_CHAN_MSG_GET_REAL_BDF,
>> + NBL_CHAN_MSG_GRC_PROCESS,
>> + NBL_CHAN_MSG_SET_SFP_STATE,
>> + NBL_CHAN_MSG_SET_ETH_LOOPBACK,
>> + NBL_CHAN_MSG_CHECK_ACTIVE_VF,
>> + NBL_CHAN_MSG_GET_PRODUCT_FLEX_CAP,
>> + NBL_CHAN_MSG_ALLOC_KTLS_TX_INDEX,
>> + NBL_CHAN_MSG_FREE_KTLS_TX_INDEX,
>> + NBL_CHAN_MSG_CFG_KTLS_TX_KEYMAT,
>> + NBL_CHAN_MSG_ALLOC_KTLS_RX_INDEX,
>> + NBL_CHAN_MSG_FREE_KTLS_RX_INDEX,
>> + NBL_CHAN_MSG_CFG_KTLS_RX_KEYMAT,
>> + NBL_CHAN_MSG_CFG_KTLS_RX_RECORD,
>> + NBL_CHAN_MSG_ADD_KTLS_RX_FLOW,
>> + NBL_CHAN_MSG_DEL_KTLS_RX_FLOW,
>> + NBL_CHAN_MSG_ALLOC_IPSEC_TX_INDEX,
>> + NBL_CHAN_MSG_FREE_IPSEC_TX_INDEX,
>> + NBL_CHAN_MSG_ALLOC_IPSEC_RX_INDEX,
>> + NBL_CHAN_MSG_FREE_IPSEC_RX_INDEX,
>> + NBL_CHAN_MSG_CFG_IPSEC_TX_SAD,
>> + NBL_CHAN_MSG_CFG_IPSEC_RX_SAD,
>> + NBL_CHAN_MSG_ADD_IPSEC_TX_FLOW,
>> + NBL_CHAN_MSG_DEL_IPSEC_TX_FLOW,
>> + NBL_CHAN_MSG_ADD_IPSEC_RX_FLOW,
>> + NBL_CHAN_MSG_DEL_IPSEC_RX_FLOW,
>> + NBL_CHAN_MSG_NOTIFY_IPSEC_HARD_EXPIRE,
>> + NBL_CHAN_MSG_GET_MBX_IRQ_NUM,
>> + NBL_CHAN_MSG_CLEAR_FLOW,
>> + NBL_CHAN_MSG_CLEAR_QUEUE,
>> + NBL_CHAN_MSG_GET_ETH_ID,
>> + NBL_CHAN_MSG_SET_OFFLOAD_STATUS,
>> + NBL_CHAN_MSG_INIT_OFLD,
>> + NBL_CHAN_MSG_INIT_CMDQ,
>> + NBL_CHAN_MSG_DESTROY_CMDQ,
>> + NBL_CHAN_MSG_RESET_CMDQ,
>> + NBL_CHAN_MSG_INIT_FLOW,
>> + NBL_CHAN_MSG_DEINIT_FLOW,
>> + NBL_CHAN_MSG_OFFLOAD_FLOW_RULE,
>> + NBL_CHAN_MSG_GET_ACL_SWITCH,
>> + NBL_CHAN_MSG_GET_VSI_GLOBAL_QUEUE_ID,
>> + NBL_CHAN_MSG_INIT_REP,
>> + NBL_CHAN_MSG_GET_LINE_RATE_INFO,
>> + NBL_CHAN_MSG_REGISTER_NET_REP,
>> + NBL_CHAN_MSG_UNREGISTER_NET_REP,
>> + NBL_CHAN_MSG_REGISTER_ETH_REP,
>> + NBL_CHAN_MSG_UNREGISTER_ETH_REP,
>> + NBL_CHAN_MSG_REGISTER_UPCALL_PORT,
>> + NBL_CHAN_MSG_UNREGISTER_UPCALL_PORT,
>> + NBL_CHAN_MSG_GET_PORT_STATE,
>> + NBL_CHAN_MSG_SET_PORT_ADVERTISING,
>> + NBL_CHAN_MSG_GET_MODULE_INFO,
>> + NBL_CHAN_MSG_GET_MODULE_EEPROM,
>> + NBL_CHAN_MSG_GET_LINK_STATE,
>> + NBL_CHAN_MSG_NOTIFY_LINK_STATE,
>> + NBL_CHAN_MSG_GET_QUEUE_CXT,
>> + NBL_CHAN_MSG_CFG_LOG,
>> + NBL_CHAN_MSG_INIT_VDPAQ,
>> + NBL_CHAN_MSG_DESTROY_VDPAQ,
>> + NBL_CHAN_MSG_GET_UPCALL_PORT,
>> + NBL_CHAN_MSG_NOTIFY_ETH_REP_LINK_STATE,
>> + NBL_CHAN_MSG_SET_ETH_MAC_ADDR,
>> + NBL_CHAN_MSG_GET_FUNCTION_ID,
>> + NBL_CHAN_MSG_GET_CHIP_TEMPERATURE,
>> + NBL_CHAN_MSG_DISABLE_HW_FLOW,
>> + NBL_CHAN_MSG_ENABLE_HW_FLOW,
>> + NBL_CHAN_MSG_SET_UPCALL_RULE,
>> + NBL_CHAN_MSG_UNSET_UPCALL_RULE,
>> + NBL_CHAN_MSG_GET_REG_DUMP,
>> + NBL_CHAN_MSG_GET_REG_DUMP_LEN,
>> + NBL_CHAN_MSG_CFG_LAG_HASH_ALGORITHM,
>> + NBL_CHAN_MSG_CFG_LAG_MEMBER_FWD,
>> + NBL_CHAN_MSG_CFG_LAG_MEMBER_LIST,
>> + NBL_CHAN_MSG_CFG_LAG_MEMBER_UP_ATTR,
>> + NBL_CHAN_MSG_ADD_LAG_FLOW,
>> + NBL_CHAN_MSG_DEL_LAG_FLOW,
>> + NBL_CHAN_MSG_SWITCHDEV_INIT_CMDQ,
>> + NBL_CHAN_MSG_SWITCHDEV_DEINIT_CMDQ,
>> + NBL_CHAN_MSG_SET_TC_FLOW_INFO,
>> + NBL_CHAN_MSG_UNSET_TC_FLOW_INFO,
>> + NBL_CHAN_MSG_INIT_ACL,
>> + NBL_CHAN_MSG_UNINIT_ACL,
>> + NBL_CHAN_MSG_CFG_LAG_MCC,
>> + NBL_CHAN_MSG_REGISTER_VSI2Q,
>> + NBL_CHAN_MSG_SETUP_Q2VSI,
>> + NBL_CHAN_MSG_REMOVE_Q2VSI,
>> + NBL_CHAN_MSG_SETUP_RSS,
>> + NBL_CHAN_MSG_REMOVE_RSS,
>> + NBL_CHAN_MSG_GET_REP_QUEUE_INFO,
>> + NBL_CHAN_MSG_CTRL_PORT_LED,
>> + NBL_CHAN_MSG_NWAY_RESET,
>> + NBL_CHAN_MSG_SET_INTL_SUPPRESS_LEVEL,
>> + NBL_CHAN_MSG_GET_ETH_STATS,
>> + NBL_CHAN_MSG_GET_MODULE_TEMPERATURE,
>> + NBL_CHAN_MSG_GET_BOARD_INFO,
>> + NBL_CHAN_MSG_GET_P4_USED,
>> + NBL_CHAN_MSG_GET_VF_BASE_VSI_ID,
>> + NBL_CHAN_MSG_ADD_LLDP_FLOW,
>> + NBL_CHAN_MSG_DEL_LLDP_FLOW,
>> + NBL_CHAN_MSG_CFG_ETH_BOND_INFO,
>> + NBL_CHAN_MSG_CFG_DUPPKT_MCC,
>> + NBL_CHAN_MSG_ADD_ND_UPCALL_FLOW,
>> + NBL_CHAN_MSG_DEL_ND_UPCALL_FLOW,
>> + NBL_CHAN_MSG_GET_BOARD_ID,
>> + NBL_CHAN_MSG_SET_SHAPING_DPORT_VLD,
>> + NBL_CHAN_MSG_SET_DPORT_FC_TH_VLD,
>> + NBL_CHAN_MSG_REGISTER_RDMA_BOND,
>> + NBL_CHAN_MSG_UNREGISTER_RDMA_BOND,
>> + NBL_CHAN_MSG_RESTORE_NETDEV_QUEUE,
>> + NBL_CHAN_MSG_RESTART_NETDEV_QUEUE,
>> + NBL_CHAN_MSG_RESTORE_HW_QUEUE,
>> + NBL_CHAN_MSG_KEEP_ALIVE,
>> + NBL_CHAN_MSG_GET_BASE_MAC_ADDR,
>> + NBL_CHAN_MSG_CFG_BOND_SHAPING,
>> + NBL_CHAN_MSG_CFG_BGID_BACK_PRESSURE,
>> + NBL_CHAN_MSG_ALLOC_KT_BLOCK,
>> + NBL_CHAN_MSG_FREE_KT_BLOCK,
>> + NBL_CHAN_MSG_GET_USER_QUEUE_INFO,
>> + NBL_CHAN_MSG_GET_ETH_BOND_INFO,
>> + NBL_CHAN_MSG_CLEAR_ACCEL_FLOW,
>> + NBL_CHAN_MSG_SET_BRIDGE_MODE,
>> + NBL_CHAN_MSG_GET_VF_FUNCTION_ID,
>> + NBL_CHAN_MSG_NOTIFY_LINK_FORCED,
>> + NBL_CHAN_MSG_SET_PMD_DEBUG,
>> + NBL_CHAN_MSG_REGISTER_FUNC_MAC,
>> + NBL_CHAN_MSG_SET_TX_RATE,
>> + NBL_CHAN_MSG_REGISTER_FUNC_LINK_FORCED,
>> + NBL_CHAN_MSG_GET_LINK_FORCED,
>> + NBL_CHAN_MSG_REGISTER_FUNC_VLAN,
>> + NBL_CHAN_MSG_GET_FD_FLOW,
>> + NBL_CHAN_MSG_GET_FD_FLOW_CNT,
>> + NBL_CHAN_MSG_GET_FD_FLOW_ALL,
>> + NBL_CHAN_MSG_GET_FD_FLOW_MAX,
>> + NBL_CHAN_MSG_REPLACE_FD_FLOW,
>> + NBL_CHAN_MSG_REMOVE_FD_FLOW,
>> + NBL_CHAN_MSG_CFG_FD_FLOW_STATE,
>> + NBL_CHAN_MSG_REGISTER_FUNC_RATE,
>> + NBL_CHAN_MSG_NOTIFY_VLAN,
>> + NBL_CHAN_MSG_GET_XDP_QUEUE_INFO,
>> + NBL_CHAN_MSG_STOP_ABNORMAL_SW_QUEUE,
>> + NBL_CHAN_MSG_STOP_ABNORMAL_HW_QUEUE,
>> + NBL_CHAN_MSG_NOTIFY_RESET_EVENT,
>> + NBL_CHAN_MSG_ACK_RESET_EVENT,
>> + NBL_CHAN_MSG_GET_VF_VSI_ID,
>> + NBL_CHAN_MSG_CONFIGURE_QOS,
>> + NBL_CHAN_MSG_GET_PFC_BUFFER_SIZE,
>> + NBL_CHAN_MSG_SET_PFC_BUFFER_SIZE,
>> + NBL_CHAN_MSG_GET_VF_STATS,
>> + NBL_CHAN_MSG_REGISTER_FUNC_TRUST,
>> + NBL_CHAN_MSG_NOTIFY_TRUST,
>> + NBL_CHAN_MSG_CHECK_VF_IS_ACTIVE,
>> + NBL_CHAN_MSG_GET_ETH_ABNORMAL_STATS,
>> + NBL_CHAN_MSG_GET_ETH_CTRL_STATS,
>> + NBL_CHAN_MSG_GET_PAUSE_STATS,
>> + NBL_CHAN_MSG_GET_ETH_MAC_STATS,
>> + NBL_CHAN_MSG_GET_FEC_STATS,
>> + NBL_CHAN_MSG_CFG_MULTI_MCAST_RULE,
>> + NBL_CHAN_MSG_GET_LINK_DOWN_COUNT,
>> + NBL_CHAN_MSG_GET_LINK_STATUS_OPCODE,
>> + NBL_CHAN_MSG_GET_RMON_STATS,
>> + NBL_CHAN_MSG_REGISTER_PF_NAME,
>> + NBL_CHAN_MSG_GET_PF_NAME,
>> + NBL_CHAN_MSG_CONFIGURE_RDMA_BW,
>> + NBL_CHAN_MSG_SET_RATE_LIMIT,
>> + NBL_CHAN_MSG_SET_TC_WGT,
>> + NBL_CHAN_MSG_REMOVE_QUEUE,
>> + NBL_CHAN_MSG_GET_MIRROR_TABLE_ID,
>> + NBL_CHAN_MSG_CONFIGURE_MIRROR,
>> + NBL_CHAN_MSG_CONFIGURE_MIRROR_TABLE,
>> + NBL_CHAN_MSG_CLEAR_MIRROR_CFG,
>> + NBL_CHAN_MSG_MIRROR_OUTPUTPORT_NOTIFY,
>> + NBL_CHAN_MSG_CHECK_FLOWTABLE_SPEC,
>> + NBL_CHAN_MSG_CHECK_VF_IS_VDPA,
>> + NBL_CHAN_MSG_GET_VDPA_VF_STATS,
>> + NBL_CHAN_MSG_SET_RX_RATE,
>> + NBL_CHAN_MSG_GET_UVN_PKT_DROP_STATS,
>> + NBL_CHAN_MSG_GET_USTORE_PKT_DROP_STATS,
>> + NBL_CHAN_MSG_GET_USTORE_TOTAL_PKT_DROP_STATS,
>> + NBL_CHAN_MSG_SET_WOL,
>> + NBL_CHAN_MSG_INIT_VF_MSIX_MAP,
>> + NBL_CHAN_MSG_GET_ST_NAME,
>> + NBL_CHAN_MSG_MTU_SET = 501,
>> + NBL_CHAN_MSG_SET_RXFH_INDIR = 506,
>> + NBL_CHAN_MSG_SET_RXFH_RSS_ALG_SEL = 508,
>> + /* mailbox msg end */
>> + NBL_CHAN_MSG_MAILBOX_MAX,
>> +};
>> +
>This is a big enum. Is there a possibility to group them by functionality?
Thank you for your feedback.
As mentioned in the commit message, for compatibility,
the msg ID values are fixed and cannot be reordered or renumbered.
This constraintensures backward compatibility with existing
implementations that rely on these numeric values.
---illusion.wang
^ permalink raw reply
* 回复:[PATCH v10 net-next 02/11] net/nebula-matrix: add our driver architecture
From: Illusion Wang @ 2026-04-07 6:40 UTC (permalink / raw)
To: Mohsin Bashir, Dimon, Alvin, Sam, netdev
Cc: andrew+netdev, corbet, kuba, linux-doc, lorenzo, pabeni, horms,
vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
hkallweit1, jani.nikula, open list
In-Reply-To: <bf9f7c6f-8759-4f4f-8e35-2bd7c446d102@gmail.com>
>> +
>> + chan_mgt = devm_kzalloc(dev, sizeof(*chan_mgt), GFP_KERNEL);
>> + if (!chan_mgt)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + chan_mgt->common = common;
>> + chan_mgt->hw_ops_tbl = hw_ops_tbl;
>> +
>> + mailbox = devm_kzalloc(dev, sizeof(*mailbox), GFP_KERNEL);
>> + if (!mailbox)
>> + return ERR_PTR(-ENOMEM);
>Here, if mailbox allocation fails, we return without freeing chan_mgt
>resulting in a leak.
>> + mailbox->chan_type = NBL_CHAN_TYPE_MAILBOX;
>> + chan_mgt->chan_info[NBL_CHAN_TYPE_MAILBOX] = mailbox;
>> +
>> + return chan_mgt;
>> +}
Thanks for your feedback.
I've carefully considered your comment about the potential
memory leak in the provided code snippet,
but I use devm_kzalloc(), the area is guaranteed to be
freed whether initialization fails half-way or the device
gets detached.
ps:Documentation\driver-api\driver-model\devres.tst
my_init_one()
{
struct mydev *d;
d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
if (!d)
return -ENOMEM;
d->ring = dmam_alloc_coherent(...);
if (!d->ring)
return -ENOMEM;
if (check something)
return -EINVAL;
...
}
--illusion.wang
^ permalink raw reply
* [PATCH] hwmon: (yogafan) various markup improvements
From: Randy Dunlap @ 2026-04-07 5:23 UTC (permalink / raw)
To: linux-kernel
Cc: Randy Dunlap, Sergio Melas, Guenter Roeck, linux-hwmon,
Jonathan Corbet, Shuah Khan, linux-doc
There are several places in yogafan.rst where it appears that lines
are meant to be presented on their own but instead they are strung
together due to the lack of markups. Fix these issues by:
- using bullets where needed
- indenting continuation lines of bulleted items
- using a table where appropriate
- using a literal block where appropriate
Fixes: c67c248ca406 ("hwmon: (yogafan) Add support for Lenovo Yoga/Legion fan monitoring")
Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
---
Cc: Sergio Melas <sergiomelas@gmail.com>
Cc: Guenter Roeck <linux@roeck-us.net>
Cc: linux-hwmon@vger.kernel.org
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Shuah Khan <skhan@linuxfoundation.org>
Cc: linux-doc@vger.kernel.org
Documentation/hwmon/yogafan.rst | 55 ++++++++++++++++--------------
1 file changed, 31 insertions(+), 24 deletions(-)
--- linux-next-20260406.orig/Documentation/hwmon/yogafan.rst
+++ linux-next-20260406/Documentation/hwmon/yogafan.rst
@@ -7,8 +7,8 @@ Kernel driver yogafan
Supported chips:
* Lenovo Yoga, Legion, IdeaPad, Slim, Flex, and LOQ Embedded Controllers
- Prefix: 'yogafan'
- Addresses: ACPI handle (See Database Below)
+ * Prefix: 'yogafan'
+ * Addresses: ACPI handle (See Database Below)
Author: Sergio Melas <sergiomelas@gmail.com>
@@ -31,19 +31,21 @@ deterministically via a DMI Product Fami
eliminating the need for runtime heuristics.
1. 8-bit EC Architecture (Multiplier: 100)
+
- **Families:** Yoga, IdeaPad, Slim, Flex.
- **Technical Detail:** These models allocate a single 8-bit register for
- tachometer data. Since 8-bit fields are limited to a value of 255, the
- BIOS stores fan speed in units of 100 RPM (e.g., 42 = 4200 RPM).
+ tachometer data. Since 8-bit fields are limited to a value of 255, the
+ BIOS stores fan speed in units of 100 RPM (e.g., 42 = 4200 RPM).
2. 16-bit EC Architecture (Multiplier: 1)
+
- **Families:** Legion, LOQ.
- **Technical Detail:** High-performance gaming models require greater
- precision for fans exceeding 6000 RPM. These use a 16-bit word (2 bytes)
- storing the raw RPM value directly.
+ precision for fans exceeding 6000 RPM. These use a 16-bit word (2 bytes)
+ storing the raw RPM value directly.
-Filter Details:
----------------
+Filter Details
+--------------
The RLLag filter is a passive discrete-time first-order lag model that ensures:
- **Smoothing:** Low-resolution step increments are smoothed into 1-RPM increments.
@@ -66,8 +68,11 @@ Usage
-----
The driver exposes standard hwmon sysfs attributes:
+
+=============== ============================
Attribute Description
fanX_input Filtered fan speed in RPM.
+=============== ============================
Note: If the hardware reports 0 RPM, the filter is bypassed and 0 is reported
@@ -78,22 +83,24 @@ immediately to ensure the user knows the
LENOVO FAN CONTROLLER: MASTER REFERENCE DATABASE (2026)
====================================================================================================
-MODEL (DMI PN) | FAMILY / SERIES | EC OFFSET | FULL ACPI OBJECT PATH | WIDTH | MULTiplier
-----------------------------------------------------------------------------------------------------
-82N7 | Yoga 14cACN | 0x06 | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
-80V2 / 81C3 | Yoga 710/720 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
-83E2 / 83DN | Yoga Pro 7/9 | 0xFE | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
-82A2 / 82A3 | Yoga Slim 7 | 0x06 | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
-81YM / 82FG | IdeaPad 5 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
-82JW / 82JU | Legion 5 (AMD) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS (Fan1) | 16-bit | 1
-82JW / 82JU | Legion 5 (AMD) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FA2S (Fan2) | 16-bit | 1
-82WQ | Legion 7i (Int) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS (Fan1) | 16-bit | 1
-82WQ | Legion 7i (Int) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FA2S (Fan2) | 16-bit | 1
-82XV / 83DV | LOQ 15/16 | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS /FA2S | 16-bit | 1
-83AK | ThinkBook G6 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
-81X1 | Flex 5 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
-*Legacy* | Pre-2020 Models | 0x06 | \_SB.PCI0.LPC.EC.FAN0 | 8-bit | 100
-----------------------------------------------------------------------------------------------------
+::
+
+ MODEL (DMI PN) | FAMILY / SERIES | EC OFFSET | FULL ACPI OBJECT PATH | WIDTH | MULTiplier
+ ----------------------------------------------------------------------------------------------------
+ 82N7 | Yoga 14cACN | 0x06 | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
+ 80V2 / 81C3 | Yoga 710/720 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
+ 83E2 / 83DN | Yoga Pro 7/9 | 0xFE | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
+ 82A2 / 82A3 | Yoga Slim 7 | 0x06 | \_SB.PCI0.LPC0.EC0.FANS | 8-bit | 100
+ 81YM / 82FG | IdeaPad 5 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
+ 82JW / 82JU | Legion 5 (AMD) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS (Fan1) | 16-bit | 1
+ 82JW / 82JU | Legion 5 (AMD) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FA2S (Fan2) | 16-bit | 1
+ 82WQ | Legion 7i (Int) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS (Fan1) | 16-bit | 1
+ 82WQ | Legion 7i (Int) | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FA2S (Fan2) | 16-bit | 1
+ 82XV / 83DV | LOQ 15/16 | 0xFE/0xFF | \_SB.PCI0.LPC0.EC0.FANS /FA2S | 16-bit | 1
+ 83AK | ThinkBook G6 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
+ 81X1 | Flex 5 | 0x06 | \_SB.PCI0.LPC0.EC0.FAN0 | 8-bit | 100
+ *Legacy* | Pre-2020 Models | 0x06 | \_SB.PCI0.LPC.EC.FAN0 | 8-bit | 100
+ ----------------------------------------------------------------------------------------------------
METHODOLOGY & IDENTIFICATION:
^ permalink raw reply
* Re: [PATCH v10 07/21] gpu: nova-core: mm: Add TLB flush support
From: Matthew Brost @ 2026-04-07 5:14 UTC (permalink / raw)
To: Joel Fernandes
Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning,
dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Alex Deucher, Christian Koenig, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui,
Matthew Auld, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple,
Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi,
Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner,
Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx,
intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <39a476f4-ecac-4313-a59f-e00e72d2b426@nvidia.com>
On Mon, Apr 06, 2026 at 06:10:07PM -0400, Joel Fernandes wrote:
>
>
> On 4/6/2026 5:24 PM, Joel Fernandes wrote:
> >
> >
> > On 4/2/2026 1:59 AM, Matthew Brost wrote:
> >> On Tue, Mar 31, 2026 at 05:20:34PM -0400, Joel Fernandes wrote:
> >>> Add TLB (Translation Lookaside Buffer) flush support for GPU MMU.
> >>>
> >>> After modifying page table entries, the GPU's TLB must be invalidated
> >>> to ensure the new mappings take effect. The Tlb struct provides flush
> >>> functionality through BAR0 registers.
> >>>
> >>> The flush operation writes the page directory base address and triggers
> >>> an invalidation, polling for completion with a 2 second timeout matching
> >>> the Nouveau driver.
> >>>
> >>> Cc: Nikola Djukic <ndjukic@nvidia.com>
> >>> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> >>> ---
> >>> drivers/gpu/nova-core/mm.rs | 1 +
> >>> drivers/gpu/nova-core/mm/tlb.rs | 95 +++++++++++++++++++++++++++++++++
> >>> drivers/gpu/nova-core/regs.rs | 42 +++++++++++++++
> >>> 3 files changed, 138 insertions(+)
> >>> create mode 100644 drivers/gpu/nova-core/mm/tlb.rs
> >>>
> >>> diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
> >>> index 8f3089a5fa88..cfe9cbe11d57 100644
> >>> --- a/drivers/gpu/nova-core/mm.rs
> >>> +++ b/drivers/gpu/nova-core/mm.rs
> >>> @@ -5,6 +5,7 @@
> >>> #![expect(dead_code)]
> >>>
> >>> pub(crate) mod pramin;
> >>> +pub(crate) mod tlb;
> >>>
> >>> use kernel::sizes::SZ_4K;
> >>>
> >>> diff --git a/drivers/gpu/nova-core/mm/tlb.rs b/drivers/gpu/nova-core/mm/tlb.rs
> >>> new file mode 100644
> >>> index 000000000000..cd3cbcf4c739
> >>> --- /dev/null
> >>> +++ b/drivers/gpu/nova-core/mm/tlb.rs
> >>> @@ -0,0 +1,95 @@
> >>> +// SPDX-License-Identifier: GPL-2.0
> >>> +
> >>> +//! TLB (Translation Lookaside Buffer) flush support for GPU MMU.
> >>> +//!
> >>> +//! After modifying page table entries, the GPU's TLB must be flushed to
> >>> +//! ensure the new mappings take effect. This module provides TLB flush
> >>> +//! functionality for virtual memory managers.
> >>> +//!
> >>> +//! # Example
> >>> +//!
> >>> +//! ```ignore
> >>> +//! use crate::mm::tlb::Tlb;
> >>> +//!
> >>> +//! fn page_table_update(tlb: &Tlb, pdb_addr: VramAddress) -> Result<()> {
> >>> +//! // ... modify page tables ...
> >>> +//!
> >>> +//! // Flush TLB to make changes visible (polls for completion).
> >>> +//! tlb.flush(pdb_addr)?;
> >>> +//!
> >>> +//! Ok(())
> >>> +//! }
> >>> +//! ```
> >>> +
> >>> +use kernel::{
> >>> + devres::Devres,
> >>> + io::poll::read_poll_timeout,
> >>> + io::Io,
> >>> + new_mutex,
> >>> + prelude::*,
> >>> + sync::{
> >>> + Arc,
> >>> + Mutex, //
> >>> + },
> >>> + time::Delta, //
> >>> +};
> >>> +
> >>> +use crate::{
> >>> + driver::Bar0,
> >>> + mm::VramAddress,
> >>> + regs, //
> >>> +};
> >>> +
> >>> +/// TLB manager for GPU translation buffer operations.
> >>> +#[pin_data]
> >>> +pub(crate) struct Tlb {
> >>> + bar: Arc<Devres<Bar0>>,
> >>> + /// TLB flush serialization lock: This lock is acquired during the
> >>> + /// DMA fence signalling critical path. It must NEVER be held across any
> >>> + /// reclaimable CPU memory allocations because the memory reclaim path can
> >>> + /// call `dma_fence_wait()`, which would deadlock with this lock held.
> >>> + #[pin]
> >>> + lock: Mutex<()>,
> >>> +}
> >>> +
> >>> +impl Tlb {
> >>> + /// Create a new TLB manager.
> >>> + pub(super) fn new(bar: Arc<Devres<Bar0>>) -> impl PinInit<Self> {
> >>> + pin_init!(Self {
> >>> + bar,
> >>> + lock <- new_mutex!((), "tlb_flush"),
> >>> + })
> >>> + }
> >>> +
> >>> + /// Flush the GPU TLB for a specific page directory base.
> >>> + ///
> >>> + /// This invalidates all TLB entries associated with the given PDB address.
> >>> + /// Must be called after modifying page table entries to ensure the GPU sees
> >>> + /// the updated mappings.
> >>> + pub(crate) fn flush(&self, pdb_addr: VramAddress) -> Result {
> >>
> >> This landed on my list randomly, so I took a look.
> >>
> >> Wouldn’t you want to virtualize the invalidation based on your device?
> >> For example, what if you need to register interface changes on future hardware?
> >
> > Good point, for future hardware it indeed makes sense. I will do that.
> Actually, at least in the future as far as I can see, the register definitions
> are the same for TLB invalidation are the same, so we are good and I will not be
> making any change in this regard.
>
> But, thanks for raising the point and forcing me to double check!
>
Not my driver, but this looks like a classic “works now” change that may
not hold up later, which is why I replied to something that isn’t really
my business.
Again, not my area, but I’ve been through this before. Generally,
getting the abstractions right up front pays off.
Matt
> --
> Joel Fernandes
>
^ permalink raw reply
* [PATCH v2 5/5] HID: hid-oxp: Add Vibration Intensity Attributes
From: Derek J. Clark @ 2026-04-07 4:13 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Pierre-Loup A . Griffais, Lambert Fan, Derek J . Clark,
linux-input, linux-doc, linux-kernel
In-Reply-To: <20260407041354.2283201-1-derekjohn.clark@gmail.com>
Adds attribute for setting the rumble intensity level. This setting must
be re-applied after the gamepad mode is set as doing so resets this to
the default value.
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
drivers/hid/hid-oxp.c | 80 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 78 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-oxp.c b/drivers/hid/hid-oxp.c
index 1100f1f14f35..cad6973089a0 100644
--- a/drivers/hid/hid-oxp.c
+++ b/drivers/hid/hid-oxp.c
@@ -34,6 +34,7 @@ enum oxp_function_index {
OXP_FID_GEN1_RGB_SET = 0x07,
OXP_FID_GEN1_RGB_REPLY = 0x0f,
OXP_FID_GEN2_TOGGLE_MODE = 0xb2,
+ OXP_FID_GEN2_RUMBLE_SET = 0xb3,
OXP_FID_GEN2_KEY_STATE = 0xb4,
OXP_FID_GEN2_STATUS_EVENT = 0xb8,
};
@@ -178,6 +179,7 @@ static struct oxp_hid_cfg {
struct mutex cfg_mutex; /*ensure single synchronous output report*/
u8 rgb_brightness;
u8 gamepad_mode;
+ u8 rumble_intensity;
u8 rgb_effect;
u8 rgb_speed;
u8 rgb_en;
@@ -263,6 +265,11 @@ static const char *const oxp_rgb_effect_text[] = {
[OXP_EFFECT_MONO_LIST] = "monocolor",
};
+enum oxp_rumble_side_index {
+ OXP_RUMBLE_LEFT = 0x00,
+ OXP_RUMBLE_RIGHT,
+};
+
struct oxp_gen_1_rgb_report {
u8 report_id;
u8 message_id;
@@ -338,6 +345,7 @@ static int oxp_hid_raw_event_gen_1(struct hid_device *hdev,
static int oxp_gen_2_property_out(enum oxp_function_index fid, u8 *data, u8 data_size);
static int oxp_set_buttons(void);
+static int oxp_rumble_intensity_set(u8 intensity);
static void oxp_mcu_init_fn(struct work_struct *work)
{
@@ -365,6 +373,12 @@ static void oxp_mcu_init_fn(struct work_struct *work)
if (ret)
dev_err(&drvdata.hdev->dev,
"Error: Failed to set gamepad mode: %i\n", ret);
+
+ /* Set vibration level */
+ ret = oxp_rumble_intensity_set(drvdata.rumble_intensity);
+ if (ret)
+ dev_err(&drvdata.hdev->dev,
+ "Error: Failed to set rumble intensity: %i\n", ret);
}
static DECLARE_DELAYED_WORK(oxp_mcu_init, oxp_mcu_init_fn);
@@ -513,6 +527,14 @@ static ssize_t gamepad_mode_store(struct device *dev,
drvdata.gamepad_mode = data[0];
+ if (drvdata.gamepad_mode == OXP_GP_MODE_DEBUG)
+ return count;
+
+ /* Re-apply rumble settings as switching gamepad mode will override */
+ ret = oxp_rumble_intensity_set(drvdata.rumble_intensity);
+ if (ret)
+ return ret;
+
return count;
}
@@ -858,6 +880,59 @@ static ssize_t button_mapping_options_show(struct device *dev,
}
static DEVICE_ATTR_RO(button_mapping_options);
+static int oxp_rumble_intensity_set(u8 intensity)
+{
+ u8 header[15] = { 0x02, 0x38, 0x02, 0xe3, 0x39, 0xe3, 0x39, 0xe3,
+ 0x39, 0x01, intensity, 0x05, 0xe3, 0x39, 0xe3 };
+ u8 footer[9] = { 0x39, 0xe3, 0x39, 0xe3, 0xe3, 0x02, 0x04, 0x39, 0x39 };
+ size_t footer_size = ARRAY_SIZE(footer);
+ size_t header_size = ARRAY_SIZE(header);
+ u8 data[59] = { 0x0 };
+ size_t data_size = ARRAY_SIZE(data);
+
+ memcpy(data, header, header_size);
+ memcpy(data + data_size - footer_size, footer, footer_size);
+
+ return oxp_gen_2_property_out(OXP_FID_GEN2_RUMBLE_SET, data, data_size);
+}
+
+static ssize_t rumble_intensity_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret;
+ u8 val;
+
+ ret = kstrtou8(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ if (val < 0 || val > 5)
+ return -EINVAL;
+
+ ret = oxp_rumble_intensity_set(val);
+ if (ret)
+ return ret;
+
+ drvdata.rumble_intensity = val;
+
+ return count;
+}
+
+static ssize_t rumble_intensity_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%i\n", drvdata.rumble_intensity);
+}
+static DEVICE_ATTR_RW(rumble_intensity);
+
+static ssize_t rumble_intensity_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "0-5\n");
+}
+static DEVICE_ATTR_RO(rumble_intensity_range);
+
#define OXP_DEVICE_ATTR_RW(_name, _group) \
static ssize_t _name##_store(struct device *dev, \
struct device_attribute *attr, \
@@ -949,6 +1024,8 @@ static struct attribute *oxp_cfg_attrs[] = {
&dev_attr_gamepad_mode.attr,
&dev_attr_gamepad_mode_index.attr,
&dev_attr_reset_buttons.attr,
+ &dev_attr_rumble_intensity.attr,
+ &dev_attr_rumble_intensity_range.attr,
NULL,
};
@@ -1420,10 +1497,9 @@ static int oxp_cfg_probe(struct hid_device *hdev, u16 up)
drvdata.bmap_1 = bmap_1;
drvdata.bmap_2 = bmap_2;
+ drvdata.rumble_intensity = 5;
mod_delayed_work(system_wq, &oxp_mcu_init, msecs_to_jiffies(50));
- drvdata.gamepad_mode = OXP_GP_MODE_XINPUT;
-
ret = devm_device_add_group(&hdev->dev, &oxp_cfg_attrs_group);
if (ret)
return dev_err_probe(&hdev->dev, ret,
--
2.53.0
^ permalink raw reply related
* [PATCH v2 4/5] HID: hid-oxp: Add Button Mapping Interface
From: Derek J. Clark @ 2026-04-07 4:13 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Pierre-Loup A . Griffais, Lambert Fan, Derek J . Clark,
linux-input, linux-doc, linux-kernel
In-Reply-To: <20260407041354.2283201-1-derekjohn.clark@gmail.com>
Adds button mapping interface for second generation OneXPlayer
configuration HID interfaces. This interface allows the MCU to swap
button mappings at the hardware level. The current state cannot be
retrieved, and the mappings may have been modified in Windows prior, so
we reset the button mapping at init and expose an attribute to allow
userspace to do this again at any time.
The interface requires two pages of button mapping data to be sent
before the settings will take place. Since the MCU requires a 200ms
delay after each message (total 400ms for these attributes) use the same
debounce work queue method we used for RGB. This will allow for
userspace or udev rules to rapidly map all buttons. The values will
be cached before the final write is finally sent to the device.
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v2:
- Add detection of post-suspend MCU init to trigger setting the button
map again.
---
drivers/hid/hid-oxp.c | 565 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 565 insertions(+)
diff --git a/drivers/hid/hid-oxp.c b/drivers/hid/hid-oxp.c
index c62952537d98..1100f1f14f35 100644
--- a/drivers/hid/hid-oxp.c
+++ b/drivers/hid/hid-oxp.c
@@ -34,10 +34,145 @@ enum oxp_function_index {
OXP_FID_GEN1_RGB_SET = 0x07,
OXP_FID_GEN1_RGB_REPLY = 0x0f,
OXP_FID_GEN2_TOGGLE_MODE = 0xb2,
+ OXP_FID_GEN2_KEY_STATE = 0xb4,
OXP_FID_GEN2_STATUS_EVENT = 0xb8,
};
+#define OXP_MAPPING_GAMEPAD 0x01
+#define OXP_MAPPING_KEYBOARD 0x02
+
+struct oxp_button_data {
+ u8 mode;
+ u8 index;
+ u8 key_id;
+ u8 padding[2];
+} __packed;
+
+struct oxp_button_entry {
+ struct oxp_button_data data;
+ const char *name;
+};
+
+static const struct oxp_button_entry oxp_button_table[] = {
+ /* Gamepad Buttons */
+ { { OXP_MAPPING_GAMEPAD, 0x01 }, "BTN_A" },
+ { { OXP_MAPPING_GAMEPAD, 0x02 }, "BTN_B" },
+ { { OXP_MAPPING_GAMEPAD, 0x03 }, "BTN_X" },
+ { { OXP_MAPPING_GAMEPAD, 0x04 }, "BTN_Y" },
+ { { OXP_MAPPING_GAMEPAD, 0x05 }, "BTN_LB" },
+ { { OXP_MAPPING_GAMEPAD, 0x06 }, "BTN_RB" },
+ { { OXP_MAPPING_GAMEPAD, 0x07 }, "BTN_LT" },
+ { { OXP_MAPPING_GAMEPAD, 0x08 }, "BTN_RT" },
+ { { OXP_MAPPING_GAMEPAD, 0x09 }, "BTN_START" },
+ { { OXP_MAPPING_GAMEPAD, 0x0a }, "BTN_SELECT" },
+ { { OXP_MAPPING_GAMEPAD, 0x0b }, "BTN_L3" },
+ { { OXP_MAPPING_GAMEPAD, 0x0c }, "BTN_R3" },
+ { { OXP_MAPPING_GAMEPAD, 0x0d }, "DPAD_UP" },
+ { { OXP_MAPPING_GAMEPAD, 0x0e }, "DPAD_DOWN" },
+ { { OXP_MAPPING_GAMEPAD, 0x0f }, "DPAD_LEFT" },
+ { { OXP_MAPPING_GAMEPAD, 0x10 }, "DPAD_RIGHT" },
+ { { OXP_MAPPING_GAMEPAD, 0x11 }, "JOY_L_UP" },
+ { { OXP_MAPPING_GAMEPAD, 0x12 }, "JOY_L_UP_RIGHT" },
+ { { OXP_MAPPING_GAMEPAD, 0x13 }, "JOY_L_RIGHT" },
+ { { OXP_MAPPING_GAMEPAD, 0x14 }, "JOY_L_DOWN_RIGHT" },
+ { { OXP_MAPPING_GAMEPAD, 0x15 }, "JOY_L_DOWN" },
+ { { OXP_MAPPING_GAMEPAD, 0x16 }, "JOY_L_DOWN_LEFT" },
+ { { OXP_MAPPING_GAMEPAD, 0x17 }, "JOY_L_LEFT" },
+ { { OXP_MAPPING_GAMEPAD, 0x18 }, "JOY_L_UP_LEFT" },
+ { { OXP_MAPPING_GAMEPAD, 0x19 }, "JOY_R_UP" },
+ { { OXP_MAPPING_GAMEPAD, 0x1a }, "JOY_R_UP_RIGHT" },
+ { { OXP_MAPPING_GAMEPAD, 0x1b }, "JOY_R_RIGHT" },
+ { { OXP_MAPPING_GAMEPAD, 0x1c }, "JOY_R_DOWN_RIGHT" },
+ { { OXP_MAPPING_GAMEPAD, 0x1d }, "JOY_R_DOWN" },
+ { { OXP_MAPPING_GAMEPAD, 0x1e }, "JOY_R_DOWN_LEFT" },
+ { { OXP_MAPPING_GAMEPAD, 0x1f }, "JOY_R_LEFT" },
+ { { OXP_MAPPING_GAMEPAD, 0x20 }, "JOY_R_UP_LEFT" },
+ { { OXP_MAPPING_GAMEPAD, 0x22 }, "BTN_GUIDE" },
+ /* Keyboard Keys */
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x5a }, "KEY_F1" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x5b }, "KEY_F2" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x5c }, "KEY_F3" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x5d }, "KEY_F4" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x5e }, "KEY_F5" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x5f }, "KEY_F6" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x60 }, "KEY_F7" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x61 }, "KEY_F8" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x62 }, "KEY_F9" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x63 }, "KEY_F10" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x64 }, "KEY_F11" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x65 }, "KEY_F12" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x66 }, "KEY_F13" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x67 }, "KEY_F14" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x68 }, "KEY_F15" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x69 }, "KEY_F16" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x6a }, "KEY_F17" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x6b }, "KEY_F18" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x6c }, "KEY_F19" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x6d }, "KEY_F20" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x6e }, "KEY_F21" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x6f }, "KEY_F22" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x70 }, "KEY_F23" },
+ { { OXP_MAPPING_KEYBOARD, 0x01, 0x71 }, "KEY_F24" },
+};
+
+enum oxp_joybutton_index {
+ BUTTON_A = 0x01,
+ BUTTON_B,
+ BUTTON_X,
+ BUTTON_Y,
+ BUTTON_LB,
+ BUTTON_RB,
+ BUTTON_LT,
+ BUTTON_RT,
+ BUTTON_START,
+ BUTTON_SELECT,
+ BUTTON_L3,
+ BUTTON_R3,
+ BUTTON_DUP,
+ BUTTON_DDOWN,
+ BUTTON_DLEFT,
+ BUTTON_DRIGHT,
+ BUTTON_M1 = 0x22,
+ BUTTON_M2,
+ /* These are unused currently, reserved for future devices */
+ BUTTON_M3,
+ BUTTON_M4,
+ BUTTON_M5,
+ BUTTON_M6,
+};
+
+struct oxp_button_idx {
+ enum oxp_joybutton_index button_idx;
+ u8 mapping_idx;
+} __packed;
+
+struct oxp_bmap_page_1 {
+ struct oxp_button_idx btn_a;
+ struct oxp_button_idx btn_b;
+ struct oxp_button_idx btn_x;
+ struct oxp_button_idx btn_y;
+ struct oxp_button_idx btn_lb;
+ struct oxp_button_idx btn_rb;
+ struct oxp_button_idx btn_lt;
+ struct oxp_button_idx btn_rt;
+ struct oxp_button_idx btn_start;
+} __packed;
+
+struct oxp_bmap_page_2 {
+ struct oxp_button_idx btn_select;
+ struct oxp_button_idx btn_l3;
+ struct oxp_button_idx btn_r3;
+ struct oxp_button_idx btn_dup;
+ struct oxp_button_idx btn_ddown;
+ struct oxp_button_idx btn_dleft;
+ struct oxp_button_idx btn_dright;
+ struct oxp_button_idx btn_m1;
+ struct oxp_button_idx btn_m2;
+} __packed;
+
static struct oxp_hid_cfg {
+ struct oxp_bmap_page_1 *bmap_1;
+ struct oxp_bmap_page_2 *bmap_2;
struct led_classdev_mc *led_mc;
struct hid_device *hdev;
struct mutex cfg_mutex; /*ensure single synchronous output report*/
@@ -48,6 +183,10 @@ static struct oxp_hid_cfg {
u8 rgb_en;
} drvdata;
+#define OXP_FILL_PAGE_SLOT(page, btn) \
+ { .button_idx = (page)->btn.button_idx, \
+ .mapping_idx = (page)->btn.mapping_idx }
+
enum oxp_gamepad_mode_index {
OXP_GP_MODE_XINPUT = 0x00,
OXP_GP_MODE_DEBUG = 0x03,
@@ -153,6 +292,10 @@ struct oxp_gen_2_rgb_report {
u8 effect;
} __packed;
+struct oxp_attr {
+ u8 index;
+};
+
static u16 get_usage_page(struct hid_device *hdev)
{
return hdev->collection[0].usage >> 16;
@@ -194,12 +337,19 @@ static int oxp_hid_raw_event_gen_1(struct hid_device *hdev,
}
static int oxp_gen_2_property_out(enum oxp_function_index fid, u8 *data, u8 data_size);
+static int oxp_set_buttons(void);
static void oxp_mcu_init_fn(struct work_struct *work)
{
u8 gp_mode_data[3] = { OXP_GP_MODE_DEBUG, 0x01, 0x02 };
int ret;
+ /* Re-apply the button mapping */
+ ret = oxp_set_buttons();
+ if (ret)
+ dev_err(&drvdata.hdev->dev,
+ "Error: Failed to set button mapping: %i\n", ret);
+
/* Cycle the gamepad mode */
ret = oxp_gen_2_property_out(OXP_FID_GEN2_TOGGLE_MODE, gp_mode_data, 3);
if (ret)
@@ -395,9 +545,410 @@ static ssize_t gamepad_mode_index_show(struct device *dev,
}
static DEVICE_ATTR_RO(gamepad_mode_index);
+static void oxp_set_defaults_bmap_1(struct oxp_bmap_page_1 *bmap)
+{
+ bmap->btn_a.button_idx = BUTTON_A;
+ bmap->btn_a.mapping_idx = 0;
+ bmap->btn_b.button_idx = BUTTON_B;
+ bmap->btn_b.mapping_idx = 1;
+ bmap->btn_x.button_idx = BUTTON_X;
+ bmap->btn_x.mapping_idx = 2;
+ bmap->btn_y.button_idx = BUTTON_Y;
+ bmap->btn_y.mapping_idx = 3;
+ bmap->btn_lb.button_idx = BUTTON_LB;
+ bmap->btn_lb.mapping_idx = 4;
+ bmap->btn_rb.button_idx = BUTTON_RB;
+ bmap->btn_rb.mapping_idx = 5;
+ bmap->btn_lt.button_idx = BUTTON_LT;
+ bmap->btn_lt.mapping_idx = 6;
+ bmap->btn_rt.button_idx = BUTTON_RT;
+ bmap->btn_rt.mapping_idx = 7;
+ bmap->btn_start.button_idx = BUTTON_START;
+ bmap->btn_start.mapping_idx = 8;
+}
+
+static void oxp_set_defaults_bmap_2(struct oxp_bmap_page_2 *bmap)
+{
+ bmap->btn_select.button_idx = BUTTON_SELECT;
+ bmap->btn_select.mapping_idx = 9;
+ bmap->btn_l3.button_idx = BUTTON_L3;
+ bmap->btn_l3.mapping_idx = 10;
+ bmap->btn_r3.button_idx = BUTTON_R3;
+ bmap->btn_r3.mapping_idx = 11;
+ bmap->btn_dup.button_idx = BUTTON_DUP;
+ bmap->btn_dup.mapping_idx = 12;
+ bmap->btn_ddown.button_idx = BUTTON_DDOWN;
+ bmap->btn_ddown.mapping_idx = 13;
+ bmap->btn_dleft.button_idx = BUTTON_DLEFT;
+ bmap->btn_dleft.mapping_idx = 14;
+ bmap->btn_dright.button_idx = BUTTON_DRIGHT;
+ bmap->btn_dright.mapping_idx = 15;
+ bmap->btn_m1.button_idx = BUTTON_M1;
+ bmap->btn_m1.mapping_idx = 48; /* KEY_F15 */
+ bmap->btn_m2.button_idx = BUTTON_M2;
+ bmap->btn_m2.mapping_idx = 49; /* KEY_F16 */
+}
+
+static void oxp_page_fill_data(char *buf, const struct oxp_button_idx *buttons,
+ size_t len)
+{
+ size_t offset_increment = sizeof(u8) + sizeof(struct oxp_button_idx);
+ size_t offset = 5;
+ unsigned int i;
+
+ for (i = 0; i < len; i++, offset += offset_increment) {
+ buf[offset] = (u8)buttons[i].button_idx;
+ memcpy(buf + offset + 1,
+ &oxp_button_table[buttons[i].mapping_idx].data,
+ sizeof(struct oxp_button_data));
+ }
+}
+
+static int oxp_set_buttons(void)
+{
+ u8 page_1[59] = { 0x02, 0x38, 0x20, 0x01, 0x01 };
+ u8 page_2[59] = { 0x02, 0x38, 0x20, 0x02, 0x01 };
+ u16 up = get_usage_page(drvdata.hdev);
+ int ret;
+
+ if (up != GEN2_USAGE_PAGE)
+ return -EINVAL;
+
+ const struct oxp_button_idx p1[] = {
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_a),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_b),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_x),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_y),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_lb),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_rb),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_lt),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_rt),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_start),
+ };
+
+ const struct oxp_button_idx p2[] = {
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_select),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_l3),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_r3),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_dup),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_ddown),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_dleft),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_dright),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_m1),
+ OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_m2),
+ };
+
+ oxp_page_fill_data(page_1, p1, ARRAY_SIZE(p1));
+ oxp_page_fill_data(page_2, p2, ARRAY_SIZE(p2));
+
+ ret = oxp_gen_2_property_out(OXP_FID_GEN2_KEY_STATE, page_1, ARRAY_SIZE(page_1));
+ if (ret)
+ return ret;
+
+ return oxp_gen_2_property_out(OXP_FID_GEN2_KEY_STATE, page_2, ARRAY_SIZE(page_2));
+}
+
+static int oxp_reset_buttons(void)
+{
+ oxp_set_defaults_bmap_1(drvdata.bmap_1);
+ oxp_set_defaults_bmap_2(drvdata.bmap_2);
+ return oxp_set_buttons();
+}
+
+static ssize_t reset_buttons_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ int val, ret;
+
+ ret = kstrtoint(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ if (val != 1)
+ return -EINVAL;
+
+ ret = oxp_reset_buttons();
+ if (ret)
+ return ret;
+
+ return count;
+}
+static DEVICE_ATTR_WO(reset_buttons);
+
+static void oxp_btn_queue_fn(struct work_struct *work)
+{
+ int ret;
+
+ ret = oxp_set_buttons();
+ if (ret)
+ dev_err(&drvdata.hdev->dev,
+ "Error: Failed to write button mapping: %i\n", ret);
+}
+
+static DECLARE_DELAYED_WORK(oxp_btn_queue, oxp_btn_queue_fn);
+
+static int oxp_button_idx_from_str(const char *buf)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(oxp_button_table); i++)
+ if (sysfs_streq(buf, oxp_button_table[i].name))
+ return i;
+
+ return -EINVAL;
+}
+
+static ssize_t map_button_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count, u8 index)
+{
+ int idx;
+
+ idx = oxp_button_idx_from_str(buf);
+ if (idx < 0)
+ return idx;
+
+ switch (index) {
+ case BUTTON_A:
+ drvdata.bmap_1->btn_a.mapping_idx = idx;
+ break;
+ case BUTTON_B:
+ drvdata.bmap_1->btn_b.mapping_idx = idx;
+ break;
+ case BUTTON_X:
+ drvdata.bmap_1->btn_x.mapping_idx = idx;
+ break;
+ case BUTTON_Y:
+ drvdata.bmap_1->btn_y.mapping_idx = idx;
+ break;
+ case BUTTON_LB:
+ drvdata.bmap_1->btn_lb.mapping_idx = idx;
+ break;
+ case BUTTON_RB:
+ drvdata.bmap_1->btn_rb.mapping_idx = idx;
+ break;
+ case BUTTON_LT:
+ drvdata.bmap_1->btn_lt.mapping_idx = idx;
+ break;
+ case BUTTON_RT:
+ drvdata.bmap_1->btn_rt.mapping_idx = idx;
+ break;
+ case BUTTON_START:
+ drvdata.bmap_1->btn_start.mapping_idx = idx;
+ break;
+ case BUTTON_SELECT:
+ drvdata.bmap_2->btn_select.mapping_idx = idx;
+ break;
+ case BUTTON_L3:
+ drvdata.bmap_2->btn_l3.mapping_idx = idx;
+ break;
+ case BUTTON_R3:
+ drvdata.bmap_2->btn_r3.mapping_idx = idx;
+ break;
+ case BUTTON_DUP:
+ drvdata.bmap_2->btn_dup.mapping_idx = idx;
+ break;
+ case BUTTON_DDOWN:
+ drvdata.bmap_2->btn_ddown.mapping_idx = idx;
+ break;
+ case BUTTON_DLEFT:
+ drvdata.bmap_2->btn_dleft.mapping_idx = idx;
+ break;
+ case BUTTON_DRIGHT:
+ drvdata.bmap_2->btn_dright.mapping_idx = idx;
+ break;
+ case BUTTON_M1:
+ drvdata.bmap_2->btn_m1.mapping_idx = idx;
+ break;
+ case BUTTON_M2:
+ drvdata.bmap_2->btn_m2.mapping_idx = idx;
+ break;
+ default:
+ return -EINVAL;
+ }
+ mod_delayed_work(system_wq, &oxp_btn_queue, msecs_to_jiffies(50));
+ return count;
+}
+
+static ssize_t map_button_show(struct device *dev,
+ struct device_attribute *attr, char *buf,
+ u8 index)
+{
+ u8 i;
+
+ switch (index) {
+ case BUTTON_A:
+ i = drvdata.bmap_1->btn_a.mapping_idx;
+ break;
+ case BUTTON_B:
+ i = drvdata.bmap_1->btn_b.mapping_idx;
+ break;
+ case BUTTON_X:
+ i = drvdata.bmap_1->btn_x.mapping_idx;
+ break;
+ case BUTTON_Y:
+ i = drvdata.bmap_1->btn_y.mapping_idx;
+ break;
+ case BUTTON_LB:
+ i = drvdata.bmap_1->btn_lb.mapping_idx;
+ break;
+ case BUTTON_RB:
+ i = drvdata.bmap_1->btn_rb.mapping_idx;
+ break;
+ case BUTTON_LT:
+ i = drvdata.bmap_1->btn_lt.mapping_idx;
+ break;
+ case BUTTON_RT:
+ i = drvdata.bmap_1->btn_rt.mapping_idx;
+ break;
+ case BUTTON_START:
+ i = drvdata.bmap_1->btn_start.mapping_idx;
+ break;
+ case BUTTON_SELECT:
+ i = drvdata.bmap_2->btn_select.mapping_idx;
+ break;
+ case BUTTON_L3:
+ i = drvdata.bmap_2->btn_l3.mapping_idx;
+ break;
+ case BUTTON_R3:
+ i = drvdata.bmap_2->btn_r3.mapping_idx;
+ break;
+ case BUTTON_DUP:
+ i = drvdata.bmap_2->btn_dup.mapping_idx;
+ break;
+ case BUTTON_DDOWN:
+ i = drvdata.bmap_2->btn_ddown.mapping_idx;
+ break;
+ case BUTTON_DLEFT:
+ i = drvdata.bmap_2->btn_dleft.mapping_idx;
+ break;
+ case BUTTON_DRIGHT:
+ i = drvdata.bmap_2->btn_dright.mapping_idx;
+ break;
+ case BUTTON_M1:
+ i = drvdata.bmap_2->btn_m1.mapping_idx;
+ break;
+ case BUTTON_M2:
+ i = drvdata.bmap_2->btn_m2.mapping_idx;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (i >= ARRAY_SIZE(oxp_button_table))
+ return -EINVAL;
+
+ return sysfs_emit(buf, "%s\n", oxp_button_table[i].name);
+}
+
+static ssize_t button_mapping_options_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t count = 0;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(oxp_button_table); i++)
+ count += sysfs_emit_at(buf, count, "%s ", oxp_button_table[i].name);
+
+ if (count)
+ buf[count - 1] = '\n';
+
+ return count;
+}
+static DEVICE_ATTR_RO(button_mapping_options);
+
+#define OXP_DEVICE_ATTR_RW(_name, _group) \
+ static ssize_t _name##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ return _group##_store(dev, attr, buf, count, _name.index); \
+ } \
+ static ssize_t _name##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+ { \
+ return _group##_show(dev, attr, buf, _name.index); \
+ } \
+ static DEVICE_ATTR_RW(_name)
+
+static struct oxp_attr button_a = { BUTTON_A };
+OXP_DEVICE_ATTR_RW(button_a, map_button);
+
+static struct oxp_attr button_b = { BUTTON_B };
+OXP_DEVICE_ATTR_RW(button_b, map_button);
+
+static struct oxp_attr button_x = { BUTTON_X };
+OXP_DEVICE_ATTR_RW(button_x, map_button);
+
+static struct oxp_attr button_y = { BUTTON_Y };
+OXP_DEVICE_ATTR_RW(button_y, map_button);
+
+static struct oxp_attr button_lb = { BUTTON_LB };
+OXP_DEVICE_ATTR_RW(button_lb, map_button);
+
+static struct oxp_attr button_rb = { BUTTON_RB };
+OXP_DEVICE_ATTR_RW(button_rb, map_button);
+
+static struct oxp_attr button_lt = { BUTTON_LT };
+OXP_DEVICE_ATTR_RW(button_lt, map_button);
+
+static struct oxp_attr button_rt = { BUTTON_RT };
+OXP_DEVICE_ATTR_RW(button_rt, map_button);
+
+static struct oxp_attr button_start = { BUTTON_START };
+OXP_DEVICE_ATTR_RW(button_start, map_button);
+
+static struct oxp_attr button_select = { BUTTON_SELECT };
+OXP_DEVICE_ATTR_RW(button_select, map_button);
+
+static struct oxp_attr button_l3 = { BUTTON_L3 };
+OXP_DEVICE_ATTR_RW(button_l3, map_button);
+
+static struct oxp_attr button_r3 = { BUTTON_R3 };
+OXP_DEVICE_ATTR_RW(button_r3, map_button);
+
+static struct oxp_attr button_d_up = { BUTTON_DUP };
+OXP_DEVICE_ATTR_RW(button_d_up, map_button);
+
+static struct oxp_attr button_d_down = { BUTTON_DDOWN };
+OXP_DEVICE_ATTR_RW(button_d_down, map_button);
+
+static struct oxp_attr button_d_left = { BUTTON_DLEFT };
+OXP_DEVICE_ATTR_RW(button_d_left, map_button);
+
+static struct oxp_attr button_d_right = { BUTTON_DRIGHT };
+OXP_DEVICE_ATTR_RW(button_d_right, map_button);
+
+static struct oxp_attr button_m1 = { BUTTON_M1 };
+OXP_DEVICE_ATTR_RW(button_m1, map_button);
+
+static struct oxp_attr button_m2 = { BUTTON_M2 };
+OXP_DEVICE_ATTR_RW(button_m2, map_button);
+
static struct attribute *oxp_cfg_attrs[] = {
+ &dev_attr_button_a.attr,
+ &dev_attr_button_b.attr,
+ &dev_attr_button_d_down.attr,
+ &dev_attr_button_d_left.attr,
+ &dev_attr_button_d_right.attr,
+ &dev_attr_button_d_up.attr,
+ &dev_attr_button_l3.attr,
+ &dev_attr_button_lb.attr,
+ &dev_attr_button_lt.attr,
+ &dev_attr_button_m1.attr,
+ &dev_attr_button_m2.attr,
+ &dev_attr_button_mapping_options.attr,
+ &dev_attr_button_r3.attr,
+ &dev_attr_button_rb.attr,
+ &dev_attr_button_rt.attr,
+ &dev_attr_button_select.attr,
+ &dev_attr_button_start.attr,
+ &dev_attr_button_x.attr,
+ &dev_attr_button_y.attr,
&dev_attr_gamepad_mode.attr,
&dev_attr_gamepad_mode_index.attr,
+ &dev_attr_reset_buttons.attr,
NULL,
};
@@ -823,6 +1374,8 @@ static bool oxp_hybrid_mcu_device(void)
static int oxp_cfg_probe(struct hid_device *hdev, u16 up)
{
+ struct oxp_bmap_page_1 *bmap_1;
+ struct oxp_bmap_page_2 *bmap_2;
int ret;
hid_set_drvdata(hdev, &drvdata);
@@ -855,6 +1408,18 @@ static int oxp_cfg_probe(struct hid_device *hdev, u16 up)
return 0;
skip_rgb:
+ bmap_1 = devm_kzalloc(&hdev->dev, sizeof(struct oxp_bmap_page_1), GFP_KERNEL);
+ if (!bmap_1)
+ return dev_err_probe(&hdev->dev, -ENOMEM,
+ "Unable to allocate button map page 1\n");
+
+ bmap_2 = devm_kzalloc(&hdev->dev, sizeof(struct oxp_bmap_page_2), GFP_KERNEL);
+ if (!bmap_2)
+ return dev_err_probe(&hdev->dev, -ENOMEM,
+ "Unable to allocate button map page 2\n");
+
+ drvdata.bmap_1 = bmap_1;
+ drvdata.bmap_2 = bmap_2;
mod_delayed_work(system_wq, &oxp_mcu_init, msecs_to_jiffies(50));
drvdata.gamepad_mode = OXP_GP_MODE_XINPUT;
--
2.53.0
^ permalink raw reply related
* [PATCH v2 3/5] HID: hid-oxp: Add Second Generation Gamepad Mode Switch
From: Derek J. Clark @ 2026-04-07 4:13 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Pierre-Loup A . Griffais, Lambert Fan, Derek J . Clark,
linux-input, linux-doc, linux-kernel
In-Reply-To: <20260407041354.2283201-1-derekjohn.clark@gmail.com>
Adds "gamepad_mode" attribute to second generation OneXPlayer
configuration HID devices. This attribute initiates a mode shift in the
device MCU that puts it into a state where all events are routed to an
hidraw interface instead of the xpad evdev interface. This allows for
debugging the hardware input mapping added in the next patch.
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v2:
- Rename to gamepad_mode & show relevant gamepad modes instead of
using a debug enable/disable paradigm, to match other drivers.
---
drivers/hid/hid-oxp.c | 130 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 130 insertions(+)
diff --git a/drivers/hid/hid-oxp.c b/drivers/hid/hid-oxp.c
index 25214356163e..c62952537d98 100644
--- a/drivers/hid/hid-oxp.c
+++ b/drivers/hid/hid-oxp.c
@@ -33,6 +33,7 @@
enum oxp_function_index {
OXP_FID_GEN1_RGB_SET = 0x07,
OXP_FID_GEN1_RGB_REPLY = 0x0f,
+ OXP_FID_GEN2_TOGGLE_MODE = 0xb2,
OXP_FID_GEN2_STATUS_EVENT = 0xb8,
};
@@ -41,11 +42,22 @@ static struct oxp_hid_cfg {
struct hid_device *hdev;
struct mutex cfg_mutex; /*ensure single synchronous output report*/
u8 rgb_brightness;
+ u8 gamepad_mode;
u8 rgb_effect;
u8 rgb_speed;
u8 rgb_en;
} drvdata;
+enum oxp_gamepad_mode_index {
+ OXP_GP_MODE_XINPUT = 0x00,
+ OXP_GP_MODE_DEBUG = 0x03,
+};
+
+static const char *const oxp_gamepad_mode_text[] = {
+ [OXP_GP_MODE_XINPUT] = "xinput",
+ [OXP_GP_MODE_DEBUG] = "debug",
+};
+
enum oxp_feature_en_index {
OXP_FEAT_DISABLED,
OXP_FEAT_ENABLED,
@@ -181,6 +193,32 @@ static int oxp_hid_raw_event_gen_1(struct hid_device *hdev,
return 0;
}
+static int oxp_gen_2_property_out(enum oxp_function_index fid, u8 *data, u8 data_size);
+
+static void oxp_mcu_init_fn(struct work_struct *work)
+{
+ u8 gp_mode_data[3] = { OXP_GP_MODE_DEBUG, 0x01, 0x02 };
+ int ret;
+
+ /* Cycle the gamepad mode */
+ ret = oxp_gen_2_property_out(OXP_FID_GEN2_TOGGLE_MODE, gp_mode_data, 3);
+ if (ret)
+ dev_err(&drvdata.hdev->dev,
+ "Error: Failed to set gamepad mode: %i\n", ret);
+
+ /* Remainder only applies for xinput mode */
+ if (drvdata.gamepad_mode == OXP_GP_MODE_DEBUG)
+ return;
+
+ gp_mode_data[0] = OXP_GP_MODE_XINPUT;
+ ret = oxp_gen_2_property_out(OXP_FID_GEN2_TOGGLE_MODE, gp_mode_data, 3);
+ if (ret)
+ dev_err(&drvdata.hdev->dev,
+ "Error: Failed to set gamepad mode: %i\n", ret);
+}
+
+static DECLARE_DELAYED_WORK(oxp_mcu_init, oxp_mcu_init_fn);
+
static int oxp_hid_raw_event_gen_2(struct hid_device *hdev,
struct hid_report *report, u8 *data,
int size)
@@ -191,6 +229,14 @@ static int oxp_hid_raw_event_gen_2(struct hid_device *hdev,
if (data[0] != OXP_FID_GEN2_STATUS_EVENT)
return 0;
+ /* Sent ~6s after resume event, indicating the MCU has fully reset.
+ * Re-apply our settings after this has been received.
+ */
+ if (data[3] == OXP_EFFECT_MONO_TRUE) {
+ mod_delayed_work(system_wq, &oxp_mcu_init, msecs_to_jiffies(50));
+ return 0;
+ }
+
if (data[3] != OXP_GET_PROPERTY)
return 0;
@@ -288,6 +334,77 @@ static int oxp_gen_2_property_out(enum oxp_function_index fid, u8 *data,
footer_size);
}
+static ssize_t gamepad_mode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ u16 up = get_usage_page(drvdata.hdev);
+ u8 data[3] = { 0x00, 0x01, 0x02 };
+ int ret = -EINVAL;
+ int i;
+
+ if (up != GEN2_USAGE_PAGE)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(oxp_gamepad_mode_text); i++) {
+ if (oxp_gamepad_mode_text[i] && sysfs_streq(buf, oxp_gamepad_mode_text[i])) {
+ ret = i;
+ break;
+ }
+ }
+ if (ret < 0)
+ return ret;
+
+ data[0] = ret;
+
+ ret = oxp_gen_2_property_out(OXP_FID_GEN2_TOGGLE_MODE, data, 3);
+ if (ret)
+ return ret;
+
+ drvdata.gamepad_mode = data[0];
+
+ return count;
+}
+
+static ssize_t gamepad_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%s\n", oxp_gamepad_mode_text[drvdata.gamepad_mode]);
+}
+static DEVICE_ATTR_RW(gamepad_mode);
+
+static ssize_t gamepad_mode_index_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ ssize_t count = 0;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(oxp_gamepad_mode_text); i++) {
+ if (!oxp_gamepad_mode_text[i] ||
+ oxp_gamepad_mode_text[i][0] == '\0')
+ continue;
+
+ count += sysfs_emit_at(buf, count, "%s ", oxp_gamepad_mode_text[i]);
+ }
+
+ if (count)
+ buf[count - 1] = '\n';
+
+ return count;
+}
+static DEVICE_ATTR_RO(gamepad_mode_index);
+
+static struct attribute *oxp_cfg_attrs[] = {
+ &dev_attr_gamepad_mode.attr,
+ &dev_attr_gamepad_mode_index.attr,
+ NULL,
+};
+
+static const struct attribute_group oxp_cfg_attrs_group = {
+ .attrs = oxp_cfg_attrs,
+};
+
static int oxp_rgb_status_store(u8 enabled, u8 speed, u8 brightness)
{
u16 up = get_usage_page(drvdata.hdev);
@@ -733,7 +850,20 @@ static int oxp_cfg_probe(struct hid_device *hdev, u16 up)
dev_warn(drvdata.led_mc->led_cdev.dev,
"Failed to query RGB initial state: %i\n", ret);
+ /* Below features are only implemented in gen 2 */
+ if (up != GEN2_USAGE_PAGE)
+ return 0;
+
skip_rgb:
+ mod_delayed_work(system_wq, &oxp_mcu_init, msecs_to_jiffies(50));
+
+ drvdata.gamepad_mode = OXP_GP_MODE_XINPUT;
+
+ ret = devm_device_add_group(&hdev->dev, &oxp_cfg_attrs_group);
+ if (ret)
+ return dev_err_probe(&hdev->dev, ret,
+ "Failed to attach configuration attributes\n");
+
return 0;
}
--
2.53.0
^ permalink raw reply related
* [PATCH v2 2/5] HID: hid-oxp: Add Second Generation RGB Control
From: Derek J. Clark @ 2026-04-07 4:13 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Pierre-Loup A . Griffais, Lambert Fan, Derek J . Clark,
linux-input, linux-doc, linux-kernel
In-Reply-To: <20260407041354.2283201-1-derekjohn.clark@gmail.com>
Adds support for the second generation of RGB Control for OneXPlayer
devices. The interface mirrors the first generation, with some
differences to how messages are formatted.
Some devices have both a GEN1 MCU for RGB control and a GEN2 MCU for
button mapping. To avoid conflicts, quirk these devices to skip RGB
setup for the GEN2_USAGE_PAGE.
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v2:
- Add DMI quirks table.
---
drivers/hid/Kconfig | 1 +
drivers/hid/hid-ids.h | 3 +
drivers/hid/hid-oxp.c | 151 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 155 insertions(+)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 2deaec9f467d..b779088b80b6 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -924,6 +924,7 @@ config HID_OXP
depends on USB_HID
depends on LEDS_CLASS
depends on LEDS_CLASS_MULTICOLOR
+ depends on DMI
help
Say Y here if you would like to enable support for OneXPlayer handheld
devices that come with RGB LED rings around the joysticks and macro buttons.
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index dcc5a3a70eaf..0d1ff879e959 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -1134,6 +1134,9 @@
#define USB_VENDOR_ID_CRSC 0x1a2c
#define USB_DEVICE_ID_ONEXPLAYER_GEN1 0xb001
+#define USB_VENDOR_ID_WCH 0x1a86
+#define USB_DEVICE_ID_ONEXPLAYER_GEN2 0xfe00
+
#define USB_VENDOR_ID_ONTRAK 0x0a07
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
diff --git a/drivers/hid/hid-oxp.c b/drivers/hid/hid-oxp.c
index c4219ecd8d71..25214356163e 100644
--- a/drivers/hid/hid-oxp.c
+++ b/drivers/hid/hid-oxp.c
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/dev_printk.h>
#include <linux/device.h>
+#include <linux/dmi.h>
#include <linux/hid.h>
#include <linux/jiffies.h>
#include <linux/kstrtox.h>
@@ -24,12 +25,15 @@
#define OXP_PACKET_SIZE 64
#define GEN1_MESSAGE_ID 0xff
+#define GEN2_MESSAGE_ID 0x3f
#define GEN1_USAGE_PAGE 0xff01
+#define GEN2_USAGE_PAGE 0xff00
enum oxp_function_index {
OXP_FID_GEN1_RGB_SET = 0x07,
OXP_FID_GEN1_RGB_REPLY = 0x0f,
+ OXP_FID_GEN2_STATUS_EVENT = 0xb8,
};
static struct oxp_hid_cfg {
@@ -121,6 +125,22 @@ struct oxp_gen_1_rgb_report {
u8 blue;
} __packed;
+struct oxp_gen_2_rgb_report {
+ u8 report_id;
+ u8 header_id;
+ u8 padding_2;
+ u8 message_id;
+ u8 padding_4[2];
+ u8 enabled;
+ u8 speed;
+ u8 brightness;
+ u8 red;
+ u8 green;
+ u8 blue;
+ u8 padding_12[3];
+ u8 effect;
+} __packed;
+
static u16 get_usage_page(struct hid_device *hdev)
{
return hdev->collection[0].usage >> 16;
@@ -161,6 +181,44 @@ static int oxp_hid_raw_event_gen_1(struct hid_device *hdev,
return 0;
}
+static int oxp_hid_raw_event_gen_2(struct hid_device *hdev,
+ struct hid_report *report, u8 *data,
+ int size)
+{
+ struct led_classdev_mc *led_mc = drvdata.led_mc;
+ struct oxp_gen_2_rgb_report *rgb_rep;
+
+ if (data[0] != OXP_FID_GEN2_STATUS_EVENT)
+ return 0;
+
+ if (data[3] != OXP_GET_PROPERTY)
+ return 0;
+
+ rgb_rep = (struct oxp_gen_2_rgb_report *)data;
+ /* Ensure we save monocolor as the list value */
+ drvdata.rgb_effect = rgb_rep->effect == OXP_EFFECT_MONO_TRUE ?
+ OXP_EFFECT_MONO_LIST :
+ rgb_rep->effect;
+ drvdata.rgb_speed = rgb_rep->speed;
+ drvdata.rgb_en = rgb_rep->enabled == 0 ? OXP_FEAT_DISABLED :
+ OXP_FEAT_ENABLED;
+ drvdata.rgb_brightness = rgb_rep->brightness;
+ led_mc->led_cdev.brightness = rgb_rep->brightness / 4 *
+ led_mc->led_cdev.max_brightness;
+ /* If monocolor had less than 100% brightness on the previous boot,
+ * there will be no reliable way to determine the real intensity.
+ * Since intensity scaling is used with a hardware brightness set at max,
+ * our brightness will always look like 100%. Use the last set value to
+ * prevent successive boots from lowering the brightness further.
+ * Brightness will be "wrong" but the effect will remain the same visually.
+ */
+ led_mc->subled_info[0].intensity = rgb_rep->red;
+ led_mc->subled_info[1].intensity = rgb_rep->green;
+ led_mc->subled_info[2].intensity = rgb_rep->blue;
+
+ return 0;
+}
+
static int oxp_hid_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{
@@ -171,6 +229,8 @@ static int oxp_hid_raw_event(struct hid_device *hdev, struct hid_report *report,
switch (up) {
case GEN1_USAGE_PAGE:
return oxp_hid_raw_event_gen_1(hdev, report, data, size);
+ case GEN2_USAGE_PAGE:
+ return oxp_hid_raw_event_gen_2(hdev, report, data, size);
default:
break;
}
@@ -216,6 +276,18 @@ static int oxp_gen_1_property_out(enum oxp_function_index fid, u8 *data,
return mcu_property_out(header, header_size, data, data_size, NULL, 0);
}
+static int oxp_gen_2_property_out(enum oxp_function_index fid, u8 *data,
+ u8 data_size)
+{
+ u8 header[] = { fid, GEN2_MESSAGE_ID, 0x01 };
+ u8 footer[] = { GEN2_MESSAGE_ID, fid };
+ size_t header_size = ARRAY_SIZE(header);
+ size_t footer_size = ARRAY_SIZE(footer);
+
+ return mcu_property_out(header, header_size, data, data_size, footer,
+ footer_size);
+}
+
static int oxp_rgb_status_store(u8 enabled, u8 speed, u8 brightness)
{
u16 up = get_usage_page(drvdata.hdev);
@@ -230,6 +302,11 @@ static int oxp_rgb_status_store(u8 enabled, u8 speed, u8 brightness)
if (drvdata.rgb_effect == OXP_EFFECT_MONO_LIST)
data[3] = 0x04;
return oxp_gen_1_property_out(OXP_FID_GEN1_RGB_SET, data, 4);
+ case GEN2_USAGE_PAGE:
+ data = (u8[6]) { OXP_SET_PROPERTY, 0x00, 0x02, enabled, speed, brightness };
+ if (drvdata.rgb_effect == OXP_EFFECT_MONO_LIST)
+ data[5] = 0x04;
+ return oxp_gen_2_property_out(OXP_FID_GEN2_STATUS_EVENT, data, 6);
default:
return -ENODEV;
}
@@ -244,6 +321,9 @@ static ssize_t oxp_rgb_status_show(void)
case GEN1_USAGE_PAGE:
data = (u8[1]) { OXP_GET_PROPERTY };
return oxp_gen_1_property_out(OXP_FID_GEN1_RGB_SET, data, 1);
+ case GEN2_USAGE_PAGE:
+ data = (u8[3]) { OXP_GET_PROPERTY, 0x00, 0x02 };
+ return oxp_gen_2_property_out(OXP_FID_GEN2_STATUS_EVENT, data, 3);
default:
return -ENODEV;
}
@@ -274,6 +354,16 @@ static int oxp_rgb_color_set(void)
data[3 * i + 3] = blue;
}
return oxp_gen_1_property_out(OXP_FID_GEN1_RGB_SET, data, size);
+ case GEN2_USAGE_PAGE:
+ size = 57;
+ data = (u8[57]) { OXP_EFFECT_MONO_TRUE, 0x00, 0x02 };
+
+ for (i = 1; i < size / 3; i++) {
+ data[3 * i] = red;
+ data[3 * i + 1] = green;
+ data[3 * i + 2] = blue;
+ }
+ return oxp_gen_2_property_out(OXP_FID_GEN2_STATUS_EVENT, data, size);
default:
return -ENODEV;
}
@@ -310,6 +400,10 @@ static int oxp_rgb_effect_set(u8 effect)
data = (u8[1]) { effect };
ret = oxp_gen_1_property_out(OXP_FID_GEN1_RGB_SET, data, 1);
break;
+ case GEN2_USAGE_PAGE:
+ data = (u8[3]) { effect, 0x00, 0x02 };
+ ret = oxp_gen_2_property_out(OXP_FID_GEN2_STATUS_EVENT, data, 3);
+ break;
default:
ret = -ENODEV;
}
@@ -560,6 +654,56 @@ static struct led_classdev_mc oxp_cdev_rgb = {
.subled_info = oxp_rgb_subled_info,
};
+struct quirk_entry {
+ bool hybrid_mcu;
+};
+
+static struct quirk_entry quirk_hybrid_mcu = {
+ .hybrid_mcu = true,
+};
+
+static const struct dmi_system_id oxp_hybrid_mcu_list[] = {
+ {
+ .ident = "OneXPlayer Apex",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ONE-NETBOOK"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ONEXPLAYER APEX"),
+ },
+ .driver_data = &quirk_hybrid_mcu,
+ },
+ {
+ .ident = "OneXPlayer G1 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ONE-NETBOOK"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ONEXPLAYER G1 A"),
+ },
+ .driver_data = &quirk_hybrid_mcu,
+ },
+ {
+ .ident = "OneXPlayer G1 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ONE-NETBOOK"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ONEXPLAYER G1 i"),
+ },
+ .driver_data = &quirk_hybrid_mcu,
+ },
+ {},
+};
+
+static bool oxp_hybrid_mcu_device(void)
+{
+ const struct dmi_system_id *dmi_id;
+ struct quirk_entry *quirks;
+
+ dmi_id = dmi_first_match(oxp_hybrid_mcu_list);
+ if (!dmi_id)
+ return false;
+
+ quirks = dmi_id->driver_data;
+
+ return quirks->hybrid_mcu;
+}
+
static int oxp_cfg_probe(struct hid_device *hdev, u16 up)
{
int ret;
@@ -567,6 +711,10 @@ static int oxp_cfg_probe(struct hid_device *hdev, u16 up)
hid_set_drvdata(hdev, &drvdata);
mutex_init(&drvdata.cfg_mutex);
drvdata.hdev = hdev;
+
+ if (up == GEN2_USAGE_PAGE && oxp_hybrid_mcu_device())
+ goto skip_rgb;
+
drvdata.led_mc = &oxp_cdev_rgb;
ret = devm_led_classdev_multicolor_register(&hdev->dev, &oxp_cdev_rgb);
@@ -585,6 +733,7 @@ static int oxp_cfg_probe(struct hid_device *hdev, u16 up)
dev_warn(drvdata.led_mc->led_cdev.dev,
"Failed to query RGB initial state: %i\n", ret);
+skip_rgb:
return 0;
}
@@ -613,6 +762,7 @@ static int oxp_hid_probe(struct hid_device *hdev,
switch (up) {
case GEN1_USAGE_PAGE:
+ case GEN2_USAGE_PAGE:
ret = oxp_cfg_probe(hdev, up);
if (ret) {
hid_hw_close(hdev);
@@ -633,6 +783,7 @@ static void oxp_hid_remove(struct hid_device *hdev)
static const struct hid_device_id oxp_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CRSC, USB_DEVICE_ID_ONEXPLAYER_GEN1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WCH, USB_DEVICE_ID_ONEXPLAYER_GEN2) },
{}
};
--
2.53.0
^ permalink raw reply related
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