Linux Documentation
 help / color / mirror / Atom feed
* [PATCH v3 02/13] docs: maintainers_include: split state machine on multiple funcs
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux, Shuah Khan
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

Instead of one big __init__ code, split the MaintainersParser
code in a way that the state machine remains on __init__, but
the actual parser for descriptions and subsystems are moved
to separate functions.

To make parser easier, instead storing parsed results on a list,
place them directly on a string.

That granted 15% of performance increase(*) with Python 3.14 and
made the logic simpler.

(*) measured by creating a new directory under Documentation/,
    and placing justmaintainers.rst and an index file there,
    building it via sphinx-build-wrapper.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Message-ID: <0b72530cf496ce5e2987ca784058a50f4dc814d2.1777987027.git.mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 297 +++++++++++---------
 1 file changed, 158 insertions(+), 139 deletions(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index 694cdbdc4caf..6d47d55f5b73 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -47,167 +47,186 @@ class MaintainersParser:
         self.profile_toc = set()
         self.profile_entries = {}
 
-        result = list()
-        result.append(".. _maintainers:")
-        result.append("")
+        self.output = ".. _maintainers:\n\n"
 
         # Poor man's state machine.
-        descriptions = False
-        maintainers = False
-        subsystems = False
+        self.descriptions = False
+        self.maintainers = False
+        self.subsystems = False
 
         # Field letter to field name mapping.
-        field_letter = None
-        fields = dict()
+        self.field_letter = None
+        self.fields = dict()
+
+        self.field_prev = ""
+        self.field_content = ""
+        self.subsystem_name = None
+
+        self.app_dir = app_dir
+        self.base_dir, self.doc_dir, self.sphinx_dir = app_dir.partition("Documentation")
+
+        self.re_doc = re.compile(r'(Documentation/([^\s\?\*]*)\.rst)')
 
         prev = None
-        field_prev = ""
-        field_content = ""
-        subsystem_name = None
-
-        base_dir, doc_dir, sphinx_dir = app_dir.partition("Documentation")
-
         for line in open(path):
-            # Have we reached the end of the preformatted Descriptions text?
-            if descriptions and line.startswith('Maintainers'):
-                descriptions = False
-                # Ensure a blank line following the last "|"-prefixed line.
-                result.append("")
-
-            # Start subsystem processing? This is to skip processing the text
-            # between the Maintainers heading and the first subsystem name.
-            if maintainers and not subsystems:
+            if self.descriptions:
+                self.parse_descriptions(line)
+            elif self.maintainers and not self.subsystems:
                 if re.search('^[A-Z0-9]', line):
-                    subsystems = True
-
-            # Drop needless input whitespace.
-            line = line.rstrip()
-
-            #
-            # Handle profile entries - either as files or as https refs
-            #
-            match = re.match(rf"P:\s*({doc_dir})(/\S+)\.rst", line)
-            if match:
-                name = "".join(match.groups())
-                entry = os.path.relpath(base_dir + name, app_dir)
-
-                full_name = os.path.join(base_dir, name)
-                path = os.path.relpath(full_name, app_dir)
-                #
-                # When SPHINXDIRS is used, it will try to reference files
-                # outside srctree, causing warnings. To avoid that, point
-                # to the latest official documentation
-                #
-                if path.startswith("../"):
-                    entry = KERNELDOC_URL + match.group(2) + ".html"
+                    self.subsystems = True
+                    self.parse_subsystems(line)
                 else:
-                    entry = "/" + entry
-
-                if "*" in entry:
-                    for e in glob(entry):
-                        self.profile_toc.add(e)
-                        self.profile_entries[subsystem_name] = e
-                else:
-                    self.profile_toc.add(entry)
-                    self.profile_entries[subsystem_name] = entry
-            else:
-                match = re.match(r"P:\s*(https?://.*)", line)
-                if match:
-                    entry = match.group(1).strip()
-                    self.profile_entries[subsystem_name] = entry
-
-            # Linkify all non-wildcard refs to ReST files in Documentation/.
-            pat = r'(Documentation/([^\s\?\*]*)\.rst)'
-            m = re.search(pat, line)
-            if m:
-                # maintainers.rst is in a subdirectory, so include "../".
-                line = re.sub(pat, ':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line)
-
-            # Check state machine for output rendering behavior.
-            output = None
-            if descriptions:
-                # Escape the escapes in preformatted text.
-                output = "| %s" % (line.replace("\\", "\\\\"))
-                # Look for and record field letter to field name mappings:
-                #   R: Designated *reviewer*: FullName <address@domain>
-                m = re.search(r"\s(\S):\s", line)
-                if m:
-                    field_letter = m.group(1)
-                if field_letter and not field_letter in fields:
-                    m = re.search(r"\*([^\*]+)\*", line)
-                    if m:
-                        fields[field_letter] = m.group(1)
-            elif subsystems:
-                # Skip empty lines: subsystem parser adds them as needed.
-                if len(line) == 0:
-                    continue
-                # Subsystem fields are batched into "field_content"
-                if line[1] != ':':
-                    # Render a subsystem entry as:
-                    #   SUBSYSTEM NAME
-                    #   ~~~~~~~~~~~~~~
-
-                    # Flush pending field content.
-                    output = field_content + "\n\n"
-                    field_content = ""
-
-                    subsystem_name = line.title()
-
-                    # Collapse whitespace in subsystem name.
-                    heading = re.sub(r"\s+", " ", line)
-                    output = output + "%s\n%s" % (heading, "~" * len(heading))
-                    field_prev = ""
-                else:
-                    # Render a subsystem field as:
-                    #   :Field: entry
-                    #           entry...
-                    field, details = line.split(':', 1)
-                    details = details.strip()
-
-                    # Mark paths (and regexes) as literal text for improved
-                    # readability and to escape any escapes.
-                    if field in ['F', 'N', 'X', 'K']:
-                        # But only if not already marked :)
-                        if not ':doc:' in details:
-                            details = '``%s``' % (details)
-
-                    # Comma separate email field continuations.
-                    if field == field_prev and field_prev in ['M', 'R', 'L']:
-                        field_content = field_content + ","
-
-                    # Do not repeat field names, so that field entries
-                    # will be collapsed together.
-                    if field != field_prev:
-                        output = field_content + "\n"
-                        field_content = ":%s:" % (fields.get(field, field))
-                    field_content = field_content + "\n\t%s" % (details)
-                    field_prev = field
+                    self.output += line
+            elif self.subsystems:
+                self.parse_subsystems(line)
             else:
-                output = line
-
-            # Re-split on any added newlines in any above parsing.
-            if output != None:
-                for separated in output.split('\n'):
-                    result.append(separated)
+                self.output += line
 
             # Update the state machine when we find heading separators.
             if line.startswith('----------'):
                 if prev.startswith('Descriptions'):
-                    descriptions = True
+                    self.descriptions = True
                 if prev.startswith('Maintainers'):
-                    maintainers = True
+                    self.maintainers = True
 
             # Retain previous line for state machine transitions.
             prev = line
 
         # Flush pending field contents.
-        if field_content != "":
-            for separated in field_content.split('\n'):
-                result.append(separated)
+        if self.field_content:
+            self.output += self.field_content + "\n\n"
 
-        self.output = "\n".join(result)
+        self.output = self.output.rstrip()
+
+    def parse_descriptions(self, line):
+        """Handle contents of the descriptions section."""
+
+        # Have we reached the end of the preformatted Descriptions text?
+        if line.startswith('Maintainers'):
+            self.descriptions = False
+            self.output += "\n" + line
+            return
+
+        # Linkify all non-wildcard refs to ReST files in Documentation/.
+        m = self.re_doc.search(line)
+        if m:
+            # maintainers.rst is in a subdirectory, so include "../".
+            line = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line)
+
+        # Escape the escapes in preformatted text.
+        output = "| %s" % (line.replace("\\", "\\\\"))
+
+        # Look for and record field letter to field name mappings:
+        #   R: Designated *reviewer*: FullName <address@domain>
+        m = re.search(r"\s(\S):\s", line)
+        if m:
+            self.field_letter = m.group(1)
+
+        if self.field_letter and self.field_letter not in self.fields:
+            m = re.search(r"\*([^\*]+)\*", line)
+            if m:
+                self.fields[self.field_letter] = m.group(1)
+
+        # Append parsed content to self.output
+        self.output += output
+
+    def parse_subsystems(self, line):
+        """Handle contents of the per-subsystem sections."""
+
+        # Drop needless input whitespace.
+        line = line.rstrip()
+
+        #
+        # Handle profile entries - either as files or as https refs
+        #
+        match = re.match(rf"P:\s*({self.doc_dir})(/\S+)\.rst", line)
+        if match:
+            name = "".join(match.groups())
+            entry = os.path.relpath(self.base_dir + name, self.app_dir)
+
+            full_name = os.path.join(self.base_dir, name)
+            path = os.path.relpath(full_name, self.app_dir)
+            #
+            # When SPHINXDIRS is used, it will try to reference files
+            # outside srctree, causing warnings. To avoid that, point
+            # to the latest official documentation
+            #
+            if path.startswith("../"):
+                entry = KERNELDOC_URL + match.group(2) + ".html"
+            else:
+                entry = "/" + entry
+
+            if "*" in entry:
+                for e in glob(entry):
+                    self.profile_toc.add(e)
+                    self.profile_entries[self.subsystem_name] = e
+            else:
+                self.profile_toc.add(entry)
+                self.profile_entries[self.subsystem_name] = entry
+        else:
+            match = re.match(r"P:\s*(https?://.*)", line)
+            if match:
+                entry = match.group(1).strip()
+                self.profile_entries[self.subsystem_name] = entry
+
+        # Linkify all non-wildcard refs to ReST files in Documentation/.
+        m = self.re_doc.search(line)
+        if m:
+            # maintainers.rst is in a subdirectory, so include "../".
+            line = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line)
+
+        # Check state machine for output rendering behavior.
+        output = None
+        if self.subsystems:
+            # Skip empty lines: subsystem parser adds them as needed.
+            if len(line) == 0:
+                return
+            # Subsystem fields are batched into "field_content"
+            if line[1] != ':':
+                # Render a subsystem entry as:
+                #   SUBSYSTEM NAME
+                #   ~~~~~~~~~~~~~~
+                # Flush pending field content.
+                output = self.field_content + "\n\n"
+                self.field_content = ""
+
+                self.subsystem_name = line.title()
+
+                # Collapse whitespace in subsystem name.
+                heading = re.sub(r"\s+", " ", line)
+                output = output + "%s\n%s" % (heading, "~" * len(heading))
+                self.field_prev = ""
+            else:
+                # Render a subsystem field as:
+                #   :Field: entry
+                #           entry...
+                field, details = line.split(':', 1)
+                details = details.strip()
+
+                # Mark paths (and regexes) as literal text for improved
+                # readability and to escape any escapes.
+                if field in ['F', 'N', 'X', 'K']:
+                    # But only if not already marked :)
+                    if not ':doc:' in details:
+                        details = '``%s``' % (details)
+
+                # Comma separate email field continuations.
+                if field == self.field_prev and self.field_prev in ['M', 'R', 'L']:
+                    self.field_content = self.field_content + ","
+
+                # Do not repeat field names, so that field entries
+                # will be collapsed together.
+                if field != self.field_prev:
+                    output = self.field_content + "\n"
+                    self.field_content = ":%s:" % (self.fields.get(field, field))
+                self.field_content = self.field_content + "\n\t%s" % (details)
+                self.field_prev = field
+        elif not self.descriptions:
+            output = line
+
+        if output is not None:
+            self.output += output + "\n"
 
-        # Create a TOC class
 
 class MaintainersInclude(Include):
     """MaintainersInclude (``maintainers-include``) directive"""
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 05/13] docs: maintainers_include: do some coding style cleanups
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux, Shuah Khan
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

Minor coding style adjustments to use the style most python
doc scripts are following.

No functional changes.

