[openwrt/openwrt] rockchip: backport PCIe MSI fixes for RK356x SoC

LEDE Commits lede-commits at lists.infradead.org
Sat May 17 02:30:26 PDT 2025


robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/6b99c5d21e8245e982c847189897040c55751d17

commit 6b99c5d21e8245e982c847189897040c55751d17
Author: Chukun Pan <amadeus at jmu.edu.cn>
AuthorDate: Sat May 10 21:06:20 2025 +0800

    rockchip: backport PCIe MSI fixes for RK356x SoC
    
    Backport GIC ITS support for RK356x SoC, which fixes long-standing
    MSI/MSI-X bug. (Previously MSI-X could only work on one PCIe node)
    
    e.g. [    7.250882] r8125 0002:01:00.0: no MSI/MSI-X. Back to INTx.
    
    Tested on Radxa E25 with kmod-r8125-rss driver.
    
    Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
    Link: https://github.com/openwrt/openwrt/pull/18800
    Signed-off-by: Robert Marko <robimarko at gmail.com>
---
 target/linux/rockchip/armv8/config-6.6             |   1 +
 ...-v3-its-Share-ITS-tables-with-a-non-trust.patch | 337 +++++++++++++++++++++
 ...c-v3-its-Fix-over-allocation-in-itt_alloc.patch |  33 ++
 ...3-Add-Rockchip-3568002-erratum-workaround.patch | 105 +++++++
 ...s-rockchip-rk356x-Add-MSI-controller-node.patch |  51 ++++
 ...-rockchip-rk356x-Move-PCIe-MSI-to-use-GIC.patch |  28 ++
 ...ockchip-Move-rk3568-PCIe3-MSI-to-use-GIC-.patch |  54 ++++
 7 files changed, 609 insertions(+)

diff --git a/target/linux/rockchip/armv8/config-6.6 b/target/linux/rockchip/armv8/config-6.6
index be5b4b4b5c..5018b6e2f5 100644
--- a/target/linux/rockchip/armv8/config-6.6
+++ b/target/linux/rockchip/armv8/config-6.6
@@ -563,6 +563,7 @@ CONFIG_RELOCATABLE=y
 CONFIG_RESET_CONTROLLER=y
 CONFIG_RESET_SCMI=y
 CONFIG_RFS_ACCEL=y
+CONFIG_ROCKCHIP_ERRATUM_3568002=y
 CONFIG_ROCKCHIP_ERRATUM_3588001=y
 CONFIG_ROCKCHIP_GRF=y
 CONFIG_ROCKCHIP_IODOMAIN=y
