linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper
@ 2025-06-18 15:20 Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 01/13] PCI: dwc: Add dw_pcie_clear_and_set_dword() for register bit manipulation Hans Zhang
                   ` (13 more replies)
  0 siblings, 14 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:20 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

Register bit manipulation in DesignWare PCIe controllers currently
uses repetitive read-modify-write sequences across multiple drivers.
This pattern leads to code duplication and increases maintenance
complexity as each driver implements similar logic with minor variations.

This series introduces dw_pcie_clear_and_set_dword() to centralize atomic
register modification. The helper performs read-clear-set-write operations
in a single function, replacing open-coded implementations. Subsequent
patches refactor individual drivers to use this helper, eliminating
redundant code and ensuring consistent bit handling.

The change reduces overall code size by ~350 lines while improving
maintainability. Each controller driver is updated in a separate
patch to preserve bisectability and simplify review.

---
Hi all,

At the beginning, two patches were made, 0001*.patch, and the others were
one patch. After consideration, I still split the patches. If splitting
is not necessary, I will recombine them into two patches in future
versions.


Changes for v2:
- Re-send it in the company environment so that the entire patch series is in the 00/13 cover letter. (Bjorn)
- Modify the subject. (Bjorn and Frank)
---

Hans Zhang (13):
  PCI: dwc: Add dw_pcie_clear_and_set_dword() for register bit
    manipulation
  PCI: dwc: Refactor code by using dw_pcie_clear_and_set_dword()
  PCI: dra7xx: Refactor code by using dw_pcie_clear_and_set_dword()
  PCI: imx6: Refactor code by using dw_pcie_clear_and_set_dword()
  PCI: meson: Refactor code by using dw_pcie_clear_and_set_dword()
  PCI: armada8k: Refactor code by using dw_pcie_clear_and_set_dword()
  PCI: bt1: Refactor code by using dw_pcie_clear_and_set_dword()
  PCI: dw-rockchip: Refactor code by using dw_pcie_clear_and_set_dword()
  PCI: fu740: Refactor code by using dw_pcie_clear_and_set_dword()
  PCI: qcom: Refactor code by using dw_pcie_clear_and_set_dword()
  PCI: qcom-ep: Refactor code by using dw_pcie_clear_and_set_dword()
  PCI: rcar-gen4: Refactor code by using dw_pcie_clear_and_set_dword()
  PCI: tegra194: Refactor code by using dw_pcie_clear_and_set_dword()

 drivers/pci/controller/dwc/pci-dra7xx.c       |  10 +-
 drivers/pci/controller/dwc/pci-imx6.c         |  26 ++-
 drivers/pci/controller/dwc/pci-meson.c        |  22 +--
 drivers/pci/controller/dwc/pcie-armada8k.c    |  48 ++----
 drivers/pci/controller/dwc/pcie-bt1.c         |   5 +-
 .../controller/dwc/pcie-designware-debugfs.c  |  67 +++-----
 .../pci/controller/dwc/pcie-designware-ep.c   |  20 +--
 .../pci/controller/dwc/pcie-designware-host.c |  27 ++-
 drivers/pci/controller/dwc/pcie-designware.c  |  74 ++++-----
 drivers/pci/controller/dwc/pcie-designware.h  |  27 +--
 drivers/pci/controller/dwc/pcie-dw-rockchip.c |   7 +-
 drivers/pci/controller/dwc/pcie-fu740.c       |   5 +-
 drivers/pci/controller/dwc/pcie-qcom-common.c |  59 ++++---
 drivers/pci/controller/dwc/pcie-qcom-ep.c     |  14 +-
 drivers/pci/controller/dwc/pcie-rcar-gen4.c   |  23 +--
 drivers/pci/controller/dwc/pcie-tegra194.c    | 155 ++++++++----------
 16 files changed, 239 insertions(+), 350 deletions(-)


base-commit: 19272b37aa4f83ca52bdf9c16d5d81bdd1354494
-- 
2.25.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2 01/13] PCI: dwc: Add dw_pcie_clear_and_set_dword() for register bit manipulation
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-19  4:29   ` Frank Li
  2025-06-18 15:21 ` [PATCH v2 02/13] PCI: dwc: Refactor code by using dw_pcie_clear_and_set_dword() Hans Zhang
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

DesignWare PCIe controller drivers implement register bit manipulation
through explicit read-modify-write sequences. These patterns appear
repeatedly across multiple drivers with minor variations, creating
code duplication and maintenance overhead.

Implement dw_pcie_clear_and_set_dword() helper to encapsulate atomic
register modification. The function reads the current register value,
clears specified bits, sets new bits, and writes back the result in
a single operation. This abstraction hides bitwise manipulation details
while ensuring consistent behavior across all usage sites.

Centralizing this logic reduces future maintenance effort when modifying
register access patterns and minimizes the risk of implementation
divergence between drivers.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pcie-designware.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index ce9e18554e42..f401c144df0f 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -707,6 +707,17 @@ static inline void dw_pcie_ep_writel_dbi2(struct dw_pcie_ep *ep, u8 func_no,
 	dw_pcie_ep_write_dbi2(ep, func_no, reg, 0x4, val);
 }
 
+static inline void dw_pcie_clear_and_set_dword(struct dw_pcie *pci, int pos,
+					       u32 clear, u32 set)
+{
+	u32 val;
+
+	val = dw_pcie_readl_dbi(pci, pos);
+	val &= ~clear;
+	val |= set;
+	dw_pcie_writel_dbi(pci, pos, val);
+}
+
 static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
 {
 	u32 reg;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 02/13] PCI: dwc: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 01/13] PCI: dwc: Add dw_pcie_clear_and_set_dword() for register bit manipulation Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 03/13] PCI: dra7xx: " Hans Zhang
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

DesignWare core modules contain multiple instances of manual
read-modify-write operations for register bit manipulation.
These patterns duplicate functionality now provided by
dw_pcie_clear_and_set_dword(), particularly in debugfs, endpoint,
host, and core initialization paths.

Replace open-coded bit manipulation sequences with calls to
dw_pcie_clear_and_set_dword(). Affected areas include debugfs register
control, endpoint capability configuration, host setup routines, and
core link initialization logic. The changes simplify power management
handling, capability masking, and feature configuration.

Standardizing on the helper function reduces code duplication by ~140
lines across core modules while improving readability. The refactoring
also ensures consistent error handling for register operations and
provides a single point of control for future bit manipulation logi
updates.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 .../controller/dwc/pcie-designware-debugfs.c  | 67 +++++++----------
 .../pci/controller/dwc/pcie-designware-ep.c   | 20 +++--
 .../pci/controller/dwc/pcie-designware-host.c | 27 +++----
 drivers/pci/controller/dwc/pcie-designware.c  | 74 +++++++------------
 drivers/pci/controller/dwc/pcie-designware.h  | 18 +----
 5 files changed, 76 insertions(+), 130 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-debugfs.c b/drivers/pci/controller/dwc/pcie-designware-debugfs.c
index c67601096c48..7e01d4575d0b 100644
--- a/drivers/pci/controller/dwc/pcie-designware-debugfs.c
+++ b/drivers/pci/controller/dwc/pcie-designware-debugfs.c
@@ -213,10 +213,8 @@ static ssize_t lane_detect_write(struct file *file, const char __user *buf,
 	if (val)
 		return val;
 
-	val = dw_pcie_readl_dbi(pci, rinfo->ras_cap_offset + SD_STATUS_L1LANE_REG);
-	val &= ~(LANE_SELECT);
-	val |= FIELD_PREP(LANE_SELECT, lane);
-	dw_pcie_writel_dbi(pci, rinfo->ras_cap_offset + SD_STATUS_L1LANE_REG, val);
+	dw_pcie_clear_and_set_dword(pci, rinfo->ras_cap_offset + SD_STATUS_L1LANE_REG,
+				    LANE_SELECT, FIELD_PREP(LANE_SELECT, lane));
 
 	return count;
 }
@@ -307,14 +305,13 @@ static ssize_t err_inj_write(struct file *file, const char __user *buf,
 static void set_event_number(struct dwc_pcie_rasdes_priv *pdata,
 			     struct dw_pcie *pci, struct dwc_pcie_rasdes_info *rinfo)
 {
-	u32 val;
+	u32 val = 0;
 
-	val = dw_pcie_readl_dbi(pci, rinfo->ras_cap_offset + RAS_DES_EVENT_COUNTER_CTRL_REG);
-	val &= ~EVENT_COUNTER_ENABLE;
-	val &= ~(EVENT_COUNTER_GROUP_SELECT | EVENT_COUNTER_EVENT_SELECT);
 	val |= FIELD_PREP(EVENT_COUNTER_GROUP_SELECT, event_list[pdata->idx].group_no);
 	val |= FIELD_PREP(EVENT_COUNTER_EVENT_SELECT, event_list[pdata->idx].event_no);
-	dw_pcie_writel_dbi(pci, rinfo->ras_cap_offset + RAS_DES_EVENT_COUNTER_CTRL_REG, val);
+	dw_pcie_clear_and_set_dword(pci, rinfo->ras_cap_offset + RAS_DES_EVENT_COUNTER_CTRL_REG,
+				    EVENT_COUNTER_ENABLE | EVENT_COUNTER_GROUP_SELECT |
+				    EVENT_COUNTER_EVENT_SELECT, val);
 }
 
 static ssize_t counter_enable_read(struct file *file, char __user *buf,
@@ -354,13 +351,9 @@ static ssize_t counter_enable_write(struct file *file, const char __user *buf,
 
 	mutex_lock(&rinfo->reg_event_lock);
 	set_event_number(pdata, pci, rinfo);
-	val = dw_pcie_readl_dbi(pci, rinfo->ras_cap_offset + RAS_DES_EVENT_COUNTER_CTRL_REG);
-	if (enable)
-		val |= FIELD_PREP(EVENT_COUNTER_ENABLE, PER_EVENT_ON);
-	else
-		val |= FIELD_PREP(EVENT_COUNTER_ENABLE, PER_EVENT_OFF);
-
-	dw_pcie_writel_dbi(pci, rinfo->ras_cap_offset + RAS_DES_EVENT_COUNTER_CTRL_REG, val);
+	val |= FIELD_PREP(EVENT_COUNTER_ENABLE, enable ? PER_EVENT_ON : PER_EVENT_OFF);
+	dw_pcie_clear_and_set_dword(pci, rinfo->ras_cap_offset + RAS_DES_EVENT_COUNTER_CTRL_REG,
+				    0, val);
 
 	/*
 	 * While enabling the counter, always read the status back to check if
@@ -415,10 +408,9 @@ static ssize_t counter_lane_write(struct file *file, const char __user *buf,
 
 	mutex_lock(&rinfo->reg_event_lock);
 	set_event_number(pdata, pci, rinfo);
-	val = dw_pcie_readl_dbi(pci, rinfo->ras_cap_offset + RAS_DES_EVENT_COUNTER_CTRL_REG);
-	val &= ~(EVENT_COUNTER_LANE_SELECT);
-	val |= FIELD_PREP(EVENT_COUNTER_LANE_SELECT, lane);
-	dw_pcie_writel_dbi(pci, rinfo->ras_cap_offset + RAS_DES_EVENT_COUNTER_CTRL_REG, val);
+	dw_pcie_clear_and_set_dword(pci, rinfo->ras_cap_offset + RAS_DES_EVENT_COUNTER_CTRL_REG,
+				    EVENT_COUNTER_LANE_SELECT,
+				    FIELD_PREP(EVENT_COUNTER_LANE_SELECT, lane));
 	mutex_unlock(&rinfo->reg_event_lock);
 
 	return count;
@@ -654,20 +646,15 @@ static int dw_pcie_ptm_check_capability(void *drvdata)
 static int dw_pcie_ptm_context_update_write(void *drvdata, u8 mode)
 {
 	struct dw_pcie *pci = drvdata;
-	u32 val;
 
-	if (mode == PCIE_PTM_CONTEXT_UPDATE_AUTO) {
-		val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL);
-		val |= PTM_REQ_AUTO_UPDATE_ENABLED;
-		dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val);
-	} else if (mode == PCIE_PTM_CONTEXT_UPDATE_MANUAL) {
-		val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL);
-		val &= ~PTM_REQ_AUTO_UPDATE_ENABLED;
-		val |= PTM_REQ_START_UPDATE;
-		dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val);
-	} else {
+	if (mode == PCIE_PTM_CONTEXT_UPDATE_AUTO)
+		dw_pcie_clear_and_set_dword(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL,
+					    0, PTM_REQ_AUTO_UPDATE_ENABLED);
+	else if (mode == PCIE_PTM_CONTEXT_UPDATE_MANUAL)
+		dw_pcie_clear_and_set_dword(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL,
+					    PTM_REQ_AUTO_UPDATE_ENABLED, PTM_REQ_START_UPDATE);
+	else
 		return -EINVAL;
-	}
 
 	return 0;
 }
@@ -694,17 +681,13 @@ static int dw_pcie_ptm_context_update_read(void *drvdata, u8 *mode)
 static int dw_pcie_ptm_context_valid_write(void *drvdata, bool valid)
 {
 	struct dw_pcie *pci = drvdata;
-	u32 val;
 
-	if (valid) {
-		val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL);
-		val |= PTM_RES_CCONTEXT_VALID;
-		dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val);
-	} else {
-		val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL);
-		val &= ~PTM_RES_CCONTEXT_VALID;
-		dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val);
-	}
+	if (valid)
+		dw_pcie_clear_and_set_dword(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL,
+					    0, PTM_RES_CCONTEXT_VALID);
+	else
+		dw_pcie_clear_and_set_dword(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL,
+					    PTM_RES_CCONTEXT_VALID, 0);
 
 	return 0;
 }
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 0ae54a94809b..7e52892f632b 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -277,7 +277,7 @@ static int dw_pcie_ep_set_bar_resizable(struct dw_pcie_ep *ep, u8 func_no,
 	int flags = epf_bar->flags;
 	u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
 	unsigned int rebar_offset;
-	u32 rebar_cap, rebar_ctrl;
+	u32 rebar_cap;
 	int ret;
 
 	rebar_offset = dw_pcie_ep_get_rebar_offset(pci, bar);
@@ -310,9 +310,8 @@ static int dw_pcie_ep_set_bar_resizable(struct dw_pcie_ep *ep, u8 func_no,
 	 * 1 MB to 128 TB. Bits 31:16 in PCI_REBAR_CTRL define "supported sizes"
 	 * bits for sizes 256 TB to 8 EB. Disallow sizes 256 TB to 8 EB.
 	 */
-	rebar_ctrl = dw_pcie_readl_dbi(pci, rebar_offset + PCI_REBAR_CTRL);
-	rebar_ctrl &= ~GENMASK(31, 16);
-	dw_pcie_writel_dbi(pci, rebar_offset + PCI_REBAR_CTRL, rebar_ctrl);
+	dw_pcie_clear_and_set_dword(pci, rebar_offset + PCI_REBAR_CTRL,
+				    GENMASK(31, 16), 0);
 
 	/*
 	 * The "selected size" (bits 13:8) in PCI_REBAR_CTRL are automatically
@@ -925,7 +924,7 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
 	struct dw_pcie_ep_func *ep_func;
 	struct device *dev = pci->dev;
 	struct pci_epc *epc = ep->epc;
-	u32 ptm_cap_base, reg;
+	u32 ptm_cap_base;
 	u8 hdr_type;
 	u8 func_no;
 	void *addr;
@@ -1001,13 +1000,12 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
 	 */
 	if (ptm_cap_base) {
 		dw_pcie_dbi_ro_wr_en(pci);
-		reg = dw_pcie_readl_dbi(pci, ptm_cap_base + PCI_PTM_CAP);
-		reg &= ~PCI_PTM_CAP_ROOT;
-		dw_pcie_writel_dbi(pci, ptm_cap_base + PCI_PTM_CAP, reg);
+		dw_pcie_clear_and_set_dword(pci, ptm_cap_base + PCI_PTM_CAP,
+					    PCI_PTM_CAP_ROOT, 0);
 
-		reg = dw_pcie_readl_dbi(pci, ptm_cap_base + PCI_PTM_CAP);
-		reg &= ~(PCI_PTM_CAP_RES | PCI_PTM_GRANULARITY_MASK);
-		dw_pcie_writel_dbi(pci, ptm_cap_base + PCI_PTM_CAP, reg);
+		dw_pcie_clear_and_set_dword(pci, ptm_cap_base + PCI_PTM_CAP,
+					    PCI_PTM_CAP_RES |
+					    PCI_PTM_GRANULARITY_MASK, 0);
 		dw_pcie_dbi_ro_wr_dis(pci);
 	}
 
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 906277f9ffaf..e43d66d48439 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -909,7 +909,7 @@ static void dw_pcie_config_presets(struct dw_pcie_rp *pp)
 int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
 {
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-	u32 val, ctrl, num_ctrls;
+	u32 ctrl, num_ctrls;
 	int ret;
 
 	/*
@@ -941,23 +941,17 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
 	dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0x00000000);
 
 	/* Setup interrupt pins */
-	val = dw_pcie_readl_dbi(pci, PCI_INTERRUPT_LINE);
-	val &= 0xffff00ff;
-	val |= 0x00000100;
-	dw_pcie_writel_dbi(pci, PCI_INTERRUPT_LINE, val);
+	dw_pcie_clear_and_set_dword(pci, PCI_INTERRUPT_LINE,
+				    0x0000ff00, 0x00000100);
 
 	/* Setup bus numbers */
-	val = dw_pcie_readl_dbi(pci, PCI_PRIMARY_BUS);
-	val &= 0xff000000;
-	val |= 0x00ff0100;
-	dw_pcie_writel_dbi(pci, PCI_PRIMARY_BUS, val);
+	dw_pcie_clear_and_set_dword(pci, PCI_PRIMARY_BUS,
+				    0x00ffffff, 0x00ff0100);
 
 	/* Setup command register */
-	val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
-	val &= 0xffff0000;
-	val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-		PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
-	dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
+	dw_pcie_clear_and_set_dword(pci, PCI_COMMAND, 0x0000ffff,
+				    PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+				    PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
 
 	dw_pcie_config_presets(pp);
 	/*
@@ -976,9 +970,8 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
 	/* Program correct class for RC */
 	dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
 
-	val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
-	val |= PORT_LOGIC_SPEED_CHANGE;
-	dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
+	dw_pcie_clear_and_set_dword(pci, PCIE_LINK_WIDTH_SPEED_CONTROL,
+				    0, PORT_LOGIC_SPEED_CHANGE);
 
 	dw_pcie_dbi_ro_wr_dis(pci);
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 4d794964fa0f..d424e5e55c9f 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -740,11 +740,8 @@ EXPORT_SYMBOL_GPL(dw_pcie_link_up);
 
 void dw_pcie_upconfig_setup(struct dw_pcie *pci)
 {
-	u32 val;
-
-	val = dw_pcie_readl_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL);
-	val |= PORT_MLTI_UPCFG_SUPPORT;
-	dw_pcie_writel_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL, val);
+	dw_pcie_clear_and_set_dword(pci, PCIE_PORT_MULTI_LANE_CTRL,
+				    0, PORT_MLTI_UPCFG_SUPPORT);
 }
 EXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup);
 
@@ -805,21 +802,12 @@ int dw_pcie_link_get_max_link_width(struct dw_pcie *pci)
 
 static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes)
 {
-	u32 lnkcap, lwsc, plc;
+	u32 plc = 0;
 	u8 cap;
 
 	if (!num_lanes)
 		return;
 
-	/* Set the number of lanes */
-	plc = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
-	plc &= ~PORT_LINK_FAST_LINK_MODE;
-	plc &= ~PORT_LINK_MODE_MASK;
-
-	/* Set link width speed control register */
-	lwsc = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
-	lwsc &= ~PORT_LOGIC_LINK_WIDTH_MASK;
-	lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES;
 	switch (num_lanes) {
 	case 1:
 		plc |= PORT_LINK_MODE_1_LANES;
@@ -837,14 +825,19 @@ static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes)
 		dev_err(pci->dev, "num-lanes %u: invalid value\n", num_lanes);
 		return;
 	}
-	dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, plc);
-	dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, lwsc);
+	/* Set the number of lanes */
+	dw_pcie_clear_and_set_dword(pci, PCIE_PORT_LINK_CONTROL,
+				    PORT_LINK_FAST_LINK_MODE | PORT_LINK_MODE_MASK,
+				    plc);
+	/* Set link width speed control register */
+	dw_pcie_clear_and_set_dword(pci, PCIE_LINK_WIDTH_SPEED_CONTROL,
+				    PORT_LOGIC_LINK_WIDTH_MASK,
+				    PORT_LOGIC_LINK_WIDTH_1_LANES);
 
 	cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
-	lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
-	lnkcap &= ~PCI_EXP_LNKCAP_MLW;
-	lnkcap |= FIELD_PREP(PCI_EXP_LNKCAP_MLW, num_lanes);
-	dw_pcie_writel_dbi(pci, cap + PCI_EXP_LNKCAP, lnkcap);
+	dw_pcie_clear_and_set_dword(pci, cap + PCI_EXP_LNKCAP,
+				    PCI_EXP_LNKCAP_MLW,
+				    FIELD_PREP(PCI_EXP_LNKCAP_MLW, num_lanes));
 }
 
 void dw_pcie_iatu_detect(struct dw_pcie *pci)
@@ -1133,38 +1126,27 @@ void dw_pcie_edma_remove(struct dw_pcie *pci)
 
 void dw_pcie_setup(struct dw_pcie *pci)
 {
-	u32 val;
-
 	dw_pcie_link_set_max_speed(pci);
 
 	/* Configure Gen1 N_FTS */
-	if (pci->n_fts[0]) {
-		val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
-		val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK);
-		val |= PORT_AFR_N_FTS(pci->n_fts[0]);
-		val |= PORT_AFR_CC_N_FTS(pci->n_fts[0]);
-		dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
-	}
+	if (pci->n_fts[0])
+		dw_pcie_clear_and_set_dword(pci, PCIE_PORT_AFR,
+					    PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK,
+					    PORT_AFR_N_FTS(pci->n_fts[0]) |
+					    PORT_AFR_CC_N_FTS(pci->n_fts[0]));
 
 	/* Configure Gen2+ N_FTS */
-	if (pci->n_fts[1]) {
-		val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
-		val &= ~PORT_LOGIC_N_FTS_MASK;
-		val |= pci->n_fts[1];
-		dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
-	}
+	if (pci->n_fts[1])
+		dw_pcie_clear_and_set_dword(pci, PCIE_LINK_WIDTH_SPEED_CONTROL,
+					    PORT_LOGIC_N_FTS_MASK, pci->n_fts[1]);
 
-	if (dw_pcie_cap_is(pci, CDM_CHECK)) {
-		val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
-		val |= PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS |
-		       PCIE_PL_CHK_REG_CHK_REG_START;
-		dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);
-	}
+	if (dw_pcie_cap_is(pci, CDM_CHECK))
+		dw_pcie_clear_and_set_dword(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, 0,
+					    PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS |
+					    PCIE_PL_CHK_REG_CHK_REG_START);
 
-	val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
-	val &= ~PORT_LINK_FAST_LINK_MODE;
-	val |= PORT_LINK_DLL_LINK_EN;
-	dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
+	dw_pcie_clear_and_set_dword(pci, PCIE_PORT_LINK_CONTROL,
+				    PORT_LINK_FAST_LINK_MODE, PORT_LINK_DLL_LINK_EN);
 
 	dw_pcie_link_set_max_link_width(pci, pci->num_lanes);
 }
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index f401c144df0f..5a0aa154eb2a 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -720,24 +720,14 @@ static inline void dw_pcie_clear_and_set_dword(struct dw_pcie *pci, int pos,
 
 static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
 {
-	u32 reg;
-	u32 val;
-
-	reg = PCIE_MISC_CONTROL_1_OFF;
-	val = dw_pcie_readl_dbi(pci, reg);
-	val |= PCIE_DBI_RO_WR_EN;
-	dw_pcie_writel_dbi(pci, reg, val);
+	dw_pcie_clear_and_set_dword(pci, PCIE_MISC_CONTROL_1_OFF,
+				    0, PCIE_DBI_RO_WR_EN);
 }
 
 static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
 {
-	u32 reg;
-	u32 val;
-
-	reg = PCIE_MISC_CONTROL_1_OFF;
-	val = dw_pcie_readl_dbi(pci, reg);
-	val &= ~PCIE_DBI_RO_WR_EN;
-	dw_pcie_writel_dbi(pci, reg, val);
+	dw_pcie_clear_and_set_dword(pci, PCIE_MISC_CONTROL_1_OFF,
+				    PCIE_DBI_RO_WR_EN, 0);
 }
 
 static inline int dw_pcie_start_link(struct dw_pcie *pci)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 03/13] PCI: dra7xx: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 01/13] PCI: dwc: Add dw_pcie_clear_and_set_dword() for register bit manipulation Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 02/13] PCI: dwc: Refactor code by using dw_pcie_clear_and_set_dword() Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 04/13] PCI: imx6: " Hans Zhang
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

The dra7xx PCIe driver implements suspend/resume handling through
direct register manipulation. The current approach uses explicit
read-modify-write sequences to control the MEMORY enable bit in the
PCI_COMMAND register, declaring local variables for temporary storage.

Replace manual bit manipulation with dw_pcie_clear_and_set_dword()
during suspend and resume operations. This eliminates redundant variable
declarations and simplifies the power management flow by handling bit
operations within a single function call.

Using the centralized helper improves code readability and aligns the
driver with standard DesignWare register access patterns. The change also
reduces the risk of bit manipulation errors in future modifications to the
power management logic.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pci-dra7xx.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
index f97f5266d196..9cbba1b28882 100644
--- a/drivers/pci/controller/dwc/pci-dra7xx.c
+++ b/drivers/pci/controller/dwc/pci-dra7xx.c
@@ -867,15 +867,12 @@ static int dra7xx_pcie_suspend(struct device *dev)
 {
 	struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
 	struct dw_pcie *pci = dra7xx->pci;
-	u32 val;
 
 	if (dra7xx->mode != DW_PCIE_RC_TYPE)
 		return 0;
 
 	/* clear MSE */
-	val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
-	val &= ~PCI_COMMAND_MEMORY;
-	dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
+	dw_pcie_clear_and_set_dword(pci, PCI_COMMAND, PCI_COMMAND_MEMORY, 0);
 
 	return 0;
 }
@@ -884,15 +881,12 @@ static int dra7xx_pcie_resume(struct device *dev)
 {
 	struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
 	struct dw_pcie *pci = dra7xx->pci;
-	u32 val;
 
 	if (dra7xx->mode != DW_PCIE_RC_TYPE)
 		return 0;
 
 	/* set MSE */
-	val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
-	val |= PCI_COMMAND_MEMORY;
-	dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
+	dw_pcie_clear_and_set_dword(pci, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
 
 	return 0;
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 04/13] PCI: imx6: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
                   ` (2 preceding siblings ...)
  2025-06-18 15:21 ` [PATCH v2 03/13] PCI: dra7xx: " Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-19 15:16   ` Frank Li
  2025-06-18 15:21 ` [PATCH v2 05/13] PCI: meson: " Hans Zhang
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

i.MX6 PCIe driver contains multiple read-modify-write sequences for
link training and speed configuration. These operations manually handle
bit masking and shifting to update specific fields in control registers,
particularly for link capabilities and speed change initiation.

Refactor link capability configuration and speed change handling using
dw_pcie_clear_and_set_dword(). The helper simplifies LNKCAP modification
by encapsulating bit clear/set operations and eliminates intermediate
variables. For speed change control, replace explicit bit manipulation
with direct register updates through the helper.

Adopting the standard interface reduces code complexity in link training
paths and ensures consistent handling of speed-related bits. The change
also prepares the driver for future enhancements to Gen3 link training
by centralizing bit manipulation logic.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pci-imx6.c | 26 ++++++++++----------------
 1 file changed, 10 insertions(+), 16 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 5a38cfaf989b..3004e432f013 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -941,7 +941,6 @@ static int imx_pcie_start_link(struct dw_pcie *pci)
 	struct imx_pcie *imx_pcie = to_imx_pcie(pci);
 	struct device *dev = pci->dev;
 	u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
-	u32 tmp;
 	int ret;
 
 	if (!(imx_pcie->drvdata->flags &
@@ -956,10 +955,9 @@ static int imx_pcie_start_link(struct dw_pcie *pci)
 	 * bus will not be detected at all.  This happens with PCIe switches.
 	 */
 	dw_pcie_dbi_ro_wr_en(pci);
-	tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
-	tmp &= ~PCI_EXP_LNKCAP_SLS;
-	tmp |= PCI_EXP_LNKCAP_SLS_2_5GB;
-	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp);
+	dw_pcie_clear_and_set_dword(pci, offset + PCI_EXP_LNKCAP,
+				    PCI_EXP_LNKCAP_SLS,
+				    PCI_EXP_LNKCAP_SLS_2_5GB);
 	dw_pcie_dbi_ro_wr_dis(pci);
 
 	/* Start LTSSM. */
@@ -972,18 +970,16 @@ static int imx_pcie_start_link(struct dw_pcie *pci)
 
 		/* Allow faster modes after the link is up */
 		dw_pcie_dbi_ro_wr_en(pci);
-		tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
-		tmp &= ~PCI_EXP_LNKCAP_SLS;
-		tmp |= pci->max_link_speed;
-		dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp);
+		dw_pcie_clear_and_set_dword(pci, offset + PCI_EXP_LNKCAP,
+					    PCI_EXP_LNKCAP_SLS,
+					    pci->max_link_speed);
 
 		/*
 		 * Start Directed Speed Change so the best possible
 		 * speed both link partners support can be negotiated.
 		 */
-		tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
-		tmp |= PORT_LOGIC_SPEED_CHANGE;
-		dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
+		dw_pcie_clear_and_set_dword(pci, PCIE_LINK_WIDTH_SPEED_CONTROL,
+					    0, PORT_LOGIC_SPEED_CHANGE);
 		dw_pcie_dbi_ro_wr_dis(pci);
 
 		ret = imx_pcie_wait_for_speed_change(imx_pcie);
@@ -1295,7 +1291,6 @@ static void imx_pcie_host_post_init(struct dw_pcie_rp *pp)
 {
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 	struct imx_pcie *imx_pcie = to_imx_pcie(pci);
-	u32 val;
 
 	if (imx_pcie->drvdata->flags & IMX_PCIE_FLAG_8GT_ECN_ERR051586) {
 		/*
@@ -1310,9 +1305,8 @@ static void imx_pcie_host_post_init(struct dw_pcie_rp *pp)
 		 * to 0.
 		 */
 		dw_pcie_dbi_ro_wr_en(pci);
-		val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
-		val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
-		dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
+		dw_pcie_clear_and_set_dword(pci, GEN3_RELATED_OFF,
+					    GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL, 0);
 		dw_pcie_dbi_ro_wr_dis(pci);
 	}
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 05/13] PCI: meson: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
                   ` (3 preceding siblings ...)
  2025-06-18 15:21 ` [PATCH v2 04/13] PCI: imx6: " Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 06/13] PCI: armada8k: " Hans Zhang
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

Meson PCIe driver implements payload size configuration through manual
register manipulation. The current code reads device control registers,
modifies specific bitfields for maximum payload and read request sizes,
then writes back the updated values. This pattern repeats twice with
similar logic but different bit masks.

Replace explicit bit manipulation with dw_pcie_clear_and_set_dword() for
payload and read request size configuration. The helper consolidates
read-clear-set-write operations into a single call, eliminating redundant
register read operations and local variable usage.

This refactoring reduces code duplication in size configuration logic
and improves maintainability. By using the DesignWare helper, the driver
aligns with standard PCIe controller programming patterns and simplifies
future updates to device capability settings.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pci-meson.c | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
index 787469d1b396..cd6280a8e619 100644
--- a/drivers/pci/controller/dwc/pci-meson.c
+++ b/drivers/pci/controller/dwc/pci-meson.c
@@ -264,33 +264,27 @@ static int meson_size_to_payload(struct meson_pcie *mp, int size)
 static void meson_set_max_payload(struct meson_pcie *mp, int size)
 {
 	struct dw_pcie *pci = &mp->pci;
-	u32 val;
 	u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
 	int max_payload_size = meson_size_to_payload(mp, size);
 
-	val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
-	val &= ~PCI_EXP_DEVCTL_PAYLOAD;
-	dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
+	dw_pcie_clear_and_set_dword(pci, offset + PCI_EXP_DEVCTL,
+				    PCI_EXP_DEVCTL_PAYLOAD, 0);
 
-	val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
-	val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
-	dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
+	dw_pcie_clear_and_set_dword(pci, offset + PCI_EXP_DEVCTL, 0,
+				    PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size));
 }
 
 static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
 {
 	struct dw_pcie *pci = &mp->pci;
-	u32 val;
 	u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
 	int max_rd_req_size = meson_size_to_payload(mp, size);
 
-	val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
-	val &= ~PCI_EXP_DEVCTL_READRQ;
-	dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
+	dw_pcie_clear_and_set_dword(pci, offset + PCI_EXP_DEVCTL,
+				    PCI_EXP_DEVCTL_READRQ, 0);
 
-	val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
-	val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
-	dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
+	dw_pcie_clear_and_set_dword(pci, offset + PCI_EXP_DEVCTL, 0,
+				    PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size));
 }
 
 static int meson_pcie_start_link(struct dw_pcie *pci)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 06/13] PCI: armada8k: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
                   ` (4 preceding siblings ...)
  2025-06-18 15:21 ` [PATCH v2 05/13] PCI: meson: " Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 07/13] PCI: bt1: " Hans Zhang
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

Armada8k PCIe driver uses explicit bitwise operations for global control
register configuration. The driver manually handles bit masking and
shifting for multiple fields including device type, domain attributes,
and interrupt masking. This approach requires repetitive read-modify-write
sequences and temporary variables.

Refactor global control setup, domain attribute configuration, and
interrupt masking using dw_pcie_clear_and_set_dword(). The helper replaces
manual bit manipulation with declarative bit masks, directly specifying
which bits to clear and set. This eliminates intermediate variables and
reduces code complexity.

Standardizing on the helper improves code clarity in initialization paths
and ensures consistent handling of control register bits. The change also
centralizes bit manipulation logic, reducing the risk of errors in future
modifications to device configuration.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pcie-armada8k.c | 48 ++++++++--------------
 1 file changed, 18 insertions(+), 30 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c
index c2650fd0d458..67348307aa28 100644
--- a/drivers/pci/controller/dwc/pcie-armada8k.c
+++ b/drivers/pci/controller/dwc/pcie-armada8k.c
@@ -155,54 +155,44 @@ static bool armada8k_pcie_link_up(struct dw_pcie *pci)
 
 static int armada8k_pcie_start_link(struct dw_pcie *pci)
 {
-	u32 reg;
-
 	/* Start LTSSM */
-	reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
-	reg |= PCIE_APP_LTSSM_EN;
-	dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg);
+	dw_pcie_clear_and_set_dword(pci, PCIE_GLOBAL_CONTROL_REG,
+				    0, PCIE_APP_LTSSM_EN);
 
 	return 0;
 }
 
 static int armada8k_pcie_host_init(struct dw_pcie_rp *pp)
 {
-	u32 reg;
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
-	if (!dw_pcie_link_up(pci)) {
+	if (!dw_pcie_link_up(pci))
 		/* Disable LTSSM state machine to enable configuration */
-		reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
-		reg &= ~(PCIE_APP_LTSSM_EN);
-		dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg);
-	}
+		dw_pcie_clear_and_set_dword(pci, PCIE_GLOBAL_CONTROL_REG,
+					    PCIE_APP_LTSSM_EN, 0);
 
 	/* Set the device to root complex mode */
-	reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
-	reg &= ~(PCIE_DEVICE_TYPE_MASK << PCIE_DEVICE_TYPE_SHIFT);
-	reg |= PCIE_DEVICE_TYPE_RC << PCIE_DEVICE_TYPE_SHIFT;
-	dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg);
+	dw_pcie_clear_and_set_dword(pci, PCIE_GLOBAL_CONTROL_REG,
+				    PCIE_DEVICE_TYPE_MASK << PCIE_DEVICE_TYPE_SHIFT,
+				    PCIE_DEVICE_TYPE_RC << PCIE_DEVICE_TYPE_SHIFT);
 
 	/* Set the PCIe master AxCache attributes */
 	dw_pcie_writel_dbi(pci, PCIE_ARCACHE_TRC_REG, ARCACHE_DEFAULT_VALUE);
 	dw_pcie_writel_dbi(pci, PCIE_AWCACHE_TRC_REG, AWCACHE_DEFAULT_VALUE);
 
 	/* Set the PCIe master AxDomain attributes */
-	reg = dw_pcie_readl_dbi(pci, PCIE_ARUSER_REG);
-	reg &= ~(AX_USER_DOMAIN_MASK << AX_USER_DOMAIN_SHIFT);
-	reg |= DOMAIN_OUTER_SHAREABLE << AX_USER_DOMAIN_SHIFT;
-	dw_pcie_writel_dbi(pci, PCIE_ARUSER_REG, reg);
+	dw_pcie_clear_and_set_dword(pci, PCIE_ARUSER_REG,
+				    AX_USER_DOMAIN_MASK << AX_USER_DOMAIN_SHIFT,
+				    DOMAIN_OUTER_SHAREABLE << AX_USER_DOMAIN_SHIFT);
 
-	reg = dw_pcie_readl_dbi(pci, PCIE_AWUSER_REG);
-	reg &= ~(AX_USER_DOMAIN_MASK << AX_USER_DOMAIN_SHIFT);
-	reg |= DOMAIN_OUTER_SHAREABLE << AX_USER_DOMAIN_SHIFT;
-	dw_pcie_writel_dbi(pci, PCIE_AWUSER_REG, reg);
+	dw_pcie_clear_and_set_dword(pci, PCIE_AWUSER_REG,
+				    AX_USER_DOMAIN_MASK << AX_USER_DOMAIN_SHIFT,
+				    DOMAIN_OUTER_SHAREABLE << AX_USER_DOMAIN_SHIFT);
 
 	/* Enable INT A-D interrupts */
-	reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_INT_MASK1_REG);
-	reg |= PCIE_INT_A_ASSERT_MASK | PCIE_INT_B_ASSERT_MASK |
-	       PCIE_INT_C_ASSERT_MASK | PCIE_INT_D_ASSERT_MASK;
-	dw_pcie_writel_dbi(pci, PCIE_GLOBAL_INT_MASK1_REG, reg);
+	dw_pcie_clear_and_set_dword(pci, PCIE_GLOBAL_INT_MASK1_REG, 0,
+				    PCIE_INT_A_ASSERT_MASK | PCIE_INT_B_ASSERT_MASK |
+				    PCIE_INT_C_ASSERT_MASK | PCIE_INT_D_ASSERT_MASK);
 
 	return 0;
 }
@@ -211,15 +201,13 @@ static irqreturn_t armada8k_pcie_irq_handler(int irq, void *arg)
 {
 	struct armada8k_pcie *pcie = arg;
 	struct dw_pcie *pci = pcie->pci;
-	u32 val;
 
 	/*
 	 * Interrupts are directly handled by the device driver of the
 	 * PCI device. However, they are also latched into the PCIe
 	 * controller, so we simply discard them.
 	 */
-	val = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_INT_CAUSE1_REG);
-	dw_pcie_writel_dbi(pci, PCIE_GLOBAL_INT_CAUSE1_REG, val);
+	dw_pcie_clear_and_set_dword(pci, PCIE_GLOBAL_INT_CAUSE1_REG, 0, 0);
 
 	return IRQ_HANDLED;
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 07/13] PCI: bt1: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
                   ` (5 preceding siblings ...)
  2025-06-18 15:21 ` [PATCH v2 06/13] PCI: armada8k: " Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 08/13] PCI: dw-rockchip: " Hans Zhang
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

Baikal-T1 PCIe driver contains a direct register write to initiate
speed change during link training. The current implementation sets
the PORT_LOGIC_SPEED_CHANGE bit via read-modify-write without using
the standard bit manipulation helper.

Replace manual bit set operation with dw_pcie_clear_and_set_dword() to
enable speed change. The helper clearly expresses the intent to modify
a specific bit while preserving others, eliminating the need for explicit
read-before-write.

Using the standardized interface improves consistency with other
DesignWare drivers and reduces the risk of unintended bit modifications.
The change also simplifies future updates to link training logic.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pcie-bt1.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-bt1.c b/drivers/pci/controller/dwc/pcie-bt1.c
index 1340edc18d12..7cbaeeed033d 100644
--- a/drivers/pci/controller/dwc/pcie-bt1.c
+++ b/drivers/pci/controller/dwc/pcie-bt1.c
@@ -289,9 +289,8 @@ static int bt1_pcie_start_link(struct dw_pcie *pci)
 	 * attempt to reach a higher bus performance (up to Gen.3 - 8.0 GT/s).
 	 * This is required at least to get 8.0 GT/s speed.
 	 */
-	val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
-	val |= PORT_LOGIC_SPEED_CHANGE;
-	dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
+	dw_pcie_clear_and_set_dword(pci, PCIE_LINK_WIDTH_SPEED_CONTROL,
+				    0, PORT_LOGIC_SPEED_CHANGE);
 
 	ret = regmap_read_poll_timeout(btpci->sys_regs, BT1_CCU_PCIE_PMSC, val,
 				       BT1_CCU_PCIE_LTSSM_LINKUP(val),
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 08/13] PCI: dw-rockchip: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
                   ` (6 preceding siblings ...)
  2025-06-18 15:21 ` [PATCH v2 07/13] PCI: bt1: " Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 09/13] PCI: fu740: " Hans Zhang
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

Rockchip PCIe driver implements L0s capability enablement through
explicit register read-modify-write. The current approach reads the
LNKCAP register, modifies the ASPM_L0S bit, then writes back the
value with DBI write protection handling.

Refactor ASPM capability configuration using
dw_pcie_clear_and_set_dword(). The helper combines bit manipulation with
DBI protection in a single call, replacing three-step manual operations.
This simplifies the capability setup flow and reduces code complexity.

Adopting the standard helper improves maintainability by eliminating
local variables and explicit bitwise operations. The change also ensures
consistent handling of DBI write protection across capability modification
functions.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 93171a392879..e6bd9c54b164 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -194,15 +194,14 @@ static bool rockchip_pcie_link_up(struct dw_pcie *pci)
 
 static void rockchip_pcie_enable_l0s(struct dw_pcie *pci)
 {
-	u32 cap, lnkcap;
+	u32 cap;
 
 	/* Enable L0S capability for all SoCs */
 	cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
 	if (cap) {
-		lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
-		lnkcap |= PCI_EXP_LNKCAP_ASPM_L0S;
 		dw_pcie_dbi_ro_wr_en(pci);
-		dw_pcie_writel_dbi(pci, cap + PCI_EXP_LNKCAP, lnkcap);
+		dw_pcie_clear_and_set_dword(pci, cap + PCI_EXP_LNKCAP,
+					    0, PCI_EXP_LNKCAP_ASPM_L0S);
 		dw_pcie_dbi_ro_wr_dis(pci);
 	}
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 09/13] PCI: fu740: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
                   ` (7 preceding siblings ...)
  2025-06-18 15:21 ` [PATCH v2 08/13] PCI: dw-rockchip: " Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 10/13] PCI: qcom: " Hans Zhang
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

SiFive FU740 PCIe driver uses direct register write to initiate link speed
change after setting target link capabilities. The current implementation
sets PORT_LOGIC_SPEED_CHANGE bit via explicit read-modify-write sequence.

Replace manual bit manipulation with dw_pcie_clear_and_set_dword() for
speed change initiation. The helper encapsulates read-modify-write
operations while providing clear intent through "clear 0, set BIT" usage.

This refactoring aligns the driver with standard DesignWare programming
patterns and reduces code complexity. The change also ensures consistent
handling of speed change initiation across all DesignWare base
controllers.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pcie-fu740.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-fu740.c b/drivers/pci/controller/dwc/pcie-fu740.c
index 66367252032b..8210ff1fd91e 100644
--- a/drivers/pci/controller/dwc/pcie-fu740.c
+++ b/drivers/pci/controller/dwc/pcie-fu740.c
@@ -216,9 +216,8 @@ static int fu740_pcie_start_link(struct dw_pcie *pci)
 		tmp |= orig;
 		dw_pcie_writel_dbi(pci, cap_exp + PCI_EXP_LNKCAP, tmp);
 
-		tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
-		tmp |= PORT_LOGIC_SPEED_CHANGE;
-		dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
+		dw_pcie_clear_and_set_dword(pci, PCIE_LINK_WIDTH_SPEED_CONTROL,
+					    0, PORT_LOGIC_SPEED_CHANGE);
 
 		ret = dw_pcie_wait_for_link(pci);
 		if (ret) {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 10/13] PCI: qcom: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
                   ` (8 preceding siblings ...)
  2025-06-18 15:21 ` [PATCH v2 09/13] PCI: fu740: " Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 11/13] PCI: qcom-ep: " Hans Zhang
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

Qcom PCIe common code contains complex bit manipulation for 16GT/s
equalization and lane margining configuration. These functions use
multiple read-modify-write sequences with manual bit masking and
field preparation, leading to verbose and error-prone code.

Refactor equalization and lane margining setup using
dw_pcie_clear_and_set_dword(). The helper simplifies multi-field
configuration by combining clear and set operations in a single call.
Initialize local variables to zero before field insertion to ensure
unused bits are cleared appropriately.

This change reduces code complexity by ~40% in affected functions
while improving readability. Centralizing bit manipulation ensures
consistent handling of register fields across Qcom PCIe implementations
and provides a solid foundation for future 16GT/s enhancements.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pcie-qcom-common.c | 59 +++++++++----------
 1 file changed, 29 insertions(+), 30 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-qcom-common.c b/drivers/pci/controller/dwc/pcie-qcom-common.c
index 3aad19b56da8..8ea521147b7e 100644
--- a/drivers/pci/controller/dwc/pcie-qcom-common.c
+++ b/drivers/pci/controller/dwc/pcie-qcom-common.c
@@ -10,7 +10,7 @@
 
 void qcom_pcie_common_set_16gt_equalization(struct dw_pcie *pci)
 {
-	u32 reg;
+	u32 reg = 0;
 
 	/*
 	 * GEN3_RELATED_OFF register is repurposed to apply equalization
@@ -19,60 +19,59 @@ void qcom_pcie_common_set_16gt_equalization(struct dw_pcie *pci)
 	 * determines the data rate for which these equalization settings are
 	 * applied.
 	 */
-	reg = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
-	reg &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
-	reg &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
 	reg |= FIELD_PREP(GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK,
 			  GEN3_RELATED_OFF_RATE_SHADOW_SEL_16_0GT);
-	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, reg);
+	dw_pcie_clear_and_set_dword(pci, GEN3_RELATED_OFF,
+				    GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL |
+				    GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK,
+				    reg);
 
-	reg = dw_pcie_readl_dbi(pci, GEN3_EQ_FB_MODE_DIR_CHANGE_OFF);
-	reg &= ~(GEN3_EQ_FMDC_T_MIN_PHASE23 |
-		GEN3_EQ_FMDC_N_EVALS |
-		GEN3_EQ_FMDC_MAX_PRE_CUSROR_DELTA |
-		GEN3_EQ_FMDC_MAX_POST_CUSROR_DELTA);
+	reg = 0;
 	reg |= FIELD_PREP(GEN3_EQ_FMDC_T_MIN_PHASE23, 0x1) |
 		FIELD_PREP(GEN3_EQ_FMDC_N_EVALS, 0xd) |
 		FIELD_PREP(GEN3_EQ_FMDC_MAX_PRE_CUSROR_DELTA, 0x5) |
 		FIELD_PREP(GEN3_EQ_FMDC_MAX_POST_CUSROR_DELTA, 0x5);
-	dw_pcie_writel_dbi(pci, GEN3_EQ_FB_MODE_DIR_CHANGE_OFF, reg);
+	dw_pcie_clear_and_set_dword(pci, GEN3_EQ_FB_MODE_DIR_CHANGE_OFF,
+				    GEN3_EQ_FMDC_T_MIN_PHASE23 |
+				    GEN3_EQ_FMDC_N_EVALS |
+				    GEN3_EQ_FMDC_MAX_PRE_CUSROR_DELTA |
+				    GEN3_EQ_FMDC_MAX_POST_CUSROR_DELTA,
+				    reg);
 
-	reg = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
-	reg &= ~(GEN3_EQ_CONTROL_OFF_FB_MODE |
-		GEN3_EQ_CONTROL_OFF_PHASE23_EXIT_MODE |
-		GEN3_EQ_CONTROL_OFF_FOM_INC_INITIAL_EVAL |
-		GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
-	dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, reg);
+	dw_pcie_clear_and_set_dword(pci, GEN3_EQ_CONTROL_OFF,
+				    GEN3_EQ_CONTROL_OFF_FB_MODE |
+				    GEN3_EQ_CONTROL_OFF_PHASE23_EXIT_MODE |
+				    GEN3_EQ_CONTROL_OFF_FOM_INC_INITIAL_EVAL |
+				    GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC, 0);
 }
 EXPORT_SYMBOL_GPL(qcom_pcie_common_set_16gt_equalization);
 
 void qcom_pcie_common_set_16gt_lane_margining(struct dw_pcie *pci)
 {
-	u32 reg;
+	u32 reg = 0;
 
-	reg = dw_pcie_readl_dbi(pci, GEN4_LANE_MARGINING_1_OFF);
-	reg &= ~(MARGINING_MAX_VOLTAGE_OFFSET |
-		MARGINING_NUM_VOLTAGE_STEPS |
-		MARGINING_MAX_TIMING_OFFSET |
-		MARGINING_NUM_TIMING_STEPS);
 	reg |= FIELD_PREP(MARGINING_MAX_VOLTAGE_OFFSET, 0x24) |
 		FIELD_PREP(MARGINING_NUM_VOLTAGE_STEPS, 0x78) |
 		FIELD_PREP(MARGINING_MAX_TIMING_OFFSET, 0x32) |
 		FIELD_PREP(MARGINING_NUM_TIMING_STEPS, 0x10);
-	dw_pcie_writel_dbi(pci, GEN4_LANE_MARGINING_1_OFF, reg);
+	dw_pcie_clear_and_set_dword(pci, GEN4_LANE_MARGINING_1_OFF,
+				    MARGINING_MAX_VOLTAGE_OFFSET |
+				    MARGINING_NUM_VOLTAGE_STEPS |
+				    MARGINING_MAX_TIMING_OFFSET |
+				    MARGINING_NUM_TIMING_STEPS, reg);
 
-	reg = dw_pcie_readl_dbi(pci, GEN4_LANE_MARGINING_2_OFF);
+	reg = 0;
 	reg |= MARGINING_IND_ERROR_SAMPLER |
 		MARGINING_SAMPLE_REPORTING_METHOD |
 		MARGINING_IND_LEFT_RIGHT_TIMING |
 		MARGINING_VOLTAGE_SUPPORTED;
-	reg &= ~(MARGINING_IND_UP_DOWN_VOLTAGE |
-		MARGINING_MAXLANES |
-		MARGINING_SAMPLE_RATE_TIMING |
-		MARGINING_SAMPLE_RATE_VOLTAGE);
 	reg |= FIELD_PREP(MARGINING_MAXLANES, pci->num_lanes) |
 		FIELD_PREP(MARGINING_SAMPLE_RATE_TIMING, 0x3f) |
 		FIELD_PREP(MARGINING_SAMPLE_RATE_VOLTAGE, 0x3f);
-	dw_pcie_writel_dbi(pci, GEN4_LANE_MARGINING_2_OFF, reg);
+	dw_pcie_clear_and_set_dword(pci, GEN4_LANE_MARGINING_2_OFF,
+				    MARGINING_IND_UP_DOWN_VOLTAGE |
+				    MARGINING_MAXLANES |
+				    MARGINING_SAMPLE_RATE_TIMING |
+				    MARGINING_SAMPLE_RATE_VOLTAGE, reg);
 }
 EXPORT_SYMBOL_GPL(qcom_pcie_common_set_16gt_lane_margining);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 11/13] PCI: qcom-ep: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
                   ` (9 preceding siblings ...)
  2025-06-18 15:21 ` [PATCH v2 10/13] PCI: qcom: " Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 12/13] PCI: rcar-gen4: " Hans Zhang
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

Qcom PCIe endpoint driver implements L0s/L1 latency configuration through
manual register manipulation. The current approach reads LNKCAP register,
modifies specific latency fields, then writes back the value. This pattern
repeats twice with similar logic but different bit masks.

Replace explicit latency configuration with dw_pcie_clear_and_set_dword().
The helper combines field clearing and setting in a single operation,
replacing three-step manual sequences. Initialize the set value with
FIELD_PREP() to clearly express the intended bitfield value.

This refactoring reduces code duplication in latency configuration paths
and improves maintainability. Using the standard helper ensures consistent
handling of capability registers and simplifies future updates to ASPM
settings.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pcie-qcom-ep.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c
index bf7c6ac0f3e3..c2b4f172385d 100644
--- a/drivers/pci/controller/dwc/pcie-qcom-ep.c
+++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c
@@ -475,17 +475,15 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci)
 
 	/* Set the L0s Exit Latency to 2us-4us = 0x6 */
 	offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
-	val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
-	val &= ~PCI_EXP_LNKCAP_L0SEL;
-	val |= FIELD_PREP(PCI_EXP_LNKCAP_L0SEL, 0x6);
-	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, val);
+	dw_pcie_clear_and_set_dword(pci, offset + PCI_EXP_LNKCAP,
+				    PCI_EXP_LNKCAP_L0SEL,
+				    FIELD_PREP(PCI_EXP_LNKCAP_L0SEL, 0x6));
 
 	/* Set the L1 Exit Latency to be 32us-64 us = 0x6 */
 	offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
-	val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
-	val &= ~PCI_EXP_LNKCAP_L1EL;
-	val |= FIELD_PREP(PCI_EXP_LNKCAP_L1EL, 0x6);
-	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, val);
+	dw_pcie_clear_and_set_dword(pci, offset + PCI_EXP_LNKCAP,
+				    PCI_EXP_LNKCAP_L1EL,
+				    FIELD_PREP(PCI_EXP_LNKCAP_L1EL, 0x6));
 
 	dw_pcie_dbi_ro_wr_dis(pci);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 12/13] PCI: rcar-gen4: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
                   ` (10 preceding siblings ...)
  2025-06-18 15:21 ` [PATCH v2 11/13] PCI: qcom-ep: " Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-18 15:21 ` [PATCH v2 13/13] PCI: tegra194: " Hans Zhang
  2025-06-25 21:00 ` [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Manivannan Sadhasivam
  13 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

R-Car Gen4 PCIe driver contains multiple read-modify-write sequences for
speed change control and lane configuration. The driver manually handles
speed change initiation through bit set/clear operations and configures
lane skew with explicit bit masking.

Refactor speed change handling and lane skew configuration using
dw_pcie_clear_and_set_dword(). For speed change operations, replace
manual bit toggling with clear-and-set sequences. For lane skew, use
the helper to conditionally set bits based on lane count.

Adopting the standard interface simplifies link training logic and
reduces code complexity. The change also ensures consistent handling
of control register bits and provides better documentation of intent
through declarative bit masks.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pcie-rcar-gen4.c | 23 ++++++++-------------
 1 file changed, 9 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 18055807a4f5..20a6c88252d6 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -107,13 +107,11 @@ static int rcar_gen4_pcie_speed_change(struct dw_pcie *dw)
 	u32 val;
 	int i;
 
-	val = dw_pcie_readl_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL);
-	val &= ~PORT_LOGIC_SPEED_CHANGE;
-	dw_pcie_writel_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
+	dw_pcie_clear_and_set_dword(dw, PCIE_LINK_WIDTH_SPEED_CONTROL,
+				    PORT_LOGIC_SPEED_CHANGE, 0);
 
-	val = dw_pcie_readl_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL);
-	val |= PORT_LOGIC_SPEED_CHANGE;
-	dw_pcie_writel_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
+	dw_pcie_clear_and_set_dword(dw, PCIE_LINK_WIDTH_SPEED_CONTROL,
+				    0, PORT_LOGIC_SPEED_CHANGE);
 
 	for (i = 0; i < RCAR_NUM_SPEED_CHANGE_RETRIES; i++) {
 		val = dw_pcie_readl_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL);
@@ -565,11 +563,9 @@ static void rcar_gen4_pcie_additional_common_init(struct rcar_gen4_pcie *rcar)
 	struct dw_pcie *dw = &rcar->dw;
 	u32 val;
 
-	val = dw_pcie_readl_dbi(dw, PCIE_PORT_LANE_SKEW);
-	val &= ~PORT_LANE_SKEW_INSERT_MASK;
-	if (dw->num_lanes < 4)
-		val |= BIT(6);
-	dw_pcie_writel_dbi(dw, PCIE_PORT_LANE_SKEW, val);
+	dw_pcie_clear_and_set_dword(dw, PCIE_PORT_LANE_SKEW,
+				    PORT_LANE_SKEW_INSERT_MASK,
+				    (dw->num_lanes < 4) ? BIT(6) : 0);
 
 	val = readl(rcar->base + PCIEPWRMNGCTRL);
 	val |= APP_CLK_REQ_N | APP_CLK_PM_EN;
@@ -680,9 +676,8 @@ static int rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable
 		return 0;
 	}
 
-	val = dw_pcie_readl_dbi(dw, PCIE_PORT_FORCE);
-	val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
-	dw_pcie_writel_dbi(dw, PCIE_PORT_FORCE, val);
+	dw_pcie_clear_and_set_dword(dw, PCIE_PORT_FORCE,
+				    0, PORT_FORCE_DO_DESKEW_FOR_SRIS);
 
 	val = readl(rcar->base + PCIEMSR0);
 	val |= APP_SRIS_MODE;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 13/13] PCI: tegra194: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
                   ` (11 preceding siblings ...)
  2025-06-18 15:21 ` [PATCH v2 12/13] PCI: rcar-gen4: " Hans Zhang
@ 2025-06-18 15:21 ` Hans Zhang
  2025-06-25 20:57   ` Manivannan Sadhasivam
  2025-06-25 21:00 ` [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Manivannan Sadhasivam
  13 siblings, 1 reply; 22+ messages in thread
From: Hans Zhang @ 2025-06-18 15:21 UTC (permalink / raw)
  To: lpieralisi, bhelgaas, mani, kwilczynski
  Cc: robh, jingoohan1, linux-pci, linux-kernel, Hans Zhang

Tegra194 PCIe driver contains extensive manual bit manipulation across
interrupt handling, ASPM configuration, and controller initialization.
The driver implements complex read-modify-write sequences with explicit
bit masking, leading to verbose and hard-to-maintain code.

Refactor interrupt handling, ASPM setup, capability configuration, and
controller initialization using dw_pcie_clear_and_set_dword(). Replace
multi-step register modifications with single helper calls, eliminating
intermediate variables and reducing code size by ~100 lines. For CDMA
error handling, initialize the value variable to zero before setting
status bits.

This comprehensive refactoring significantly improves code readability
and maintainability. Standardizing on the helper ensures consistent
register access patterns across all driver components and reduces the
risk of bit manipulation errors in this complex controller driver.

Signed-off-by: Hans Zhang <18255117159@163.com>
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 155 +++++++++------------
 1 file changed, 64 insertions(+), 91 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 4f26086f25da..c6f5c35a4be4 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -378,9 +378,8 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
 			val |= APPL_CAR_RESET_OVRD_CYA_OVERRIDE_CORE_RST_N;
 			appl_writel(pcie, val, APPL_CAR_RESET_OVRD);
 
-			val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
-			val |= PORT_LOGIC_SPEED_CHANGE;
-			dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
+			dw_pcie_clear_and_set_dword(pci, PCIE_LINK_WIDTH_SPEED_CONTROL,
+						    0, PORT_LOGIC_SPEED_CHANGE);
 		}
 	}
 