Assisted-by: pylint, black
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Message-ID: <460aabd0518f080b34e12fdc0beb7ec7685d5866.1777987027.git.mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 101 ++++++++++----------
 1 file changed, 51 insertions(+), 50 deletions(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index d3ad01e5309e..345eb28804ff 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -1,30 +1,25 @@
 #!/usr/bin/env python
 # SPDX-License-Identifier: GPL-2.0
 # -*- coding: utf-8; mode: python -*-
-# pylint: disable=R0903, C0330, R0914, R0912, E0401
+# pylint: disable=C0209, C0301, E0401, R0022, R0902, R0903, R0912, R0914
 
 """
-    maintainers-include
-    ~~~~~~~~~~~~~~~~~~~
+Implementation of the ``maintainers-include`` reST-directive.
 
-    Implementation of the ``maintainers-include`` reST-directive.
+:copyright:  Copyright (C) 2019  Kees Cook <keescook@chromium.org>
+:license:    GPL Version 2, June 1991 see linux/COPYING for details.
 
-    :copyright:  Copyright (C) 2019  Kees Cook <keescook@chromium.org>
-    :license:    GPL Version 2, June 1991 see linux/COPYING for details.
-
-    The ``maintainers-include`` reST-directive performs extensive parsing
-    specific to the Linux kernel's standard "MAINTAINERS" file, in an
-    effort to avoid needing to heavily mark up the original plain text.
+The ``maintainers-include`` reST-directive performs extensive parsing
+specific to the Linux kernel's standard "MAINTAINERS" file, in an
+effort to avoid needing to heavily mark up the original plain text.
 """
 
-import sys
-import re
 import os.path
+import re
 
 from glob import glob
 
 from docutils import statemachine
-from docutils.parsers.rst import Directive
 from docutils.parsers.rst.directives.misc import Include
 
 #
@@ -32,12 +27,14 @@ from docutils.parsers.rst.directives.misc import Include
 #
 KERNELDOC_URL = "https://docs.kernel.org/"
 
-def ErrorString(exc):  # Shamelessly stolen from docutils
-    return f'{exc.__class__.__name}: {exc}'
+__version__ = "1.0"
 
-__version__  = '1.0'
+maint_parser = None  # pylint: disable=C0103
 
-maint_parser = None
+
+# Shamelessly stolen from docutils
+def ErrorString(exc):  # pylint: disable=C0103, C0116
+    return f"{exc.__class__.__name}: {exc}"  # pylint: disable=W0212
 
 class MaintainersParser:
     """Parse MAINTAINERS file(s) content"""
@@ -52,7 +49,7 @@ class MaintainersParser:
 
         # Field letter to field name mapping.
         self.field_letter = None
-        self.fields = dict()
+        self.fields = {}
 
         self.field_prev = ""
         self.field_content = ""
@@ -71,29 +68,30 @@ class MaintainersParser:
         self.output = ".. _maintainers:\n\n"
 
         prev = None
-        for line in open(path):
-            if self.descriptions:
-                self.parse_descriptions(line)
-            elif self.maintainers and not self.subsystems:
-                if re.search('^[A-Z0-9]', line):
-                    self.subsystems = True
+        with open(path, "r", encoding="utf-8") as fp:
+            for line in fp:
+                if self.descriptions:
+                    self.parse_descriptions(line)
+                elif self.maintainers and not self.subsystems:
+                    if re.search('^[A-Z0-9]', line):
+                        self.subsystems = True
+                        self.parse_subsystems(line)
+                    else:
+                        self.output += line
+                elif self.subsystems:
                     self.parse_subsystems(line)
                 else:
                     self.output += line
-            elif self.subsystems:
-                self.parse_subsystems(line)
-            else:
-                self.output += line
 
-            # Update the state machine when we find heading separators.
-            if line.startswith('----------'):
-                if prev.startswith('Descriptions'):
-                    self.descriptions = True
-                if prev.startswith('Maintainers'):
-                    self.maintainers = True
+                # Update the state machine when we find heading separators.
+                if line.startswith("----------"):
+                    if prev.startswith("Descriptions"):
+                        self.descriptions = True
+                    if prev.startswith("Maintainers"):
+                        self.maintainers = True
 
-            # Retain previous line for state machine transitions.
-            prev = line
+                # Retain previous line for state machine transitions.
+                prev = line
 
         # Flush pending field contents.
         if self.field_content:
@@ -130,7 +128,7 @@ class MaintainersParser:
         """Handle contents of the descriptions section."""
 
         # Have we reached the end of the preformatted Descriptions text?
-        if line.startswith('Maintainers'):
+        if line.startswith("Maintainers"):
             self.descriptions = False
             self.output += "\n" + line
             return
@@ -182,7 +180,7 @@ class MaintainersParser:
         # Render a subsystem field as:
         #   :Field: entry
         #           entry...
-        field, details = line.split(':', 1)
+        field, details = line.split(":", 1)
         details = details.strip()
 
         #
@@ -248,12 +246,11 @@ class MaintainersParser:
 
 class MaintainersInclude(Include):
     """MaintainersInclude (``maintainers-include``) directive"""
+
     required_arguments = 0
 
     def emit(self):
         """Parse all the MAINTAINERS lines into ReST for human-readability"""
-        global maint_parser
-
         path = maint_parser.path
         output = maint_parser.output
 
@@ -269,20 +266,21 @@ class MaintainersInclude(Include):
             raise self.warning('"%s" directive disabled.' % self.name)
 
         try:
-            lines = self.emit()
+            self.emit()
         except IOError as error:
             raise self.severe('Problems with "%s" directive path:\n%s.' %
                       (self.name, ErrorString(error)))
 
         return []
 
+
 class MaintainersProfile(Include):
+    """Generate a list with all maintainer's profiles"""
+
     required_arguments = 0
 
     def emit(self):
         """Parse all the MAINTAINERS lines looking for profile entries"""
-        global maint_parser
-
         path = maint_parser.path
 
         #
@@ -316,15 +314,17 @@ class MaintainersProfile(Include):
             raise self.warning('"%s" directive disabled.' % self.name)
 
         try:
-            lines = self.emit()
+            self.emit()
         except IOError as error:
             raise self.severe('Problems with "%s" directive path:\n%s.' %
                       (self.name, ErrorString(error)))
 
         return []
 
+
 def setup(app):
-    global maint_parser
+    """Setup Sphinx extension"""
+    global maint_parser  # pylint: disable=W0603
 
     #
     # NOTE: we're using os.fspath() here because of a Sphinx warning:
@@ -338,8 +338,9 @@ def setup(app):
 
     app.add_directive("maintainers-include", MaintainersInclude)
     app.add_directive("maintainers-profile-toc", MaintainersProfile)
-    return dict(
-        version = __version__,
-        parallel_read_safe = True,
-        parallel_write_safe = True
-    )
+
+    return {
+        "version": __version__,
+        "parallel_read_safe": True,
+        "parallel_write_safe": True,
+    }
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 03/13] docs: maintainers_include: cleanup the code
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux, Shuah Khan
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

Simplify the logic without affecting the output result.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Message-ID: <24a83995778de8710cac40a3089c2f2fe5c38dbd.1777987027.git.mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 184 ++++++++++----------
 1 file changed, 91 insertions(+), 93 deletions(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index 6d47d55f5b73..615af227a8f8 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -44,10 +44,6 @@ class MaintainersParser:
 
     def __init__(self, app_dir, path):
         self.path = path
-        self.profile_toc = set()
-        self.profile_entries = {}
-
-        self.output = ".. _maintainers:\n\n"
 
         # Poor man's state machine.
         self.descriptions = False
@@ -67,6 +63,13 @@ class MaintainersParser:
 
         self.re_doc = re.compile(r'(Documentation/([^\s\?\*]*)\.rst)')
 
+        #
+        # Output variables with maintainers content to be stored
+        #
+        self.profile_toc = set()
+        self.profile_entries = {}
+        self.output = ".. _maintainers:\n\n"
+
         prev = None
         for line in open(path):
             if self.descriptions:
@@ -98,6 +101,16 @@ class MaintainersParser:
 
         self.output = self.output.rstrip()
 
+
+    def linkify(self, text):
+        """Linkify all non-wildcard refs to ReST files in Documentation/"""
+        m = self.re_doc.search(text)
+        if m:
+            # maintainers.rst is in a subdirectory, so include "../".
+            text = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), text)
+
+        return text
+
     def parse_descriptions(self, line):
         """Handle contents of the descriptions section."""
 
@@ -107,14 +120,8 @@ class MaintainersParser:
             self.output += "\n" + line
             return
 
-        # Linkify all non-wildcard refs to ReST files in Documentation/.
-        m = self.re_doc.search(line)
-        if m:
-            # maintainers.rst is in a subdirectory, so include "../".
-            line = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line)
-
         # Escape the escapes in preformatted text.
-        output = "| %s" % (line.replace("\\", "\\\\"))
+        self.output += "| " + self.linkify(line).replace("\\", "\\\\")
 
         # Look for and record field letter to field name mappings:
         #   R: Designated *reviewer*: FullName <address@domain>
@@ -127,105 +134,96 @@ class MaintainersParser:
             if m:
                 self.fields[self.field_letter] = m.group(1)
 
-        # Append parsed content to self.output
-        self.output += output
-
     def parse_subsystems(self, line):
         """Handle contents of the per-subsystem sections."""
 
         # Drop needless input whitespace.
         line = line.rstrip()
 
+        # Skip empty lines: subsystem parser adds them as needed.
+        if not line:
+            return
+
+        # Subsystem fields are batched into "field_content"
+        if line[1] != ':':
+            line = self.linkify(line)
+
+            # Render a subsystem entry as:
+            #   SUBSYSTEM NAME
+            #   ~~~~~~~~~~~~~~
+            # Flush pending field content.
+            self.output += self.field_content + "\n\n"
+            self.field_content = ""
+
+            self.subsystem_name = line.title()
+
+            # Collapse whitespace in subsystem name.
+            heading = re.sub(r"\s+", " ", line)
+            self.output += "%s\n%s" % (heading, "~" * len(heading)) + "\n"
+            self.field_prev = ""
+
+            return
+
+        # Render a subsystem field as:
+        #   :Field: entry
+        #           entry...
+        field, details = line.split(':', 1)
+        details = details.strip()
+
         #
         # Handle profile entries - either as files or as https refs
         #
-        match = re.match(rf"P:\s*({self.doc_dir})(/\S+)\.rst", line)
-        if match:
-            name = "".join(match.groups())
-            entry = os.path.relpath(self.base_dir + name, self.app_dir)
-
-            full_name = os.path.join(self.base_dir, name)
-            path = os.path.relpath(full_name, self.app_dir)
-            #
-            # When SPHINXDIRS is used, it will try to reference files
-            # outside srctree, causing warnings. To avoid that, point
-            # to the latest official documentation
-            #
-            if path.startswith("../"):
-                entry = KERNELDOC_URL + match.group(2) + ".html"
-            else:
-                entry = "/" + entry
-
-            if "*" in entry:
-                for e in glob(entry):
-                    self.profile_toc.add(e)
-                    self.profile_entries[self.subsystem_name] = e
-            else:
-                self.profile_toc.add(entry)
-                self.profile_entries[self.subsystem_name] = entry
-        else:
-            match = re.match(r"P:\s*(https?://.*)", line)
+        if field == "P":
+            match = self.re_doc.match(details)
             if match:
-                entry = match.group(1).strip()
-                self.profile_entries[self.subsystem_name] = entry
+                name = "".join(match.groups())
+                entry = os.path.relpath(self.base_dir + name, self.app_dir)
 
-        # Linkify all non-wildcard refs to ReST files in Documentation/.
-        m = self.re_doc.search(line)
-        if m:
-            # maintainers.rst is in a subdirectory, so include "../".
-            line = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line)
+                full_name = os.path.join(self.base_dir, name)
+                path = os.path.relpath(full_name, self.app_dir)
+                #
+                # When SPHINXDIRS is used, it will try to reference files
+                # outside srctree, causing warnings. To avoid that, point
+                # to the latest official documentation
+                #
+                if path.startswith("../"):
+                    entry = KERNELDOC_URL + "/" + match.group(2) + ".html"
+                else:
+                    entry = "/" + entry
 
-        # Check state machine for output rendering behavior.
-        output = None
-        if self.subsystems:
-            # Skip empty lines: subsystem parser adds them as needed.
-            if len(line) == 0:
-                return
-            # Subsystem fields are batched into "field_content"
-            if line[1] != ':':
-                # Render a subsystem entry as:
-                #   SUBSYSTEM NAME
-                #   ~~~~~~~~~~~~~~
-                # Flush pending field content.
-                output = self.field_content + "\n\n"
-                self.field_content = ""
-
-                self.subsystem_name = line.title()
-
-                # Collapse whitespace in subsystem name.
-                heading = re.sub(r"\s+", " ", line)
-                output = output + "%s\n%s" % (heading, "~" * len(heading))
-                self.field_prev = ""
+                if "*" in entry:
+                    for e in glob(entry):
+                        self.profile_toc.add(e)
+                        self.profile_entries[self.subsystem_name] = e
+                else:
+                    self.profile_toc.add(entry)
+                    self.profile_entries[self.subsystem_name] = entry
             else:
