Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 07 Aug 2026 04:31:12 +0000
From:      Kevin Bowling <kbowling@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: a9752e9ac8a6 - main - pci: Preserve adjusted PCIe control state
Message-ID:  <6a755f90.2698a.4e64aa79@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by kbowling:

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

commit a9752e9ac8a635f49ca058dd7268298840c7e915
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-06 09:36:43 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
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);
 	}
 }
 


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a755f90.2698a.4e64aa79>