@@ -412,7 +411,7 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
 
 	if (status_l0 & APPL_INTR_STATUS_L0_CDM_REG_CHK_INT) {
 		status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_18);
-		val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
+		val = 0;
 		if (status_l1 & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMPLT) {
 			dev_info(pci->dev, "CDM check complete\n");
 			val |= PCIE_PL_CHK_REG_CHK_REG_COMPLETE;
@@ -425,7 +424,8 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
 			dev_err(pci->dev, "CDM Logic error\n");
 			val |= PCIE_PL_CHK_REG_CHK_REG_LOGIC_ERROR;
 		}
-		dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);
+		dw_pcie_clear_and_set_dword(pci, PCIE_PL_CHK_REG_CONTROL_STATUS,
+					    PORT_LOGIC_SPEED_CHANGE, val);
 		val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_ERR_ADDR);
 		dev_err(pci->dev, "CDM Error Address Offset = 0x%08X\n", val);
 	}
@@ -610,34 +610,27 @@ static struct pci_ops tegra_pci_ops = {
 #if defined(CONFIG_PCIEASPM)
 static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
 {
-	u32 val;
-
-	val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
-	val &= ~PCI_L1SS_CAP_ASPM_L1_1;
-	dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
+	dw_pcie_clear_and_set_dword(&pcie->pci, pcie->cfg_link_cap_l1sub,
+				    PCI_L1SS_CAP_ASPM_L1_1, 0);
 }
 
 static void disable_aspm_l12(struct tegra_pcie_dw *pcie)
 {
-	u32 val;
-
-	val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
-	val &= ~PCI_L1SS_CAP_ASPM_L1_2;
-	dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
+	dw_pcie_clear_and_set_dword(&pcie->pci, pcie->cfg_link_cap_l1sub,
+				    PCI_L1SS_CAP_ASPM_L1_2, 0);
 }
 
 static inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event)
 {
-	u32 val;
+	u32 val = 0;
 
-	val = dw_pcie_readl_dbi(&pcie->pci, pcie->ras_des_cap +
-				PCIE_RAS_DES_EVENT_COUNTER_CONTROL);
-	val &= ~(EVENT_COUNTER_EVENT_SEL_MASK << EVENT_COUNTER_EVENT_SEL_SHIFT);
 	val |= EVENT_COUNTER_GROUP_5 << EVENT_COUNTER_GROUP_SEL_SHIFT;
 	val |= event << EVENT_COUNTER_EVENT_SEL_SHIFT;
 	val |= EVENT_COUNTER_ENABLE_ALL << EVENT_COUNTER_ENABLE_SHIFT;
-	dw_pcie_writel_dbi(&pcie->pci, pcie->ras_des_cap +
-			   PCIE_RAS_DES_EVENT_COUNTER_CONTROL, val);
+	dw_pcie_clear_and_set_dword(&pcie->pci, pcie->ras_des_cap +
+				    PCIE_RAS_DES_EVENT_COUNTER_CONTROL,
+				    EVENT_COUNTER_EVENT_SEL_MASK << EVENT_COUNTER_EVENT_SEL_SHIFT,
+				    val);
 	val = dw_pcie_readl_dbi(&pcie->pci, pcie->ras_des_cap +
 				PCIE_RAS_DES_EVENT_COUNTER_DATA);
 
@@ -697,18 +690,20 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
 			   PCIE_RAS_DES_EVENT_COUNTER_CONTROL, val);
 
 	/* Program T_cmrt and T_pwr_on values */
