Thread (51 messages) 51 messages, 7 authors, 2025-09-09

Re: [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC

From: Claudiu Beznea <claudiu.beznea@tuxon.dev>
Date: 2025-09-08 13:04:32
Also in: linux-clk, linux-devicetree, linux-pci, linux-renesas-soc, lkml

Hi, Manivannan,

Apologies for the late reply, I've been off for a while.

On 8/31/25 07:07, Manivannan Sadhasivam wrote:
On Sat, Aug 30, 2025 at 02:22:45PM GMT, Claudiu Beznea wrote:
quoted

On 30.08.2025 09:59, Manivannan Sadhasivam wrote:
quoted
On Fri, Jul 04, 2025 at 07:14:05PM GMT, Claudiu wrote:
quoted
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

The Renesas RZ/G3S features a PCIe IP that complies with the PCI Express
Base Specification 4.0 and supports speeds of up to 5 GT/s. It functions
only as a root complex, with a single-lane (x1) configuration. The
controller includes Type 1 configuration registers, as well as IP
specific registers (called AXI registers) required for various adjustments.

Hardware manual can be downloaded from the address in the "Link" section.
The following steps should be followed to access the manual:
1/ Click the "User Manual" button
2/ Click "Confirm"; this will start downloading an archive
3/ Open the downloaded archive
4/ Navigate to r01uh1014ej*-rzg3s-users-manual-hardware -> Deliverables
5/ Open the file r01uh1014ej*-rzg3s.pdf

Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
[...]
quoted
+static bool rzg3s_pcie_child_issue_request(struct rzg3s_pcie_host *host)
+{
+	u32 val;
+	int ret;
+
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_REQISS,
+			       RZG3S_PCI_REQISS_REQ_ISSUE,
+			       RZG3S_PCI_REQISS_REQ_ISSUE);
+	ret = readl_poll_timeout_atomic(host->axi + RZG3S_PCI_REQISS, val,
+					!(val & RZG3S_PCI_REQISS_REQ_ISSUE),
+					5, RZG3S_REQ_ISSUE_TIMEOUT_US);
+
+	return !!ret || (val & RZG3S_PCI_REQISS_MOR_STATUS);
You don't need to do !!ret as the C11 standard guarantees that any scalar type
stored as bool will have the value of 0 or 1.
OK, will drop it anyway as suggested in another thread.
quoted
quoted
+}
+
[...]
quoted
+static void __iomem *rzg3s_pcie_root_map_bus(struct pci_bus *bus,
+					     unsigned int devfn,
+					     int where)
+{
+	struct rzg3s_pcie_host *host = bus->sysdata;
+
+	if (devfn)
+		return NULL;
Is it really possible to have devfn as non-zero for a root bus?
I will drop it.
quoted
quoted
+
+	return host->pcie + where;
+}
+
[...]
quoted
+static int rzg3s_pcie_msi_setup(struct rzg3s_pcie_host *host)
+{
+	size_t size = RZG3S_PCI_MSI_INT_NR * sizeof(u32);
+	struct rzg3s_pcie_msi *msi = &host->msi;
+	struct device *dev = host->dev;
+	int id, ret;
+
+	msi->pages = __get_free_pages(GFP_KERNEL | GFP_DMA, 0);
+	if (!msi->pages)
+		return -ENOMEM;
+
+	msi->dma_addr = dma_map_single(dev, (void *)msi->pages, size * 2,
+				       DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, msi->dma_addr)) {
+		ret = -ENOMEM;
+		goto free_pages;
+	}
+
+	/*
+	 * According to the RZ/G3S HW manual (Rev.1.10, section 34.4.5.2 Setting
+	 * the MSI Window) the MSI window need to be within any AXI window. Find
+	 * an AXI window to setup the MSI window.
Are you really finding the AXI window or just making sure that the MSI window
falls into one of the AXI window?
I'm making sure the MSI windows falls into one of the enabled AXI windows.
Then you need to reword the comment as such. Currently, it is not clear.
OK
quoted
quoted
And I believe it is OK to have more than one MSI window within an AXI window.
This IP supports a single MSI window that need to fit into one of the
enabled AXI windows.
[...]
quoted
quoted
quoted
+
+	/* Update vendor ID and device ID */
Are you really updating it or setting it? If you are updating it, are the
default IDs invalid?
Default IDs are valid (at least on RZ/G3S) but Renesas specific. Renesas
wants to let individual users to set their own IDs.
So they are optional then? But the binding treats them as required, which should
be changed if the default IDs are valid.
On RZ/G3S the default IDs are valid. On other SoCs that will be using this
driver (e.g. RZ/G3E) the default IDs are not valid.

