* Re: [PATCH for-7.1-fixes 1/2] rhashtable: add no_sync_grow option
From: Herbert Xu @ 2026-04-18 0:53 UTC (permalink / raw)
To: Tejun Heo
Cc: Thomas Graf, David Vernet, Andrea Righi, Changwoo Min,
Emil Tsalapatis, linux-crypto, sched-ext, linux-kernel,
Florian Westphal, netdev
In-Reply-To: <aeLV6aDhM0-S4oQ1@slm.duckdns.org>
On Fri, Apr 17, 2026 at 02:52:57PM -1000, Tejun Heo wrote:
>
> I see. Thanks, that should work. How should we go about reverting the
> removal?
I'll work on that today and then you can include it in your
two-patch series.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH for-7.1-fixes 1/2] rhashtable: add no_sync_grow option
From: Tejun Heo @ 2026-04-18 0:52 UTC (permalink / raw)
To: Herbert Xu
Cc: Thomas Graf, David Vernet, Andrea Righi, Changwoo Min,
Emil Tsalapatis, linux-crypto, sched-ext, linux-kernel,
Florian Westphal, netdev
In-Reply-To: <aeLT8eB_xfzLxqbI@gondor.apana.org.au>
Hello,
On Sat, Apr 18, 2026 at 08:44:33AM +0800, Herbert Xu wrote:
> On Fri, Apr 17, 2026 at 06:25:22AM -1000, Tejun Heo wrote:
> >
> > That'd be great but looking at the commit, I'm not sure it reliably avoids
> > allocation in the synchronous path.
>
> If insecure_elasticity is set it should skip the slow path
> altogether and just do the insertion unconditionally. So
> there will be no kmallocs at all.
I see. Thanks, that should work. How should we go about reverting the
removal?
Thanks.
--
tejun
^ permalink raw reply
* Re: [BUG] net: tcp: SO_LINGER with l_linger=0 leaks memory when closing sockets with pending send data
From: Kuniyuki Iwashima @ 2026-04-18 0:44 UTC (permalink / raw)
To: Ahmed, Aaron
Cc: stable@vger.kernel.org, netdev@vger.kernel.org,
ncardwell@google.com, edumazet@google.com
In-Reply-To: <48BADABE-4DFB-4DAD-8248-E94D8F5238D2@amazon.com>
Hi Aaron :)
Thanks for the report.
On Fri, Apr 17, 2026 at 5:20 PM Ahmed, Aaron <aarnahmd@amazon.com> wrote:
>
> Hi,
>
> We have identified a TCP memory leak issue on Amazon Linux with kernel versions 5.15.168 through 6.18.20 that occurs when closing sockets with SO_LINGER set to l_onoff=1, l_linger=0, on servers handling many persistent connections with full write buffers.
>
> Overview:
>
> The issue was discovered on a public-facing non-blocking TCP server that maintains many persistent connections and streams data to clients. When a client cannot read fast enough, the TCP write socket buffer on the server side fills up and send() returns EAGAIN. At that point, the server application disconnects the slow client by setting SO_LINGER to l_onoff=1, l_linger=0 and calling close(). This is intended to immediately reset the connection and release all associated kernel resources. However, while the socket disappears from netstat and sockstat (TCP inuse drops), the write buffer memory is not properly reclaimed. /proc/net/sockstat shows TCP mem pages accumulating with no owning sockets, causing the leaked memory to grow past the tcp_mem limits. Setting SO_LINGER to l_onoff=1, l_linger=1 instead does not leak. With l_linger=1, the connection goes through FIN_WAIT1 → FIN_WAIT2 → CLOSE (confirmed with BPF tcpstates), and all memory is freed properly. With l_linger=0, the connection transitions directly from ESTABLISHED → CLOSE via RST, bypassing the FIN states entirely.
>
> Reproducer:
> ```
> /* tcp_linger_memleak.c - SO_LINGER(0) TCP memory leak reproducer
> *
> * Build: gcc -O2 -o tcp_linger_memleak tcp_linger_memleak.c
> * Run: sudo sysctl -w net.core.wmem_max=4194304
> * sudo sysctl -w net.ipv4.tcp_rmem="4096 8192 16384"
> * ./tcp_linger_memleak
> */
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <signal.h>
> #include <sys/socket.h>
> #include <sys/wait.h>
> #include <netinet/in.h>
>
> #define NUM_CONNS 5000
> #define PORT 6666
>
> static void print_mem(const char *label) {
> FILE *f;
> char line[256];
> f = fopen("/proc/meminfo", "r");
> while (fgets(line, sizeof(line), f))
> if (strncmp(line, "MemAvailable:", 13) == 0)
> printf("%s: %s", label, line);
> fclose(f);
> f = fopen("/proc/net/sockstat", "r");
> while (fgets(line, sizeof(line), f))
> if (strncmp(line, "TCP:", 4) == 0)
> printf("%s: %s", label, line);
> fclose(f);
> }
>
> int main(void) {
> struct sockaddr_in addr = {
> .sin_family = AF_INET,
> .sin_port = htons(PORT),
> .sin_addr.s_addr = htonl(INADDR_LOOPBACK)
> };
> int opt = 1;
> signal(SIGPIPE, SIG_IGN);
>
> int lsn = socket(AF_INET, SOCK_STREAM, 0);
> setsockopt(lsn, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
> bind(lsn, (struct sockaddr *)&addr, sizeof(addr));
> listen(lsn, NUM_CONNS);
>
> /* Fork client: connect N times, never read */
> pid_t child = fork();
> if (child == 0) {
> int fds[NUM_CONNS];
> for (int i = 0; i < NUM_CONNS; i++) {
> fds[i] = socket(AF_INET, SOCK_STREAM, 0);
> connect(fds[i], (struct sockaddr *)&addr, sizeof(addr));
> }
> pause(); /* sit forever, never read */
> _exit(0);
> }
>
> /* Accept all connections */
> int clients[NUM_CONNS];
> for (int i = 0; i < NUM_CONNS; i++)
> clients[i] = accept(lsn, NULL, NULL);
>
> /* Freeze client so it stops reading */
> kill(child, SIGSTOP);
> printf("=== %d connections established, client frozen ===\n", NUM_CONNS);
> print_mem("BEFORE");
>
> /* Fill buffers and close with SO_LINGER(1,0) */
> char buf[2048];
> memset(buf, 'A', sizeof(buf));
> for (int i = 0; i < NUM_CONNS; i++) {
> int flags = fcntl(clients[i], F_GETFL, 0);
> fcntl(clients[i], F_SETFL, flags | O_NONBLOCK);
> while (send(clients[i], buf, sizeof(buf), MSG_NOSIGNAL) > 0);
> struct linger lg = { .l_onoff = 1, .l_linger = 0 };
> setsockopt(clients[i], SOL_SOCKET, SO_LINGER, &lg, sizeof(lg));
> close(clients[i]);
> }
>
> sleep(2);
> printf("\n=== All sockets closed with SO_LINGER(1,0) ===\n");
> print_mem("AFTER");
> kill(child, SIGKILL);
> waitpid(child, NULL, 0);
> close(lsn);
> return 0;
> }
> ```
> Output (Tested on 6.18.20):
> ```
> === 5000 connections established, client frozen ===
> BEFORE: MemAvailable: 95491288 kB
> BEFORE: TCP: inuse 10005 orphan 0 tw 5 alloc 10006 mem 0
>
> === All sockets closed with SO_LINGER(1,0) ===
> AFTER: MemAvailable: 95321800 kB
> AFTER: TCP: inuse 5 orphan 0 tw 5 alloc 5006 mem 8300
> ```
Unfortunately, it dies immediately on my end.
=== 5000 connections established, client frozen ===
Segmentation fault (core dumped) ./linux/tcp_linger
Did you see actual memory leak with kmemleak or is it
just the tcp_mem counter that is really leaked ?
# echo clear > /sys/kernel/debug/kmemleak
~ run repro ~
# echo scan > /sys/kernel/debug/kmemleak
^ permalink raw reply
* Re: [PATCH for-7.1-fixes 1/2] rhashtable: add no_sync_grow option
From: Herbert Xu @ 2026-04-18 0:44 UTC (permalink / raw)
To: Tejun Heo
Cc: Thomas Graf, David Vernet, Andrea Righi, Changwoo Min,
Emil Tsalapatis, linux-crypto, sched-ext, linux-kernel,
Florian Westphal, netdev
In-Reply-To: <aeJe8oIyYUi-NtCQ@slm.duckdns.org>
On Fri, Apr 17, 2026 at 06:25:22AM -1000, Tejun Heo wrote:
>
> That'd be great but looking at the commit, I'm not sure it reliably avoids
> allocation in the synchronous path.
If insecure_elasticity is set it should skip the slow path
altogether and just do the insertion unconditionally. So
there will be no kmallocs at all.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* [BUG] net: tcp: SO_LINGER with l_linger=0 leaks memory when closing sockets with pending send data
From: Ahmed, Aaron @ 2026-04-18 0:19 UTC (permalink / raw)
To: stable@vger.kernel.org, netdev@vger.kernel.org
Cc: ncardwell@google.com, edumazet@google.com, kuniyu@google.com
Hi,
We have identified a TCP memory leak issue on Amazon Linux with kernel versions 5.15.168 through 6.18.20 that occurs when closing sockets with SO_LINGER set to l_onoff=1, l_linger=0, on servers handling many persistent connections with full write buffers.
Overview:
The issue was discovered on a public-facing non-blocking TCP server that maintains many persistent connections and streams data to clients. When a client cannot read fast enough, the TCP write socket buffer on the server side fills up and send() returns EAGAIN. At that point, the server application disconnects the slow client by setting SO_LINGER to l_onoff=1, l_linger=0 and calling close(). This is intended to immediately reset the connection and release all associated kernel resources. However, while the socket disappears from netstat and sockstat (TCP inuse drops), the write buffer memory is not properly reclaimed. /proc/net/sockstat shows TCP mem pages accumulating with no owning sockets, causing the leaked memory to grow past the tcp_mem limits. Setting SO_LINGER to l_onoff=1, l_linger=1 instead does not leak. With l_linger=1, the connection goes through FIN_WAIT1 → FIN_WAIT2 → CLOSE (confirmed with BPF tcpstates), and all memory is freed properly. With l_linger=0, the connection transitions directly from ESTABLISHED → CLOSE via RST, bypassing the FIN states entirely.
Reproducer:
```
/* tcp_linger_memleak.c - SO_LINGER(0) TCP memory leak reproducer
*
* Build: gcc -O2 -o tcp_linger_memleak tcp_linger_memleak.c
* Run: sudo sysctl -w net.core.wmem_max=4194304
* sudo sysctl -w net.ipv4.tcp_rmem="4096 8192 16384"
* ./tcp_linger_memleak
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#define NUM_CONNS 5000
#define PORT 6666
static void print_mem(const char *label) {
FILE *f;
char line[256];
f = fopen("/proc/meminfo", "r");
while (fgets(line, sizeof(line), f))
if (strncmp(line, "MemAvailable:", 13) == 0)
printf("%s: %s", label, line);
fclose(f);
f = fopen("/proc/net/sockstat", "r");
while (fgets(line, sizeof(line), f))
if (strncmp(line, "TCP:", 4) == 0)
printf("%s: %s", label, line);
fclose(f);
}
int main(void) {
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
.sin_addr.s_addr = htonl(INADDR_LOOPBACK)
};
int opt = 1;
signal(SIGPIPE, SIG_IGN);
int lsn = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(lsn, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bind(lsn, (struct sockaddr *)&addr, sizeof(addr));
listen(lsn, NUM_CONNS);
/* Fork client: connect N times, never read */
pid_t child = fork();
if (child == 0) {
int fds[NUM_CONNS];
for (int i = 0; i < NUM_CONNS; i++) {
fds[i] = socket(AF_INET, SOCK_STREAM, 0);
connect(fds[i], (struct sockaddr *)&addr, sizeof(addr));
}
pause(); /* sit forever, never read */
_exit(0);
}
/* Accept all connections */
int clients[NUM_CONNS];
for (int i = 0; i < NUM_CONNS; i++)
clients[i] = accept(lsn, NULL, NULL);
/* Freeze client so it stops reading */
kill(child, SIGSTOP);
printf("=== %d connections established, client frozen ===\n", NUM_CONNS);
print_mem("BEFORE");
/* Fill buffers and close with SO_LINGER(1,0) */
char buf[2048];
memset(buf, 'A', sizeof(buf));
for (int i = 0; i < NUM_CONNS; i++) {
int flags = fcntl(clients[i], F_GETFL, 0);
fcntl(clients[i], F_SETFL, flags | O_NONBLOCK);
while (send(clients[i], buf, sizeof(buf), MSG_NOSIGNAL) > 0);
struct linger lg = { .l_onoff = 1, .l_linger = 0 };
setsockopt(clients[i], SOL_SOCKET, SO_LINGER, &lg, sizeof(lg));
close(clients[i]);
}
sleep(2);
printf("\n=== All sockets closed with SO_LINGER(1,0) ===\n");
print_mem("AFTER");
kill(child, SIGKILL);
waitpid(child, NULL, 0);
close(lsn);
return 0;
}
```
Output (Tested on 6.18.20):
```
=== 5000 connections established, client frozen ===
BEFORE: MemAvailable: 95491288 kB
BEFORE: TCP: inuse 10005 orphan 0 tw 5 alloc 10006 mem 0
=== All sockets closed with SO_LINGER(1,0) ===
AFTER: MemAvailable: 95321800 kB
AFTER: TCP: inuse 5 orphan 0 tw 5 alloc 5006 mem 8300
```
Thanks,
Aaron Ahmed
^ permalink raw reply
* [PATCH net] ipv6: Apply max_dst_opts_cnt to ip6_tnl_parse_tlv_enc_lim
From: Daniel Borkmann @ 2026-04-17 22:03 UTC (permalink / raw)
To: kuba; +Cc: edumazet, dsahern, tom, willemdebruijn.kernel, idosch, pabeni,
netdev
Commit 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and
Destination options") added net.ipv6.max_{hbh,dst}_opts_{cnt,len}
and applied them in ip6_parse_tlv(), the generic TLV walker
invoked from ipv6_destopt_rcv() and ipv6_parse_hopopts().
ip6_tnl_parse_tlv_enc_lim() does not go through ip6_parse_tlv();
it has its own hand-rolled TLV scanner inside its NEXTHDR_DEST
branch which looks for IPV6_TLV_TNL_ENCAP_LIMIT. That inner
loop is bounded only by optlen, which can be up to 2048 bytes.
Stuffing the Destination Options header with 2046 Pad1 (type=0)
entries advances the scanner a single byte at a time, yielding
~2000 TLV iterations per extension header.
Reuse max_dst_opts_cnt to bound the TLV iterations, matching
the semantics from 47d3d7ac656a.
Fixes: 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and Destination options")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
net/ipv6/ip6_tunnel.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 907c6a2af331..0ab76f93c136 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -430,11 +430,16 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
break;
}
if (nexthdr == NEXTHDR_DEST) {
+ int tlv_max = READ_ONCE(init_net.ipv6.sysctl.max_dst_opts_cnt);
+ int tlv_cnt = 0;
u16 i = 2;
while (1) {
struct ipv6_tlv_tnl_enc_lim *tel;
+ if (unlikely(tlv_cnt++ >= tlv_max))
+ break;
+
/* No more room for encapsulation limit */
if (i + sizeof(*tel) > optlen)
break;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net] ipv6: Implement limits on extension header parsing
From: Eric Dumazet @ 2026-04-17 21:45 UTC (permalink / raw)
To: Daniel Borkmann
Cc: kuba, dsahern, tom, willemdebruijn.kernel, idosch, pabeni, netdev
In-Reply-To: <20260417171831.687053-1-daniel@iogearbox.net>
On Fri, Apr 17, 2026 at 10:18 AM Daniel Borkmann <daniel@iogearbox.net> wrote:
>
> ipv6_{skip_exthdr,find_hdr}() and ip6_tnl_parse_tlv_enc_lim() iterate
> over IPv6 extension headers until they find a non-extension-header
> protocol or run out of packet data. The loops have no iteration counter,
> relying solely on the packet length to bound them. For a crafted packet
> with 8-byte extension headers filling a 64KB jumbogram, this means a
> worst case of up to ~8k iterations with a skb_header_pointer call each.
> ipv6_skip_exthdr(), for example, is used where it parses the inner
> quoted packet inside an incoming ICMPv6 error:
>
> - icmpv6_rcv
> - checksum validation
> - case ICMPV6_DEST_UNREACH
> - icmpv6_notify
> - pskb_may_pull() <- pull inner IPv6 header
> - ipv6_skip_exthdr() <- iterates here
> - pskb_may_pull()
> - ipprot->err_handler() <- sk lookup (matching sk not required)
>
> The per-iteration cost of ipv6_skip_exthdr itself is generally light,
> but skb_header_pointer becomes more costly on reassembled packets: the
> first ~1KB of the inner packet are in the skb's linear area, but the
> remaining ~63KB are in the frag_list where skb_copy_bits is needed to
> read data.
>
> Add a configurable limit via a new sysctl net.ipv6.max_ext_hdrs_number
> (default 32, minimum 1). All three extension header walking functions
> are bound by this limit. The sysctl is in line with commit 47d3d7ac656a
> ("ipv6: Implement limits on Hop-by-Hop and Destination options"). The
> init_net is used since plumbing a struct net * through all helpers
> would touch a lot of callsites.
>
> There's an ongoing IETF draft-ietf-6man-eh-limits-18 that states that
> 8 extension headers before the transport header is the baseline which
> routers MUST handle; section 7 details also why limits are needed.
>
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Thanks!
^ permalink raw reply
* Re: [PATCH] tcp: fix orphan count order in __tcp_close()
From: Eric Dumazet @ 2026-04-17 21:43 UTC (permalink / raw)
To: Ruben Kelevra
Cc: netdev, ncardwell, kuniyu, davem, dsahern, kuba, pabeni, horms
In-Reply-To: <CAGHX7-OsuADyxGr-QoRRspuXYm_3aS590Ez4zvGsjyPsSKLJsg@mail.gmail.com>
On Fri, Apr 17, 2026 at 2:36 PM Ruben Kelevra <rubenkelevra@gmail.com> wrote:
>
> Hey Eric,
>
> no. But I'm not a native speaker. I'm sorry if my explanation did not
> meet your or the project's communication quality.
>
> The point I was trying to make is that currently we underflow and
> overflow an unsigned and signed int in case we start with 0 in
> tcp_orphan_count. And while it currently has no real effect on real
> world applications, as we use a 100ms cached value anyway, I just
> wanted to clean up this "old" approach which was apparently chosen for
> historical reasons to circumvent bugs, not because it was the intent
> implementation.
>
> That's what my list of old commits about the history was meant to reference.
We are using per-cpu counters, folded every 100ms, so the precise
value is irrelevant,
as long as it is balanced (does not increase to infinity)
Thanks.
^ permalink raw reply
* Re: [PATCH] tcp: fix orphan count order in __tcp_close()
From: Ruben Kelevra @ 2026-04-17 21:36 UTC (permalink / raw)
To: Eric Dumazet
Cc: netdev, ncardwell, kuniyu, davem, dsahern, kuba, pabeni, horms
In-Reply-To: <CANn89i+zy=YttsDesBzvtSrkdY+==L_L6j4O7EFjYKEggcXbGA@mail.gmail.com>
On Fri, Apr 17, 2026 at 10:54 PM Eric Dumazet <edumazet@google.com> wrote:
>
> On Fri, Apr 17, 2026 at 1:25 PM RubenKelevra <rubenkelevra@gmail.com> wrote:
> >
> > __tcp_close() calls sock_orphan(sk) first and drains the backlog with
> > __release_sock(sk), which might call tcp_done() which decrements the
> > tcp_orphan_count. After which we will increment tcp_orphan_count again.
> >
> > Since tcp_orphan_count is an unsigned int, we underflow to uint_max if we
> > started with a 0 - at least on all current supported platforms.
> >
> > I could not locate a direct user of this value, and in
> > tcp_orphan_count_sum() this underflow is contained by adding the unsigned
> > int value into a signed int sum, causing it to behave like -1 on current
> > supported platforms and then get clamped by max(n, 0) to 0.
> >
> > The impact therefore is currently limited to e.g. tcp_too_many_orphans()
> > checking an artificially low value, if the cached sum is refreshed within
> > this timeframe.
> >
> > This fix mirrors the previous fix I found while investigating: commit
> > 75c2d9077c63 ("[TCP]: Fix sock_orphan dead lock")
> >
> > Later commit eb4dea585304 ("net: Fix percpu counters deadlock") moved the
> > increment down for old percpu_counter reasons. commit 19757cebf0c5 ("tcp:
> > switch orphan_count to bare per-cpu counters") changed orphan accounting to
> > plain per-cpu counters, so that old reason no longer applies the same way
> > now.
>
> I find this patch rather confusing. Have you used an LLM to generate it?
>
> You are mentioning old patches that are not relevant (bh disable/enable).
>
> Given we advise only increasing tcp_max_orphans value (default being
> 262144 on modern hosts),
> your patch has really no effect.
Hey Eric,
no. But I'm not a native speaker. I'm sorry if my explanation did not
meet your or the project's communication quality.
The point I was trying to make is that currently we underflow and
overflow an unsigned and signed int in case we start with 0 in
tcp_orphan_count. And while it currently has no real effect on real
world applications, as we use a 100ms cached value anyway, I just
wanted to clean up this "old" approach which was apparently chosen for
historical reasons to circumvent bugs, not because it was the intent
implementation.
That's what my list of old commits about the history was meant to reference.
Best regards,
Ruben
On Fri, Apr 17, 2026 at 10:54 PM Eric Dumazet <edumazet@google.com> wrote:
>
> On Fri, Apr 17, 2026 at 1:25 PM RubenKelevra <rubenkelevra@gmail.com> wrote:
> >
> > __tcp_close() calls sock_orphan(sk) first and drains the backlog with
> > __release_sock(sk), which might call tcp_done() which decrements the
> > tcp_orphan_count. After which we will increment tcp_orphan_count again.
> >
> > Since tcp_orphan_count is an unsigned int, we underflow to uint_max if we
> > started with a 0 - at least on all current supported platforms.
> >
> > I could not locate a direct user of this value, and in
> > tcp_orphan_count_sum() this underflow is contained by adding the unsigned
> > int value into a signed int sum, causing it to behave like -1 on current
> > supported platforms and then get clamped by max(n, 0) to 0.
> >
> > The impact therefore is currently limited to e.g. tcp_too_many_orphans()
> > checking an artificially low value, if the cached sum is refreshed within
> > this timeframe.
> >
> > This fix mirrors the previous fix I found while investigating: commit
> > 75c2d9077c63 ("[TCP]: Fix sock_orphan dead lock")
> >
> > Later commit eb4dea585304 ("net: Fix percpu counters deadlock") moved the
> > increment down for old percpu_counter reasons. commit 19757cebf0c5 ("tcp:
> > switch orphan_count to bare per-cpu counters") changed orphan accounting to
> > plain per-cpu counters, so that old reason no longer applies the same way
> > now.
>
> I find this patch rather confusing. Have you used an LLM to generate it?
>
> You are mentioning old patches that are not relevant (bh disable/enable).
>
> Given we advise only increasing tcp_max_orphans value (default being
> 262144 on modern hosts),
> your patch has really no effect.
^ permalink raw reply
* Re: [PATCH v6 3/3] dts: s32g: Add GPR syscon region
From: Jared Kangas @ 2026-04-17 21:36 UTC (permalink / raw)
To: Dan Carpenter
Cc: Chester Lin, Matthias Brugger, Ghennadi Procopciuc,
NXP S32 Linux Team, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-arm-kernel, imx,
devicetree, linux-kernel, linaro-s32, netdev
In-Reply-To: <0e922537c02d1c47734142090f98eb78e921ed34.1769764941.git.dan.carpenter@linaro.org>
Hi Dan,
On Fri, Jan 30, 2026 at 04:19:52PM +0300, Dan Carpenter wrote:
> Add the GPR syscon region for the s32 chipset.
>
> Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
> ---
>
> [snip]
>
> diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
> index e314f3c7d61d..be03db737384 100644
> --- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
> +++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
> @@ -383,6 +383,11 @@ usdhc0-200mhz-grp4 {
> };
> };
>
> + gpr: syscon@4007c000 {
> + compatible = "nxp,s32g3-gpr", "syscon";
> + reg = <0x4007c000 0x3000>;
> + };
> +
> ocotp: nvmem@400a4000 {
> compatible = "nxp,s32g3-ocotp", "nxp,s32g2-ocotp";
> reg = <0x400a4000 0x400>;
> @@ -808,6 +813,7 @@ gmac0: ethernet@4033c000 {
> compatible = "nxp,s32g2-dwmac";
> reg = <0x4033c000 0x2000>, /* gmac IP */
> <0x4007c004 0x4>; /* GMAC_0_CTRL_STS */
> + nxp,phy-sel = <&gpr 0x4>;
> interrupt-parent = <&gic>;
> interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
> interrupt-names = "macirq";
I gave this a test on an S32G-VNP-RDB3 and didn't see any issues on the
dwmac-s32 side, but this appears to trigger a panic when reading the new
debugfs regmap/*/registers file for the syscon node:
# grep 4007c000 /proc/vmallocinfo
0xffff800083da8000-0xffff800083dac000 16384 ioremap_prot+0x74/0xe0 phys=0x000000004007c000 ioremap
# cat /sys/kernel/debug/regmap/dummy-syscon@0x000000004007c000/registers
Internal error: synchronous external abort: 0000000096000210 [#1] SMP
[...]
CPU: 0 UID: 0 PID: 4344 Comm: cat Tainted: G M E X ------ --- 6.12.0+ #226 PREEMPT_RT
Tainted: [M]=MACHINE_CHECK, [E]=UNSIGNED_MODULE, [X]=AUX
[...]
pc : regmap_mmio_read32le+0x44/0xa0
lr : regmap_mmio_read32le+0x44/0xa0
[...]
x23: ffff00080c080000 x22: ffff000802ac4c00 x21: ffff800087b13c9c
x20: ffff800080a46494 x19: ffff800083da810c x18: 0000000000000004
[...]
x5 : ffff800080a46448 x4 : ffff800083da8000 x3 : ffff800080a46494
x2 : ffff800080a47230 x1 : ffff800083da810c x0 : 0000000000000020
Call trace:
regmap_mmio_read32le+0x44/0xa0 (P)
regmap_mmio_read+0x4c/0x80
[...]
Code: 52800400 8b214093 aa1303e1 97f4caf0 (b9400275)
---[ end trace 0000000000000000 ]---
Kernel panic - not syncing: synchronous external abort: Fatal exception
Running this through decodecode gives:
All code
========
0: 52800400 mov w0, #0x20 // #32
4: 8b214093 add x19, x4, w1, uxtw
8: aa1303e1 mov x1, x19
c: 97f4caf0 bl 0xffffffffffd32bcc
10:* b9400275 ldr w21, [x19] <-- trapping instruction
Code starting with the faulting instruction
===========================================
0: b9400275 ldr w21, [x19]
x19's offset from the base address in /proc/vmallocinfo is 0x10c, which
points to a bad read at physical address 0x4007c10c; I also confirmed
that the preceding memory reads back without issues:
# head -c 990 /sys/kernel/debug/regmap/dummy-syscon@0x000000004007c000/registers | tail -1
0104: 00000000
# head -c 1005 /sys/kernel/debug/regmap/dummy-syscon@0x000000004007c000/registers | tail -1
0108: 00000000
# head -c 1020 /sys/kernel/debug/regmap/dummy-syscon@0x000000004007c000/registers | tail -1
<panic>
Best,
Jared
^ permalink raw reply
* [PATCH v1 11/11] drm/xe/ras: Add flag for Xe RAS
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
In-Reply-To: <20260417211730.837345-1-raag.jadav@intel.com>
From: Riana Tauro <riana.tauro@intel.com>
Add a flag for RAS. If enabled, XE driver registers with
drm_ras and exposes supported counters.
Currently this is enabled for PVC and CRI.
Signed-off-by: Riana Tauro <riana.tauro@intel.com>
---
drivers/gpu/drm/xe/xe_device_types.h | 2 ++
drivers/gpu/drm/xe/xe_hw_error.c | 2 +-
drivers/gpu/drm/xe/xe_pci.c | 3 +++
drivers/gpu/drm/xe/xe_pci_types.h | 1 +
4 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index 31df9debcbb0..7a8afd06e6b8 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -191,6 +191,8 @@ struct xe_device {
u8 has_ctx_tlb_inval:1;
/** @info.has_range_tlb_inval: Has range based TLB invalidations */
u8 has_range_tlb_inval:1;
+ /** @info.has_ras: Device supports RAS (Reliability, Availability, Serviceability) */
+ u8 has_ras:1;
/** @info.has_soc_remapper_sysctrl: Has SoC remapper system controller */
u8 has_soc_remapper_sysctrl:1;
/** @info.has_soc_remapper_telem: Has SoC remapper telemetry support */
diff --git a/drivers/gpu/drm/xe/xe_hw_error.c b/drivers/gpu/drm/xe/xe_hw_error.c
index 2a31b430570e..3ab0fceb151f 100644
--- a/drivers/gpu/drm/xe/xe_hw_error.c
+++ b/drivers/gpu/drm/xe/xe_hw_error.c
@@ -520,7 +520,7 @@ void xe_hw_error_irq_handler(struct xe_tile *tile, const u32 master_ctl)
static int hw_error_info_init(struct xe_device *xe)
{
- if (xe->info.platform != XE_PVC)
+ if (!xe->info.has_ras)
return 0;
return xe_drm_ras_init(xe);
diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
index 278c2860a4f6..10ff207affa9 100644
--- a/drivers/gpu/drm/xe/xe_pci.c
+++ b/drivers/gpu/drm/xe/xe_pci.c
@@ -365,6 +365,7 @@ static const __maybe_unused struct xe_device_desc pvc_desc = {
.vm_max_level = 4,
.vram_flags = XE_VRAM_FLAGS_NEED64K,
.has_mbx_power_limits = false,
+ .has_ras = true,
};
static const struct xe_device_desc mtl_desc = {
@@ -472,6 +473,7 @@ static const struct xe_device_desc cri_desc = {
.require_force_probe = true,
.va_bits = 57,
.vm_max_level = 4,
+ .has_ras = true,
};
static const struct xe_device_desc nvlp_desc = {
@@ -761,6 +763,7 @@ static int xe_info_init_early(struct xe_device *xe,
xe->info.has_page_reclaim_hw_assist = desc->has_page_reclaim_hw_assist;
xe->info.has_pre_prod_wa = desc->has_pre_prod_wa;
xe->info.has_pxp = desc->has_pxp;
+ xe->info.has_ras = desc->has_ras;
xe->info.has_soc_remapper_sysctrl = desc->has_soc_remapper_sysctrl;
xe->info.has_soc_remapper_telem = desc->has_soc_remapper_telem;
xe->info.has_sriov = xe_configfs_primary_gt_allowed(to_pci_dev(xe->drm.dev)) &&
diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h
index 5b85e2c24b7b..70a9d4995cbd 100644
--- a/drivers/gpu/drm/xe/xe_pci_types.h
+++ b/drivers/gpu/drm/xe/xe_pci_types.h
@@ -54,6 +54,7 @@ struct xe_device_desc {
u8 has_pre_prod_wa:1;
u8 has_page_reclaim_hw_assist:1;
u8 has_pxp:1;
+ u8 has_ras:1;
u8 has_soc_remapper_sysctrl:1;
u8 has_soc_remapper_telem:1;
u8 has_sriov:1;
--
2.43.0
^ permalink raw reply related
* [PATCH v1 10/11] drm/xe/drm_ras: Wire up error threshold callbacks
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
In-Reply-To: <20260417211730.837345-1-raag.jadav@intel.com>
Now that we have get/set error threshold support in xe driver, wire them
up to drm_ras so that the user can make use of both functionalities.
$ sudo ynl --family drm_ras --do get-error-threshold --json \
'{"node-id":0, "error-id":2}'
{'error-id': 2, 'error-name': 'soc-internal', 'error-threshold': 0}
$ sudo ynl --family drm_ras --do set-error-threshold --json \
'{"node-id":0, "error-id":2, "error-threshold":8}'
None
Signed-off-by: Raag Jadav <raag.jadav@intel.com>
---
drivers/gpu/drm/xe/xe_drm_ras.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_drm_ras.c b/drivers/gpu/drm/xe/xe_drm_ras.c
index e07dc23a155e..824dabd5c29e 100644
--- a/drivers/gpu/drm/xe/xe_drm_ras.c
+++ b/drivers/gpu/drm/xe/xe_drm_ras.c
@@ -11,6 +11,7 @@
#include "xe_device_types.h"
#include "xe_drm_ras.h"
+#include "xe_ras.h"
static const char * const error_components[] = DRM_XE_RAS_ERROR_COMPONENT_NAMES;
static const char * const error_severity[] = DRM_XE_RAS_ERROR_SEVERITY_NAMES;
@@ -47,6 +48,27 @@ static int query_correctable_error_counter(struct drm_ras_node *ep, u32 error_id
return hw_query_error_counter(info, error_id, name, val);
}
+static int query_correctable_error_threshold(struct drm_ras_node *ep, u32 error_id,
+ const char **name, u32 *val)
+{
+ struct xe_device *xe = ep->priv;
+
+ if (!xe->info.has_sysctrl)
+ return -EOPNOTSUPP;
+
+ return xe_ras_get_threshold(xe, DRM_XE_RAS_ERR_SEV_CORRECTABLE, error_id, val);
+}
+
+static int set_correctable_error_threshold(struct drm_ras_node *ep, u32 error_id, u32 val)
+{
+ struct xe_device *xe = ep->priv;
+
+ if (!xe->info.has_sysctrl)
+ return -EOPNOTSUPP;
+
+ return xe_ras_set_threshold(xe, DRM_XE_RAS_ERR_SEV_CORRECTABLE, error_id, val);
+}
+
static struct xe_drm_ras_counter *allocate_and_copy_counters(struct xe_device *xe)
{
struct xe_drm_ras_counter *counter;
@@ -92,10 +114,13 @@ static int assign_node_params(struct xe_device *xe, struct drm_ras_node *node,
if (IS_ERR(ras->info[severity]))
return PTR_ERR(ras->info[severity]);
- if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE)
+ if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE) {
node->query_error_counter = query_correctable_error_counter;
- else
+ node->query_error_threshold = query_correctable_error_threshold;
+ node->set_error_threshold = set_correctable_error_threshold;
+ } else {
node->query_error_counter = query_uncorrectable_error_counter;
+ }
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v1 09/11] drm/xe/ras: Set error threshold support
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
In-Reply-To: <20260417211730.837345-1-raag.jadav@intel.com>
System controller allows programming per error threshold value, which
it uses to raise error events to the driver. Set it using mailbox
command so that it can be programmed by the user.
Signed-off-by: Raag Jadav <raag.jadav@intel.com>
---
drivers/gpu/drm/xe/xe_ras.c | 42 +++++++++++++++++++
drivers/gpu/drm/xe/xe_ras.h | 1 +
drivers/gpu/drm/xe/xe_ras_types.h | 28 +++++++++++++
drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h | 2 +
4 files changed, 73 insertions(+)
diff --git a/drivers/gpu/drm/xe/xe_ras.c b/drivers/gpu/drm/xe/xe_ras.c
index 3e93f838aa4a..26e063166c5f 100644
--- a/drivers/gpu/drm/xe/xe_ras.c
+++ b/drivers/gpu/drm/xe/xe_ras.c
@@ -163,3 +163,45 @@ int xe_ras_get_threshold(struct xe_device *xe, u32 severity, u32 component, u32
comp_to_str(counter.common.component), sev_to_str(counter.common.severity));
return 0;
}
+
+int xe_ras_set_threshold(struct xe_device *xe, u32 severity, u32 component, u32 threshold)
+{
+ struct xe_ras_set_threshold_response response = {};
+ struct xe_ras_set_threshold_request request = {};
+ struct xe_sysctrl_mailbox_command command = {};
+ struct xe_ras_error_class counter = {};
+ size_t len;
+ int ret;
+
+ counter.common.severity = drm_to_xe_ras_severities[severity];
+ counter.common.component = drm_to_xe_ras_components[component];
+ request.counter = counter;
+ request.threshold = threshold;
+
+ ras_command_prepare(&command, &request, sizeof(request), &response,
+ sizeof(response), XE_SYSCTRL_CMD_SET_THRESHOLD);
+
+ guard(xe_pm_runtime)(xe);
+ ret = xe_sysctrl_send_command(&xe->sc, &command, &len);
+ if (ret) {
+ xe_err(xe, "sysctrl: failed to set threshold %d\n", ret);
+ return ret;
+ }
+
+ if (len != sizeof(response)) {
+ xe_err(xe, "sysctrl: unexpected set threshold response length %zu (expected %zu)\n",
+ len, sizeof(response));
+ return -EIO;
+ }
+
+ if (response.status) {
+ xe_err(xe, "sysctrl: set threshold operation failed %#x\n", response.status);
+ return -EIO;
+ }
+
+ counter = response.counter;
+
+ xe_dbg(xe, "[RAS]: Set threshold %u for %s %s\n", response.threshold,
+ comp_to_str(counter.common.component), sev_to_str(counter.common.severity));
+ return 0;
+}
diff --git a/drivers/gpu/drm/xe/xe_ras.h b/drivers/gpu/drm/xe/xe_ras.h
index 982bbe61461e..d1f71b1de723 100644
--- a/drivers/gpu/drm/xe/xe_ras.h
+++ b/drivers/gpu/drm/xe/xe_ras.h
@@ -14,5 +14,6 @@ struct xe_sysctrl_event_response;
void xe_ras_counter_threshold_crossed(struct xe_device *xe,
struct xe_sysctrl_event_response *response);
int xe_ras_get_threshold(struct xe_device *xe, u32 severity, u32 component, u32 *threshold);
+int xe_ras_set_threshold(struct xe_device *xe, u32 severity, u32 component, u32 threshold);
#endif
diff --git a/drivers/gpu/drm/xe/xe_ras_types.h b/drivers/gpu/drm/xe/xe_ras_types.h
index d5da93d65cf5..d7e4a02a661d 100644
--- a/drivers/gpu/drm/xe/xe_ras_types.h
+++ b/drivers/gpu/drm/xe/xe_ras_types.h
@@ -92,4 +92,32 @@ struct xe_ras_get_threshold_response {
u32 reserved[4];
} __packed;
+/**
+ * struct xe_ras_set_threshold_request - Request structure for set threshold
+ */
+struct xe_ras_set_threshold_request {
+ /** @counter: Counter to set threshold for */
+ struct xe_ras_error_class counter;
+ /** @threshold: Threshold value to set */
+ u32 threshold;
+ /** @reserved: Reserved for future use */
+ u32 reserved;
+} __packed;
+
+/**
+ * struct xe_ras_set_threshold_response - Response structure for set threshold
+ */
+struct xe_ras_set_threshold_response {
+ /** @counter: Counter id */
+ struct xe_ras_error_class counter;
+ /** @threshold_old: Old threshold value */
+ u32 threshold_old;
+ /** @threshold: New threshold value */
+ u32 threshold;
+ /** @status: Set threshold operation status */
+ u32 status;
+ /** @reserved: Reserved for future use */
+ u32 reserved[2];
+} __packed;
+
#endif
diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
index a1b71218deca..b865768e903b 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
+++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
@@ -23,10 +23,12 @@ enum xe_sysctrl_group {
* enum xe_sysctrl_gfsp_cmd - Commands supported by GFSP group
*
* @XE_SYSCTRL_CMD_GET_THRESHOLD: Retrieve error threshold
+ * @XE_SYSCTRL_CMD_SET_THRESHOLD: Set error threshold
* @XE_SYSCTRL_CMD_GET_PENDING_EVENT: Retrieve pending event
*/
enum xe_sysctrl_gfsp_cmd {
XE_SYSCTRL_CMD_GET_THRESHOLD = 0x05,
+ XE_SYSCTRL_CMD_SET_THRESHOLD = 0x06,
XE_SYSCTRL_CMD_GET_PENDING_EVENT = 0x07,
};
--
2.43.0
^ permalink raw reply related
* [PATCH v1 08/11] drm/xe/ras: Get error threshold support
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
In-Reply-To: <20260417211730.837345-1-raag.jadav@intel.com>
System controller allows programming per error threshold value, which
it uses to raise error events to the driver. Get it using mailbox
command so that it can be exposed to the user.
Signed-off-by: Raag Jadav <raag.jadav@intel.com>
---
drivers/gpu/drm/xe/xe_ras.c | 73 +++++++++++++++++++
drivers/gpu/drm/xe/xe_ras.h | 3 +
drivers/gpu/drm/xe/xe_ras_types.h | 22 ++++++
drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h | 2 +
4 files changed, 100 insertions(+)
diff --git a/drivers/gpu/drm/xe/xe_ras.c b/drivers/gpu/drm/xe/xe_ras.c
index 08e91348c459..3e93f838aa4a 100644
--- a/drivers/gpu/drm/xe/xe_ras.c
+++ b/drivers/gpu/drm/xe/xe_ras.c
@@ -3,11 +3,14 @@
* Copyright © 2026 Intel Corporation
*/
+#include "xe_pm.h"
#include "xe_printk.h"
#include "xe_ras.h"
#include "xe_ras_types.h"
#include "xe_sysctrl.h"
#include "xe_sysctrl_event_types.h"
+#include "xe_sysctrl_mailbox.h"
+#include "xe_sysctrl_mailbox_types.h"
/* Severity of detected errors */
enum xe_ras_severity {
@@ -49,6 +52,23 @@ static const char *const xe_ras_components[] = {
};
static_assert(ARRAY_SIZE(xe_ras_components) == XE_RAS_COMP_MAX);
+/* uAPI mapping */
+static const int drm_to_xe_ras_components[] = {
+ [DRM_XE_RAS_ERR_COMP_CORE_COMPUTE] = XE_RAS_COMP_CORE_COMPUTE,
+ [DRM_XE_RAS_ERR_COMP_SOC_INTERNAL] = XE_RAS_COMP_SOC_INTERNAL,
+ [DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY] = XE_RAS_COMP_DEVICE_MEMORY,
+ [DRM_XE_RAS_ERR_COMP_PCIE] = XE_RAS_COMP_PCIE,
+ [DRM_XE_RAS_ERR_COMP_FABRIC] = XE_RAS_COMP_FABRIC
+};
+static_assert(ARRAY_SIZE(drm_to_xe_ras_components) == DRM_XE_RAS_ERR_COMP_MAX);
+
+/* uAPI mapping */
+static const int drm_to_xe_ras_severities[] = {
+ [DRM_XE_RAS_ERR_SEV_CORRECTABLE] = XE_RAS_SEV_CORRECTABLE,
+ [DRM_XE_RAS_ERR_SEV_UNCORRECTABLE] = XE_RAS_SEV_UNCORRECTABLE
+};
+static_assert(ARRAY_SIZE(drm_to_xe_ras_severities) == DRM_XE_RAS_ERR_SEV_MAX);
+
static inline const char *sev_to_str(u8 sev)
{
if (sev >= XE_RAS_SEV_MAX)
@@ -90,3 +110,56 @@ void xe_ras_counter_threshold_crossed(struct xe_device *xe,
comp_to_str(component), sev_to_str(severity));
}
}
+
+static void ras_command_prepare(struct xe_sysctrl_mailbox_command *command,
+ void *request, size_t request_len, void *response,
+ size_t response_len, u8 hdr_cmd)
+{
+ struct xe_sysctrl_app_msg_hdr header = {};
+
+ header.data = REG_FIELD_PREP(APP_HDR_GROUP_ID_MASK, XE_SYSCTRL_GROUP_GFSP) |
+ REG_FIELD_PREP(APP_HDR_COMMAND_MASK, hdr_cmd);
+
+ command->header = header;
+ command->data_in = request;
+ command->data_in_len = request_len;
+ command->data_out = response;
+ command->data_out_len = response_len;
+}
+
+int xe_ras_get_threshold(struct xe_device *xe, u32 severity, u32 component, u32 *threshold)
+{
+ struct xe_ras_get_threshold_response response = {};
+ struct xe_ras_get_threshold_request request = {};
+ struct xe_sysctrl_mailbox_command command = {};
+ struct xe_ras_error_class counter = {};
+ size_t len;
+ int ret;
+
+ counter.common.severity = drm_to_xe_ras_severities[severity];
+ counter.common.component = drm_to_xe_ras_components[component];
+ request.counter = counter;
+
+ ras_command_prepare(&command, &request, sizeof(request), &response,
+ sizeof(response), XE_SYSCTRL_CMD_GET_THRESHOLD);
+
+ guard(xe_pm_runtime)(xe);
+ ret = xe_sysctrl_send_command(&xe->sc, &command, &len);
+ if (ret) {
+ xe_err(xe, "sysctrl: failed to get threshold %d\n", ret);
+ return ret;
+ }
+
+ if (len != sizeof(response)) {
+ xe_err(xe, "sysctrl: unexpected get threshold response length %zu (expected %zu)\n",
+ len, sizeof(response));
+ return -EIO;
+ }
+
+ counter = response.counter;
+ *threshold = response.threshold;
+
+ xe_dbg(xe, "[RAS]: Get threshold %u for %s %s\n", response.threshold,
+ comp_to_str(counter.common.component), sev_to_str(counter.common.severity));
+ return 0;
+}
diff --git a/drivers/gpu/drm/xe/xe_ras.h b/drivers/gpu/drm/xe/xe_ras.h
index ea90593b62dc..982bbe61461e 100644
--- a/drivers/gpu/drm/xe/xe_ras.h
+++ b/drivers/gpu/drm/xe/xe_ras.h
@@ -6,10 +6,13 @@
#ifndef _XE_RAS_H_
#define _XE_RAS_H_
+#include <linux/types.h>
+
struct xe_device;
struct xe_sysctrl_event_response;
void xe_ras_counter_threshold_crossed(struct xe_device *xe,
struct xe_sysctrl_event_response *response);
+int xe_ras_get_threshold(struct xe_device *xe, u32 severity, u32 component, u32 *threshold);
#endif
diff --git a/drivers/gpu/drm/xe/xe_ras_types.h b/drivers/gpu/drm/xe/xe_ras_types.h
index 4e63c67f806a..d5da93d65cf5 100644
--- a/drivers/gpu/drm/xe/xe_ras_types.h
+++ b/drivers/gpu/drm/xe/xe_ras_types.h
@@ -70,4 +70,26 @@ struct xe_ras_threshold_crossed {
struct xe_ras_error_class counters[XE_RAS_NUM_COUNTERS];
} __packed;
+/**
+ * struct xe_ras_get_threshold_request - Request structure for get threshold
+ */
+struct xe_ras_get_threshold_request {
+ /** @counter: Counter to get threshold for */
+ struct xe_ras_error_class counter;
+ /** @reserved: Reserved for future use */
+ u32 reserved;
+} __packed;
+
+/**
+ * struct xe_ras_get_threshold_response - Response structure for get threshold
+ */
+struct xe_ras_get_threshold_response {
+ /** @counter: Counter id */
+ struct xe_ras_error_class counter;
+ /** @threshold: Threshold value */
+ u32 threshold;
+ /** @reserved: Reserved for future use */
+ u32 reserved[4];
+} __packed;
+
#endif
diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
index 84d7c647e743..a1b71218deca 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
+++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
@@ -22,9 +22,11 @@ enum xe_sysctrl_group {
/**
* enum xe_sysctrl_gfsp_cmd - Commands supported by GFSP group
*
+ * @XE_SYSCTRL_CMD_GET_THRESHOLD: Retrieve error threshold
* @XE_SYSCTRL_CMD_GET_PENDING_EVENT: Retrieve pending event
*/
enum xe_sysctrl_gfsp_cmd {
+ XE_SYSCTRL_CMD_GET_THRESHOLD = 0x05,
XE_SYSCTRL_CMD_GET_PENDING_EVENT = 0x07,
};
--
2.43.0
^ permalink raw reply related
* [PATCH v1 07/11] drm/xe/ras: Introduce correctable error handling
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
In-Reply-To: <20260417211730.837345-1-raag.jadav@intel.com>
Add initial support for correctable error handling which is serviced
using system controller event. Currently we only log the errors in
dmesg but this serves as a foundation for RAS infrastructure and will
be further extended to facilitate other RAS features.
Signed-off-by: Raag Jadav <raag.jadav@intel.com>
Reviewed-by: Mallesh Koujalagi <mallesh.koujalagi@intel.com>
---
drivers/gpu/drm/xe/Makefile | 1 +
drivers/gpu/drm/xe/xe_ras.c | 92 +++++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_ras.h | 15 +++++
drivers/gpu/drm/xe/xe_ras_types.h | 73 +++++++++++++++++++++
drivers/gpu/drm/xe/xe_sysctrl_event.c | 3 +-
5 files changed, 183 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/xe/xe_ras.c
create mode 100644 drivers/gpu/drm/xe/xe_ras.h
create mode 100644 drivers/gpu/drm/xe/xe_ras_types.h
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 1c863b711ae9..22f17bd1082d 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -114,6 +114,7 @@ xe-y += xe_bb.o \
xe_pxp_submit.o \
xe_query.o \
xe_range_fence.o \
+ xe_ras.o \
xe_reg_sr.o \
xe_reg_whitelist.o \
xe_ring_ops.o \
diff --git a/drivers/gpu/drm/xe/xe_ras.c b/drivers/gpu/drm/xe/xe_ras.c
new file mode 100644
index 000000000000..08e91348c459
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_ras.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include "xe_printk.h"
+#include "xe_ras.h"
+#include "xe_ras_types.h"
+#include "xe_sysctrl.h"
+#include "xe_sysctrl_event_types.h"
+
+/* Severity of detected errors */
+enum xe_ras_severity {
+ XE_RAS_SEV_NOT_SUPPORTED = 0,
+ XE_RAS_SEV_CORRECTABLE,
+ XE_RAS_SEV_UNCORRECTABLE,
+ XE_RAS_SEV_INFORMATIONAL,
+ XE_RAS_SEV_MAX
+};
+
+/* Major IP blocks/components where errors can originate */
+enum xe_ras_component {
+ XE_RAS_COMP_NOT_SUPPORTED = 0,
+ XE_RAS_COMP_DEVICE_MEMORY,
+ XE_RAS_COMP_CORE_COMPUTE,
+ XE_RAS_COMP_RESERVED,
+ XE_RAS_COMP_PCIE,
+ XE_RAS_COMP_FABRIC,
+ XE_RAS_COMP_SOC_INTERNAL,
+ XE_RAS_COMP_MAX
+};
+
+static const char *const xe_ras_severities[] = {
+ [XE_RAS_SEV_NOT_SUPPORTED] = "Not Supported",
+ [XE_RAS_SEV_CORRECTABLE] = "Correctable Error",
+ [XE_RAS_SEV_UNCORRECTABLE] = "Uncorrectable Error",
+ [XE_RAS_SEV_INFORMATIONAL] = "Informational Error",
+};
+static_assert(ARRAY_SIZE(xe_ras_severities) == XE_RAS_SEV_MAX);
+
+static const char *const xe_ras_components[] = {
+ [XE_RAS_COMP_NOT_SUPPORTED] = "Not Supported",
+ [XE_RAS_COMP_DEVICE_MEMORY] = "Device Memory",
+ [XE_RAS_COMP_CORE_COMPUTE] = "Core Compute",
+ [XE_RAS_COMP_RESERVED] = "Reserved",
+ [XE_RAS_COMP_PCIE] = "PCIe",
+ [XE_RAS_COMP_FABRIC] = "Fabric",
+ [XE_RAS_COMP_SOC_INTERNAL] = "SoC Internal",
+};
+static_assert(ARRAY_SIZE(xe_ras_components) == XE_RAS_COMP_MAX);
+
+static inline const char *sev_to_str(u8 sev)
+{
+ if (sev >= XE_RAS_SEV_MAX)
+ sev = XE_RAS_SEV_NOT_SUPPORTED;
+
+ return xe_ras_severities[sev];
+}
+
+static inline const char *comp_to_str(u8 comp)
+{
+ if (comp >= XE_RAS_COMP_MAX)
+ comp = XE_RAS_COMP_NOT_SUPPORTED;
+
+ return xe_ras_components[comp];
+}
+
+void xe_ras_counter_threshold_crossed(struct xe_device *xe,
+ struct xe_sysctrl_event_response *response)
+{
+ struct xe_ras_threshold_crossed *pending = (void *)&response->data;
+ struct xe_ras_error_class *errors = pending->counters;
+ u32 counter_id, ncounters = pending->ncounters;
+
+ if (!ncounters || ncounters > XE_RAS_NUM_COUNTERS) {
+ xe_err(xe, "sysctrl: unexpected counter threshold crossed %u\n", ncounters);
+ return;
+ }
+
+ BUILD_BUG_ON(sizeof(response->data) < sizeof(*pending));
+ xe_warn(xe, "[RAS]: counter threshold crossed, %u new errors\n", ncounters);
+
+ for (counter_id = 0; counter_id < ncounters; counter_id++) {
+ u8 severity, component;
+
+ severity = errors[counter_id].common.severity;
+ component = errors[counter_id].common.component;
+
+ xe_warn(xe, "[RAS]: %s %s detected\n",
+ comp_to_str(component), sev_to_str(severity));
+ }
+}
diff --git a/drivers/gpu/drm/xe/xe_ras.h b/drivers/gpu/drm/xe/xe_ras.h
new file mode 100644
index 000000000000..ea90593b62dc
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_ras.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef _XE_RAS_H_
+#define _XE_RAS_H_
+
+struct xe_device;
+struct xe_sysctrl_event_response;
+
+void xe_ras_counter_threshold_crossed(struct xe_device *xe,
+ struct xe_sysctrl_event_response *response);
+
+#endif
diff --git a/drivers/gpu/drm/xe/xe_ras_types.h b/drivers/gpu/drm/xe/xe_ras_types.h
new file mode 100644
index 000000000000..4e63c67f806a
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_ras_types.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef _XE_RAS_TYPES_H_
+#define _XE_RAS_TYPES_H_
+
+#include <linux/types.h>
+
+#define XE_RAS_NUM_COUNTERS 16
+
+/**
+ * struct xe_ras_error_common - Error fields that are common across all products
+ */
+struct xe_ras_error_common {
+ /** @severity: Error severity */
+ u8 severity;
+ /** @component: IP block where error originated */
+ u8 component;
+} __packed;
+
+/**
+ * struct xe_ras_error_unit - Error unit information
+ */
+struct xe_ras_error_unit {
+ /** @tile: Tile identifier */
+ u8 tile;
+ /** @instance: Instance identifier specific to IP */
+ u32 instance;
+} __packed;
+
+/**
+ * struct xe_ras_error_cause - Error cause information
+ */
+struct xe_ras_error_cause {
+ /** @cause: Cause/checker */
+ u32 cause;
+ /** @reserved: For future use */
+ u8 reserved;
+} __packed;
+
+/**
+ * struct xe_ras_error_product - Error fields that are specific to the product
+ */
+struct xe_ras_error_product {
+ /** @unit: Unit within IP block */
+ struct xe_ras_error_unit unit;
+ /** @cause: Cause/checker */
+ struct xe_ras_error_cause cause;
+} __packed;
+
+/**
+ * struct xe_ras_error_class - Combines common and product-specific parts
+ */
+struct xe_ras_error_class {
+ /** @common: Common error type and component */
+ struct xe_ras_error_common common;
+ /** @product: Product-specific unit and cause */
+ struct xe_ras_error_product product;
+} __packed;
+
+/**
+ * struct xe_ras_threshold_crossed - Data for threshold crossed event
+ */
+struct xe_ras_threshold_crossed {
+ /** @ncounters: Number of error counters that crossed thresholds */
+ u32 ncounters;
+ /** @counters: Array of error counters that crossed threshold */
+ struct xe_ras_error_class counters[XE_RAS_NUM_COUNTERS];
+} __packed;
+
+#endif
diff --git a/drivers/gpu/drm/xe/xe_sysctrl_event.c b/drivers/gpu/drm/xe/xe_sysctrl_event.c
index 74163e0bafe2..e96af8be07a2 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl_event.c
+++ b/drivers/gpu/drm/xe/xe_sysctrl_event.c
@@ -6,6 +6,7 @@
#include "xe_device.h"
#include "xe_irq.h"
#include "xe_printk.h"
+#include "xe_ras.h"
#include "xe_sysctrl.h"
#include "xe_sysctrl_event_types.h"
#include "xe_sysctrl_mailbox.h"
@@ -35,7 +36,7 @@ static void get_pending_event(struct xe_sysctrl *sc, struct xe_sysctrl_mailbox_c
}
if (response->event == XE_SYSCTRL_EVENT_THRESHOLD_CROSSED)
- xe_warn(xe, "[RAS]: counter threshold crossed\n");
+ xe_ras_counter_threshold_crossed(xe, response);
else
xe_err(xe, "sysctrl: unexpected event %#x\n", response->event);
--
2.43.0
^ permalink raw reply related
* [PATCH v1 06/11] drm/xe/sysctrl: Add system controller event support
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
In-Reply-To: <20260417211730.837345-1-raag.jadav@intel.com>
System controller reports different types of events to GFX endpoint for
different usecases, add initial support for them. This will be further
extended to service those usecases.
Signed-off-by: Raag Jadav <raag.jadav@intel.com>
Reviewed-by: Mallesh Koujalagi <mallesh.koujalagi@intel.com>
---
drivers/gpu/drm/xe/Makefile | 1 +
drivers/gpu/drm/xe/xe_sysctrl.c | 11 +++
drivers/gpu/drm/xe/xe_sysctrl.h | 1 +
drivers/gpu/drm/xe/xe_sysctrl_event.c | 86 +++++++++++++++++++
drivers/gpu/drm/xe/xe_sysctrl_event_types.h | 57 ++++++++++++
drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h | 18 ++++
drivers/gpu/drm/xe/xe_sysctrl_types.h | 3 +
7 files changed, 177 insertions(+)
create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_event.c
create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_event_types.h
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 3fceda259834..1c863b711ae9 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -126,6 +126,7 @@ xe-y += xe_bb.o \
xe_survivability_mode.o \
xe_sync.o \
xe_sysctrl.o \
+ xe_sysctrl_event.o \
xe_sysctrl_mailbox.o \
xe_tile.o \
xe_tile_sysfs.o \
diff --git a/drivers/gpu/drm/xe/xe_sysctrl.c b/drivers/gpu/drm/xe/xe_sysctrl.c
index 7de3e73bd8e0..6a7da5d2794a 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl.c
+++ b/drivers/gpu/drm/xe/xe_sysctrl.c
@@ -12,6 +12,7 @@
#include "regs/xe_sysctrl_regs.h"
#include "xe_device.h"
#include "xe_mmio.h"
+#include "xe_pm.h"
#include "xe_soc_remapper.h"
#include "xe_sysctrl.h"
#include "xe_sysctrl_mailbox.h"
@@ -39,6 +40,12 @@ static void sysctrl_fini(void *arg)
static void xe_sysctrl_work(struct work_struct *work)
{
+ struct xe_sysctrl *sc = container_of(work, struct xe_sysctrl, work);
+ struct xe_device *xe = sc_to_xe(sc);
+
+ guard(xe_pm_runtime)(xe);
+ guard(mutex)(&sc->work_lock);
+ xe_sysctrl_event(sc);
}
/**
@@ -74,6 +81,10 @@ int xe_sysctrl_init(struct xe_device *xe)
if (ret)
return ret;
+ ret = devm_mutex_init(xe->drm.dev, &sc->work_lock);
+ if (ret)
+ return ret;
+
xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX);
xe_sysctrl_mailbox_init(sc);
INIT_WORK(&sc->work, xe_sysctrl_work);
diff --git a/drivers/gpu/drm/xe/xe_sysctrl.h b/drivers/gpu/drm/xe/xe_sysctrl.h
index f7469bfc9324..090dffb6d55f 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl.h
+++ b/drivers/gpu/drm/xe/xe_sysctrl.h
@@ -16,6 +16,7 @@ static inline struct xe_device *sc_to_xe(struct xe_sysctrl *sc)
return container_of(sc, struct xe_device, sc);
}
+void xe_sysctrl_event(struct xe_sysctrl *sc);
int xe_sysctrl_init(struct xe_device *xe);
void xe_sysctrl_irq_handler(struct xe_device *xe, u32 master_ctl);
void xe_sysctrl_pm_resume(struct xe_device *xe);
diff --git a/drivers/gpu/drm/xe/xe_sysctrl_event.c b/drivers/gpu/drm/xe/xe_sysctrl_event.c
new file mode 100644
index 000000000000..74163e0bafe2
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_sysctrl_event.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include "xe_device.h"
+#include "xe_irq.h"
+#include "xe_printk.h"
+#include "xe_sysctrl.h"
+#include "xe_sysctrl_event_types.h"
+#include "xe_sysctrl_mailbox.h"
+#include "xe_sysctrl_mailbox_types.h"
+
+static void get_pending_event(struct xe_sysctrl *sc, struct xe_sysctrl_mailbox_command *command)
+{
+ struct xe_sysctrl_event_response *response = command->data_out;
+ struct xe_device *xe = sc_to_xe(sc);
+ u32 count = XE_SYSCTRL_EVENT_FLOOD;
+ size_t len;
+ int ret;
+
+ do {
+ memset(response, 0, sizeof(*response));
+
+ ret = xe_sysctrl_send_command(sc, command, &len);
+ if (ret) {
+ xe_err(xe, "sysctrl: failed to get pending event %d\n", ret);
+ return;
+ }
+
+ if (len != sizeof(*response)) {
+ xe_err(xe, "sysctrl: unexpected event response length %zu (expected %zu)\n",
+ len, sizeof(*response));
+ return;
+ }
+
+ if (response->event == XE_SYSCTRL_EVENT_THRESHOLD_CROSSED)
+ xe_warn(xe, "[RAS]: counter threshold crossed\n");
+ else
+ xe_err(xe, "sysctrl: unexpected event %#x\n", response->event);
+
+ if (!--count) {
+ xe_err(xe, "sysctrl: event flooding\n");
+ return;
+ }
+
+ xe_dbg(xe, "sysctrl: %u events pending\n", response->count);
+ } while (response->count);
+}
+
+static void event_request_prepare(struct xe_device *xe, struct xe_sysctrl_app_msg_hdr *header,
+ struct xe_sysctrl_event_request *request)
+{
+ struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
+
+ header->data = REG_FIELD_PREP(APP_HDR_GROUP_ID_MASK, XE_SYSCTRL_GROUP_GFSP) |
+ REG_FIELD_PREP(APP_HDR_COMMAND_MASK, XE_SYSCTRL_CMD_GET_PENDING_EVENT);
+
+ request->vector = xe_device_has_msix(xe) ? XE_IRQ_DEFAULT_MSIX : 0;
+ request->fn = PCI_FUNC(pdev->devfn);
+}
+
+/**
+ * xe_sysctrl_event() - Handler for System Controller events
+ * @sc: System Controller instance
+ *
+ * Handle events generated by System Controller.
+ */
+void xe_sysctrl_event(struct xe_sysctrl *sc)
+{
+ struct xe_sysctrl_mailbox_command command = {};
+ struct xe_sysctrl_event_response response = {};
+ struct xe_sysctrl_event_request request = {};
+ struct xe_sysctrl_app_msg_hdr header = {};
+
+ xe_device_assert_mem_access(sc_to_xe(sc));
+ event_request_prepare(sc_to_xe(sc), &header, &request);
+
+ command.header = header;
+ command.data_in = &request;
+ command.data_in_len = sizeof(request);
+ command.data_out = &response;
+ command.data_out_len = sizeof(response);
+
+ get_pending_event(sc, &command);
+}
diff --git a/drivers/gpu/drm/xe/xe_sysctrl_event_types.h b/drivers/gpu/drm/xe/xe_sysctrl_event_types.h
new file mode 100644
index 000000000000..4d444ba40b9b
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_sysctrl_event_types.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef _XE_SYSCTRL_EVENT_TYPES_H_
+#define _XE_SYSCTRL_EVENT_TYPES_H_
+
+#include <linux/types.h>
+
+#define XE_SYSCTRL_EVENT_DATA_LEN 59
+
+/* Modify as needed */
+#define XE_SYSCTRL_EVENT_FLOOD 16
+
+/**
+ * enum xe_sysctrl_event - Events reported by System Controller
+ *
+ * @XE_SYSCTRL_EVENT_THRESHOLD_CROSSED: Error counter threshold crossed
+ */
+enum xe_sysctrl_event {
+ XE_SYSCTRL_EVENT_THRESHOLD_CROSSED = 0x01,
+};
+
+/**
+ * struct xe_sysctrl_event_request - Request structure for pending event
+ */
+struct xe_sysctrl_event_request {
+ /** @vector: MSI-X vector that was triggered */
+ u32 vector;
+ /** @fn: Function index (0-7) of PCIe device */
+ u32 fn:8;
+ /** @reserved: Reserved for future use */
+ u32 reserved:24;
+ /** @reserved2: Reserved for future use */
+ u32 reserved2[2];
+} __packed;
+
+/**
+ * struct xe_sysctrl_event_response - Response structure for pending event
+ */
+struct xe_sysctrl_event_response {
+ /** @count: Pending event count, decremented by fw on each response */
+ u32 count;
+ /** @event: Pending event type */
+ u32 event;
+ /** @timestamp: Timestamp of most recent event */
+ u64 timestamp;
+ /** @extended: Event has extended payload */
+ u32 extended:1;
+ /** @reserved: Reserved for future use */
+ u32 reserved:31;
+ /** @data: Generic event data */
+ u32 data[XE_SYSCTRL_EVENT_DATA_LEN];
+} __packed;
+
+#endif /* _XE_SYSCTRL_EVENT_TYPES_H_ */
diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
index 89456aec6097..84d7c647e743 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
+++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
@@ -10,6 +10,24 @@
#include "abi/xe_sysctrl_abi.h"
+/**
+ * enum xe_sysctrl_group - System Controller command groups
+ *
+ * @XE_SYSCTRL_GROUP_GFSP: GFSP group
+ */
+enum xe_sysctrl_group {
+ XE_SYSCTRL_GROUP_GFSP = 0x01,
+};
+
+/**
+ * enum xe_sysctrl_gfsp_cmd - Commands supported by GFSP group
+ *
+ * @XE_SYSCTRL_CMD_GET_PENDING_EVENT: Retrieve pending event
+ */
+enum xe_sysctrl_gfsp_cmd {
+ XE_SYSCTRL_CMD_GET_PENDING_EVENT = 0x07,
+};
+
/**
* struct xe_sysctrl_mailbox_command - System Controller mailbox command
*/
diff --git a/drivers/gpu/drm/xe/xe_sysctrl_types.h b/drivers/gpu/drm/xe/xe_sysctrl_types.h
index 5f408d6491ef..95359af691c9 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl_types.h
+++ b/drivers/gpu/drm/xe/xe_sysctrl_types.h
@@ -31,6 +31,9 @@ struct xe_sysctrl {
/** @work: Pending events worker */
struct work_struct work;
+
+ /** @work_lock: Mutex protecting pending events */
+ struct mutex work_lock;
};
#endif
--
2.43.0
^ permalink raw reply related
* [PATCH v1 05/11] drm/xe/sysctrl: Add system controller interrupt handler
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
In-Reply-To: <20260417211730.837345-1-raag.jadav@intel.com>
Add system controller interrupt handler which is denoted by 11th bit in
GFX master interrupt register. While at it, add worker for scheduling
system controller work.
Co-developed-by: Soham Purkait <soham.purkait@intel.com>
Signed-off-by: Soham Purkait <soham.purkait@intel.com>
Signed-off-by: Raag Jadav <raag.jadav@intel.com>
Reviewed-by: Mallesh Koujalagi <mallesh.koujalagi@intel.com>
Reviewed-by: Riana Tauro <riana.tauro@intel.com>
---
drivers/gpu/drm/xe/regs/xe_irq_regs.h | 1 +
drivers/gpu/drm/xe/xe_irq.c | 2 ++
drivers/gpu/drm/xe/xe_sysctrl.c | 35 +++++++++++++++++++++------
drivers/gpu/drm/xe/xe_sysctrl.h | 1 +
drivers/gpu/drm/xe/xe_sysctrl_types.h | 4 +++
5 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/xe/regs/xe_irq_regs.h b/drivers/gpu/drm/xe/regs/xe_irq_regs.h
index 9d74f454d3ff..1d6b976c4de0 100644
--- a/drivers/gpu/drm/xe/regs/xe_irq_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_irq_regs.h
@@ -22,6 +22,7 @@
#define DISPLAY_IRQ REG_BIT(16)
#define SOC_H2DMEMINT_IRQ REG_BIT(13)
#define I2C_IRQ REG_BIT(12)
+#define SYSCTRL_IRQ REG_BIT(11)
#define GT_DW_IRQ(x) REG_BIT(x)
/*
diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c
index 9a775c6588dc..e9f0b3cad06d 100644
--- a/drivers/gpu/drm/xe/xe_irq.c
+++ b/drivers/gpu/drm/xe/xe_irq.c
@@ -24,6 +24,7 @@
#include "xe_mmio.h"
#include "xe_pxp.h"
#include "xe_sriov.h"
+#include "xe_sysctrl.h"
#include "xe_tile.h"
/*
@@ -525,6 +526,7 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg)
xe_heci_csc_irq_handler(xe, master_ctl);
xe_display_irq_handler(xe, master_ctl);
xe_i2c_irq_handler(xe, master_ctl);
+ xe_sysctrl_irq_handler(xe, master_ctl);
xe_mert_irq_handler(xe, master_ctl);
gu_misc_iir = gu_misc_irq_ack(xe, master_ctl);
}
diff --git a/drivers/gpu/drm/xe/xe_sysctrl.c b/drivers/gpu/drm/xe/xe_sysctrl.c
index 2bcef304eb9a..7de3e73bd8e0 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl.c
+++ b/drivers/gpu/drm/xe/xe_sysctrl.c
@@ -8,6 +8,7 @@
#include <drm/drm_managed.h>
+#include "regs/xe_irq_regs.h"
#include "regs/xe_sysctrl_regs.h"
#include "xe_device.h"
#include "xe_mmio.h"
@@ -30,10 +31,16 @@
static void sysctrl_fini(void *arg)
{
struct xe_device *xe = arg;
+ struct xe_sysctrl *sc = &xe->sc;
+ disable_work_sync(&sc->work);
xe->soc_remapper.set_sysctrl_region(xe, 0);
}
+static void xe_sysctrl_work(struct work_struct *work)
+{
+}
+
/**
* xe_sysctrl_init() - Initialize System Controller subsystem
* @xe: xe device instance
@@ -55,12 +62,6 @@ int xe_sysctrl_init(struct xe_device *xe)
if (!xe->info.has_sysctrl)
return 0;
- xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX);
-
- ret = devm_add_action_or_reset(xe->drm.dev, sysctrl_fini, xe);
- if (ret)
- return ret;
-
sc->mmio = devm_kzalloc(xe->drm.dev, sizeof(*sc->mmio), GFP_KERNEL);
if (!sc->mmio)
return -ENOMEM;
@@ -73,9 +74,29 @@ int xe_sysctrl_init(struct xe_device *xe)
if (ret)
return ret;
+ xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX);
xe_sysctrl_mailbox_init(sc);
+ INIT_WORK(&sc->work, xe_sysctrl_work);
- return 0;
+ return devm_add_action_or_reset(xe->drm.dev, sysctrl_fini, xe);
+}
+
+/**
+ * xe_sysctrl_irq_handler() - Handler for System Controller interrupts
+ * @xe: xe device instance
+ * @master_ctl: interrupt register
+ *
+ * Handle interrupts generated by System Controller.
+ */
+void xe_sysctrl_irq_handler(struct xe_device *xe, u32 master_ctl)
+{
+ struct xe_sysctrl *sc = &xe->sc;
+
+ if (!xe->info.has_sysctrl || !sc->work.func)
+ return;
+
+ if (master_ctl & SYSCTRL_IRQ)
+ schedule_work(&sc->work);
}
/**
diff --git a/drivers/gpu/drm/xe/xe_sysctrl.h b/drivers/gpu/drm/xe/xe_sysctrl.h
index f3b0f3716b2f..f7469bfc9324 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl.h
+++ b/drivers/gpu/drm/xe/xe_sysctrl.h
@@ -17,6 +17,7 @@ static inline struct xe_device *sc_to_xe(struct xe_sysctrl *sc)
}
int xe_sysctrl_init(struct xe_device *xe);
+void xe_sysctrl_irq_handler(struct xe_device *xe, u32 master_ctl);
void xe_sysctrl_pm_resume(struct xe_device *xe);
#endif
diff --git a/drivers/gpu/drm/xe/xe_sysctrl_types.h b/drivers/gpu/drm/xe/xe_sysctrl_types.h
index 8217f6befe70..5f408d6491ef 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl_types.h
+++ b/drivers/gpu/drm/xe/xe_sysctrl_types.h
@@ -8,6 +8,7 @@
#include <linux/mutex.h>
#include <linux/types.h>
+#include <linux/workqueue_types.h>
struct xe_mmio;
@@ -27,6 +28,9 @@ struct xe_sysctrl {
/** @phase_bit: Message boundary phase toggle bit (0 or 1) */
bool phase_bit;
+
+ /** @work: Pending events worker */
+ struct work_struct work;
};
#endif
--
2.43.0
^ permalink raw reply related
* [PATCH v1 04/11] drm/xe/uapi: Add additional error components to XE drm_ras
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
In-Reply-To: <20260417211730.837345-1-raag.jadav@intel.com>
From: Riana Tauro <riana.tauro@intel.com>
Add additional Error components supported by XE RAS (Reliability,
Availability and Serviceability).
Signed-off-by: Riana Tauro <riana.tauro@intel.com>
Reviewed-by: Aravind Iddamsetty <aravind.iddamsetty@linux.intel.com>
---
include/uapi/drm/xe_drm.h | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
index 48e9f1fdb78d..50c80af4ad4e 100644
--- a/include/uapi/drm/xe_drm.h
+++ b/include/uapi/drm/xe_drm.h
@@ -2589,6 +2589,12 @@ enum drm_xe_ras_error_component {
DRM_XE_RAS_ERR_COMP_CORE_COMPUTE = 1,
/** @DRM_XE_RAS_ERR_COMP_SOC_INTERNAL: SoC Internal Error */
DRM_XE_RAS_ERR_COMP_SOC_INTERNAL,
+ /** @DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY: Device Memory Error */
+ DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY,
+ /** @DRM_XE_RAS_ERR_COMP_PCIE: PCIe Subsystem Error */
+ DRM_XE_RAS_ERR_COMP_PCIE,
+ /** @DRM_XE_RAS_ERR_COMP_FABRIC: Fabric Subsystem Error */
+ DRM_XE_RAS_ERR_COMP_FABRIC,
/** @DRM_XE_RAS_ERR_COMP_MAX: Max Error */
DRM_XE_RAS_ERR_COMP_MAX /* non-ABI */
};
@@ -2606,7 +2612,10 @@ enum drm_xe_ras_error_component {
*/
#define DRM_XE_RAS_ERROR_COMPONENT_NAMES { \
[DRM_XE_RAS_ERR_COMP_CORE_COMPUTE] = "core-compute", \
- [DRM_XE_RAS_ERR_COMP_SOC_INTERNAL] = "soc-internal" \
+ [DRM_XE_RAS_ERR_COMP_SOC_INTERNAL] = "soc-internal", \
+ [DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY] = "device-memory", \
+ [DRM_XE_RAS_ERR_COMP_PCIE] = "pcie", \
+ [DRM_XE_RAS_ERR_COMP_FABRIC] = "fabric", \
}
#if defined(__cplusplus)
--
2.43.0
^ permalink raw reply related
* [PATCH v1 03/11] drm/ras: Introduce set-error-threshold
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
In-Reply-To: <20260417211730.837345-1-raag.jadav@intel.com>
Add set-error-threshold command support which allows setting threshold
value of the error. Threshold in RAS context means the number of errors
the hardware is expected to accumulate before it raises them to software.
This is to have a fine grained control over error notifications that are
raised by the hardware.
Signed-off-by: Raag Jadav <raag.jadav@intel.com>
---
Documentation/gpu/drm-ras.rst | 9 +++++
Documentation/netlink/specs/drm_ras.yaml | 12 ++++++
drivers/gpu/drm/drm_ras.c | 48 ++++++++++++++++++++++++
drivers/gpu/drm/drm_ras_nl.c | 14 +++++++
drivers/gpu/drm/drm_ras_nl.h | 2 +
include/drm/drm_ras.h | 13 +++++++
include/uapi/drm/drm_ras.h | 1 +
7 files changed, 99 insertions(+)
diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst
index 6443dfd1677f..a819aa150604 100644
--- a/Documentation/gpu/drm-ras.rst
+++ b/Documentation/gpu/drm-ras.rst
@@ -54,6 +54,8 @@ User space tools can:
``node-id`` and ``error-id`` as parameters.
* Query specific error threshold value with the ``get-error-threshold`` command, using both
``node-id`` and ``error-id`` as parameters.
+* Set specific error threshold value with the ``set-error-threshold`` command, using
+ ``node-id``, ``error-id`` and ``error-threshold`` as parameters.
YAML-based Interface
--------------------
@@ -109,3 +111,10 @@ Example: Query threshold value of a given error
sudo ynl --family drm_ras --do get-error-threshold --json '{"node-id":0, "error-id":1}'
{'error-id': 1, 'error-name': 'error_name1', 'error-threshold': 0}
+
+Example: Set threshold value of a given error
+
+.. code-block:: bash
+
+ sudo ynl --family drm_ras --do set-error-threshold --json '{"node-id":0, "error-id":1, "error-threshold":8}'
+ None
diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml
index 95a939fb987d..09824309cdff 100644
--- a/Documentation/netlink/specs/drm_ras.yaml
+++ b/Documentation/netlink/specs/drm_ras.yaml
@@ -150,3 +150,15 @@ operations:
- error-id
- error-name
- error-threshold
+ -
+ name: set-error-threshold
+ doc: >-
+ Set threshold value of the error.
+ attribute-set: error-threshold-attrs
+ flags: [admin-perm]
+ do:
+ request:
+ attributes:
+ - node-id
+ - error-id
+ - error-threshold
diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c
index d2d853d5d69c..e4ff6d87f824 100644
--- a/drivers/gpu/drm/drm_ras.c
+++ b/drivers/gpu/drm/drm_ras.c
@@ -41,6 +41,9 @@
* Userspace must provide Node ID and Error ID.
* Returns the threshold value of a specific error.
*
+ * 4. SET_ERROR_THRESHOLD: Set threshold value of the error.
+ * Userspace must provide Node ID, Error ID and Threshold value to be set.
+ *
* Node registration:
*
* - drm_ras_node_register(): Registers a new node and assigns
@@ -72,6 +75,8 @@
* operation, fetching a counter value from a specific node.
* - drm_ras_nl_get_error_threshold_doit(): Implements the GET_ERROR_THRESHOLD doit
* operation, fetching the threshold value of a specific error.
+ * - drm_ras_nl_set_error_threshold_doit(): Implements the SET_ERROR_THRESHOLD doit
+ * operation, setting the threshold value of a specific error.
*/
static DEFINE_XARRAY_ALLOC(drm_ras_xa);
@@ -184,6 +189,21 @@ static int get_node_error_threshold(u32 node_id, u32 error_id,
return node->query_error_threshold(node, error_id, name, value);
}
+static int set_node_error_threshold(u32 node_id, u32 error_id, u32 value)
+{
+ struct drm_ras_node *node;
+
+ node = xa_load(&drm_ras_xa, node_id);
+ if (!node || !node->set_error_threshold)
+ return -ENOENT;
+
+ if (error_id < node->error_counter_range.first ||
+ error_id > node->error_counter_range.last)
+ return -EINVAL;
+
+ return node->set_error_threshold(node, error_id, value);
+}
+
static int msg_reply_counter_value(struct sk_buff *msg, u32 error_id,
const char *error_name, u32 value)
{
@@ -417,6 +437,34 @@ int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
return doit_reply_threshold_value(info, node_id, error_id);
}
+/**
+ * drm_ras_nl_set_error_threshold_doit() - Set threshold value of the error
+ * @skb: Netlink message buffer
+ * @info: Generic Netlink info containing attributes of the request
+ *
+ * Extracts the node ID, error ID and threshold value from the netlink attributes
+ * and sets the threshold of the corresponding error.
+ *
+ * Return: 0 on success, or negative errno on failure.
+ */
+int drm_ras_nl_set_error_threshold_doit(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ u32 node_id, error_id, value;
+
+ if (!info->attrs ||
+ GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID) ||
+ GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID) ||
+ GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD))
+ return -EINVAL;
+
+ node_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID]);
+ error_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID]);
+ value = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD]);
+
+ return set_node_error_threshold(node_id, error_id, value);
+}
+
/**
* drm_ras_node_register() - Register a new RAS node
* @node: Node structure to register
diff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c
index 48e231734f4d..8b202d773dac 100644
--- a/drivers/gpu/drm/drm_ras_nl.c
+++ b/drivers/gpu/drm/drm_ras_nl.c
@@ -28,6 +28,13 @@ static const struct nla_policy drm_ras_get_error_threshold_nl_policy[DRM_RAS_A_E
[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID] = { .type = NLA_U32, },
};
+/* DRM_RAS_CMD_SET_ERROR_THRESHOLD - do */
+static const struct nla_policy drm_ras_set_error_threshold_nl_policy[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD + 1] = {
+ [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID] = { .type = NLA_U32, },
+ [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID] = { .type = NLA_U32, },
+ [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD] = { .type = NLA_U32, },
+};
+
/* Ops table for drm_ras */
static const struct genl_split_ops drm_ras_nl_ops[] = {
{
@@ -56,6 +63,13 @@ static const struct genl_split_ops drm_ras_nl_ops[] = {
.maxattr = DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
+ {
+ .cmd = DRM_RAS_CMD_SET_ERROR_THRESHOLD,
+ .doit = drm_ras_nl_set_error_threshold_doit,
+ .policy = drm_ras_set_error_threshold_nl_policy,
+ .maxattr = DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
};
struct genl_family drm_ras_nl_family __ro_after_init = {
diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h
index 540fe22e2312..9db7f5d00201 100644
--- a/drivers/gpu/drm/drm_ras_nl.h
+++ b/drivers/gpu/drm/drm_ras_nl.h
@@ -20,6 +20,8 @@ int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb,
struct netlink_callback *cb);
int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
struct genl_info *info);
+int drm_ras_nl_set_error_threshold_doit(struct sk_buff *skb,
+ struct genl_info *info);
extern struct genl_family drm_ras_nl_family;
diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h
index 50cee70bd065..7a69821b8b78 100644
--- a/include/drm/drm_ras.h
+++ b/include/drm/drm_ras.h
@@ -71,6 +71,19 @@ struct drm_ras_node {
*/
int (*query_error_threshold)(struct drm_ras_node *node, u32 error_id,
const char **name, u32 *val);
+ /**
+ * @set_error_threshold:
+ *
+ * This callback is used by drm-ras to set threshold value of a specific
+ * error.
+ *
+ * Driver should expect set_error_threshold() to be called with error_id
+ * from `error_counter_range.first` to `error_counter_range.last`.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+ int (*set_error_threshold)(struct drm_ras_node *node, u32 error_id,
+ u32 val);
/** @priv: Driver private data */
void *priv;
diff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h
index 49c5ca497d73..8ff0311d0d63 100644
--- a/include/uapi/drm/drm_ras.h
+++ b/include/uapi/drm/drm_ras.h
@@ -52,6 +52,7 @@ enum {
DRM_RAS_CMD_LIST_NODES = 1,
DRM_RAS_CMD_GET_ERROR_COUNTER,
DRM_RAS_CMD_GET_ERROR_THRESHOLD,
+ DRM_RAS_CMD_SET_ERROR_THRESHOLD,
__DRM_RAS_CMD_MAX,
DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1)
--
2.43.0
^ permalink raw reply related
* [PATCH v1 02/11] drm/ras: Introduce get-error-threshold
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
In-Reply-To: <20260417211730.837345-1-raag.jadav@intel.com>
Add get-error-threshold command support which allows querying threshold
value of the error. Threshold in RAS context means the number of errors
the hardware is expected to accumulate before it raises them to software.
This is to have a fine grained control over error notifications that are
raised by the hardware.
Signed-off-by: Raag Jadav <raag.jadav@intel.com>
---
Documentation/gpu/drm-ras.rst | 8 ++
Documentation/netlink/specs/drm_ras.yaml | 37 ++++++++
drivers/gpu/drm/drm_ras.c | 103 +++++++++++++++++++++++
drivers/gpu/drm/drm_ras_nl.c | 13 +++
drivers/gpu/drm/drm_ras_nl.h | 2 +
include/drm/drm_ras.h | 14 +++
include/uapi/drm/drm_ras.h | 11 +++
7 files changed, 188 insertions(+)
diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst
index 70b246a78fc8..6443dfd1677f 100644
--- a/Documentation/gpu/drm-ras.rst
+++ b/Documentation/gpu/drm-ras.rst
@@ -52,6 +52,8 @@ User space tools can:
as a parameter.
* Query specific error counter values with the ``get-error-counter`` command, using both
``node-id`` and ``error-id`` as parameters.
+* Query specific error threshold value with the ``get-error-threshold`` command, using both
+ ``node-id`` and ``error-id`` as parameters.
YAML-based Interface
--------------------
@@ -101,3 +103,9 @@ Example: Query an error counter for a given node
sudo ynl --family drm_ras --do get-error-counter --json '{"node-id":0, "error-id":1}'
{'error-id': 1, 'error-name': 'error_name1', 'error-value': 0}
+Example: Query threshold value of a given error
+
+.. code-block:: bash
+
+ sudo ynl --family drm_ras --do get-error-threshold --json '{"node-id":0, "error-id":1}'
+ {'error-id': 1, 'error-name': 'error_name1', 'error-threshold': 0}
diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml
index 79af25dac3c5..95a939fb987d 100644
--- a/Documentation/netlink/specs/drm_ras.yaml
+++ b/Documentation/netlink/specs/drm_ras.yaml
@@ -69,6 +69,25 @@ attribute-sets:
name: error-value
type: u32
doc: Current value of the requested error counter.
+ -
+ name: error-threshold-attrs
+ attributes:
+ -
+ name: node-id
+ type: u32
+ doc: Node ID targeted by this operation.
+ -
+ name: error-id
+ type: u32
+ doc: Unique identifier for a specific error within the node.
+ -
+ name: error-name
+ type: string
+ doc: Name of the error.
+ -
+ name: error-threshold
+ type: u32
+ doc: Threshold value of the error.
operations:
list:
@@ -113,3 +132,21 @@ operations:
- node-id
reply:
attributes: *errorinfo
+ -
+ name: get-error-threshold
+ doc: >-
+ Retrieve threshold value of the error.
+ The response includes the id, the name, and current threshold
+ value of the error.
+ attribute-set: error-threshold-attrs
+ flags: [admin-perm]
+ do:
+ request:
+ attributes:
+ - node-id
+ - error-id
+ reply:
+ attributes:
+ - error-id
+ - error-name
+ - error-threshold
diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c
index 1f7435d60f11..d2d853d5d69c 100644
--- a/drivers/gpu/drm/drm_ras.c
+++ b/drivers/gpu/drm/drm_ras.c
@@ -37,6 +37,10 @@
* Returns all counters of a node if only Node ID is provided or specific
* error counters.
*
+ * 3. GET_ERROR_THRESHOLD: Query threshold value of the error.
+ * Userspace must provide Node ID and Error ID.
+ * Returns the threshold value of a specific error.
+ *
* Node registration:
*
* - drm_ras_node_register(): Registers a new node and assigns
@@ -66,6 +70,8 @@
* operation, fetching all counters from a specific node.
* - drm_ras_nl_get_error_counter_doit(): Implements the GET_ERROR_COUNTER doit
* operation, fetching a counter value from a specific node.
+ * - drm_ras_nl_get_error_threshold_doit(): Implements the GET_ERROR_THRESHOLD doit
+ * operation, fetching the threshold value of a specific error.
*/
static DEFINE_XARRAY_ALLOC(drm_ras_xa);
@@ -162,6 +168,22 @@ static int get_node_error_counter(u32 node_id, u32 error_id,
return node->query_error_counter(node, error_id, name, value);
}
+static int get_node_error_threshold(u32 node_id, u32 error_id,
+ const char **name, u32 *value)
+{
+ struct drm_ras_node *node;
+
+ node = xa_load(&drm_ras_xa, node_id);
+ if (!node || !node->query_error_threshold)
+ return -ENOENT;
+
+ if (error_id < node->error_counter_range.first ||
+ error_id > node->error_counter_range.last)
+ return -EINVAL;
+
+ return node->query_error_threshold(node, error_id, name, value);
+}
+
static int msg_reply_counter_value(struct sk_buff *msg, u32 error_id,
const char *error_name, u32 value)
{
@@ -180,6 +202,24 @@ static int msg_reply_counter_value(struct sk_buff *msg, u32 error_id,
value);
}
+static int msg_reply_threshold_value(struct sk_buff *msg, u32 error_id,
+ const char *error_name, u32 value)
+{
+ int ret;
+
+ ret = nla_put_u32(msg, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID, error_id);
+ if (ret)
+ return ret;
+
+ ret = nla_put_string(msg, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_NAME,
+ error_name);
+ if (ret)
+ return ret;
+
+ return nla_put_u32(msg, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD,
+ value);
+}
+
static int doit_reply_counter_value(struct genl_info *info, u32 node_id,
u32 error_id)
{
@@ -216,6 +256,42 @@ static int doit_reply_counter_value(struct genl_info *info, u32 node_id,
return genlmsg_reply(msg, info);
}
+static int doit_reply_threshold_value(struct genl_info *info, u32 node_id,
+ u32 error_id)
+{
+ struct sk_buff *msg;
+ struct nlattr *hdr;
+ const char *error_name;
+ u32 value;
+ int ret;
+
+ msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = genlmsg_iput(msg, info);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return -EMSGSIZE;
+ }
+
+ ret = get_node_error_threshold(node_id, error_id,
+ &error_name, &value);
+ if (ret)
+ return ret;
+
+ ret = msg_reply_threshold_value(msg, error_id, error_name, value);
+ if (ret) {
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+ return ret;
+ }
+
+ genlmsg_end(msg, hdr);
+
+ return genlmsg_reply(msg, info);
+}
+
/**
* drm_ras_nl_get_error_counter_dumpit() - Dump all Error Counters
* @skb: Netlink message buffer
@@ -314,6 +390,33 @@ int drm_ras_nl_get_error_counter_doit(struct sk_buff *skb,
return doit_reply_counter_value(info, node_id, error_id);
}
+/**
+ * drm_ras_nl_get_error_threshold_doit() - Query threshold value of the error
+ * @skb: Netlink message buffer
+ * @info: Generic Netlink info containing attributes of the request
+ *
+ * Extracts the node ID and error ID from the netlink attributes and
+ * retrieves the current threshold of the corresponding error. Sends the
+ * result back to the requesting user via the standard Genl reply.
+ *
+ * Return: 0 on success, or negative errno on failure.
+ */
+int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ u32 node_id, error_id;
+
+ if (!info->attrs ||
+ GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID) ||
+ GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID))
+ return -EINVAL;
+
+ node_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID]);
+ error_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID]);
+
+ return doit_reply_threshold_value(info, node_id, error_id);
+}
+
/**
* drm_ras_node_register() - Register a new RAS node
* @node: Node structure to register
diff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c
index 16803d0c4a44..48e231734f4d 100644
--- a/drivers/gpu/drm/drm_ras_nl.c
+++ b/drivers/gpu/drm/drm_ras_nl.c
@@ -22,6 +22,12 @@ static const struct nla_policy drm_ras_get_error_counter_dump_nl_policy[DRM_RAS_
[DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID] = { .type = NLA_U32, },
};
+/* DRM_RAS_CMD_GET_ERROR_THRESHOLD - do */
+static const struct nla_policy drm_ras_get_error_threshold_nl_policy[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID + 1] = {
+ [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID] = { .type = NLA_U32, },
+ [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID] = { .type = NLA_U32, },
+};
+
/* Ops table for drm_ras */
static const struct genl_split_ops drm_ras_nl_ops[] = {
{
@@ -43,6 +49,13 @@ static const struct genl_split_ops drm_ras_nl_ops[] = {
.maxattr = DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
},
+ {
+ .cmd = DRM_RAS_CMD_GET_ERROR_THRESHOLD,
+ .doit = drm_ras_nl_get_error_threshold_doit,
+ .policy = drm_ras_get_error_threshold_nl_policy,
+ .maxattr = DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
};
struct genl_family drm_ras_nl_family __ro_after_init = {
diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h
index 06ccd9342773..540fe22e2312 100644
--- a/drivers/gpu/drm/drm_ras_nl.h
+++ b/drivers/gpu/drm/drm_ras_nl.h
@@ -18,6 +18,8 @@ int drm_ras_nl_get_error_counter_doit(struct sk_buff *skb,
struct genl_info *info);
int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb,
struct netlink_callback *cb);
+int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
+ struct genl_info *info);
extern struct genl_family drm_ras_nl_family;
diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h
index 5d50209e51db..50cee70bd065 100644
--- a/include/drm/drm_ras.h
+++ b/include/drm/drm_ras.h
@@ -57,6 +57,20 @@ struct drm_ras_node {
*/
int (*query_error_counter)(struct drm_ras_node *node, u32 error_id,
const char **name, u32 *val);
+ /**
+ * @query_error_threshold:
+ *
+ * This callback is used by drm-ras to query threshold value of a
+ * specific error.
+ *
+ * Driver should expect query_error_threshold() to be called with
+ * error_id from `error_counter_range.first` to
+ * `error_counter_range.last`.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+ int (*query_error_threshold)(struct drm_ras_node *node, u32 error_id,
+ const char **name, u32 *val);
/** @priv: Driver private data */
void *priv;
diff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h
index 5f40fa5b869d..49c5ca497d73 100644
--- a/include/uapi/drm/drm_ras.h
+++ b/include/uapi/drm/drm_ras.h
@@ -38,9 +38,20 @@ enum {
DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX = (__DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX - 1)
};
+enum {
+ DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID = 1,
+ DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID,
+ DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_NAME,
+ DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD,
+
+ __DRM_RAS_A_ERROR_THRESHOLD_ATTRS_MAX,
+ DRM_RAS_A_ERROR_THRESHOLD_ATTRS_MAX = (__DRM_RAS_A_ERROR_THRESHOLD_ATTRS_MAX - 1)
+};
+
enum {
DRM_RAS_CMD_LIST_NODES = 1,
DRM_RAS_CMD_GET_ERROR_COUNTER,
+ DRM_RAS_CMD_GET_ERROR_THRESHOLD,
__DRM_RAS_CMD_MAX,
DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1)
--
2.43.0
^ permalink raw reply related
* [PATCH v1 01/11] drm/ras: Update counter helpers with counter naming
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
In-Reply-To: <20260417211730.837345-1-raag.jadav@intel.com>
Counter helpers deal with counter values. Use the appropriate naming to
match with their functionality.
Signed-off-by: Raag Jadav <raag.jadav@intel.com>
---
drivers/gpu/drm/drm_ras.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c
index b2fa5ab86d87..1f7435d60f11 100644
--- a/drivers/gpu/drm/drm_ras.c
+++ b/drivers/gpu/drm/drm_ras.c
@@ -162,8 +162,8 @@ static int get_node_error_counter(u32 node_id, u32 error_id,
return node->query_error_counter(node, error_id, name, value);
}
-static int msg_reply_value(struct sk_buff *msg, u32 error_id,
- const char *error_name, u32 value)
+static int msg_reply_counter_value(struct sk_buff *msg, u32 error_id,
+ const char *error_name, u32 value)
{
int ret;
@@ -180,8 +180,8 @@ static int msg_reply_value(struct sk_buff *msg, u32 error_id,
value);
}
-static int doit_reply_value(struct genl_info *info, u32 node_id,
- u32 error_id)
+static int doit_reply_counter_value(struct genl_info *info, u32 node_id,
+ u32 error_id)
{
struct sk_buff *msg;
struct nlattr *hdr;
@@ -204,7 +204,7 @@ static int doit_reply_value(struct genl_info *info, u32 node_id,
if (ret)
return ret;
- ret = msg_reply_value(msg, error_id, error_name, value);
+ ret = msg_reply_counter_value(msg, error_id, error_name, value);
if (ret) {
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
@@ -272,7 +272,7 @@ int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb,
break;
}
- ret = msg_reply_value(skb, error_id, error_name, value);
+ ret = msg_reply_counter_value(skb, error_id, error_name, value);
if (ret) {
genlmsg_cancel(skb, hdr);
break;
@@ -311,7 +311,7 @@ int drm_ras_nl_get_error_counter_doit(struct sk_buff *skb,
node_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID]);
error_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID]);
- return doit_reply_value(info, node_id, error_id);
+ return doit_reply_counter_value(info, node_id, error_id);
}
/**
--
2.43.0
^ permalink raw reply related
* [PATCH v1 00/11] Introduce error threshold to drm_ras
From: Raag Jadav @ 2026-04-17 21:16 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty, Raag Jadav
This series reuses some pieces of [1] and [2] and introduces error
threshold to drm_ras infrastructure. This allows user to get and set
the threshold value of a specific error.
Detailed description in commit message and documentation.
[1] https://patchwork.freedesktop.org/series/164393/
[2] https://patchwork.freedesktop.org/series/160184/
Raag Jadav (9):
drm/ras: Update counter helpers with counter naming
drm/ras: Introduce get-error-threshold
drm/ras: Introduce set-error-threshold
drm/xe/sysctrl: Add system controller interrupt handler
drm/xe/sysctrl: Add system controller event support
drm/xe/ras: Introduce correctable error handling
drm/xe/ras: Get error threshold support
drm/xe/ras: Set error threshold support
drm/xe/drm_ras: Wire up error threshold callbacks
Riana Tauro (2):
drm/xe/uapi: Add additional error components to XE drm_ras
drm/xe/ras: Add flag for Xe RAS
Documentation/gpu/drm-ras.rst | 17 ++
Documentation/netlink/specs/drm_ras.yaml | 49 +++++
drivers/gpu/drm/drm_ras.c | 165 +++++++++++++-
drivers/gpu/drm/drm_ras_nl.c | 27 +++
drivers/gpu/drm/drm_ras_nl.h | 4 +
drivers/gpu/drm/xe/Makefile | 2 +
drivers/gpu/drm/xe/regs/xe_irq_regs.h | 1 +
drivers/gpu/drm/xe/xe_device_types.h | 2 +
drivers/gpu/drm/xe/xe_drm_ras.c | 29 ++-
drivers/gpu/drm/xe/xe_hw_error.c | 2 +-
drivers/gpu/drm/xe/xe_irq.c | 2 +
drivers/gpu/drm/xe/xe_pci.c | 3 +
drivers/gpu/drm/xe/xe_pci_types.h | 1 +
drivers/gpu/drm/xe/xe_ras.c | 207 ++++++++++++++++++
drivers/gpu/drm/xe/xe_ras.h | 19 ++
drivers/gpu/drm/xe/xe_ras_types.h | 123 +++++++++++
drivers/gpu/drm/xe/xe_sysctrl.c | 46 +++-
drivers/gpu/drm/xe/xe_sysctrl.h | 2 +
drivers/gpu/drm/xe/xe_sysctrl_event.c | 87 ++++++++
drivers/gpu/drm/xe/xe_sysctrl_event_types.h | 57 +++++
drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h | 22 ++
drivers/gpu/drm/xe/xe_sysctrl_types.h | 7 +
include/drm/drm_ras.h | 27 +++
include/uapi/drm/drm_ras.h | 12 +
include/uapi/drm/xe_drm.h | 11 +-
25 files changed, 906 insertions(+), 18 deletions(-)
create mode 100644 drivers/gpu/drm/xe/xe_ras.c
create mode 100644 drivers/gpu/drm/xe/xe_ras.h
create mode 100644 drivers/gpu/drm/xe/xe_ras_types.h
create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_event.c
create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_event_types.h
--
2.43.0
^ permalink raw reply
* Re: [PATCH] net: hsr: avoid synchronize_net() in hsr_del_port() under rtnl_mutex
From: Shardul Bankar @ 2026-04-17 21:12 UTC (permalink / raw)
To: Eric Dumazet
Cc: davem, kuba, pabeni, horms, netdev, liuhangbin, lukma, acsjakub,
kees, xiaoliang.yang_1, fmancera, linux-kernel, janak,
kalpan.jani, syzbot+f2fbf7478a35a94c8b7c
In-Reply-To: <CANn89i+Yug-M2HFnoz5LrffTaB4AHtC74sPKjLWA7cJ2fKF4-w@mail.gmail.com>
On Fri, 2026-04-17 at 11:18 -0700, Eric Dumazet wrote:
> On Fri, Apr 17, 2026 at 10:53 AM Shardul Bankar
> <shardulsb08@gmail.com> wrote:
> >
>
> synchronize_rcu_expedited() should be quite fast...
Confirmed. I ran a targeted HSR-only teardown stress on current
mainline (many HSR-bearing netns torn down concurrently, no WireGuard,
no syzkaller harness). At N=1000, patched-vs-baseline cleanup_net
wall time is within run-to-run noise- the patch has no measurable
benefit on the workload it was meant to address.
> Signature looks like bug fixed recently in wireguard.
>
> commit 60a25ef8dacb3566b1a8c4de00572a498e2a3bf9
Agreed. 60a25ef8dacb covers what I was actually observing, and
standalone evidence for the HSR path on current mainline is not
strong enough to justify this change.
Please drop this patch.
Thanks,
Shardul
^ permalink raw reply
* Re: [PATCH 1/9] bitfield: add FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-17 21:09 UTC (permalink / raw)
To: David Laight
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
David Lechner, Nuno Sá, Andy Shevchenko, Ping-Ke Shih,
Richard Cochran, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Alexandre Belloni, Yury Norov,
Rasmus Villemoes, Hans de Goede, Linus Walleij, Sakari Ailus,
Salah Triki, Achim Gratz, Ben Collins, linux-kernel, linux-iio,
linux-wireless, netdev, linux-rtc
In-Reply-To: <20260417204355.37fd960d@pumpkin>
On Fri, Apr 17, 2026 at 08:43:55PM +0100, David Laight wrote:
> On Fri, 17 Apr 2026 13:36:12 -0400
> Yury Norov <ynorov@nvidia.com> wrote:
>
> > The bitfields are designed in assumption that fields contain unsigned
> > integer values, thus extracting the values from the field implies
> > zero-extending.
> >
> > Some drivers need to sign-extend their fields, and currently do it like:
> >
> > dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11);
> > dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11);
> >
> > It's error-prone because it relies on user to provide the correct
> > index of the most significant bit and proper 32 vs 64 function flavor.
> >
> > Thus, introduce a FIELD_GET_SIGNED() macro, which is the more
> > convenient and compiles (on x86_64) to just a couple instructions:
> > shl and sar.
> >
> > Signed-off-by: Yury Norov <ynorov@nvidia.com>
> > ---
> > include/linux/bitfield.h | 16 ++++++++++++++++
> > 1 file changed, 16 insertions(+)
> >
> > diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
> > index 54aeeef1f0ec..35ef63972810 100644
> > --- a/include/linux/bitfield.h
> > +++ b/include/linux/bitfield.h
> > @@ -178,6 +178,22 @@
> > __FIELD_GET(_mask, _reg, "FIELD_GET: "); \
> > })
> >
> > +/**
> > + * FIELD_GET_SIGNED() - extract a signed bitfield element
> > + * @mask: shifted mask defining the field's length and position
> > + * @reg: value of entire bitfield
> > + *
> > + * Returns the sign-extended field specified by @_mask from the
> > + * bitfield passed in as @_reg by masking and shifting it down.
> > + */
> > +#define FIELD_GET_SIGNED(mask, reg) \
> > + ({ \
> > + __BF_FIELD_CHECK(mask, reg, 0U, "FIELD_GET_SIGNED: "); \
> > + ((__signed_scalar_typeof(mask))((long long)(reg) << \
> > + __builtin_clzll(mask) >> (__builtin_clzll(mask) + \
> > + __builtin_ctzll(mask))));\
>
> Have you looked at what that generates on a typical 32bit architecture?
Yes, for arm32:
#define FIELD_GET_SIGNED(mask, reg) \
((long long)(reg) << \
__builtin_clzll(mask) >> (__builtin_clzll(mask) + \
__builtin_ctzll(mask)))
long long foo(long long reg)
{
return FIELD_GET_SIGNED(0x00f00000ULL, reg);
}
generates:
foo(long long):
lsls r1, r0, #8
asrs r0, r1, #28
asrs r1, r1, #31
bx lr
Just as good as x86_64.
https://godbolt.org/z/eMnKrnocq
> It really a bad idea to use __signed_scalar_typeof() on anything that isn't
> a simple variable.
> The bloat from all this when 'mask' is an expansion of GENMASK() is horrid.
> Indeed both signed_scalar_typeof() and unsigned_scalar_typeof() should
> really not be used - there are generally much better ways.
David, it's not the first time you're throwing "bad idea, horrid bloat,
really not be used"-like rant with absolutely no evidence that people
do something wrong. Today I became another random victim of your style
of communication, and I don't think there's any benefit to tolerate it
for me or anybody else.
I encourage you to change your attitude, and use professional and
specific communication style in the kernel mailing list.
Starting from now, I'm not a free tester for your ideas anymore. If
you think that my patch is wrong, please prove it yourself. If you
think that 32-bit or whatever code generation is bad - please send
an example. If you believe that your implementation is any better -
please bother yourself to convince me.
I will continue receiving patches from you in my tree, but if your
patch is claimed to improve code generation, performance of any sort,
or similar things, and doesn't provide any numbers - I'll not waste
my time on it.
Thanks,
Yury
> In this case you can just write:
> ({
> auto _mask = mask;
> unsigned int __sl = __builtin_clzll(_mask);
> unsigned int __sr = __sl + __builtin_ctzll(_mask);
> __builtin_chose_expr(sizeof(_mask) <= 4,
> (int)(reg) << __sl - 32 >> __sr - 32,
> ((long long)(reg) << __sl >> __sr)
> })
> and let the compiler do any more integer promotions (etc).
>
> I'm also not convinced that the checks __BF_FIELD_CHECK() does
> on 'reg' are in any sense worth the effort.
>
> I have tried some simpler alternatives, eg:
> !__builtin_constant_p(reg) && statically_true((reg & mask) == 0)
> however that throws up some false positives due to some of weird ways
> people have used FIELD_GET() where it is nothing like the simplest
> (or most obvious) way to do things.
> That might have been the code that split a 32bit value into bytes
> in a printf with:
> FIELD_GET(GENMASK(7, 0), val), FIELD_GET(GENMASK(15, 8), val),
> FIELD_GET(GENMASK(23, 16), val), FIELD_GET(GENMASK(31, 24), val),
>
> David
>
> > + })
> > +
> > /**
> > * FIELD_MODIFY() - modify a bitfield element
> > * @_mask: shifted mask defining the field's length and position
^ permalink raw reply
* [PATCH net] sctp: fix sockets_allocated imbalance after sk_clone()
From: Xin Long @ 2026-04-17 21:09 UTC (permalink / raw)
To: network dev, linux-sctp
Cc: davem, kuba, Eric Dumazet, Paolo Abeni, Simon Horman,
Marcelo Ricardo Leitner, Kuniyuki Iwashima
sk_clone() increments sockets_allocated and sets the socket refcount to 2.
SCTP performs additional accounting in sctp_clone_sock(), so the clone-time
increment must be undone to avoid double counting.
Note we cannot simply remove the SCTP-side increment, because the SCTP
destroy path in sctp_destroy_sock() only decrements sockets_allocated when
sp->ep is set, which may not be true for all failure paths in
sctp_clone_sock().
Fixes: 16942cf4d3e3 ("sctp: Use sk_clone() in sctp_accept().")
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/socket.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index d2665bbd41a2..d0e7048230c0 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4855,8 +4855,9 @@ static struct sock *sctp_clone_sock(struct sock *sk,
if (!newsk)
return ERR_PTR(err);
- /* sk_clone() sets refcnt to 2 */
+ /* sk_clone() sets refcnt to 2 and increments sockets_allocated */
sock_put(newsk);
+ sk_sockets_allocated_dec(newsk);
newinet = inet_sk(newsk);
newsp = sctp_sk(newsk);
--
2.47.1
^ 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