-                # Render a subsystem field as:
-                #   :Field: entry
-                #           entry...
-                field, details = line.split(':', 1)
-                details = details.strip()
+                match = re.match(r"(https?://.*)", details)
+                if match:
+                    entry = match.group(1).strip()
+                    self.profile_entries[self.subsystem_name] = entry
 
-                # Mark paths (and regexes) as literal text for improved
-                # readability and to escape any escapes.
-                if field in ['F', 'N', 'X', 'K']:
-                    # But only if not already marked :)
-                    if not ':doc:' in details:
-                        details = '``%s``' % (details)
+        details = self.linkify(details)
 
-                # Comma separate email field continuations.
-                if field == self.field_prev and self.field_prev in ['M', 'R', 'L']:
-                    self.field_content = self.field_content + ","
+        # Mark paths (and regexes) as literal text for improved
+        # readability and to escape any escapes.
+        if field in ['F', 'N', 'X', 'K']:
+            # But only if not already marked :)
+            if not ':doc:' in details:
+                details = '``%s``' % (details)
 
-                # Do not repeat field names, so that field entries
-                # will be collapsed together.
-                if field != self.field_prev:
-                    output = self.field_content + "\n"
-                    self.field_content = ":%s:" % (self.fields.get(field, field))
-                self.field_content = self.field_content + "\n\t%s" % (details)
-                self.field_prev = field
-        elif not self.descriptions:
-            output = line
+        # Comma separate email field continuations.
+        if field == self.field_prev and self.field_prev in ['M', 'R', 'L']:
+            self.field_content = self.field_content + ","
 
-        if output is not None:
-            self.output += output + "\n"
+        # Do not repeat field names, so that field entries
+        # will be collapsed together.
+        if field != self.field_prev:
+            self.output += self.field_content + "\n\n"
+            self.field_content = ":%s:" % (self.fields.get(field, field))
+        self.field_content = self.field_content + "\n\t%s" % (details)
+        self.field_prev = field
 
 
 class MaintainersInclude(Include):
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 13/13] MAINTAINERS: use a URL for pin-init maintainer's profile entry
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Miguel Ojeda
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux,
	Björn Roy Baron, Alice Ryhl, Andreas Hindborg, Benno Lossin,
	Boqun Feng, Danilo Krummrich, Gary Guo, Mauro Carvalho Chehab,
	Trevor Gross
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

This maintainer's entry is not inside documentation nor is
ReST, preventing Sphinx to create a hyperlink to it.

Change it to point to the already-formatted URL.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Message-ID: <1bceee886b9027d66bbb48d9d6c8d1250ce8dbcb.1777987028.git.mchehab+huawei@kernel.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 MAINTAINERS | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 77244b7f9545..dd424a4f9f3b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23402,7 +23402,7 @@ S:	Maintained
 W:	https://rust-for-linux.com/pin-init
 B:	https://github.com/Rust-for-Linux/pin-init/issues
 C:	zulip://rust-for-linux.zulipchat.com
-P:	rust/pin-init/CONTRIBUTING.md
+P:	https://github.com/Rust-for-Linux/pin-init/blob/main/CONTRIBUTING.md
 T:	git https://github.com/Rust-for-Linux/linux.git pin-init-next
 F:	rust/kernel/init.rs
 F:	rust/pin-init/
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 07/13] docs: maintainers_include: properly handle file patterns
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux,
	Andrew Morton, Joe Perches, Matteo Croce, Shuah Khan,
	Matteo Croce
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

handling asterisks inside file patterns atdescription part is
problematic, as ReST has special meaning for them. Due to
that, convert such patterns to literal strings.

Reported-by: Matteo Croce <teknoraver@meta.com>
Fixes: 420849332f9f ("get_maintainer: add ** glob pattern support")
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Message-ID: <89127706fb3493d00ecb21e528c8a27081e5ed40.1777987027.git.mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 26 ++++++++++-----------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index ed9cd7b3dc66..5361774b61bc 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -47,9 +47,6 @@ class MaintainersParser:
         self.maintainers = False
         self.subsystems = False
 
-        # Field letter to field name mapping.
-        self.field_letter = None
-
         self.subsystem_name = None
 
         self.app_dir = os.path.abspath(app_dir)
@@ -125,19 +122,22 @@ class MaintainersParser:
             self.header += "\n" + line
             return
 
-        # Escape the escapes in preformatted text.
-        self.header += "| " + self.linkify(line).replace("\\", "\\\\")
-
         # Look for and record field letter to field name mappings:
         #   R: Designated *reviewer*: FullName <address@domain>
-        m = re.search(r"\s(\S):\s", line)
+        m = re.match(r"\s+(\S):\s+(\S+)", line)
         if m:
-            self.field_letter = m.group(1)
+            field = m.group(1)
+            details = m.group(2)
+
+            if field not in self.fields:
+                m = re.search(r"\*([^\*]+)\*", line)
+                if m:
+                    self.fields[field] = m.group(1)
+            elif field in ['F', 'N', 'X', 'K']:
+                line = line.replace(details, f'``{details}``')
+
+        self.header += "| " + self.linkify(line)
 
-        if self.field_letter and self.field_letter not in self.fields:
-            m = re.search(r"\*([^\*]+)\*", line)
-            if m:
-                self.fields[self.field_letter] = m.group(1)
 
     def parse_subsystems(self, line):
         """Handle contents of the per-subsystem sections."""
@@ -206,7 +206,7 @@ class MaintainersParser:
         #
         if field in ['F', 'N', 'X', 'K']:
             # But only if not already marked :)
-            if not ':doc:' in details:
+            if ':doc:' not in details and "http" not in details:
                 details = '``%s``' % (details)
 
         if self.subsystem_name not in self.maint_entries:
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 12/13] MAINTAINERS: make clearer about what's expected for "P" field
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux,
	Mauro Carvalho Chehab
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

The "P" field is meant to point to a subsystem maintainer's
profile, stored either at the Kernel documentation or on an
external site. Make it clearer.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Message-ID: <921e5e6a074f9d8cf77483d73e6801f49254bbb8.1777987027.git.mchehab+huawei@kernel.org>
---
 MAINTAINERS | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..77244b7f9545 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25,9 +25,9 @@ Descriptions of section entries and preferred order
 	C: URI for *chat* protocol, server and channel where developers
 	   usually hang out, for example irc://server/channel.
 	P: *Subsystem Profile* document for more details submitting
-	   patches to the given subsystem. This is either an in-tree file,
-	   or a URI. See Documentation/maintainer/maintainer-entry-profile.rst
-	   for details.
+	   patches to the given subsystem. This is either an in-tree .rst file
+       inside Documentation/, or a URI.
+       See Documentation/maintainer/maintainer-entry-profile.rst for details.
 	T: *SCM* tree type and location.
 	   Type is one of: git, hg, quilt, stgit, topgit
 	F: *Files* and directories wildcard patterns.
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 09/13] docs: maintainers_include: don't ignore invalid profile entries
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux,
	Björn Roy Baron, Alice Ryhl, Andreas Hindborg, Benno Lossin,
	Boqun Feng, Danilo Krummrich, Gary Guo, Miguel Ojeda, Shuah Khan,
	Trevor Gross
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

Currently, there is a "P" entry for Rust pin-init that is
neither a valid ReST file inside Documentation nor an URL.

A proper fix is to either convert/move the file or point to
a URL. Yet, the parser should be able to pick what's there and
show on its output.

Add a logic to produce a warning when this happens.

Message-ID: <63228e005fcf3dc4583cee06905341e8bce84181.1777987027.git.mchehab+huawei@kernel.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index 7035754a1c66..073a10575872 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -240,6 +240,8 @@ class MaintainersParser:
                 if match:
                     entry = match.group(1).strip()
                     self.profile_entries[self.subsystem_name] = entry
+                else:
+                    self.profile_entries[self.subsystem_name] = f"``{details}``"
 
         details = self.linkify(details)
 
@@ -328,12 +330,15 @@ class MaintainersProfile(Include):
         #
         output = ""
         for profile, entry in sorted(maint_parser.profile_entries.items()):
-            profile = profile.title()
+            name = profile.title()
 
             if entry.startswith("http"):
-                output += f"- `{profile} <{entry}>`_\n"
+                output += f"- `{name} <{entry}>`_\n"
+            elif entry.startswith("`"):
+                output += f"- {name}: {entry}\n"
+                self.warning(f"{profile}: Invalid 'P' tag: {entry}\n")
             else:
-                output += f"- :doc:`{profile} <{entry}>`\n"
+                output += f"- :doc:`{name} <{entry}>`\n"
 
         #
         # Create a hidden TOC table with all profiles. That allows adding
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 08/13] docs: maintainers_include: add a filtering javascript
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux, Shuah Khan
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

The maintainers table is big. Add a javascript to allow filtering
it. Such script is only added at the page which contains the
maintainers-include tag.

