The branch main has been updated by kbowling:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=a9752e9ac8a635f49ca058dd7268298840c7e915

commit a9752e9ac8a635f49ca058dd7268298840c7e915
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-08-06 09:36:43 +0000
Commit:     Kevin Bowling <[email protected]>
CommitDate: 2026-08-07 04:30:50 +0000

    pci: Preserve adjusted PCIe control state
    
    The PCI bus changes live capability registers after the initial
    configuration snapshot has been saved. A later driver reprobe restores
    that snapshot and can silently undo the adjustment.
    
    Update the cached Device Control and Root Control bits together with
    pcie_adjust_config() writes. Route the persistent Maximum Read Request
    setter and the bus-owned AER control changes through that helper as
    well, so they share the same restore semantics as MPS reconciliation.
    
    Document the persistent-write contract. Merge only explicitly adjusted
    bits into the saved image so unrelated or transient bits observed during
    the hardware read-modify-write cannot become persistent.
    
    MFC after:      2 weeks
---
 share/man/man9/pci.9 | 11 ++++++++++-
 sys/dev/pci/pci.c    | 41 +++++++++++++++++++++++++----------------
 2 files changed, 35 insertions(+), 17 deletions(-)

diff --git a/share/man/man9/pci.9 b/share/man/man9/pci.9
index 4d69d3a4240f..c94982f5f218 100644
--- a/share/man/man9/pci.9
+++ b/share/man/man9/pci.9
@@ -23,7 +23,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd May 18, 2026
+.Dd August 6, 2026
 .Dt PCI 9
 .Os
 .Sh NAME
@@ -253,6 +253,15 @@ to the value in
 Any bits not specified in
 .Fa mask
 are preserved.
+For 16-bit accesses to
+.Dv PCIER_DEVICE_CTL
+or
+.Dv PCIER_ROOT_CTL ,
+the corresponding bits in the saved PCI configuration state are also updated
+so the adjustment persists across configuration restores.
+Use
+.Fn pcie_write_config
+for transient changes that must not be saved.
 The previous value of the register is returned.
 .Pp
 The
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index b690c3412356..95b8e831e743 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -2312,10 +2312,9 @@ pci_set_max_read_req(device_t dev, int size)
        if (size > 4096)
                size = 4096;
        size = (1 << (fls(size) - 1));
-       val = pci_read_config(dev, cap + PCIER_DEVICE_CTL, 2);
-       val &= ~PCIEM_CTL_MAX_READ_REQUEST;
-       val |= (fls(size) - 8) << 12;
-       pci_write_config(dev, cap + PCIER_DEVICE_CTL, val, 2);
+       val = (fls(size) - 8) << 12;
+       pcie_adjust_config(dev, PCIER_DEVICE_CTL,
+           PCIEM_CTL_MAX_READ_REQUEST, val, 2);
        return (size);
 }
 
@@ -2359,6 +2358,7 @@ pcie_adjust_config(device_t dev, int reg, uint32_t mask, 
uint32_t value,
     int width)
 {
        struct pci_devinfo *dinfo = device_get_ivars(dev);
+       uint16_t *saved;
        uint32_t old, new;
        int cap;
 
@@ -2373,6 +2373,22 @@ pcie_adjust_config(device_t dev, int reg, uint32_t mask, 
uint32_t value,
        new = old & ~mask;
        new |= (value & mask);
        pci_write_config(dev, cap + reg, new, width);
+       /* Apply only the requested policy bits to the saved restore image. */
+       if (width == 2) {
+               saved = NULL;
+               switch (reg) {
+               case PCIER_DEVICE_CTL:
+                       saved = &dinfo->cfg.pcie.pcie_device_ctl;
+                       break;
+               case PCIER_ROOT_CTL:
+                       saved = &dinfo->cfg.pcie.pcie_root_ctl;
+                       break;
+               }
+               if (saved != NULL) {
+                       *saved &= ~(uint16_t)mask;
+                       *saved |= (uint16_t)(value & mask);
+               }
+       }
        return (old);
 }
 
@@ -4461,16 +4477,12 @@ pci_add_child_clear_aer(device_t dev, struct 
pci_devinfo *dinfo)
 {
        int aer;
        uint32_t r;
-       uint16_t r2;
 
        if (dinfo->cfg.pcie.pcie_location != 0 &&
            dinfo->cfg.pcie.pcie_type == PCIEM_TYPE_ROOT_PORT) {
-               r2 = pci_read_config(dev, dinfo->cfg.pcie.pcie_location +
-                   PCIER_ROOT_CTL, 2);
-               r2 &= ~(PCIEM_ROOT_CTL_SERR_CORR |
-                   PCIEM_ROOT_CTL_SERR_NONFATAL | PCIEM_ROOT_CTL_SERR_FATAL);
-               pci_write_config(dev, dinfo->cfg.pcie.pcie_location +
-                   PCIER_ROOT_CTL, r2, 2);
+               r = PCIEM_ROOT_CTL_SERR_CORR |
+                   PCIEM_ROOT_CTL_SERR_NONFATAL | PCIEM_ROOT_CTL_SERR_FATAL;
+               pcie_adjust_config(dev, PCIER_ROOT_CTL, r, 0, 2);
        }
        if (pci_find_extcap(dev, PCIZ_AER, &aer) == 0) {
                r = pci_read_config(dev, aer + PCIR_AER_UC_STATUS, 4);
@@ -4522,12 +4534,9 @@ pci_add_child_clear_aer(device_t dev, struct pci_devinfo 
*dinfo)
                    PCIM_AER_COR_HEADER_LOG_OVFLOW);
                pci_write_config(dev, aer + PCIR_AER_COR_MASK, r, 4);
 
-               r = pci_read_config(dev, dinfo->cfg.pcie.pcie_location +
-                   PCIER_DEVICE_CTL, 2);
-               r |=  PCIEM_CTL_COR_ENABLE | PCIEM_CTL_NFER_ENABLE |
+               r = PCIEM_CTL_COR_ENABLE | PCIEM_CTL_NFER_ENABLE |
                    PCIEM_CTL_FER_ENABLE | PCIEM_CTL_URR_ENABLE;
-               pci_write_config(dev, dinfo->cfg.pcie.pcie_location +
-                   PCIER_DEVICE_CTL, r, 2);
+               pcie_adjust_config(dev, PCIER_DEVICE_CTL, r, r, 2);
        }
 }
 

Reply via email to