diff --git a/target/linux/rockchip/patches-6.6/020-v6.13-irqchip-gic-v3-its-Share-ITS-tables-with-a-non-trust.patch b/target/linux/rockchip/patches-6.6/020-v6.13-irqchip-gic-v3-its-Share-ITS-tables-with-a-non-trust.patch
new file mode 100644
index 0000000000..92e9bf6c86
--- /dev/null
+++ b/target/linux/rockchip/patches-6.6/020-v6.13-irqchip-gic-v3-its-Share-ITS-tables-with-a-non-trust.patch
@@ -0,0 +1,337 @@
+From b08e2f42e86b5848add254da45b56fc672e2bced Mon Sep 17 00:00:00 2001
+From: Steven Price <steven.price at arm.com>
+Date: Wed, 2 Oct 2024 15:16:29 +0100
+Subject: [PATCH] irqchip/gic-v3-its: Share ITS tables with a non-trusted
+ hypervisor
+
+Within a realm guest the ITS is emulated by the host. This means the
+allocations must have been made available to the host by a call to
+set_memory_decrypted(). Introduce an allocation function which performs
+this extra call.
+
+For the ITT use a custom genpool-based allocator that calls
+set_memory_decrypted() for each page allocated, but then suballocates the
+size needed for each ITT. Note that there is no mechanism implemented to
+return pages from the genpool, but it is unlikely that the peak number of
+devices will be much larger than the normal level - so this isn't expected
+to be an issue.
+
+Co-developed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
+Signed-off-by: Suzuki K Poulose <suzuki.poulose at arm.com>
+Signed-off-by: Steven Price <steven.price at arm.com>
+Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
+Tested-by: Will Deacon <will at kernel.org>
+Reviewed-by: Marc Zyngier <maz at kernel.org>
+Link: https://lore.kernel.org/all/20241002141630.433502-2-steven.price@arm.com
+---
+ drivers/irqchip/irq-gic-v3-its.c | 138 +++++++++++++++++++++++++------
+ 1 file changed, 115 insertions(+), 23 deletions(-)
+
+--- a/drivers/irqchip/irq-gic-v3-its.c
++++ b/drivers/irqchip/irq-gic-v3-its.c
+@@ -12,12 +12,14 @@
+ #include <linux/crash_dump.h>
+ #include <linux/delay.h>
+ #include <linux/efi.h>
++#include <linux/genalloc.h>
+ #include <linux/interrupt.h>
+ #include <linux/iommu.h>
+ #include <linux/iopoll.h>
+ #include <linux/irqdomain.h>
+ #include <linux/list.h>
+ #include <linux/log2.h>
++#include <linux/mem_encrypt.h>
+ #include <linux/memblock.h>
+ #include <linux/mm.h>
+ #include <linux/msi.h>
+@@ -27,6 +29,7 @@
+ #include <linux/of_pci.h>
+ #include <linux/of_platform.h>
+ #include <linux/percpu.h>
++#include <linux/set_memory.h>
+ #include <linux/slab.h>
+ #include <linux/syscore_ops.h>
+ 
+@@ -163,6 +166,7 @@ struct its_device {
+ 	struct its_node		*its;
+ 	struct event_lpi_map	event_map;
+ 	void			*itt;
++	u32			itt_sz;
+ 	u32			nr_ites;
+ 	u32			device_id;
+ 	bool			shared;
+@@ -198,6 +202,87 @@ static DEFINE_IDA(its_vpeid_ida);
+ #define gic_data_rdist_rd_base()	(gic_data_rdist()->rd_base)
+ #define gic_data_rdist_vlpi_base()	(gic_data_rdist_rd_base() + SZ_128K)
+ 
++static struct page *its_alloc_pages_node(int node, gfp_t gfp,
++					 unsigned int order)
++{
++	struct page *page;
++	int ret = 0;
++
++	page = alloc_pages_node(node, gfp, order);
++
++	if (!page)
++		return NULL;
++
++	ret = set_memory_decrypted((unsigned long)page_address(page),
++				   1 << order);
++	/*
++	 * If set_memory_decrypted() fails then we don't know what state the
++	 * page is in, so we can't free it. Instead we leak it.
++	 * set_memory_decrypted() will already have WARNed.
++	 */
++	if (ret)
++		return NULL;
++
++	return page;
++}
++
++static struct page *its_alloc_pages(gfp_t gfp, unsigned int order)
++{
++	return its_alloc_pages_node(NUMA_NO_NODE, gfp, order);
++}
++
++static void its_free_pages(void *addr, unsigned int order)
++{
++	/*
++	 * If the memory cannot be encrypted again then we must leak the pages.
++	 * set_memory_encrypted() will already have WARNed.
++	 */
++	if (set_memory_encrypted((unsigned long)addr, 1 << order))
++		return;
++	free_pages((unsigned long)addr, order);
++}
++
++static struct gen_pool *itt_pool;
++
++static void *itt_alloc_pool(int node, int size)
++{
++	unsigned long addr;
++	struct page *page;
++
++	if (size >= PAGE_SIZE) {
++		page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, get_order(size));
++
++		return page ? page_address(page) : NULL;
++	}
++
++	do {
++		addr = gen_pool_alloc(itt_pool, size);
++		if (addr)
++			break;
++
++		page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 1);
++		if (!page)
++			break;
++
++		gen_pool_add(itt_pool, (unsigned long)page_address(page), PAGE_SIZE, node);
++	} while (!addr);
++
++	return (void *)addr;
++}
++
++static void itt_free_pool(void *addr, int size)
++{
++	if (!addr)
++		return;
++
++	if (size >= PAGE_SIZE) {
++		its_free_pages(addr, get_order(size));
++		return;
++	}
++
++	gen_pool_free(itt_pool, (unsigned long)addr, size);
++}
++
+ /*
+  * Skip ITSs that have no vLPIs mapped, unless we're on GICv4.1, as we
+  * always have vSGIs mapped.
+@@ -2192,7 +2277,8 @@ static struct page *its_allocate_prop_ta
+ {
+ 	struct page *prop_page;
+ 
+-	prop_page = alloc_pages(gfp_flags, get_order(LPI_PROPBASE_SZ));
++	prop_page = its_alloc_pages(gfp_flags,
++				    get_order(LPI_PROPBASE_SZ));
+ 	if (!prop_page)
+ 		return NULL;
+ 
+@@ -2203,8 +2289,7 @@ static struct page *its_allocate_prop_ta
+ 
+ static void its_free_prop_table(struct page *prop_page)
+ {
+-	free_pages((unsigned long)page_address(prop_page),
+-		   get_order(LPI_PROPBASE_SZ));
++	its_free_pages(page_address(prop_page), get_order(LPI_PROPBASE_SZ));
+ }
+ 
+ static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size)
+@@ -2326,7 +2411,7 @@ static int its_setup_baser(struct its_no
+ 		order = get_order(GITS_BASER_PAGES_MAX * psz);
+ 	}
+ 
+-	page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order);
++	page = its_alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order);
+ 	if (!page)
+ 		return -ENOMEM;
+ 
+@@ -2339,7 +2424,7 @@ static int its_setup_baser(struct its_no
+ 		/* 52bit PA is supported only when PageSize=64K */
+ 		if (psz != SZ_64K) {
+ 			pr_err("ITS: no 52bit PA support when psz=%d\n", psz);
+-			free_pages((unsigned long)base, order);
++			its_free_pages(base, order);
+ 			return -ENXIO;
+ 		}
+ 
+@@ -2395,7 +2480,7 @@ retry_baser:
+ 		pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n",
+ 		       &its->phys_base, its_base_type_string[type],
+ 		       val, tmp);
+-		free_pages((unsigned long)base, order);
++		its_free_pages(base, order);
+ 		return -ENXIO;
+ 	}
+ 
+@@ -2534,8 +2619,7 @@ static void its_free_tables(struct its_n
+ 
+ 	for (i = 0; i < GITS_BASER_NR_REGS; i++) {
+ 		if (its->tables[i].base) {
+-			free_pages((unsigned long)its->tables[i].base,
+-				   its->tables[i].order);
++			its_free_pages(its->tables[i].base, its->tables[i].order);
+ 			its->tables[i].base = NULL;
+ 		}
+ 	}
+@@ -2801,7 +2885,7 @@ static bool allocate_vpe_l2_table(int cp
+ 
+ 	/* Allocate memory for 2nd level table */
+ 	if (!table[idx]) {
+-		page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz));
++		page = its_alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz));
+ 		if (!page)
+ 			return false;
+ 
+@@ -2920,7 +3004,7 @@ static int allocate_vpe_l1_table(void)
+ 
+ 	pr_debug("np = %d, npg = %lld, psz = %d, epp = %d, esz = %d\n",
+ 		 np, npg, psz, epp, esz);
+-	page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE));
++	page = its_alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE));
+ 	if (!page)
+ 		return -ENOMEM;
+ 
+@@ -2966,8 +3050,7 @@ static struct page *its_allocate_pending
+ {
+ 	struct page *pend_page;
+ 
+-	pend_page = alloc_pages(gfp_flags | __GFP_ZERO,
+-				get_order(LPI_PENDBASE_SZ));
++	pend_page = its_alloc_pages(gfp_flags | __GFP_ZERO, get_order(LPI_PENDBASE_SZ));
+ 	if (!pend_page)
+ 		return NULL;
+ 
+@@ -2979,7 +3062,7 @@ static struct page *its_allocate_pending
+ 
+ static void its_free_pending_table(struct page *pt)
+ {
+-	free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ));
++	its_free_pages(page_address(pt), get_order(LPI_PENDBASE_SZ));
+ }
+ 
+ /*
+@@ -3314,8 +3397,8 @@ static bool its_alloc_table_entry(struct
+ 
+ 	/* Allocate memory for 2nd level table */
+ 	if (!table[idx]) {
+-		page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
+-					get_order(baser->psz));
++		page = its_alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
++					    get_order(baser->psz));
+ 		if (!page)
+ 			return false;
+ 
+@@ -3410,7 +3493,6 @@ static struct its_device *its_create_dev
+ 	if (WARN_ON(!is_power_of_2(nvecs)))
+ 		nvecs = roundup_pow_of_two(nvecs);
+ 
+-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ 	/*
+ 	 * Even if the device wants a single LPI, the ITT must be
+ 	 * sized as a power of two (and you need at least one bit...).
+@@ -3418,7 +3500,11 @@ static struct its_device *its_create_dev
+ 	nr_ites = max(2, nvecs);
+ 	sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1);
+ 	sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
+-	itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node);
++
++	itt = itt_alloc_pool(its->numa_node, sz);
++
++	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++
+ 	if (alloc_lpis) {
+ 		lpi_map = its_lpi_alloc(nvecs, &lpi_base, &nr_lpis);
+ 		if (lpi_map)
+@@ -3430,9 +3516,9 @@ static struct its_device *its_create_dev
+ 		lpi_base = 0;
+ 	}
+ 
+-	if (!dev || !itt ||  !col_map || (!lpi_map && alloc_lpis)) {
++	if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) {
+ 		kfree(dev);
+-		kfree(itt);
++		itt_free_pool(itt, sz);
+ 		bitmap_free(lpi_map);
+ 		kfree(col_map);
+ 		return NULL;
+@@ -3442,6 +3528,7 @@ static struct its_device *its_create_dev
+ 
+ 	dev->its = its;
+ 	dev->itt = itt;
++	dev->itt_sz = sz;
+ 	dev->nr_ites = nr_ites;
+ 	dev->event_map.lpi_map = lpi_map;
+ 	dev->event_map.col_map = col_map;
+@@ -3469,7 +3556,7 @@ static void its_free_device(struct its_d
+ 	list_del(&its_dev->entry);
+ 	raw_spin_unlock_irqrestore(&its_dev->its->lock, flags);
+ 	kfree(its_dev->event_map.col_map);
+-	kfree(its_dev->itt);
++	itt_free_pool(its_dev->itt, its_dev->itt_sz);
+ 	kfree(its_dev);
+ }
+ 
+@@ -5112,8 +5199,9 @@ static int __init its_probe_one(struct i
+ 		}
+ 	}
+ 
+-	page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
+-				get_order(ITS_CMD_QUEUE_SZ));
++	page = its_alloc_pages_node(its->numa_node,
++				    GFP_KERNEL | __GFP_ZERO,
++				    get_order(ITS_CMD_QUEUE_SZ));
+ 	if (!page) {
+ 		err = -ENOMEM;
+ 		goto out_unmap_sgir;
+@@ -5177,7 +5265,7 @@ static int __init its_probe_one(struct i
+ out_free_tables:
+ 	its_free_tables(its);
+ out_free_cmd:
+-	free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
++	its_free_pages(its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
+ out_unmap_sgir:
+ 	if (its->sgir_base)
+ 		iounmap(its->sgir_base);
+@@ -5659,6 +5747,10 @@ int __init its_init(struct fwnode_handle
+ 	bool has_v4_1 = false;
+ 	int err;
+ 
++	itt_pool = gen_pool_create(get_order(ITS_ITT_ALIGN), -1);
++	if (!itt_pool)
++		return -ENOMEM;
++
+ 	gic_rdists = rdists;
+ 
+ 	its_parent = parent_domain;
diff --git a/target/linux/rockchip/patches-6.6/021-v6.13-irqchip-gic-v3-its-Fix-over-allocation-in-itt_alloc.patch b/target/linux/rockchip/patches-6.6/021-v6.13-irqchip-gic-v3-its-Fix-over-allocation-in-itt_alloc.patch
new file mode 100644
index 0000000000..a716cbee7d
--- /dev/null
+++ b/target/linux/rockchip/patches-6.6/021-v6.13-irqchip-gic-v3-its-Fix-over-allocation-in-itt_alloc.patch
@@ -0,0 +1,33 @@
+From bc88d44bd7e45b992cf8c2c2ffbc7bb3e24db4a7 Mon Sep 17 00:00:00 2001
+From: Steven Price <steven.price at arm.com>
+Date: Mon, 21 Oct 2024 11:41:05 +0100
+Subject: [PATCH] irqchip/gic-v3-its: Fix over allocation in
+ itt_alloc_pool()
+
+itt_alloc_pool() calls its_alloc_pages_node() to allocate an individual
+page to add to the pool (for allocations <PAGE_SIZE). However the final
+argument of its_alloc_pages_node() is the page order not the number of
+pages. Currently it allocates two pages and leaks the second page.
+Fix it by passing 0 instead (1 << 0 = 1 page).
+
+Fixes: b08e2f42e86b ("irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor")
+Reported-by: Shanker Donthineni <sdonthineni at nvidia.com>
+Signed-off-by: Steven Price <steven.price at arm.com>
+Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
+Link: https://lore.kernel.org/all/1f6e19c4-1fb9-43ab-a8a2-a465c9cff84b@arm.com
+Closes: https://lore.kernel.org/r/ed65312a-245c-4fa5-91ad-5d620cab7c6b%40nvidia.com
+---
+ drivers/irqchip/irq-gic-v3-its.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/irqchip/irq-gic-v3-its.c
++++ b/drivers/irqchip/irq-gic-v3-its.c
+@@ -260,7 +260,7 @@ static void *itt_alloc_pool(int node, in
+ 		if (addr)
+ 			break;
+ 
+-		page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 1);
++		page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
+ 		if (!page)
+ 			break;
+ 
diff --git a/target/linux/rockchip/patches-6.6/022-v6.15-irqchip-gic-v3-Add-Rockchip-3568002-erratum-workaround.patch b/target/linux/rockchip/patches-6.6/022-v6.15-irqchip-gic-v3-Add-Rockchip-3568002-erratum-workaround.patch
new file mode 100644
index 0000000000..9c9e643ff9
--- /dev/null
+++ b/target/linux/rockchip/patches-6.6/022-v6.15-irqchip-gic-v3-Add-Rockchip-3568002-erratum-workaround.patch
@@ -0,0 +1,105 @@
+From 2d81e1bb625238d40a686ed909ff3e1abab7556a Mon Sep 17 00:00:00 2001
+From: Dmitry Osipenko <dmitry.osipenko at collabora.com>
+Date: Mon, 17 Feb 2025 01:16:32 +0300
+Subject: [PATCH] irqchip/gic-v3: Add Rockchip 3568002 erratum workaround
+
+Rockchip RK3566/RK3568 GIC600 integration has DDR addressing
+limited to the first 32bit of physical address space. Rockchip
+assigned Erratum ID #3568002 for this issue. Add driver quirk for
+this Rockchip GIC Erratum.
+
+Note, that the 0x0201743b GIC600 ID is not Rockchip-specific and is
+common for many ARM GICv3 implementations. Hence, there is an extra
+of_machine_is_compatible() check.
+
+Signed-off-by: Dmitry Osipenko <dmitry.osipenko at collabora.com>
+Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
+Acked-by: Marc Zyngier <maz at kernel.org>
+Link: https://lore.kernel.org/all/20250216221634.364158-2-dmitry.osipenko@collabora.com
+---
+ Documentation/arch/arm64/silicon-errata.rst |  2 ++
+ arch/arm64/Kconfig                          |  9 ++++++++
+ drivers/irqchip/irq-gic-v3-its.c            | 23 ++++++++++++++++++++-
+ 3 files changed, 33 insertions(+), 1 deletion(-)
+
+--- a/Documentation/arch/arm64/silicon-errata.rst
++++ b/Documentation/arch/arm64/silicon-errata.rst
+@@ -270,6 +270,8 @@ stable kernels.
+ +----------------+-----------------+-----------------+-----------------------------+
+ | Rockchip       | RK3588          | #3588001        | ROCKCHIP_ERRATUM_3588001    |
+ +----------------+-----------------+-----------------+-----------------------------+
++| Rockchip       | RK3568          | #3568002        | ROCKCHIP_ERRATUM_3568002    |
+++----------------+-----------------+-----------------+-----------------------------+
+ 
+ +----------------+-----------------+-----------------+-----------------------------+
+ | Fujitsu        | A64FX           | E#010001        | FUJITSU_ERRATUM_010001      |
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -1267,6 +1267,15 @@ config NVIDIA_CARMEL_CNP_ERRATUM
+ 
+ 	  If unsure, say Y.
+ 
++config ROCKCHIP_ERRATUM_3568002
++	bool "Rockchip 3568002: GIC600 can not access physical addresses higher than 4GB"
++	default y
++	help
++	  The Rockchip RK3566 and RK3568 GIC600 SoC integrations have AXI
++	  addressing limited to the first 32bit of physical address space.
++
++	  If unsure, say Y.
++
+ config ROCKCHIP_ERRATUM_3588001
+ 	bool "Rockchip 3588001: GIC600 can not support shareability attributes"
+ 	default y
+--- a/drivers/irqchip/irq-gic-v3-its.c
++++ b/drivers/irqchip/irq-gic-v3-its.c
+@@ -202,13 +202,15 @@ static DEFINE_IDA(its_vpeid_ida);
+ #define gic_data_rdist_rd_base()	(gic_data_rdist()->rd_base)
+ #define gic_data_rdist_vlpi_base()	(gic_data_rdist_rd_base() + SZ_128K)
+ 
++static gfp_t gfp_flags_quirk;
++
+ static struct page *its_alloc_pages_node(int node, gfp_t gfp,
+ 					 unsigned int order)
+ {
+ 	struct page *page;
+ 	int ret = 0;
+ 
+-	page = alloc_pages_node(node, gfp, order);
++	page = alloc_pages_node(node, gfp | gfp_flags_quirk, order);
+ 
+ 	if (!page)
+ 		return NULL;
+@@ -4851,6 +4853,17 @@ static bool its_set_non_coherent(void *d
+ 	return true;
+ }
+ 
++static bool __maybe_unused its_enable_rk3568002(void *data)
++{
++	if (!of_machine_is_compatible("rockchip,rk3566") &&
++	    !of_machine_is_compatible("rockchip,rk3568"))
++		return false;
++
++	gfp_flags_quirk |= GFP_DMA32;
++
++	return true;
++}
++
+ static const struct gic_quirk its_quirks[] = {
+ #ifdef CONFIG_CAVIUM_ERRATUM_22375
+ 	{
+@@ -4910,6 +4923,14 @@ static const struct gic_quirk its_quirks
+ 		.property = "dma-noncoherent",
+ 		.init   = its_set_non_coherent,
+ 	},
++#ifdef CONFIG_ROCKCHIP_ERRATUM_3568002
++	{
++		.desc   = "ITS: Rockchip erratum RK3568002",
++		.iidr   = 0x0201743b,
++		.mask   = 0xffffffff,
++		.init   = its_enable_rk3568002,
++	},
++#endif
+ 	{
+ 	}
+ };
diff --git a/target/linux/rockchip/patches-6.6/023-01-v6.15-arm64-dts-rockchip-rk356x-Add-MSI-controller-node.patch b/target/linux/rockchip/patches-6.6/023-01-v6.15-arm64-dts-rockchip-rk356x-Add-MSI-controller-node.patch
new file mode 100644
index 0000000000..a31e4595c4
--- /dev/null
+++ b/target/linux/rockchip/patches-6.6/023-01-v6.15-arm64-dts-rockchip-rk356x-Add-MSI-controller-node.patch
@@ -0,0 +1,51 @@
+From f15be3d4a0a55db2b50f319c378a2d16ceb21f86 Mon Sep 17 00:00:00 2001
+From: Dmitry Osipenko <dmitry.osipenko at collabora.com>
+Date: Mon, 17 Feb 2025 01:16:33 +0300
+Subject: [PATCH] arm64: dts: rockchip: rk356x: Add MSI controller node
+
+Rockchip 356x SoC's GIC has two hardware integration issues that
+affect MSI functionality of the GIC. Previously, both these GIC
+issues were worked around by using MBI for MSI instead of ITS
+because kernel GIC driver didn't have necessary quirks.
+
+First issue is about RK356x GIC not supporting programmable
+shareability, while reporting it as supported in a GIC's feature
+register. Rockchip assigned Erratum ID #3568001 for this issue. This
+patch adds dma-noncoherent property to the GIC node, denoting that a SW
+workaround is required for mitigating the issue.
+
+Second issue is about GIC AXI master interface addressing limited to
+the first 4GB of physical address space. Rockchip assigned Erratum
+ID #3568002 for this issue.
+
+Now that kernel supports quirks for both of the erratums, add
+MSI controller node to RK356x device-tree.
+
+Signed-off-by: Dmitry Osipenko <dmitry.osipenko at collabora.com>
+Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
+Link: https://lore.kernel.org/all/20250216221634.364158-3-dmitry.osipenko@collabora.com
+---
+ arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+@@ -364,6 +364,18 @@
+ 		mbi-alias = <0x0 0xfd410000>;
+ 		mbi-ranges = <296 24>;
+ 		msi-controller;
++		ranges;
++		#address-cells = <2>;
++		#size-cells = <2>;
++		dma-noncoherent;
++
++		its: msi-controller at fd440000 {
++			compatible = "arm,gic-v3-its";
++			reg = <0x0 0xfd440000 0 0x20000>;
++			dma-noncoherent;
++			msi-controller;
++			#msi-cells = <1>;
++		};
+ 	};
+ 
+ 	usb_host0_ehci: usb at fd800000 {
diff --git a/target/linux/rockchip/patches-6.6/023-02-v6.15-arm64-dts-rockchip-rk356x-Move-PCIe-MSI-to-use-GIC.patch b/target/linux/rockchip/patches-6.6/023-02-v6.15-arm64-dts-rockchip-rk356x-Move-PCIe-MSI-to-use-GIC.patch
new file mode 100644
index 0000000000..d1281332b4
--- /dev/null
+++ b/target/linux/rockchip/patches-6.6/023-02-v6.15-arm64-dts-rockchip-rk356x-Move-PCIe-MSI-to-use-GIC.patch
@@ -0,0 +1,28 @@
+From b956c9de91757c9478e24fc9f6a57fd46f0a49f0 Mon Sep 17 00:00:00 2001
+From: Dmitry Osipenko <dmitry.osipenko at collabora.com>
+Date: Mon, 17 Feb 2025 01:16:34 +0300
+Subject: [PATCH] arm64: dts: rockchip: rk356x: Move PCIe MSI to use GIC
+ ITS instead of MBI
+
+Rockchip 356x device-tree now supports GIC ITS. Move PCIe controller's
+MSI to use ITS instead of MBI. This removes extra CPU overhead of handling
+PCIe MBIs by letting GIC's ITS to serve the PCIe MSIs.
+
+Signed-off-by: Dmitry Osipenko <dmitry.osipenko at collabora.com>
+Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
+Link: https://lore.kernel.org/all/20250216221634.364158-4-dmitry.osipenko@collabora.com
+---
+ arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+@@ -1043,7 +1043,7 @@
+ 		num-ib-windows = <6>;
+ 		num-ob-windows = <2>;
+ 		max-link-speed = <2>;
+-		msi-map = <0x0 &gic 0x0 0x1000>;
++		msi-map = <0x0 &its 0x0 0x1000>;
+ 		num-lanes = <1>;
+ 		phys = <&combphy2 PHY_TYPE_PCIE>;
+ 		phy-names = "pcie-phy";
diff --git a/target/linux/rockchip/patches-6.6/024-v6.16-arm64-dts-rockchip-Move-rk3568-PCIe3-MSI-to-use-GIC-.patch b/target/linux/rockchip/patches-6.6/024-v6.16-arm64-dts-rockchip-Move-rk3568-PCIe3-MSI-to-use-GIC-.patch
new file mode 100644
index 0000000000..c5bbaed492
--- /dev/null
+++ b/target/linux/rockchip/patches-6.6/024-v6.16-arm64-dts-rockchip-Move-rk3568-PCIe3-MSI-to-use-GIC-.patch
@@ -0,0 +1,54 @@
+From fbea35a661ed100cee2f3bab8015fb0155508106 Mon Sep 17 00:00:00 2001
+From: Chukun Pan <amadeus at jmu.edu.cn>
+Date: Sat, 8 Mar 2025 17:30:08 +0800
+Subject: [PATCH] arm64: dts: rockchip: Move rk3568 PCIe3 MSI to use GIC ITS
+
+Following commit b956c9de9175 ("arm64: dts: rockchip: rk356x: Move
+PCIe MSI to use GIC ITS instead of MBI"), change the PCIe3 controller's
+MSI on rk3568 to use ITS, so that all MSI-X can work properly.
+
+Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
+Link: https://lore.kernel.org/r/20250308093008.568437-2-amadeus@jmu.edu.cn
+Signed-off-by: Heiko Stuebner <heiko at sntech.de>
+---
+ arch/arm64/boot/dts/rockchip/rk3568.dtsi | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
+@@ -64,7 +64,7 @@
+ 		compatible = "rockchip,rk3568-pcie";
+ 		#address-cells = <3>;
+ 		#size-cells = <2>;
+-		bus-range = <0x0 0xf>;
++		bus-range = <0x10 0x1f>;
+ 		clocks = <&cru ACLK_PCIE30X1_MST>, <&cru ACLK_PCIE30X1_SLV>,
+ 			 <&cru ACLK_PCIE30X1_DBI>, <&cru PCLK_PCIE30X1>,
+ 			 <&cru CLK_PCIE30X1_AUX_NDFT>;
+@@ -87,7 +87,7 @@
+ 		num-ib-windows = <6>;
+ 		num-ob-windows = <2>;
+ 		max-link-speed = <3>;
+-		msi-map = <0x0 &gic 0x1000 0x1000>;
++		msi-map = <0x1000 &its 0x1000 0x1000>;
+ 		num-lanes = <1>;
+ 		phys = <&pcie30phy>;
+ 		phy-names = "pcie-phy";
+@@ -117,7 +117,7 @@
+ 		compatible = "rockchip,rk3568-pcie";
+ 		#address-cells = <3>;
+ 		#size-cells = <2>;
+-		bus-range = <0x0 0xf>;
++		bus-range = <0x20 0x2f>;
+ 		clocks = <&cru ACLK_PCIE30X2_MST>, <&cru ACLK_PCIE30X2_SLV>,
+ 			 <&cru ACLK_PCIE30X2_DBI>, <&cru PCLK_PCIE30X2>,
+ 			 <&cru CLK_PCIE30X2_AUX_NDFT>;
+@@ -140,7 +140,7 @@
+ 		num-ib-windows = <6>;
+ 		num-ob-windows = <2>;
+ 		max-link-speed = <3>;
+-		msi-map = <0x0 &gic 0x2000 0x1000>;
++		msi-map = <0x2000 &its 0x2000 0x1000>;
+ 		num-lanes = <2>;
+ 		phys = <&pcie30phy>;
+ 		phy-names = "pcie-phy";




More information about the lede-commits mailing list