I opted to keep the search case-sensitive, as, this way,
upper case searches at subsystem.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Message-ID: <c435ef150f5d6ed16570969f43d92ba6fb857842.1777987027.git.mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 78 +++++++++++++++++++--
 1 file changed, 72 insertions(+), 6 deletions(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index 5361774b61bc..7035754a1c66 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -31,6 +31,49 @@ __version__ = "1.0"
 
 maint_parser = None  # pylint: disable=C0103
 
+JS_FILTER = """
+(function() {
+  function filterTable(table) {
+    const filter = document.getElementById("filter-table").value.trim();
+    const rows = table.querySelectorAll("tbody tr");
+    for (let i = 0; i < rows.length; i++) {
+      const tds = rows[i].getElementsByTagName("td");
+      let match = false;
+      for (let j = 0; j < tds.length; j++) {
+        const cellText = (tds[j].textContent || tds[j].innerText);
+        if (cellText.includes(filter)) {
+          match = true;
+          break;
+        }
+      }
+      rows[i].style.display = match ? "table-row" : "none";
+    }
+  }
+  function addInput() {
+    const table = document.getElementById("maintainers-table");
+    if (!table) return;
+    let input = document.getElementById("filter-table");
+    if (!input) {
+      const filt_div = document.createElement('div');
+      filt_div.innerHTML = `
+        <p>Filter:
+          <input type="search" id="filter-table" placeholder="search string"/>
+          subsystem or property (case-sensitive)
+        </p>
+      `;
+      table.parentNode.insertBefore(filt_div, table);
+      const input = document.getElementById("filter-table")
+      input.addEventListener('input', () => filterTable(table));
+    }
+  }
+  if (document.readyState === 'loading') {
+    document.addEventListener('DOMContentLoaded', addInput);
+  } else {
+    addInput();
+  }
+})();
+"""
+
 
 # Shamelessly stolen from docutils
 def ErrorString(exc):  # pylint: disable=C0103, C0116
@@ -59,7 +102,7 @@ class MaintainersParser:
         #
         self.profile_toc = set()
         self.profile_entries = {}
-        self.header = ".. _maintainers:\n\n"
+        self.header = ""
         self.maint_entries = {}
         self.fields = {}
 
@@ -228,15 +271,28 @@ class MaintainersInclude(Include):
     def emit(self):
         """Parse all the MAINTAINERS lines into ReST for human-readability"""
         path = maint_parser.path
-        output = maint_parser.header
+        output = ".. _maintainers:\n\n"
+        output += maint_parser.header
+
+        output += ".. _maintainers_table:\n\n"
+        output += ".. flat-table::\n"
+        output += "  :header-rows: 1\n\n"
+        output += "  * - Subsystem\n"
+        output += "    - Properties\n\n"
+
+        self.state.document['maintainers_included'] = True
 
         for name, fields in sorted(maint_parser.maint_entries.items()):
-            output += "\n" + name + "\n"
-            output += "~" * len(name) + "\n"
-
+            output += f"  * - {name}\n"
+            tag = "-"
             for field, lines in fields.items():
                 field_name = maint_parser.fields.get(field, field)
-                output += f":{field_name}:\n\t" + ",\n\t".join(lines) + "\n\n"
+
+                output += f"    {tag} :{field_name}:\n        "
+                output += ",\n        ".join(lines) + "\n"
+                tag = " "
+
+            output += "\n"
 
         # For debugging the pre-rendered results...
         #print(output, file=open("/tmp/MAINTAINERS.rst", "w"))
@@ -308,6 +364,14 @@ class MaintainersProfile(Include):
         return []
 
 
+# pylint: disable=W0613
+def add_filter_script(app, pagename, templatename, context, doctree):
+    """Add Filter javascript only to maintainers page"""
+
+    if doctree and doctree.get('maintainers_included'):
+        app.add_js_file(None, body=JS_FILTER)
+
+
 def setup(app):
     """Setup Sphinx extension"""
     global maint_parser  # pylint: disable=W0603
@@ -325,6 +389,8 @@ def setup(app):
     app.add_directive("maintainers-include", MaintainersInclude)
     app.add_directive("maintainers-profile-toc", MaintainersProfile)
 
+    app.connect("html-page-context", add_filter_script)
+
     return {
         "version": __version__,
         "parallel_read_safe": True,
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 00/13] Improve process/maintainers output
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Mauro Carvalho Chehab, Miguel Ojeda
  Cc: Mauro Carvalho Chehab, linux-doc, linux-kernel, rust-for-linux,
	Björn Roy Baron, Alice Ryhl, Andreas Hindborg, Andrew Morton,
	Benno Lossin, Boqun Feng, Danilo Krummrich, Gary Guo, Joe Perches,
	Matteo Croce, Shuah Khan, Trevor Gross

Hi Jon,

This series improve the output at process/maintainers: instead of a
pure enriched text, the maintainer's file content is now converted
to a table, and has gained a javascript to allow filtering entries.

The initial patches change the logic to split parsing from
output generation. Then, everything is stored into a dict at
the parsing phase, and ona header description variable.

This way, it is easier to adjust the output handler to produce
a more structured document. Right now, the entries are sorted
alphabetically, per subsystem's name(*).

(*) Currently, MAINTAINERS file has several entries not sorted.
    One has to run:

	 scripts/parse-maintainers.pl --input MAINTAINERS --output MAINTAINERS.new

    to sort it.

-

v3:
  - don't remove rust/pin-init/CONTRIBUTING.md;
  - added two extra patches due to sashiko-bot feedback, to better
    handle wildcards and paths;
  - fixed some issues related with O=DIRS;

v2:
  - now, entries are sorted internally, instead of trusting that
    MAINTAINERS is already sorted;
  - file fields inside the description are now showing as literals;
  - Added a change in MAINTAINERS for rust-init profile;
  - Make it clearer at MAINTAINERS description that "P" expects
    a rst file;
  - fixed several bugs related to using or not O=DOCS.



Mauro Carvalho Chehab (13):
  docs: maintainers_include: keep hidden TOC sorted
  docs: maintainers_include: split state machine on multiple funcs
  docs: maintainers_include: cleanup the code
  docs: maintainers_include: clean most SPHINXDIRS=process warnings
  docs: maintainers_include: do some coding style cleanups
  docs: maintainers_include: store maintainers entries on a dict
  docs: maintainers_include: properly handle file patterns
  docs: maintainers_include: add a filtering javascript
  docs: maintainers_include: don't ignore invalid profile entries
  docs: maintainers_include: better handle directories
  docs: maintainers_include: better handle doc wildcards
  MAINTAINERS: make clearer about what's expected for "P" field
  MAINTAINERS: use a URL for pin-init maintainer's profile entry

 Documentation/sphinx/maintainers_include.py | 478 ++++++++++++--------
 MAINTAINERS                                 |   8 +-
 2 files changed, 294 insertions(+), 192 deletions(-)

-- 
2.54.0


^ permalink raw reply

* [PATCH v3 04/13] docs: maintainers_include: clean most SPHINXDIRS=process warnings
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux, Shuah Khan
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

building docs with SPHINXDIRS=process is too noisy, as it
generates lots of undefined refs. Fixing it is easy: just let
linkify generate html URLs for the broken links when SPHINXDIRS
is used.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Message-ID: <b57d83081c28aa52683b403f8836d098fcdd8530.1777987027.git.mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 44 +++++++++++++++------
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index 615af227a8f8..d3ad01e5309e 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -58,8 +58,8 @@ class MaintainersParser:
         self.field_content = ""
         self.subsystem_name = None
 
-        self.app_dir = app_dir
-        self.base_dir, self.doc_dir, self.sphinx_dir = app_dir.partition("Documentation")
+        self.app_dir = os.path.abspath(app_dir)
+        self.base_dir, _, self.sphinx_dir = self.app_dir.partition("Documentation")
 
         self.re_doc = re.compile(r'(Documentation/([^\s\?\*]*)\.rst)')
 
@@ -104,10 +104,25 @@ class MaintainersParser:
 
     def linkify(self, text):
         """Linkify all non-wildcard refs to ReST files in Documentation/"""
+
         m = self.re_doc.search(text)
         if m:
-            # maintainers.rst is in a subdirectory, so include "../".
-            text = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), text)
+            fname = m.group(1)
+            ename = m.group(2)
+
+            entry = os.path.relpath(self.base_dir + fname, self.app_dir)
+            entry = entry.removesuffix(".rst")
+
+            #
+            # When SPHINXDIRS is used, it will try to reference files
+            # outside srctree, causing warnings. To avoid that, point
+            # to the latest official documentation
+            #
+            if entry.startswith("../"):
+                html = KERNELDOC_URL + ename + ".html"
+                text = self.re_doc.sub(f'`{ename} <{html}>`_', text)
+            else:
+                text = self.re_doc.sub(f':doc:`{ename} </{entry}>`', text)
 
         return text
 
@@ -176,27 +191,32 @@ class MaintainersParser:
         if field == "P":
             match = self.re_doc.match(details)
             if match:
-                name = "".join(match.groups())
-                entry = os.path.relpath(self.base_dir + name, self.app_dir)
+                fname = match.group(1)
+                ename = match.group(2)
 
-                full_name = os.path.join(self.base_dir, name)
-                path = os.path.relpath(full_name, self.app_dir)
+                entry = os.path.relpath(self.base_dir + fname, self.app_dir)
+                entry = entry.removesuffix(".rst")
                 #
                 # When SPHINXDIRS is used, it will try to reference files
                 # outside srctree, causing warnings. To avoid that, point
                 # to the latest official documentation
                 #
-                if path.startswith("../"):
-                    entry = KERNELDOC_URL + "/" + match.group(2) + ".html"
+
+                if entry.startswith("../"):
+                    entry = KERNELDOC_URL + ename + ".html"
                 else:
                     entry = "/" + entry
 
                 if "*" in entry:
                     for e in glob(entry):
-                        self.profile_toc.add(e)
+                        if "html" not in e:
+                            self.profile_toc.add(e)
+
                         self.profile_entries[self.subsystem_name] = e
                 else:
-                    self.profile_toc.add(entry)
+                    if "html" not in entry:
+                        self.profile_toc.add(entry)
+
                     self.profile_entries[self.subsystem_name] = entry
             else:
                 match = re.match(r"(https?://.*)", details)
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 01/13] docs: maintainers_include: keep hidden TOC sorted
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux, Shuah Khan
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

There's no practical difference on keeping it sorted, but
it helps a lot when checking for differences after patches
to the tool.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Message-ID: <e6b302f2826e6a5c0124bb33cc517e8b5888252b.1777987027.git.mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index 436e7ac42ffc..694cdbdc4caf 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -265,7 +265,7 @@ class MaintainersProfile(Include):
         output += "\n.. toctree::\n"
         output += "   :hidden:\n\n"
 
-        for fname in maint_parser.profile_toc:
+        for fname in sorted(maint_parser.profile_toc):
             output += f"   {fname}\n"
 
         output += "\n"
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 10/13] docs: maintainers_include: better handle directories
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux, Shuah Khan
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

The TOC tree needs to use paths relative to the document containing
the maintainers-profile-toc directive. Fix it.

While here, address a warning from sashiko-bot, which points
that using partition can be problematic if the root Linux path
ends being something like:

    foo/Documentation/linux/

causing the documentation dir to be at:

    foo/Documentation/linux/Documentation

Very unlikely, but fixing it is trivial: just use regex to
pick the last one.

Notice that I dropped the comment about using os.fspath() as
the logic already uses os.path.abspath() which should work
equally well.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 28 ++++++++++++---------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index 073a10575872..8c7b79721edd 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -82,7 +82,7 @@ def ErrorString(exc):  # pylint: disable=C0103, C0116
 class MaintainersParser:
     """Parse MAINTAINERS file(s) content"""
 
-    def __init__(self, app_dir, path):
+    def __init__(self, base_dir, app_dir, path):
         self.path = path
 
         # Poor man's state machine.
@@ -92,8 +92,8 @@ class MaintainersParser:
 
         self.subsystem_name = None
 
-        self.app_dir = os.path.abspath(app_dir)
-        self.base_dir, _, self.sphinx_dir = self.app_dir.partition("Documentation")
+        self.base_dir = base_dir
+        self.app_dir = app_dir
 
         self.re_doc = re.compile(r'(Documentation/([^\s\?\*]*)\.rst)')
 
@@ -323,6 +323,8 @@ class MaintainersProfile(Include):
 
     def emit(self):
         """Parse all the MAINTAINERS lines looking for profile entries"""
+        env = self.state.document.settings.env
+        docdir = os.path.dirname(os.path.join(env.srcdir, env.docname))
         path = maint_parser.path
 
         #
@@ -347,7 +349,9 @@ class MaintainersProfile(Include):
         output += "\n.. toctree::\n"
         output += "   :hidden:\n\n"
 
-        for fname in sorted(maint_parser.profile_toc):
+        for f in sorted(maint_parser.profile_toc):
+            fname = os.path.join(maint_parser.base_dir, "Documentation", f)
+            fname = os.path.relpath(fname, docdir)
             output += f"   {fname}\n"
 
         output += "\n"
@@ -381,15 +385,15 @@ def setup(app):
     """Setup Sphinx extension"""
     global maint_parser  # pylint: disable=W0603
 
-    #
-    # NOTE: we're using os.fspath() here because of a Sphinx warning:
-    #   RemovedInSphinx90Warning: Sphinx 9 will drop support for representing paths as strings. Use "pathlib.Path" or "os.fspath" instead.
-    #
-    app_dir = os.fspath(app.srcdir)
-    srctree = os.path.abspath(os.environ["srctree"])
-    path = os.path.join(srctree, "MAINTAINERS")
+    app_dir = os.path.abspath(app.srcdir)
+    match = re.match(r"(.*/)Documentation", app_dir)
+    if not match:
+        raise ValueError('Documentation directory not found.')
 
-    maint_parser = MaintainersParser(app_dir, path)
+    base_dir = match.group(1)
+    path = os.path.join(base_dir, "MAINTAINERS")
+
+    maint_parser = MaintainersParser(base_dir, app_dir, path)
 
     app.add_directive("maintainers-include", MaintainersInclude)
     app.add_directive("maintainers-profile-toc", MaintainersProfile)
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 06/13] docs: maintainers_include: store maintainers entries on a dict
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux, Shuah Khan
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