These were marked as required as Renesas wants them to be set by the
company that manufactures the end product itself.

quoted
quoted
quoted
+	writew(host->vendor_id, host->pcie + PCI_VENDOR_ID);
+	writew(host->device_id, host->pcie + PCI_DEVICE_ID);
+
+	/* HW manual recommends to write 0xffffffff on initialization */
+	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L);
+	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U);
+
+	/* Update bus info. */
+	writeb(primary_bus, host->pcie + PCI_PRIMARY_BUS);
+	writeb(secondary_bus, host->pcie + PCI_SECONDARY_BUS);
+	writeb(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS);
+
+	/* Disable access control to the CFGU */
+	writel(0, host->axi + RZG3S_PCI_PERM);
+
+	return 0;
+}
+
[...]
quoted
+static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host, bool probe)
+{
+	u32 val;
+	int ret;
+
+	/* Initialize the PCIe related registers */
+	ret = rzg3s_pcie_config_init(host);
+	if (ret)
+		return ret;
+
+	/* Initialize the interrupts */
+	rzg3s_pcie_irq_init(host);
+
+	ret = reset_control_bulk_deassert(host->data->num_cfg_resets,
+					  host->cfg_resets);
+	if (ret)
+		return ret;
+
+	/* Wait for link up */
+	ret = readl_poll_timeout(host->axi + RZG3S_PCI_PCSTAT1, val,
+				 !(val & RZG3S_PCI_PCSTAT1_DL_DOWN_STS),
+				 PCIE_LINK_WAIT_SLEEP_MS,
+				 PCIE_LINK_WAIT_SLEEP_MS *
+				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
+	if (ret) {
+		reset_control_bulk_assert(host->data->num_cfg_resets,
+					  host->cfg_resets);
+		return ret;
+	}
+
+	val = readl(host->axi + RZG3S_PCI_PCSTAT2);
+	dev_info(host->dev, "PCIe link status [0x%x]\n", val);
+
+	val = FIELD_GET(RZG3S_PCI_PCSTAT2_STATE_RX_DETECT, val);
+	dev_info(host->dev, "PCIe x%d: link up\n", hweight32(val));
+
+	if (probe) {
+		ret = devm_add_action_or_reset(host->dev,
+					       rzg3s_pcie_cfg_resets_action,
+					       host);
Oh well, this gets ugly. Now the devm_add_action_or_reset() is sprinkled
throughout the driver :/

As I said earlier, there are concerns in unloading the driver if it implements
an irqchip. So if you change the module_platform_driver() to
builtin_platform_driver() for this driver, these devm_add_action_or_reset()
calls become unused.
They can still be useful in case the probe fails. As the initialization
path is complicated, having actions or resets looks to me that makes the
code cleaner as the rest of devm_* helpers.

I can drop it and replace with gotos and dedicated functions but this will
complicate the code, AFAICT.

Please let me know how would you like me to proceed.
It is generally preferred to cleanup the resources in err path using goto
labels.
Just to be sure I'll prepare the next version with something that was
requested: would you like to have goto lables on this driver?

I kept it like this as I considered the code is simpler.

Thank you,
Claudiu
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help