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@jmu.edu.cn> Link: https://github.com/openwrt/openwrt/pull/18800 Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
parent
cca80986b5
commit
6b99c5d21e
7 changed files with 609 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -0,0 +1,337 @@
|
|||
From b08e2f42e86b5848add254da45b56fc672e2bced Mon Sep 17 00:00:00 2001
|
||||
From: Steven Price <steven.price@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@arm.com>
|
||||
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
|
||||
Signed-off-by: Steven Price <steven.price@arm.com>
|
||||
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
||||
Tested-by: Will Deacon <will@kernel.org>
|
||||
Reviewed-by: Marc Zyngier <maz@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;
|
|
@ -0,0 +1,33 @@
|
|||
From bc88d44bd7e45b992cf8c2c2ffbc7bb3e24db4a7 Mon Sep 17 00:00:00 2001
|
||||
From: Steven Price <steven.price@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@nvidia.com>
|
||||
Signed-off-by: Steven Price <steven.price@arm.com>
|
||||
Signed-off-by: Thomas Gleixner <tglx@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;
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
From 2d81e1bb625238d40a686ed909ff3e1abab7556a Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Osipenko <dmitry.osipenko@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@collabora.com>
|
||||
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
||||
Acked-by: Marc Zyngier <maz@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
|
||||
{
|
||||
}
|
||||
};
|
|
@ -0,0 +1,51 @@
|
|||
From f15be3d4a0a55db2b50f319c378a2d16ceb21f86 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Osipenko <dmitry.osipenko@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@collabora.com>
|
||||
Signed-off-by: Thomas Gleixner <tglx@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@fd440000 {
|
||||
+ compatible = "arm,gic-v3-its";
|
||||
+ reg = <0x0 0xfd440000 0 0x20000>;
|
||||
+ dma-noncoherent;
|
||||
+ msi-controller;
|
||||
+ #msi-cells = <1>;
|
||||
+ };
|
||||
};
|
||||
|
||||
usb_host0_ehci: usb@fd800000 {
|
|
@ -0,0 +1,28 @@
|
|||
From b956c9de91757c9478e24fc9f6a57fd46f0a49f0 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Osipenko <dmitry.osipenko@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@collabora.com>
|
||||
Signed-off-by: Thomas Gleixner <tglx@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";
|
|
@ -0,0 +1,54 @@
|
|||
From fbea35a661ed100cee2f3bab8015fb0155508106 Mon Sep 17 00:00:00 2001
|
||||
From: Chukun Pan <amadeus@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@jmu.edu.cn>
|
||||
Link: https://lore.kernel.org/r/20250308093008.568437-2-amadeus@jmu.edu.cn
|
||||
Signed-off-by: Heiko Stuebner <heiko@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";
|
Loading…
Reference in a new issue