Instead of creating just a big output data, store entries inside
a dictionary. Doing that simplifies the parser a little bit
and make the code clearer.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Message-ID: <4ad88179e03436984f29780ae380d50591f86c67.1777987027.git.mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 70 +++++++++------------
 1 file changed, 28 insertions(+), 42 deletions(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index 345eb28804ff..ed9cd7b3dc66 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -49,10 +49,7 @@ class MaintainersParser:
 
         # Field letter to field name mapping.
         self.field_letter = None
-        self.fields = {}
 
-        self.field_prev = ""
-        self.field_content = ""
         self.subsystem_name = None
 
         self.app_dir = os.path.abspath(app_dir)
@@ -65,7 +62,9 @@ class MaintainersParser:
         #
         self.profile_toc = set()
         self.profile_entries = {}
-        self.output = ".. _maintainers:\n\n"
+        self.header = ".. _maintainers:\n\n"
+        self.maint_entries = {}
+        self.fields = {}
 
         prev = None
         with open(path, "r", encoding="utf-8") as fp:
@@ -77,11 +76,11 @@ class MaintainersParser:
                         self.subsystems = True
                         self.parse_subsystems(line)
                     else:
-                        self.output += line
+                        self.header += line
                 elif self.subsystems:
                     self.parse_subsystems(line)
                 else:
-                    self.output += line
+                    self.header += line
 
                 # Update the state machine when we find heading separators.
                 if line.startswith("----------"):
@@ -93,13 +92,6 @@ class MaintainersParser:
                 # Retain previous line for state machine transitions.
                 prev = line
 
-        # Flush pending field contents.
-        if self.field_content:
-            self.output += self.field_content + "\n\n"
-
-        self.output = self.output.rstrip()
-
-
     def linkify(self, text):
         """Linkify all non-wildcard refs to ReST files in Documentation/"""
 
@@ -130,11 +122,11 @@ class MaintainersParser:
         # Have we reached the end of the preformatted Descriptions text?
         if line.startswith("Maintainers"):
             self.descriptions = False
-            self.output += "\n" + line
+            self.header += "\n" + line
             return
 
         # Escape the escapes in preformatted text.
-        self.output += "| " + self.linkify(line).replace("\\", "\\\\")
+        self.header += "| " + self.linkify(line).replace("\\", "\\\\")
 
         # Look for and record field letter to field name mappings:
         #   R: Designated *reviewer*: FullName <address@domain>
@@ -157,24 +149,8 @@ class MaintainersParser:
         if not line:
             return
 
-        # Subsystem fields are batched into "field_content"
         if line[1] != ':':
-            line = self.linkify(line)
-
-            # Render a subsystem entry as:
-            #   SUBSYSTEM NAME
-            #   ~~~~~~~~~~~~~~
-            # Flush pending field content.
-            self.output += self.field_content + "\n\n"
-            self.field_content = ""
-
-            self.subsystem_name = line.title()
-
-            # Collapse whitespace in subsystem name.
-            heading = re.sub(r"\s+", " ", line)
-            self.output += "%s\n%s" % (heading, "~" * len(heading)) + "\n"
-            self.field_prev = ""
-
+            self.subsystem_name = re.sub(r"\s+", " ", self.linkify(line))
             return
 
         # Render a subsystem field as:
@@ -224,23 +200,23 @@ class MaintainersParser:
 
         details = self.linkify(details)
 
+        #
         # Mark paths (and regexes) as literal text for improved
         # readability and to escape any escapes.
+        #
         if field in ['F', 'N', 'X', 'K']:
             # But only if not already marked :)
             if not ':doc:' in details:
                 details = '``%s``' % (details)
 
-        # Comma separate email field continuations.
-        if field == self.field_prev and self.field_prev in ['M', 'R', 'L']:
-            self.field_content = self.field_content + ","
+        if self.subsystem_name not in self.maint_entries:
+            self.maint_entries[self.subsystem_name] = {}
+
+        if field not in self.maint_entries[self.subsystem_name]:
+            self.maint_entries[self.subsystem_name][field] = []
+
+        self.maint_entries[self.subsystem_name][field].append(details)
 
-        # Do not repeat field names, so that field entries
-        # will be collapsed together.
-        if field != self.field_prev:
-            self.output += self.field_content + "\n\n"
-            self.field_content = ":%s:" % (self.fields.get(field, field))
-        self.field_content = self.field_content + "\n\t%s" % (details)
         self.field_prev = field
 
 
@@ -252,7 +228,15 @@ class MaintainersInclude(Include):
     def emit(self):
         """Parse all the MAINTAINERS lines into ReST for human-readability"""
         path = maint_parser.path
-        output = maint_parser.output
+        output = maint_parser.header
+
+        for name, fields in sorted(maint_parser.maint_entries.items()):
+            output += "\n" + name + "\n"
+            output += "~" * len(name) + "\n"
+
+            for field, lines in fields.items():
+                field_name = maint_parser.fields.get(field, field)
+                output += f":{field_name}:\n\t" + ",\n\t".join(lines) + "\n\n"
 
         # For debugging the pre-rendered results...
         #print(output, file=open("/tmp/MAINTAINERS.rst", "w"))
@@ -288,6 +272,8 @@ class MaintainersProfile(Include):
         #
         output = ""
         for profile, entry in sorted(maint_parser.profile_entries.items()):
+            profile = profile.title()
+
             if entry.startswith("http"):
                 output += f"- `{profile} <{entry}>`_\n"
             else:
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 11/13] docs: maintainers_include: better handle doc wildcards
From: Mauro Carvalho Chehab @ 2026-05-09  6:56 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, rust-for-linux, Shuah Khan
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

As warned by sashiko-bot, the new logic doesn't handle wildcards
on Documentation/.

Change the logic to properly handle it, cleaning up the code
to remove some code duplication.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 103 ++++++++++----------
 1 file changed, 53 insertions(+), 50 deletions(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index 8c7b79721edd..be8e566e0363 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -95,7 +95,7 @@ class MaintainersParser:
         self.base_dir = base_dir
         self.app_dir = app_dir
 
-        self.re_doc = re.compile(r'(Documentation/([^\s\?\*]*)\.rst)')
+        self.re_doc = re.compile(r'(Documentation/(\S*)\.rst)')
 
         #
         # Output variables with maintainers content to be stored
@@ -132,29 +132,47 @@ class MaintainersParser:
                 # Retain previous line for state machine transitions.
                 prev = line
 
+    def get_entries(self, text):
+        """Generate refs to ReST files in Documentation/"""
+
+        if "Documentation/" not in text:
+            return None
+
+        if "*" in text or "?" in text:
+            m = self.re_doc.search(text)
+            if not m:
+                return None
+
+            doc_list = glob(m.group(1), root_dir=self.base_dir)
+        else:
+            doc_list = [text]
+
+        entries = {}
+        for doc in doc_list:
+            m = self.re_doc.search(doc)
+            if m:
+                fname = m.group(1)
+                ename = m.group(2)
+
+                entry = os.path.relpath(self.base_dir + fname, self.app_dir)
+                entry = entry.removesuffix(".rst")
+
+                if entry.startswith("../"):
+                    html = KERNELDOC_URL + ename + ".html"
+                    entries[entry] = f'`{ename} <{html}>`_'
+                else:
+                    entries[entry] = f':doc:`{ename} </{entry}>`'
+
+        return entries
+
     def linkify(self, text):
-        """Linkify all non-wildcard refs to ReST files in Documentation/"""
+        """Return a list of doc files converted to cross-references"""
 
-        m = self.re_doc.search(text)
-        if m:
-            fname = m.group(1)
-            ename = m.group(2)
+        entries = self.get_entries(text)
+        if not entries:
+            return text
 
-            entry = os.path.relpath(self.base_dir + fname, self.app_dir)
-            entry = entry.removesuffix(".rst")
-
-            #
-            # When SPHINXDIRS is used, it will try to reference files
-            # outside srctree, causing warnings. To avoid that, point
-            # to the latest official documentation
-            #
-            if entry.startswith("../"):
-                html = KERNELDOC_URL + ename + ".html"
-                text = self.re_doc.sub(f'`{ename} <{html}>`_', text)
-            else:
-                text = self.re_doc.sub(f':doc:`{ename} </{entry}>`', text)
-
-        return text
+        return self.re_doc.sub(", ".join(entries.values()), text)
 
     def parse_descriptions(self, line):
         """Handle contents of the descriptions section."""
@@ -206,35 +224,15 @@ class MaintainersParser:
         # Handle profile entries - either as files or as https refs
         #
         if field == "P":
-            match = self.re_doc.match(details)
-            if match:
-                fname = match.group(1)
-                ename = match.group(2)
+            entries = self.get_entries(details)
+            if entries:
+                for e, link in entries.items():
+                    if "html" not in link:
+                        self.profile_toc.add(e)
 
-                entry = os.path.relpath(self.base_dir + fname, self.app_dir)
-                entry = entry.removesuffix(".rst")
-                #
-                # When SPHINXDIRS is used, it will try to reference files
-                # outside srctree, causing warnings. To avoid that, point
-                # to the latest official documentation
-                #
+                    self.profile_entries[self.subsystem_name] = link
 
-                if entry.startswith("../"):
-                    entry = KERNELDOC_URL + ename + ".html"
-                else:
-                    entry = "/" + entry
-
-                if "*" in entry:
-                    for e in glob(entry):
-                        if "html" not in e:
-                            self.profile_toc.add(e)
-
-                        self.profile_entries[self.subsystem_name] = e
-                else:
-                    if "html" not in entry:
-                        self.profile_toc.add(entry)
-
-                    self.profile_entries[self.subsystem_name] = entry
+                details = ", ".join(entries.values())
             else:
                 match = re.match(r"(https?://.*)", details)
                 if match:
@@ -243,7 +241,9 @@ class MaintainersParser:
                 else:
                     self.profile_entries[self.subsystem_name] = f"``{details}``"
 
-        details = self.linkify(details)
+                details = self.linkify(details)
+        else:
+            details = self.linkify(details)
 
         #
         # Mark paths (and regexes) as literal text for improved
@@ -340,7 +340,7 @@ class MaintainersProfile(Include):
                 output += f"- {name}: {entry}\n"
                 self.warning(f"{profile}: Invalid 'P' tag: {entry}\n")
             else:
-                output += f"- :doc:`{name} <{entry}>`\n"
+                output += f"- {entry}\n"
 
         #
         # Create a hidden TOC table with all profiles. That allows adding
@@ -356,6 +356,9 @@ class MaintainersProfile(Include):
 
         output += "\n"
 
+        # For debugging the pre-rendered results...
+        #print(output, file=open("/tmp/profiles.rst", "w"))
+
         self.state.document.settings.record_dependencies.add(path)
         self.state_machine.insert_input(statemachine.string2lines(output), path)
 
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH v4 1/2] usb: xhci-pci: add AMD Promontory 21 PCI glue
From: Jihong Min @ 2026-05-09  6:54 UTC (permalink / raw)
  To: Mario Limonciello, Jihong Min, Greg Kroah-Hartman, Mathias Nyman
  Cc: Guenter Roeck, Jonathan Corbet, Shuah Khan, Basavaraj Natikar,
	linux-usb, linux-hwmon, linux-doc, linux-pci, linux-kernel
In-Reply-To: <93c43962-6aee-45c8-97c0-a4fbf5124ce8@amd.com>


On 5/9/26 14:52, Mario Limonciello wrote:
>
> Fine by me either way.
>
Thanks. I changed the current branch to:

   depends on X86
   default USB_XHCI_PCI

and removed the CPU_SUP_AMD-specific help text.

Sincerely,
Jihong Min


^ permalink raw reply

* Re: [PATCH v2 2/3] Documentation: security-bugs: explain what is and is not a security bug
From: Greg KH @ 2026-05-09  6:39 UTC (permalink / raw)
  To: Willy Tarreau
  Cc: Linus Torvalds, leon, security, Jonathan Corbet, skhan, workflows,
	linux-doc, linux-kernel
In-Reply-To: <af4RqzO_VHYAqcHf@1wt.eu>

On Fri, May 08, 2026 at 06:39:07PM +0200, Willy Tarreau wrote:
> Greg,
> 
> does this addition on top of the current patch address your concerns ?
> 
> --- a/Documentation/process/security-bugs.rst
> +++ b/Documentation/process/security-bugs.rst
> @@ -88,6 +88,14 @@ can be easily exploited, representing an imminent threat to many users.  Before
>  reporting, consider whether the issue actually crosses a trust boundary on such
>  a system.
> 
> +**If you resorted to AI assistance to identify a bug, you must treat it as
> +public**. While you may have valid reasons to believe it is not, the security
> +team's experience shows that bugs discovered this way systematically surface
> +simultaneously across multiple researchers, often on the same day. In this
> +case, do not publicly share a reproducer, as this could cause unintended harm;
> +just mention that one is available and maintainers might ask for it privately
> +if they need it.
> +
>  If you are unsure whether an issue qualifies, err on the side of reporting
>  privately: the security team would rather triage a borderline report than miss
>  a real vulnerability.  Reporting ordinary bugs to the security list, however,
> @@ -102,7 +110,7 @@ affected subsystem's maintainers and Cc: the Linux kernel security team.  Do
>  not send it to a public list at this stage, unless you have good reasons to
>  consider the issue as being public or trivial to discover (e.g. result of a
>  widely available automated vulnerability scanning tool that can be repeated by
> -anyone).
> +anyone, or use of AI-based tools).
> 
>  If you're sending a report for issues affecting multiple parts in the kernel,
>  even if they're fairly similar issues, please send individual messages (think
> 
> If so I can resend with it.