-	val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub);
-	val &= ~(PCI_L1SS_CAP_CM_RESTORE_TIME | PCI_L1SS_CAP_P_PWR_ON_VALUE);
+	val = 0;
 	val |= (pcie->aspm_cmrt << 8);
 	val |= (pcie->aspm_pwr_on_t << 19);
-	dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
+	dw_pcie_clear_and_set_dword(pci, pcie->cfg_link_cap_l1sub,
+				    PCI_L1SS_CAP_CM_RESTORE_TIME |
+				    PCI_L1SS_CAP_P_PWR_ON_VALUE,
+				    val);
 
 	/* Program L0s and L1 entrance latencies */
-	val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
-	val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
+	val = 0;
 	val |= (pcie->aspm_l0s_enter_lat << PORT_AFR_L0S_ENTRANCE_LAT_SHIFT);
 	val |= PORT_AFR_ENTER_ASPM;
-	dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
+	dw_pcie_clear_and_set_dword(pci, PCIE_PORT_AFR,
+				    PORT_AFR_L0S_ENTRANCE_LAT_MASK, val);
 }
 
 static void init_debugfs(struct tegra_pcie_dw *pcie)
@@ -860,31 +855,26 @@ static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
 		dw_pcie_writeb_dbi(pci, offset + i, val);
 	}
 
-	val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
-	val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
-	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
+	dw_pcie_clear_and_set_dword(pci, GEN3_RELATED_OFF,
+				    GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK, 0);
 
-	val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
-	val &= ~GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC;
-	val |= FIELD_PREP(GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC, 0x3ff);
-	val &= ~GEN3_EQ_CONTROL_OFF_FB_MODE;
-	dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
+	dw_pcie_clear_and_set_dword(pci, GEN3_EQ_CONTROL_OFF,
+				    GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC |
+				    GEN3_EQ_CONTROL_OFF_FB_MODE,
+				    FIELD_PREP(GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC, 0x3ff));
 
-	val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
-	val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
-	val |= (0x1 << GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT);
-	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
+	dw_pcie_clear_and_set_dword(pci, GEN3_RELATED_OFF,
+				    GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK,
+				    0x1 << GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT);
 
-	val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
-	val &= ~GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC;
-	val |= FIELD_PREP(GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC,
-			  pcie->of_data->gen4_preset_vec);
-	val &= ~GEN3_EQ_CONTROL_OFF_FB_MODE;
-	dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
+	dw_pcie_clear_and_set_dword(pci, GEN3_EQ_CONTROL_OFF,
+				    GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC |
+				    GEN3_EQ_CONTROL_OFF_FB_MODE,
+				    FIELD_PREP(GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC,
+					       pcie->of_data->gen4_preset_vec));
 
-	val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
-	val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
-	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
+	dw_pcie_clear_and_set_dword(pci, GEN3_RELATED_OFF,
+				    GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK, 0);
 }
 
 static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
@@ -892,7 +882,6 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
 	u32 val;
-	u16 val_16;
 
 	pp->bridge->ops = &tegra_pci_ops;
 
@@ -900,32 +889,25 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
 		pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
 							      PCI_CAP_ID_EXP);
 
-	val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
-	val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
-	dw_pcie_writel_dbi(pci, PCI_IO_BASE, val);
+	dw_pcie_clear_and_set_dword(pci, PCI_IO_BASE,
+				    IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8, 0);
 
-	val = dw_pcie_readl_dbi(pci, PCI_PREF_MEMORY_BASE);
-	val |= CFG_PREF_MEM_LIMIT_BASE_MEM_DECODE;
-	val |= CFG_PREF_MEM_LIMIT_BASE_MEM_LIMIT_DECODE;
-	dw_pcie_writel_dbi(pci, PCI_PREF_MEMORY_BASE, val);
+	dw_pcie_clear_and_set_dword(pci, PCI_PREF_MEMORY_BASE, 0,
+				    CFG_PREF_MEM_LIMIT_BASE_MEM_DECODE |
+				    CFG_PREF_MEM_LIMIT_BASE_MEM_LIMIT_DECODE);
 
 	dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
 
 	/* Enable as 0xFFFF0001 response for RRS */
-	val = dw_pcie_readl_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT);
-	val &= ~(AMBA_ERROR_RESPONSE_RRS_MASK << AMBA_ERROR_RESPONSE_RRS_SHIFT);
-	val |= (AMBA_ERROR_RESPONSE_RRS_OKAY_FFFF0001 <<
-		AMBA_ERROR_RESPONSE_RRS_SHIFT);
-	dw_pcie_writel_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT, val);
+	dw_pcie_clear_and_set_dword(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT,
+				    AMBA_ERROR_RESPONSE_RRS_MASK << AMBA_ERROR_RESPONSE_RRS_SHIFT,
+				    AMBA_ERROR_RESPONSE_RRS_OKAY_FFFF0001 <<
+				    AMBA_ERROR_RESPONSE_RRS_SHIFT);
 
 	/* Clear Slot Clock Configuration bit if SRNS configuration */
-	if (pcie->enable_srns) {
-		val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
-					   PCI_EXP_LNKSTA);
-		val_16 &= ~PCI_EXP_LNKSTA_SLC;
-		dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA,
-				   val_16);
-	}
+	if (pcie->enable_srns)
+		dw_pcie_clear_and_set_dword(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA,
+					    PCI_EXP_LNKSTA_SLC, 0);
 
 	config_gen3_gen4_eq_presets(pcie);
 
@@ -937,17 +919,13 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
 		disable_aspm_l12(pcie);
 	}
 
-	if (!pcie->of_data->has_l1ss_exit_fix) {
-		val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
-		val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
-		dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
-	}
+	if (!pcie->of_data->has_l1ss_exit_fix)
+		dw_pcie_clear_and_set_dword(pci, GEN3_RELATED_OFF,
+					    GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL, 0);
 
-	if (pcie->update_fc_fixup) {
-		val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF);
-		val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT;
-		dw_pcie_writel_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val);
-	}
+	if (pcie->update_fc_fixup)
+		dw_pcie_clear_and_set_dword(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF,
+					    0, 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT);
 
 	clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
 
@@ -1018,9 +996,8 @@ static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
 		reset_control_deassert(pcie->core_rst);
 
 		offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_DLF);
-		val = dw_pcie_readl_dbi(pci, offset + PCI_DLF_CAP);
-		val &= ~PCI_DLF_EXCHANGE_ENABLE;
-		dw_pcie_writel_dbi(pci, offset + PCI_DLF_CAP, val);
+		dw_pcie_clear_and_set_dword(pci, offset + PCI_DLF_CAP,
+					    PCI_DLF_EXCHANGE_ENABLE, 0);
 
 		tegra_pcie_dw_host_init(pp);
 		dw_pcie_setup_rc(pp);
@@ -1847,11 +1824,9 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
 
 	reset_control_deassert(pcie->core_rst);
 
-	if (pcie->update_fc_fixup) {
-		val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF);
-		val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT;
-		dw_pcie_writel_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val);
-	}
+	if (pcie->update_fc_fixup)
+		dw_pcie_clear_and_set_dword(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF,
+					    0, 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT);
 
 	config_gen3_gen4_eq_presets(pcie);
 
@@ -1863,11 +1838,9 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
 		disable_aspm_l12(pcie);
 	}
 
-	if (!pcie->of_data->has_l1ss_exit_fix) {
-		val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
-		val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
-		dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
-	}
+	if (!pcie->of_data->has_l1ss_exit_fix)
+		dw_pcie_clear_and_set_dword(pci, GEN3_RELATED_OFF,
+					    GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL, 0);
 
 	pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
 						      PCI_CAP_ID_EXP);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 01/13] PCI: dwc: Add dw_pcie_clear_and_set_dword() for register bit manipulation
  2025-06-18 15:21 ` [PATCH v2 01/13] PCI: dwc: Add dw_pcie_clear_and_set_dword() for register bit manipulation Hans Zhang
@ 2025-06-19  4:29   ` Frank Li
  2025-06-19  5:42     ` Hans Zhang
  0 siblings, 1 reply; 22+ messages in thread
From: Frank Li @ 2025-06-19  4:29 UTC (permalink / raw)
  To: Hans Zhang
  Cc: lpieralisi, bhelgaas, mani, kwilczynski, robh, jingoohan1,
	linux-pci, linux-kernel

On Wed, Jun 18, 2025 at 11:21:00PM +0800, Hans Zhang wrote:
> DesignWare PCIe controller drivers implement register bit manipulation
> through explicit read-modify-write sequences. These patterns appear
> repeatedly across multiple drivers with minor variations, creating
> code duplication and maintenance overhead.
>
> Implement dw_pcie_clear_and_set_dword() helper to encapsulate atomic
> register modification. The function reads the current register value,
> clears specified bits, sets new bits, and writes back the result in
> a single operation. This abstraction hides bitwise manipulation details
> while ensuring consistent behavior across all usage sites.
>
> Centralizing this logic reduces future maintenance effort when modifying
> register access patterns and minimizes the risk of implementation
> divergence between drivers.
>
> Signed-off-by: Hans Zhang <18255117159@163.com>
> ---
>  drivers/pci/controller/dwc/pcie-designware.h | 11 +++++++++++
>  1 file changed, 11 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index ce9e18554e42..f401c144df0f 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -707,6 +707,17 @@ static inline void dw_pcie_ep_writel_dbi2(struct dw_pcie_ep *ep, u8 func_no,
>  	dw_pcie_ep_write_dbi2(ep, func_no, reg, 0x4, val);
>  }
>
> +static inline void dw_pcie_clear_and_set_dword(struct dw_pcie *pci, int pos,
> +					       u32 clear, u32 set)

Can align with regmap_update_bits() argumnet?

dw_pcie_update_dbi_bits()?

Frank

> +{
> +	u32 val;
> +
> +	val = dw_pcie_readl_dbi(pci, pos);
> +	val &= ~clear;
> +	val |= set;
> +	dw_pcie_writel_dbi(pci, pos, val);
> +}
> +
>  static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
>  {
>  	u32 reg;
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 01/13] PCI: dwc: Add dw_pcie_clear_and_set_dword() for register bit manipulation
  2025-06-19  4:29   ` Frank Li
@ 2025-06-19  5:42     ` Hans Zhang
  2025-06-19 15:12       ` Frank Li
  0 siblings, 1 reply; 22+ messages in thread
From: Hans Zhang @ 2025-06-19  5:42 UTC (permalink / raw)
  To: Frank Li, Hans Zhang
  Cc: lpieralisi, bhelgaas, mani, kwilczynski, robh, jingoohan1,
	linux-pci, linux-kernel



On 2025/6/19 12:29, Frank Li wrote:
> EXTERNAL EMAIL
> 
> On Wed, Jun 18, 2025 at 11:21:00PM +0800, Hans Zhang wrote:
>> DesignWare PCIe controller drivers implement register bit manipulation
>> through explicit read-modify-write sequences. These patterns appear
>> repeatedly across multiple drivers with minor variations, creating
>> code duplication and maintenance overhead.
>>
>> Implement dw_pcie_clear_and_set_dword() helper to encapsulate atomic
>> register modification. The function reads the current register value,
>> clears specified bits, sets new bits, and writes back the result in
>> a single operation. This abstraction hides bitwise manipulation details
>> while ensuring consistent behavior across all usage sites.
>>
>> Centralizing this logic reduces future maintenance effort when modifying
>> register access patterns and minimizes the risk of implementation
>> divergence between drivers.
>>
>> Signed-off-by: Hans Zhang <18255117159@163.com>
>> ---
>>   drivers/pci/controller/dwc/pcie-designware.h | 11 +++++++++++
>>   1 file changed, 11 insertions(+)
>>
>> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
>> index ce9e18554e42..f401c144df0f 100644
>> --- a/drivers/pci/controller/dwc/pcie-designware.h
>> +++ b/drivers/pci/controller/dwc/pcie-designware.h
>> @@ -707,6 +707,17 @@ static inline void dw_pcie_ep_writel_dbi2(struct dw_pcie_ep *ep, u8 func_no,
>>        dw_pcie_ep_write_dbi2(ep, func_no, reg, 0x4, val);
>>   }
>>
>> +static inline void dw_pcie_clear_and_set_dword(struct dw_pcie *pci, int pos,
>> +                                            u32 clear, u32 set)
> 
> Can align with regmap_update_bits() argumnet?
> 
> dw_pcie_update_dbi_bits()?
> 

Dear Frank,

Thank you for your reply.


Personally, I think it should be the same as the following API. In this 
way, we can easily know the corresponding parameters and it also 
conforms to the usage habits of PCIe. What do you think?


drivers/pci/access.c

int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos,
					u32 clear, u32 set)
{
	int ret;
	u32 val;

	ret = pcie_capability_read_dword(dev, pos, &val);
	if (ret)
		return ret;

	val &= ~clear;
	val |= set;
	return pcie_capability_write_dword(dev, pos, val);
}
EXPORT_SYMBOL(pcie_capability_clear_and_set_dword);


void pci_clear_and_set_config_dword(const struct pci_dev *dev, int pos,
				    u32 clear, u32 set)
{
	u32 val;

	pci_read_config_dword(dev, pos, &val);
	val &= ~clear;
	val |= set;
	pci_write_config_dword(dev, pos, val);
}
EXPORT_SYMBOL(pci_clear_and_set_config_dword);


Best regards,
Hans

> Frank
> 
>> +{
>> +     u32 val;
>> +
>> +     val = dw_pcie_readl_dbi(pci, pos);
>> +     val &= ~clear;
>> +     val |= set;
>> +     dw_pcie_writel_dbi(pci, pos, val);
>> +}
>> +
>>   static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
>>   {
>>        u32 reg;
>> --
>> 2.25.1
>>
> 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 01/13] PCI: dwc: Add dw_pcie_clear_and_set_dword() for register bit manipulation
  2025-06-19  5:42     ` Hans Zhang
@ 2025-06-19 15:12       ` Frank Li
  0 siblings, 0 replies; 22+ messages in thread
From: Frank Li @ 2025-06-19 15:12 UTC (permalink / raw)
  To: Hans Zhang
  Cc: Hans Zhang, lpieralisi, bhelgaas, mani, kwilczynski, robh,
	jingoohan1, linux-pci, linux-kernel

On Thu, Jun 19, 2025 at 01:42:05PM +0800, Hans Zhang wrote:
>
>
> On 2025/6/19 12:29, Frank Li wrote:
> > EXTERNAL EMAIL
> >
> > On Wed, Jun 18, 2025 at 11:21:00PM +0800, Hans Zhang wrote:
> > > DesignWare PCIe controller drivers implement register bit manipulation
> > > through explicit read-modify-write sequences. These patterns appear
> > > repeatedly across multiple drivers with minor variations, creating
> > > code duplication and maintenance overhead.
> > >
> > > Implement dw_pcie_clear_and_set_dword() helper to encapsulate atomic
> > > register modification. The function reads the current register value,
> > > clears specified bits, sets new bits, and writes back the result in
> > > a single operation. This abstraction hides bitwise manipulation details
> > > while ensuring consistent behavior across all usage sites.
> > >
> > > Centralizing this logic reduces future maintenance effort when modifying
> > > register access patterns and minimizes the risk of implementation
> > > divergence between drivers.
> > >
> > > Signed-off-by: Hans Zhang <18255117159@163.com>
> > > ---
> > >   drivers/pci/controller/dwc/pcie-designware.h | 11 +++++++++++
> > >   1 file changed, 11 insertions(+)
> > >
> > > diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> > > index ce9e18554e42..f401c144df0f 100644
> > > --- a/drivers/pci/controller/dwc/pcie-designware.h
> > > +++ b/drivers/pci/controller/dwc/pcie-designware.h
> > > @@ -707,6 +707,17 @@ static inline void dw_pcie_ep_writel_dbi2(struct dw_pcie_ep *ep, u8 func_no,
> > >        dw_pcie_ep_write_dbi2(ep, func_no, reg, 0x4, val);
> > >   }
> > >
> > > +static inline void dw_pcie_clear_and_set_dword(struct dw_pcie *pci, int pos,
> > > +                                            u32 clear, u32 set)
> >
> > Can align with regmap_update_bits() argumnet?
> >
> > dw_pcie_update_dbi_bits()?
> >
>
> Dear Frank,
>
> Thank you for your reply.
>
>
> Personally, I think it should be the same as the following API. In this way,
> we can easily know the corresponding parameters and it also conforms to the
> usage habits of PCIe. What do you think?

You are right!

Frank
>
>
> drivers/pci/access.c
>
> int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos,
> 					u32 clear, u32 set)
> {
> 	int ret;
> 	u32 val;
>
> 	ret = pcie_capability_read_dword(dev, pos, &val);
> 	if (ret)
> 		return ret;
>
> 	val &= ~clear;
> 	val |= set;
> 	return pcie_capability_write_dword(dev, pos, val);
> }
> EXPORT_SYMBOL(pcie_capability_clear_and_set_dword);
>
>
> void pci_clear_and_set_config_dword(const struct pci_dev *dev, int pos,
> 				    u32 clear, u32 set)
> {
> 	u32 val;
>
> 	pci_read_config_dword(dev, pos, &val);
> 	val &= ~clear;
> 	val |= set;
> 	pci_write_config_dword(dev, pos, val);
> }
> EXPORT_SYMBOL(pci_clear_and_set_config_dword);
>
>
> Best regards,
> Hans
>
> > Frank
> >
> > > +{
> > > +     u32 val;
> > > +
> > > +     val = dw_pcie_readl_dbi(pci, pos);
> > > +     val &= ~clear;
> > > +     val |= set;
> > > +     dw_pcie_writel_dbi(pci, pos, val);
> > > +}
> > > +
> > >   static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
> > >   {
> > >        u32 reg;
> > > --
> > > 2.25.1
> > >
> >

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 04/13] PCI: imx6: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:21 ` [PATCH v2 04/13] PCI: imx6: " Hans Zhang
@ 2025-06-19 15:16   ` Frank Li
  0 siblings, 0 replies; 22+ messages in thread
From: Frank Li @ 2025-06-19 15:16 UTC (permalink / raw)
  To: Hans Zhang
  Cc: lpieralisi, bhelgaas, mani, kwilczynski, robh, jingoohan1,
	linux-pci, linux-kernel

On Wed, Jun 18, 2025 at 11:21:03PM +0800, Hans Zhang wrote:
> i.MX6 PCIe driver contains multiple read-modify-write sequences for
> link training and speed configuration. These operations manually handle
> bit masking and shifting to update specific fields in control registers,
> particularly for link capabilities and speed change initiation.
>
> Refactor link capability configuration and speed change handling using
> dw_pcie_clear_and_set_dword(). The helper simplifies LNKCAP modification
> by encapsulating bit clear/set operations and eliminates intermediate
> variables. For speed change control, replace explicit bit manipulation
> with direct register updates through the helper.
>
> Adopting the standard interface reduces code complexity in link training
> paths and ensures consistent handling of speed-related bits. The change
> also prepares the driver for future enhancements to Gen3 link training
> by centralizing bit manipulation logic.
>
> Signed-off-by: Hans Zhang <18255117159@163.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/pci/controller/dwc/pci-imx6.c | 26 ++++++++++----------------
>  1 file changed, 10 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
> index 5a38cfaf989b..3004e432f013 100644
> --- a/drivers/pci/controller/dwc/pci-imx6.c
> +++ b/drivers/pci/controller/dwc/pci-imx6.c
> @@ -941,7 +941,6 @@ static int imx_pcie_start_link(struct dw_pcie *pci)
>  	struct imx_pcie *imx_pcie = to_imx_pcie(pci);
>  	struct device *dev = pci->dev;
>  	u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> -	u32 tmp;
>  	int ret;
>
>  	if (!(imx_pcie->drvdata->flags &
> @@ -956,10 +955,9 @@ static int imx_pcie_start_link(struct dw_pcie *pci)
>  	 * bus will not be detected at all.  This happens with PCIe switches.
>  	 */
>  	dw_pcie_dbi_ro_wr_en(pci);
> -	tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
> -	tmp &= ~PCI_EXP_LNKCAP_SLS;
> -	tmp |= PCI_EXP_LNKCAP_SLS_2_5GB;
> -	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp);
> +	dw_pcie_clear_and_set_dword(pci, offset + PCI_EXP_LNKCAP,
> +				    PCI_EXP_LNKCAP_SLS,
> +				    PCI_EXP_LNKCAP_SLS_2_5GB);
>  	dw_pcie_dbi_ro_wr_dis(pci);
>
>  	/* Start LTSSM. */
> @@ -972,18 +970,16 @@ static int imx_pcie_start_link(struct dw_pcie *pci)
>
>  		/* Allow faster modes after the link is up */
>  		dw_pcie_dbi_ro_wr_en(pci);
> -		tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
> -		tmp &= ~PCI_EXP_LNKCAP_SLS;
> -		tmp |= pci->max_link_speed;
> -		dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp);
> +		dw_pcie_clear_and_set_dword(pci, offset + PCI_EXP_LNKCAP,
> +					    PCI_EXP_LNKCAP_SLS,
> +					    pci->max_link_speed);
>
>  		/*
>  		 * Start Directed Speed Change so the best possible
>  		 * speed both link partners support can be negotiated.
>  		 */
> -		tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
> -		tmp |= PORT_LOGIC_SPEED_CHANGE;
> -		dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
> +		dw_pcie_clear_and_set_dword(pci, PCIE_LINK_WIDTH_SPEED_CONTROL,
> +					    0, PORT_LOGIC_SPEED_CHANGE);
>  		dw_pcie_dbi_ro_wr_dis(pci);
>
>  		ret = imx_pcie_wait_for_speed_change(imx_pcie);
> @@ -1295,7 +1291,6 @@ static void imx_pcie_host_post_init(struct dw_pcie_rp *pp)
>  {
>  	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
>  	struct imx_pcie *imx_pcie = to_imx_pcie(pci);
> -	u32 val;
>
>  	if (imx_pcie->drvdata->flags & IMX_PCIE_FLAG_8GT_ECN_ERR051586) {
>  		/*
> @@ -1310,9 +1305,8 @@ static void imx_pcie_host_post_init(struct dw_pcie_rp *pp)
>  		 * to 0.
>  		 */
>  		dw_pcie_dbi_ro_wr_en(pci);
> -		val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
> -		val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
> -		dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
> +		dw_pcie_clear_and_set_dword(pci, GEN3_RELATED_OFF,
> +					    GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL, 0);
>  		dw_pcie_dbi_ro_wr_dis(pci);
>  	}
>  }
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 13/13] PCI: tegra194: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-18 15:21 ` [PATCH v2 13/13] PCI: tegra194: " Hans Zhang
@ 2025-06-25 20:57   ` Manivannan Sadhasivam
  2025-06-26 14:31     ` Hans Zhang
  0 siblings, 1 reply; 22+ messages in thread
From: Manivannan Sadhasivam @ 2025-06-25 20:57 UTC (permalink / raw)
  To: Hans Zhang
  Cc: lpieralisi, bhelgaas, kwilczynski, robh, jingoohan1, linux-pci,
	linux-kernel

On Wed, Jun 18, 2025 at 11:21:12PM +0800, Hans Zhang wrote:
> Tegra194 PCIe driver contains extensive manual bit manipulation across
> interrupt handling, ASPM configuration, and controller initialization.
> The driver implements complex read-modify-write sequences with explicit
> bit masking, leading to verbose and hard-to-maintain code.
> 
> Refactor interrupt handling, ASPM setup, capability configuration, and
> controller initialization using dw_pcie_clear_and_set_dword(). Replace
> multi-step register modifications with single helper calls, eliminating
> intermediate variables and reducing code size by ~100 lines. For CDMA
> error handling, initialize the value variable to zero before setting
> status bits.
> 
> This comprehensive refactoring significantly improves code readability
> and maintainability. Standardizing on the helper ensures consistent
> register access patterns across all driver components and reduces the
> risk of bit manipulation errors in this complex controller driver.
> 
> Signed-off-by: Hans Zhang <18255117159@163.com>
> ---
>  drivers/pci/controller/dwc/pcie-tegra194.c | 155 +++++++++------------
>  1 file changed, 64 insertions(+), 91 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 4f26086f25da..c6f5c35a4be4 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -378,9 +378,8 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
>  			val |= APPL_CAR_RESET_OVRD_CYA_OVERRIDE_CORE_RST_N;
>  			appl_writel(pcie, val, APPL_CAR_RESET_OVRD);
>  
> -			val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
> -			val |= PORT_LOGIC_SPEED_CHANGE;
> -			dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
> +			dw_pcie_clear_and_set_dword(pci, PCIE_LINK_WIDTH_SPEED_CONTROL,
> +						    0, PORT_LOGIC_SPEED_CHANGE);
>  		}
>  	}
>  
> @@ -412,7 +411,7 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
>  
>  	if (status_l0 & APPL_INTR_STATUS_L0_CDM_REG_CHK_INT) {
>  		status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_18);
> -		val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
> +		val = 0;
>  		if (status_l1 & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMPLT) {
>  			dev_info(pci->dev, "CDM check complete\n");
>  			val |= PCIE_PL_CHK_REG_CHK_REG_COMPLETE;
> @@ -425,7 +424,8 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
>  			dev_err(pci->dev, "CDM Logic error\n");
>  			val |= PCIE_PL_CHK_REG_CHK_REG_LOGIC_ERROR;
>  		}
> -		dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);
> +		dw_pcie_clear_and_set_dword(pci, PCIE_PL_CHK_REG_CONTROL_STATUS,
> +					    PORT_LOGIC_SPEED_CHANGE, val);

I don't know why you are clearing PORT_LOGIC_SPEED_CHANGE here which is not part
of PCIE_PL_CHK_REG_CONTROL_STATUS. Typo?

- Mani

-- 
மணிவண்ணன் சதாசிவம்

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper
  2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
                   ` (12 preceding siblings ...)
  2025-06-18 15:21 ` [PATCH v2 13/13] PCI: tegra194: " Hans Zhang
@ 2025-06-25 21:00 ` Manivannan Sadhasivam
  2025-06-26 14:51   ` Hans Zhang
  13 siblings, 1 reply; 22+ messages in thread
From: Manivannan Sadhasivam @ 2025-06-25 21:00 UTC (permalink / raw)
  To: Hans Zhang
  Cc: lpieralisi, bhelgaas, kwilczynski, robh, jingoohan1, linux-pci,
	linux-kernel

On Wed, Jun 18, 2025 at 11:20:59PM +0800, Hans Zhang wrote:
> Register bit manipulation in DesignWare PCIe controllers currently
> uses repetitive read-modify-write sequences across multiple drivers.
> This pattern leads to code duplication and increases maintenance
> complexity as each driver implements similar logic with minor variations.
> 
> This series introduces dw_pcie_clear_and_set_dword() to centralize atomic
> register modification. The helper performs read-clear-set-write operations
> in a single function, replacing open-coded implementations. Subsequent
> patches refactor individual drivers to use this helper, eliminating
> redundant code and ensuring consistent bit handling.
> 
> The change reduces overall code size by ~350 lines while improving
> maintainability. Each controller driver is updated in a separate
> patch to preserve bisectability and simplify review.
> 

Thanks for the cleanup! I spotted a typo in patch 13/13. Apart from that, I only
have one comment. You are initializing the temp variable like 'val' to 0 and
then ORing it with some fields. Here the initialization part is not necessary.
You could just write the first field directly instead of ORing with a 0
initialized variable.

Rest LGTM!

- Mani

-- 
மணிவண்ணன் சதாசிவம்

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 13/13] PCI: tegra194: Refactor code by using dw_pcie_clear_and_set_dword()
  2025-06-25 20:57   ` Manivannan Sadhasivam
@ 2025-06-26 14:31     ` Hans Zhang
  0 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-26 14:31 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: lpieralisi, bhelgaas, kwilczynski, robh, jingoohan1, linux-pci,
	linux-kernel



On 2025/6/26 04:57, Manivannan Sadhasivam wrote:
> On Wed, Jun 18, 2025 at 11:21:12PM +0800, Hans Zhang wrote:
>> Tegra194 PCIe driver contains extensive manual bit manipulation across
>> interrupt handling, ASPM configuration, and controller initialization.
>> The driver implements complex read-modify-write sequences with explicit
>> bit masking, leading to verbose and hard-to-maintain code.
>>
>> Refactor interrupt handling, ASPM setup, capability configuration, and
>> controller initialization using dw_pcie_clear_and_set_dword(). Replace
>> multi-step register modifications with single helper calls, eliminating
>> intermediate variables and reducing code size by ~100 lines. For CDMA
>> error handling, initialize the value variable to zero before setting
>> status bits.
>>
>> This comprehensive refactoring significantly improves code readability
>> and maintainability. Standardizing on the helper ensures consistent
>> register access patterns across all driver components and reduces the
>> risk of bit manipulation errors in this complex controller driver.
>>
>> Signed-off-by: Hans Zhang <18255117159@163.com>
>> ---
>>   drivers/pci/controller/dwc/pcie-tegra194.c | 155 +++++++++------------
>>   1 file changed, 64 insertions(+), 91 deletions(-)
>>
>> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
>> index 4f26086f25da..c6f5c35a4be4 100644
>> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
>> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
>> @@ -378,9 +378,8 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
>>   			val |= APPL_CAR_RESET_OVRD_CYA_OVERRIDE_CORE_RST_N;
>>   			appl_writel(pcie, val, APPL_CAR_RESET_OVRD);
>>   
>> -			val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
>> -			val |= PORT_LOGIC_SPEED_CHANGE;
>> -			dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
>> +			dw_pcie_clear_and_set_dword(pci, PCIE_LINK_WIDTH_SPEED_CONTROL,
>> +						    0, PORT_LOGIC_SPEED_CHANGE);
>>   		}
>>   	}
>>   
>> @@ -412,7 +411,7 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
>>   
>>   	if (status_l0 & APPL_INTR_STATUS_L0_CDM_REG_CHK_INT) {
>>   		status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_18);
>> -		val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
>> +		val = 0;
>>   		if (status_l1 & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMPLT) {
>>   			dev_info(pci->dev, "CDM check complete\n");
>>   			val |= PCIE_PL_CHK_REG_CHK_REG_COMPLETE;
>> @@ -425,7 +424,8 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
>>   			dev_err(pci->dev, "CDM Logic error\n");
>>   			val |= PCIE_PL_CHK_REG_CHK_REG_LOGIC_ERROR;
>>   		}
>> -		dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);
>> +		dw_pcie_clear_and_set_dword(pci, PCIE_PL_CHK_REG_CONTROL_STATUS,
>> +					    PORT_LOGIC_SPEED_CHANGE, val);
> 
> I don't know why you are clearing PORT_LOGIC_SPEED_CHANGE here which is not part
> of PCIE_PL_CHK_REG_CONTROL_STATUS. Typo?
> 
Dear Mani,

Thank you very much for your reply and reminder.

This is copied from the first change of this patch and will be fixed in 
the next version.

Best regards,
Hans


> - Mani
> 


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper
  2025-06-25 21:00 ` [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Manivannan Sadhasivam
@ 2025-06-26 14:51   ` Hans Zhang
  0 siblings, 0 replies; 22+ messages in thread
From: Hans Zhang @ 2025-06-26 14:51 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: lpieralisi, bhelgaas, kwilczynski, robh, jingoohan1, linux-pci,
	linux-kernel



On 2025/6/26 05:00, Manivannan Sadhasivam wrote:
> On Wed, Jun 18, 2025 at 11:20:59PM +0800, Hans Zhang wrote:
>> Register bit manipulation in DesignWare PCIe controllers currently
>> uses repetitive read-modify-write sequences across multiple drivers.
>> This pattern leads to code duplication and increases maintenance
>> complexity as each driver implements similar logic with minor variations.
>>
>> This series introduces dw_pcie_clear_and_set_dword() to centralize atomic
>> register modification. The helper performs read-clear-set-write operations
>> in a single function, replacing open-coded implementations. Subsequent
>> patches refactor individual drivers to use this helper, eliminating
>> redundant code and ensuring consistent bit handling.
>>
>> The change reduces overall code size by ~350 lines while improving
>> maintainability. Each controller driver is updated in a separate
>> patch to preserve bisectability and simplify review.
>>
> 
> Thanks for the cleanup! I spotted a typo in patch 13/13. Apart from that, I only
> have one comment. You are initializing the temp variable like 'val' to 0 and
> then ORing it with some fields. Here the initialization part is not necessary.
> You could just write the first field directly instead of ORing with a 0
> initialized variable.
> 
> Rest LGTM!

Dear Mani,

Thank you very much for your reply and reminder.

Will fix.

Best regards,
Hans

> 
> - Mani
> 


^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2025-06-26 14:51 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-18 15:20 [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Hans Zhang
2025-06-18 15:21 ` [PATCH v2 01/13] PCI: dwc: Add dw_pcie_clear_and_set_dword() for register bit manipulation Hans Zhang
2025-06-19  4:29   ` Frank Li
2025-06-19  5:42     ` Hans Zhang
2025-06-19 15:12       ` Frank Li
2025-06-18 15:21 ` [PATCH v2 02/13] PCI: dwc: Refactor code by using dw_pcie_clear_and_set_dword() Hans Zhang
2025-06-18 15:21 ` [PATCH v2 03/13] PCI: dra7xx: " Hans Zhang
2025-06-18 15:21 ` [PATCH v2 04/13] PCI: imx6: " Hans Zhang
2025-06-19 15:16   ` Frank Li
2025-06-18 15:21 ` [PATCH v2 05/13] PCI: meson: " Hans Zhang
2025-06-18 15:21 ` [PATCH v2 06/13] PCI: armada8k: " Hans Zhang
2025-06-18 15:21 ` [PATCH v2 07/13] PCI: bt1: " Hans Zhang
2025-06-18 15:21 ` [PATCH v2 08/13] PCI: dw-rockchip: " Hans Zhang
2025-06-18 15:21 ` [PATCH v2 09/13] PCI: fu740: " Hans Zhang
2025-06-18 15:21 ` [PATCH v2 10/13] PCI: qcom: " Hans Zhang
2025-06-18 15:21 ` [PATCH v2 11/13] PCI: qcom-ep: " Hans Zhang
2025-06-18 15:21 ` [PATCH v2 12/13] PCI: rcar-gen4: " Hans Zhang
2025-06-18 15:21 ` [PATCH v2 13/13] PCI: tegra194: " Hans Zhang
2025-06-25 20:57   ` Manivannan Sadhasivam
2025-06-26 14:31     ` Hans Zhang
2025-06-25 21:00 ` [PATCH v2 00/13] PCI: dwc: Refactor register access with dw_pcie_clear_and_set_dword helper Manivannan Sadhasivam
2025-06-26 14:51   ` Hans Zhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).