Looks good to me, thanks!

greg k-h

^ permalink raw reply

* Re: [PATCH v4 1/2] usb: xhci-pci: add AMD Promontory 21 PCI glue
From: Mario Limonciello @ 2026-05-09  5:52 UTC (permalink / raw)
  To: Jihong Min, Jihong Min, Greg Kroah-Hartman, Mathias Nyman
  Cc: Guenter Roeck, Jonathan Corbet, Shuah Khan, Basavaraj Natikar,
	linux-usb, linux-hwmon, linux-doc, linux-pci, linux-kernel
In-Reply-To: <e8c5f5e0-e0d7-4231-8c46-be7a175941f5@icloud.com>



On 5/9/26 00:34, Jihong Min wrote:
> On 5/9/26, Mario Limonciello wrote:
>  > Promontory 21 is only on AMD platforms and AMD platforms are only x86.
>  > I think the Kconfig should be conditional on AMD CPU support being
>  > enabled and X86 architecture so that we don't bloat other architectures
>  > with dead code that will never run.
> 
> I agree with limiting this to x86, and I changed the current branch in that
> direction.
> 
> One detail I would like to double-check is whether CPU_SUP_AMD should 
> also be
> part of the dependency, or whether X86 alone would be more accurate for the
> PCI glue.
> 
> The PROM21 xHCI function is still a PCI device. I found one public 
> example of
> a B650/PROM21-based PCIe add-in card design which is reported to work in 
> both
> AMD and Intel systems:
> 
> https://www.tomshardware.com/pc-components/chipsets/pcie-card-unlocks- 
> amd-chipset-power-on-intel-motherboards-or-you-can-turn-any-b650- 
> motherboard-into-an-x670-one
> 
> That is clearly a niche/community hardware case, not a normal AMD platform,
> and I do not want to over-weight it. But it made me wonder if:
> 
>    depends on X86
> 
> would be the more accurate dependency than:
> 
>    depends on X86 && CPU_SUP_AMD
> 
> for a PCI-attached PROM21 xHCI controller. The option would still use:
> 
>    default USB_XHCI_PCI
> 
> and the hwmon sensor driver would still stay behind its own
> SENSORS_PROM21_XHCI option.
> 
> I am fine keeping CPU_SUP_AMD if you prefer; I just wanted to check before
> locking that part in for v5.
> 
> Sincerely,
> Jihong Min
> 

Fine by me either way.


^ permalink raw reply

* Re: [PATCH v4 1/2] usb: xhci-pci: add AMD Promontory 21 PCI glue
From: Jihong Min @ 2026-05-09  5:34 UTC (permalink / raw)
  To: Mario Limonciello, Jihong Min, Greg Kroah-Hartman, Mathias Nyman
  Cc: Guenter Roeck, Jonathan Corbet, Shuah Khan, Basavaraj Natikar,
	linux-usb, linux-hwmon, linux-doc, linux-pci, linux-kernel
In-Reply-To: <966c9e07-10e6-4abe-9cb5-77b974f31302@amd.com>

On 5/9/26, Mario Limonciello wrote:
 > Promontory 21 is only on AMD platforms and AMD platforms are only x86.
 > I think the Kconfig should be conditional on AMD CPU support being
 > enabled and X86 architecture so that we don't bloat other architectures
 > with dead code that will never run.

I agree with limiting this to x86, and I changed the current branch in that
direction.

One detail I would like to double-check is whether CPU_SUP_AMD should 
also be
part of the dependency, or whether X86 alone would be more accurate for the
PCI glue.

The PROM21 xHCI function is still a PCI device. I found one public 
example of
a B650/PROM21-based PCIe add-in card design which is reported to work in 
both
AMD and Intel systems:

https://www.tomshardware.com/pc-components/chipsets/pcie-card-unlocks-amd-chipset-power-on-intel-motherboards-or-you-can-turn-any-b650-motherboard-into-an-x670-one

That is clearly a niche/community hardware case, not a normal AMD platform,
and I do not want to over-weight it. But it made me wonder if:

   depends on X86

would be the more accurate dependency than:

   depends on X86 && CPU_SUP_AMD

for a PCI-attached PROM21 xHCI controller. The option would still use:

   default USB_XHCI_PCI

and the hwmon sensor driver would still stay behind its own
SENSORS_PROM21_XHCI option.

I am fine keeping CPU_SUP_AMD if you prefer; I just wanted to check before
locking that part in for v5.

Sincerely,
Jihong Min


^ permalink raw reply

* Re: [PATCH v2 2/3] Documentation: security-bugs: explain what is and is not a security bug
From: Willy Tarreau @ 2026-05-09  4:48 UTC (permalink / raw)
  To: Shuah Khan
  Cc: greg, leon, security, Jonathan Corbet, workflows, linux-doc,
	linux-kernel, Greg KH
In-Reply-To: <a3ca798c-40ad-4afb-9c6b-35d53430b6d0@linuxfoundation.org>

Hi Shuah,

On Fri, May 08, 2026 at 02:52:13PM -0600, Shuah Khan wrote:
> > +What qualifies as a security bug
> > +--------------------------------
> > +
> > +It is important that most bugs are handled publicly so as to involve the widest
> > +possible audience and find the best solution.  By nature, bugs that are handled
> > +in closed discussions between a small set of participants are less likely to
> > +produce the best possible fix (e.g., risk of missing valid use cases, limited
> > +testing abilities).
> > +
> > +It turns out that the majority of the bugs reported via the security team are
> > +just regular bugs that have been improperly qualified as security bugs due to
> > +ignorance or misunderstanding of the Linux kernel's threat model described in
> 
> "lack of understanding" instead of ignorance?

I already had "misunderstanding", here I wanted to express the idea that
people could simply ignore that this file exists (since it's new). Do you
think we shouldn't care about this and just keep "misunderstanding" ?

(...)
> > +The Linux Kernel threat model
> > +=============================
> > +
> > +There are a lot of assumptions regarding what the kernel protects against and
> > +what it does not protect against. These assumptions tend to cause confusion for
> 
> Could simply say "what it does not" or "what the kernel does and does not protect
> against"

Ah OK good point, I'll rephrase it.

> > +* **Configuration**:
> > +
> > +  * outdated kernels and particularly end-of-life branches are out of the scope
> > +    of the kernel's threat model: administrators are responsible for keeping
> > +    their system up to date. For a bug to qualify as a security bug, it must be
> > +    demonstrated that it affects actively maintained versions.
> > +
> > +  * build-level: changes to the kernel configuration that are explicitly
> > +    documented as lowering the security level (e.g. ``CONFIG_NOMMU``), or
> > +    targeted at developers only.
> > +
> > +  * OS-level: changes to command line parameters, sysctls, filesystem
> > +    permissions, user capabilities, exposure of privileged interfaces, that
> > +    explicitly increase exposure by either offering non-default access to
> > +    unprivileged users, or reduce the kernel's ability to enforce some
> > +    protections or mitigations. Example: write access to procfs or debugfs.
> > +
> > +  * issues triggered only when using features intended for development or
> > +    debugging (e.g., lockdep, KASAN, fault-injection): these features are known
> > +    to introduce overhead and potential instability and are not intended for
> > +    production use.
> 
> Can we call out features and tools (the ones in kernel repo)

Sure!

> sched_ext's Kconfig enables
> a few debug options including LOCKDEP
> 
> tools/sched_ext/Kconfig:CONFIG_DEBUG_LOCKDEP=y

It's still there but maybe not visible enough, I should probably write
it in upper case:

   debugging (e.g., lockdep, KASAN, fault-injection):

> > +* **Excess of initial privileges**:
> > +
> > +  * actions performed by a user already possessing the privileges required to
> > +    perform that action or modify that state (e.g. ``CAP_SYS_ADMIN``,
> > +    ``CAP_NET_ADMIN``, ``CAP_SYS_RAWIO``, ``CAP_SYS_MODULE`` with no further
> > +    boundary being crossed).
> > +
> > +  * actions performed in user namespace without permitting anything in the
> > +    initial namespace that was not already permitted to the same user there.
> 
> This was a bit hard to parse - examples might help here

Yeah when rereading it now, I fully agree. I think I should avoid the
double negation here and use a form such as;

  * actions performed in user namespace that do not bypass the restrictions
    imposed to the initial user.

If examples are still needed, I could possibly add: "(e.g. ptrace, signals,
FS or device access, system/network configuration, network binding)".

> > +  * anything performed by the root user in the initial namespace (e.g. kernel
> > +    oops when writing to a privileged device).
> > +
> > +* **Out of production use**:
> > +
> > +  This covers theoretical/probabilistic attacks that rely on laboratory
> > +  conditions with zero system noise, or those requiring an unrealistic number
> > +  of attempts (e.g., billions of trials) that would be detected by standard
> > +  system monitoring long before success, such as:
> > +
> > +  * prediction of random numbers that only works in a totally silent
> > +    environment (such as IP ID, TCP ports or sequence numbers that can only be
> > +    guessed in a lab).
> > +
> > +  * activity observation and information leaks based on probabilistic
> > +    approaches that are prone to measurement noise and not realistically
> > +    reproducible on a production system.
> > +
> > +  * issues that can only be triggered by heavy attacks (e.g. brute force) whose
> > +    impact on the system makes it unlikely or impossible to remain undetected
> > +    before they succeed (e.g. consuming all memory before succeeding).
> > +
> > +  * problems seen only under development simulators, emulators, or combinations
> > +    that do not exist on real systems at the time of reporting (issues
> > +    involving tens of millions of threads, tens of thousands of CPUs,
> > +    unrealistic CPU frequencies, RAM sizes or disk capacities, network speeds.
> > +
> > +  * issues whose reproduction requires hardware modification or emulation,
> > +    including fake USB devices that pretend to be another one.
> > +
> > +  * as well as issues that can be triggered at a cost that is orders of
> > +    magnitude higher than the expected benefits (e.g. fully functional keyboard
> > +    emulator only to retrieve 7 uninitialized bytes in a structure, or
> > +    brute-force method involving millions of connection attempts to guess a
> > +    port number).
> 
> Can we add a section about problems found using experimental or tools
> in development stage?

You mean one more paragraph about CONFIG_EXPERIMENTAL ? Or what else do
you have in mind ? Do not hesiate to propose a paragraph if you have
anything in mind!

(...)

> Reviewed-by: Shuah Khan <skhan@linuxfoundation.org>
> 
> thanks,

Thank you!
Willy

^ permalink raw reply

* Re: [PATCH v17 02/11] cxl/ras: Unify Endpoint and Port AER trace events
From: Dan Williams (nvidia) @ 2026-05-09  3:49 UTC (permalink / raw)
  To: Jonathan Cameron, Bowman, Terry
  Cc: dave, dave.jiang, alison.schofield, djbw, bhelgaas, shiju.jose,
	ming.li, Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
	PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
	sathyanarayanan.kuppuswamy, vishal.l.verma, alucerop, ira.weiny,
	corbet, rafael, xueshuai, linux-cxl, linux-kernel, linux-pci,
	linux-acpi, linux-doc, Mauro Carvalho Chehab
In-Reply-To: <20260508150533.04e19cf9@jic23-huawei>

Jonathan Cameron wrote:
> On Thu, 7 May 2026 13:33:45 -0500
> "Bowman, Terry" <terry.bowman@amd.com> wrote:
[..]
> > > This concerns me (sorry I wasn't paying attention to the v16 thread).
> > > It is a userspace regression against code that is out in the wild and typically
> > > not updated in sync with the kernel.
> > > 
> > > If you are suggesting breaking ras-daemon at the very least +CC the maintainer.

Sorry, that was not the intent, see below.

> > > 
> > > To get to a unified tracepoint add a new one that does what you want, but
> > > maintain the existing ones as well.  Userspace can then migrate and maybe
> > > in 5+ years time we can delete the non unified ones.
> > > 
> > > No actually comments on the code, just left it all here for Mauro,
> > > 
> > > Thanks,
> > > 
> > > Jonathan
> > >   
> > 
> > Dan was clear about using a single set of CE and UE handlers for all CXL RAS 
> > protocol errors. While I understand there may be concerns, please direct any 
> > objections to Dan and clarify what changes are required to avoid this 
> > repeatedly going back and forth.
> > 
> > [1] https://lore.kernel.org/linux-cxl/69cb2d5ba3111_178904100b7@dwillia2-mobl4.notmuch/
> 
> Sure - Dan's on this thread so I'm sure he'll see it sooner or later.
> 
> Perhaps I'm missing something that makes this less critical than it appears.

No, it is breakage and a thinko on my part on the advice to Terry on the
backwards compatibility rules for tracepoints. At the time I was only
tracking data type and order of the payload. I.e. string at same
position. However, the name of the argument is ABI.

Something like this incremental fixup I think gets this back on track.
It keeps legacy ABI support for "memdev" field in the payload. It
incrementally lets updated userspace understand "port" and "dport"
events. It stops us from growing a new set of events just to update the
arguments. It enhances the CPER events to now handle switch ports in
addition to endpoint ports.

The bulk of the change is passing @port and @dport to the CXL trace
events instead of a plain @dev.

-- >8 --
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index ff39985d363f..ed3a56966369 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -183,9 +183,10 @@ static inline struct device *dport_to_host(struct cxl_dport *dport)
 #ifdef CONFIG_CXL_RAS
 int cxl_ras_init(void);
 void cxl_ras_exit(void);
-bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base);
-void cxl_handle_cor_ras(struct device *dev, u64 serial,
-			void __iomem *ras_base);
+bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport, u64 serial,
+		    void __iomem *ras_base);
+void cxl_handle_cor_ras(struct cxl_port *port, struct cxl_dport *dport,
+			u64 serial, void __iomem *ras_base);
 void cxl_dport_map_rch_aer(struct cxl_dport *dport);
 void cxl_disable_rch_root_ints(struct cxl_dport *dport);
 void cxl_handle_rdport_errors(struct pci_dev *pdev);
diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h
index 6f3957b3c3af..3857d2fc279d 100644
--- a/drivers/cxl/core/trace.h
+++ b/drivers/cxl/core/trace.h
@@ -49,20 +49,24 @@
 )
 
 TRACE_EVENT(cxl_aer_uncorrectable_error,
-	TP_PROTO(const struct device *dev, u32 status, u32 fe, u32 *hl,
-		 u64 serial),
-	TP_ARGS(dev, status, fe, hl, serial),
+	TP_PROTO(struct cxl_port *port, struct cxl_dport *dport, u32 status,
+		 u32 fe, u32 *hl, u64 serial),
+	TP_ARGS(port, dport, status, fe, hl, serial),
 	TP_STRUCT__entry(
-		__string(device, dev_name(dev))
-		__string(host, dev_name(dev->parent))
+		__string(memdev, cxl_trace_memdev_name(port))
+		__string(host, cxl_trace_host_name(port))
 		__field(u64, serial)
 		__field(u32, status)
 		__field(u32, first_error)
 		__array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
+		__string(port, cxl_trace_port_name(port))
+		__string(dport, cxl_trace_dport_name(dport))
 	),
 	TP_fast_assign(
-		__assign_str(device);
+		__assign_str(memdev);
 		__assign_str(host);
+		__assign_str(port);
+		__assign_str(dport);
 		__entry->serial = serial;
 		__entry->status = status;
 		__entry->first_error = fe;
@@ -72,8 +76,9 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
 		 */
 		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
 	),
-	TP_printk("device=%s host=%s serial=%lld status: '%s' first_error: '%s'",
-		  __get_str(device), __get_str(host), __entry->serial,
+	TP_printk("memdev=%s port=%s dport=%s host=%s serial=%lld status: '%s' first_error: '%s'",
+		  __get_str(memdev), __get_str(port), __get_str(dport),
+		  __get_str(host), __entry->serial,
 		  show_uc_errs(__entry->status),
 		  show_uc_errs(__entry->first_error)
 	)
@@ -98,22 +103,27 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
 )
 
 TRACE_EVENT(cxl_aer_correctable_error,
-	TP_PROTO(const struct device *dev, u32 status, u64 serial),
-	TP_ARGS(dev, status, serial),
+	TP_PROTO(struct cxl_port *port, struct cxl_dport *dport, u32 status, u64 serial),
+	TP_ARGS(port, dport, status, serial),
 	TP_STRUCT__entry(
-		__string(device, dev_name(dev))
-		__string(host, dev_name(dev->parent))
+		__string(memdev, cxl_trace_memdev_name(port))
+		__string(host, cxl_trace_host_name(port))
 		__field(u64, serial)
 		__field(u32, status)
+		__string(port, cxl_trace_port_name(port))
+		__string(dport, cxl_trace_dport_name(dport))
 	),
 	TP_fast_assign(
-		__assign_str(device);
+		__assign_str(memdev);
+		__assign_str(port);
+		__assign_str(dport);
 		__assign_str(host);
 		__entry->serial = serial;
 		__entry->status = status;
 	),
-	TP_printk("device=%s host=%s serial=%lld status: '%s'",
-		  __get_str(device), __get_str(host), __entry->serial,
+	TP_printk("memdev=%s port=%s dport=%s host=%s serial=%lld status: '%s'",
+		  __get_str(memdev), __get_str(port), __get_str(dport),
+		  __get_str(host), __entry->serial,
 		  show_ce_errs(__entry->status)
 	)
 );
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 776c50d1db51..83e161d48405 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -101,6 +101,12 @@ static inline bool is_cxl_endpoint(struct cxl_port *port)
 	return is_cxl_memdev(port->uport_dev);
 }
 
+/* trace-event helpers */
+const char *cxl_trace_memdev_name(struct cxl_port *port);
+const char *cxl_trace_host_name(struct cxl_port *port);
+const char *cxl_trace_port_name(struct cxl_port *port);
+const char *cxl_trace_dport_name(struct cxl_dport *dport);
+
 struct cxl_memdev *__devm_cxl_add_memdev(struct cxl_dev_state *cxlds,
 					 const struct cxl_memdev_attach *attach);
 struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds,
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index b45e2b539b5f..33e78f155916 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -8,16 +8,20 @@
 #include <cxlpci.h>
 #include "trace.h"
 
-static void cxl_cper_trace_corr_prot_err(struct pci_dev *pdev, u64 serial,
-					 struct cxl_ras_capability_regs *ras_cap)
+static void
+cxl_cper_trace_corr_prot_err(struct cxl_port *port, struct cxl_dport *dport,
+			     u64 serial,
+			     struct cxl_ras_capability_regs *ras_cap)
 {
 	u32 status = ras_cap->cor_status & ~ras_cap->cor_mask;
 
-	trace_cxl_aer_correctable_error(&pdev->dev, status, serial);
+	trace_cxl_aer_correctable_error(port, dport, status, serial);
 }
 
-static void cxl_cper_trace_uncorr_prot_err(struct pci_dev *pdev, u64 serial,
-					   struct cxl_ras_capability_regs *ras_cap)
+static void
+cxl_cper_trace_uncorr_prot_err(struct cxl_port *port, struct cxl_dport *dport,
+			       u64 serial,
+			       struct cxl_ras_capability_regs *ras_cap)
 {
 	u32 status = ras_cap->uncor_status & ~ras_cap->uncor_mask;
 	u32 fe;
@@ -28,10 +32,12 @@ static void cxl_cper_trace_uncorr_prot_err(struct pci_dev *pdev, u64 serial,
 	else
 		fe = status;
 
-	trace_cxl_aer_uncorrectable_error(&pdev->dev, status, fe,
+	trace_cxl_aer_uncorrectable_error(port, dport, status, fe,
 					  ras_cap->header_log, serial);
 }
 
+static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dport **dport);
+
 void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
 {
 	unsigned int devfn = PCI_DEVFN(data->prot_err.agent_addr.device,
@@ -40,19 +46,26 @@ void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
 		pci_get_domain_bus_and_slot(data->prot_err.agent_addr.segment,
 					    data->prot_err.agent_addr.bus,
 					    devfn);
+	struct cxl_dport *dport;
 
 	if (!pdev)
 		return;
 
-	guard(device)(&pdev->dev);
-	if (!pdev->dev.driver)
+	struct cxl_port *port __free(put_cxl_port) =
+		find_cxl_port_by_dev(&pdev->dev, &dport);
+
+	if (!port)
+		return;
+
+	guard(device)(&port->dev);
+	if (!port->dev.driver)
 		return;
 
 	if (data->severity == AER_CORRECTABLE)
-		cxl_cper_trace_corr_prot_err(pdev, pci_get_dsn(pdev),
+		cxl_cper_trace_corr_prot_err(port, dport, pci_get_dsn(pdev),
 					     &data->ras_cap);
 	else
-		cxl_cper_trace_uncorr_prot_err(pdev, pci_get_dsn(pdev),
+		cxl_cper_trace_uncorr_prot_err(port, dport, pci_get_dsn(pdev),
 					       &data->ras_cap);
 }
 EXPORT_SYMBOL_GPL(cxl_cper_handle_prot_err);
@@ -222,13 +235,12 @@ static void __iomem *to_ras_base(struct cxl_port *port, struct cxl_dport *dport)
 
 static void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dport *dport)
 {
-	struct device *dev = &pdev->dev;
 	bool ue;
 
 	if (pci_dev_is_disconnected(pdev))
 		panic("CXL cachemem error: device disconnected during UE recovery");
 
-	ue = cxl_handle_ras(dev, pci_get_dsn(pdev),
+	ue = cxl_handle_ras(port, dport, pci_get_dsn(pdev),
 			    to_ras_base(port, dport));
 	if (ue)
 		panic("CXL cachemem error.");
@@ -238,7 +250,8 @@ static void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct
 	pci_aer_clear_fatal_status(pdev);
 }
 
-void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
+void cxl_handle_cor_ras(struct cxl_port *port, struct cxl_dport *dport,
+			u64 serial, void __iomem *ras_base)
 {
 	void __iomem *addr;
 	u32 status;
@@ -250,7 +263,7 @@ void cxl_handle_cor_ras(struct device *dev, u64 serial, void __iomem *ras_base)
 	status = readl(addr);
 	if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
 		writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
-		trace_cxl_aer_correctable_error(dev, status, serial);
+		trace_cxl_aer_correctable_error(port, dport, status, serial);
 	}
 }
 
@@ -275,7 +288,8 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
  * Log the state of the RAS status registers and prepare them to log the
  * next error status. Return 1 if reset needed.
  */
-bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
+bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport, u64 serial,
+		    void __iomem *ras_base)
 {
 	u32 hl[CXL_HEADERLOG_SIZE_U32];
 	void __iomem *addr;
@@ -302,7 +316,7 @@ bool cxl_handle_ras(struct device *dev, u64 serial, void __iomem *ras_base)
 	}
 
 	header_log_copy(ras_base, hl);
-	trace_cxl_aer_uncorrectable_error(dev, status, fe, hl, serial);
+	trace_cxl_aer_uncorrectable_error(port, dport, status, fe, hl, serial);
 	writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
 
 	return true;
@@ -358,7 +372,7 @@ static void cxl_handle_proto_error(struct pci_dev *pdev, struct cxl_port *port,
 		cxl_handle_rdport_errors(pdev);
 
 	if (severity == AER_CORRECTABLE) {
-		cxl_handle_cor_ras(&pdev->dev, pci_get_dsn(pdev),
+		cxl_handle_cor_ras(port, dport, pci_get_dsn(pdev),
 				   to_ras_base(port, dport));
 		pcie_clear_device_status(pdev);
 	} else {
diff --git a/drivers/cxl/core/ras_rch.c b/drivers/cxl/core/ras_rch.c
index cbd02cabefbc..1bcd3c491aaa 100644
--- a/drivers/cxl/core/ras_rch.c
+++ b/drivers/cxl/core/ras_rch.c
@@ -113,9 +113,8 @@ void cxl_handle_rdport_errors(struct pci_dev *pdev)
 
 	pci_print_aer(pdev, severity, &aer_regs);
 	if (severity == AER_CORRECTABLE)
-		cxl_handle_cor_ras(&pdev->dev, pci_get_dsn(pdev),
+		cxl_handle_cor_ras(port, dport, pci_get_dsn(pdev),
 				   dport->regs.ras);
 	else
-		cxl_handle_ras(&pdev->dev, pci_get_dsn(pdev),
-			       dport->regs.ras);
+		cxl_handle_ras(port, dport, pci_get_dsn(pdev), dport->regs.ras);
 }
diff --git a/drivers/cxl/core/trace.c b/drivers/cxl/core/trace.c
index 7f2a9dd0d0e3..df42d119c53d 100644
--- a/drivers/cxl/core/trace.c
+++ b/drivers/cxl/core/trace.c
@@ -2,7 +2,42 @@
 /* Copyright(c) 2022 Intel Corporation. All rights reserved. */
 
 #include <cxl.h>
+#include <cxlmem.h>
 #include "core.h"
 
+const char *cxl_trace_memdev_name(struct cxl_port *port)
+{
+	if (is_cxl_endpoint(port)) {
+		struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
+
+		return dev_name(&cxlmd->dev);
+	}
+
+	return "";
+}
+
+const char *cxl_trace_host_name(struct cxl_port *port)
+{
+	if (is_cxl_endpoint(port)) {
+		struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
+
+		return dev_name(cxlmd->dev.parent);
+	}
+
+	return dev_name(port->uport_dev);
+}
+
+const char *cxl_trace_port_name(struct cxl_port *port)
+{
+	return dev_name(&port->dev);
+}
+
+const char *cxl_trace_dport_name(struct cxl_dport *dport)
+{
+	if (dport)
+		return dev_name(dport->dport_dev);
+	return "";
+}
+
 #define CREATE_TRACE_POINTS
 #include "trace.h"

^ permalink raw reply related

* 回复:[PATCH v13 net-next 05/11] net/nebula-matrix: add channel layer
From: Illusion Wang @ 2026-05-09  3:46 UTC (permalink / raw)
  To: Paolo Abeni, Dimon, Alvin, Sam, netdev
  Cc: andrew+netdev, corbet, kuba, linux-doc, lorenzo, horms,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <d8f24185-9987-487a-9e0c-5387bd72b629@redhat.com>

>> +static struct nbl_common_wq_mgt *wq_mgt;
>> +
>> +void nbl_common_queue_work(struct work_struct *task)
>> +{
>> +	queue_work(wq_mgt->ctrl_dev_wq, task);
>> +}
>> +
>> +void nbl_common_destroy_wq(void)
>> +{
>> +	destroy_workqueue(wq_mgt->ctrl_dev_wq);
>> +	kfree(wq_mgt);
>> +	wq_mgt = NULL;
>> +}
>> +
>> +int nbl_common_create_wq(void)
>> +{
>> +	wq_mgt = kzalloc_obj(*wq_mgt);
>> +	if (!wq_mgt)
>> +		return -ENOMEM;
>> +
>> +	wq_mgt->ctrl_dev_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM | WQ_UNBOUND,
>> +					      0, "nbl_ctrldev_wq");
>> +	if (!wq_mgt->ctrl_dev_wq) {
>> +		pr_err("Failed to create workqueue nbl_ctrldev_wq\n");
>> +		goto alloc_ctrl_dev_wq_failed;
>> +	}
>> +
>> +	return 0;
>> +alloc_ctrl_dev_wq_failed:
>> +	kfree(wq_mgt);
>> +	wq_mgt = NULL;
>> +	return -ENOMEM;
>> +}
>Does this global singleton survive multiple adapter probes?
>wq_mgt is a file-scope static pointer. If nbl_common_create_wq() is
>called from a second probe, the prior wq_mgt is overwritten and the
>previous workqueue is leaked. On remove of the second device,
>nbl_common_destroy_wq() unconditionally calls destroy_workqueue() and
>kfree() and sets wq_mgt to NULL — so a later remove of the first
>device will dereference NULL in destroy_workqueue(wq_mgt->ctrl_dev_wq).
>nbl_common_queue_work() also dereferences wq_mgt with no NULL check.
>This patch does not wire up the callers, but the later series patch
>"net/nebula-matrix: add common dev start/stop operation"
>(1ff0ad206da3) does. Would refcounting create/destroy, or switching to
>per-adapter workqueues, address this?

In the last patch:
static int __init nbl_module_init(void)
{
	int status;

	status = nbl_common_create_wq();
	if (status) {
		pr_err("Failed to create wq, err = %d\n", status);
		goto wq_create_failed;
	}
	status = pci_register_driver(&nbl_driver);
	if (status) {
		pr_err("Failed to register PCI driver, err = %d\n", status);
		goto pci_register_driver_failed;
	}

	return 0;

pci_register_driver_failed:
	nbl_common_destroy_wq();
wq_create_failed:
	return status;
}

static void __exit nbl_module_exit(void)
{
	pci_unregister_driver(&nbl_driver);
	nbl_common_destroy_wq();
}

module_init(nbl_module_init);
module_exit(nbl_module_exit);

The function nbl_common_create_wq is only called within nbl_module_init, and
nbl_common_destroy_wq is only called once within nbl_module_exit. So, is the
AI's suggestion also incorrect in this case?
---illusion

^ permalink raw reply

* 回复:回复:[PATCH v13 net-next 03/11] net/nebula-matrix: add chip related definitions
From: Illusion Wang @ 2026-05-09  3:38 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Paolo Abeni, Dimon, Alvin, Sam, netdev, andrew+netdev, corbet,
	kuba, linux-doc, lorenzo, horms, vadim.fedorenko, lukas.bulwahn,
	edumazet, enelsonmoore, skhan, hkallweit1, open list
In-Reply-To: <bdaf51a9-66d1-4469-960f-d5ec74f870de@lunn.ch>


>> But I printed out the results: 
>> ARRAY_SIZE(nbl_sec009_data) equals NBL_SEC009_SIZE,
>> ARRAY_SIZE(nbl_sec025_data) equals NBL_SEC025_SIZE,
>> and ARRAY_SIZE(nbl_sec022_data) equals NBL_SEC022_SIZE.
>> 
>> Is the AI making a mistake here?

>Just a guess, i've not looked at this patch at all.

>Are you doing this on a 32 bit build? Maybe the AI is?

 >   Andrew

 We are using this on a 64 bit build.

^ permalink raw reply

* Re: [PATCH v2 0/7] seg6: add SRv6 Mobile User Plane (RFC 9433) behaviors
From: Yuya Kusakabe @ 2026-05-09  1:53 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni,
	Simon Horman, Shuah Khan, Jonathan Corbet, Shuah Khan,
	linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
	linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org,
	Justin Iurman, stefano.salsano
In-Reply-To: <20260508033210.5149db4fc3977d33937e6942@uniroma2.it>

On Fri, May 8, 2026 at 10:32 AM Andrea Mayer <andrea.mayer@uniroma2.it> wrote:
> just a heads-up: I am going through the series (kernel and iproute2)
> and will send detailed comments within the next few days. It is a
> substantial addition so I want to take the time to review it properly.

Hi Andrea,

Thank you for the heads-up and for dedicating your time to review this
substantial series.
I will stand by for your detailed comments and prepare to address them.

Thanks,
Yuya

^ permalink raw reply

* Re: [RFC net-next 0/4] devlink: Add boot-time defaults
From: Jakub Kicinski @ 2026-05-09  0:52 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: Mark Bloch, Eric Dumazet, Paolo Abeni, Andrew Lunn,
	David S. Miller, Jonathan Corbet, Shuah Khan, Simon Horman,
	Saeed Mahameed, Leon Romanovsky, Tariq Toukan, Andrew Morton,
	Borislav Petkov (AMD), Randy Dunlap, Dave Hansen,
	Christian Brauner, Petr Mladek, Peter Zijlstra (Intel),
	Thomas Gleixner, Pawan Gupta, Dapeng Mi, Kees Cook, Marco Elver,
	Eric Biggers, Li RongQing, Paul E. McKenney, linux-doc,
	linux-kernel, netdev, linux-rdma
In-Reply-To: <af4lBIJdCuN5VKq_@FV6GYCPJ69>

On Fri, 8 May 2026 20:07:44 +0200 Jiri Pirko wrote:
> >I don't think switchdev by default should mean CX4+ in general. If we get
> >there, I would expect it to be limited to the DPU/BlueField/ECPF case, where
> >the host PF probe path can depend on the ECPF reaching switchdev. Changing the
> >default for regular host NIC deployments feels like a much larger compatibility
> >change.  
> 
> We can't travel throught time, but if from CX5 onwards the default would
> be switchdev, nobody would feel broken in terms of compatibility. That
> is my point. Having "legacy" as default is simply wrong for never NIC
> generations. That is why it is called "legacy" and it should have been
> rotten through and out since CX4 times.

legacy vs switchdev only describes the eswitch configuration.
As a non-SR-IOV user I really don't want to see the extra representors
hanging around my systems, confusing all daemons. IIRC mlx5 had some
limitations around the uplink representor. Maybe that's the disconnect.
But for a real, fully featured switchdev eswitches having the
PHY and PF representors on boot, always, will not make sense.

IOW it's not a question of the generation of the card but of
the deployment type / use case.

> >For the ASIC/NV bit: maybe technically possible, but it feels like the wrong
> >layer. This is boot/deployment policy, not a persistent hardware property, and
> >storing it in NV memory would make the state persist across kernels/hosts in a
> >surprising way.  
> 
> Well, as any other nv config, it persists across kernels/hosts. Think
> about it as "unbreak-my-not-legacy-device" bit.

For most devices the switchdev mode does not change anything
substantial about the device. It's purely a kernel / driver config. 
It changes what objects and default rules kernel / driver installs. 
So I don't get why it would make sense to flash into the device
nvmem a Linux SW stack specific config.

> >I do agree the RFC probably went too far by making a generic devlink cmdline
> >configuration language. Maybe the smaller thing to discuss is only:
> >
> >devlink=[pci/...]:esw:mode:{legacy|switchdev|switchdev_inactive}
> >
> >No runtime params, no ordering between different operations, just early eswitch
> >mode for explicitly selected handles.  

Yes, let's cut this down, AI went too far :) As I said we should just
document how we envision the format growing but for now we can literally
implement just the global "esw mode".

One note on the formatting, you mentioned:

  devlink=[pci/0000:08:00.0,pci/0000:08:00.1]:param:flow_steering_mode:hmfs,[pci/0000:08:00.0,pci/0000:08:00.1]:esw:mode:switchdev

TBH when I used the square brackets I meant that the field is optional.
But I guess you used them like we use them for IPv6 addresses to
separate the : signs, makes sense.

Since AFAIU we only care about global default should we focus on
supporting:

 devlink=*:esw:mode:switchdev

meaning all devices default to switchdev?

> FWIW, I'm still against this.

One more option, tho IDK if it actually is good enough for Mark,
would be to let user space "pause" devlink probing. So that the
systemd daemon can configure the device before it populates all
the netdev stuff. Basically make the devices probe into the reload_down
state, until user space configures them. IDK how much of the time
is spent building and tearing down the legacy mode on mlx5 but
the thinking is that we'd at least stave that wasted effort.

^ permalink raw reply

* Re: [PATCH v10 01/30] arm64/sysreg: Update SMIDR_EL1 to DDI0601 2025-06
From: Mark Brown @ 2026-05-09  0:43 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Marc Zyngier, Joey Gouly, Catalin Marinas, Suzuki K Poulose,
	Will Deacon, Paolo Bonzini, Jonathan Corbet, Shuah Khan,
	Oliver Upton, Dave Martin, Fuad Tabba, Ben Horgan,
	linux-arm-kernel, kvmarm, linux-kernel, kvm, linux-doc,
	linux-kselftest, Peter Maydell, Eric Auger
In-Reply-To: <af4ZYVFsbYlEfdOu@J2N7QTR9R3>

[-- Attachment #1: Type: text/plain, Size: 1162 bytes --]

On Fri, May 08, 2026 at 06:12:01PM +0100, Mark Rutland wrote:
> On Fri, Mar 06, 2026 at 05:00:53PM +0000, Mark Brown wrote:

> > Update the definition of SMIDR_EL1 in the sysreg definition to reflect the
> > information in DD0601 2025-06. This includes somewhat more generic ways of
> > describing the sharing of SMCUs, more information on supported priorities
> > and provides additional resolution for describing affinity groups.

> FWIW, these are all in ARM DDI 0487 M.b:

>   https://developer.arm.com/documentation/ddi0487/mb/

> Is anything later in the series going to depend on these fields, or
> would everything behave correctly with the existing RES0 field
> definitions?

We're exposing the affinity fields so there's a build time issue.

> > +Field	55:52	HIP

> Reading the ARM ARM, HIP is arguably a backwards-incompatible change.

Yes, I belive people are aware.

> Do we expect to expose that to VMs, or just hide priorities entirely? I
> suspect we probably want to require that the guest sees
> SMIDR_EL1.SMPS==0, and not care about any of that.

Currently we're not exposing priority support to guests so we don't need
to worry about it yet.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox