* [PATCH net 0/2] net: enetc: fix command BD ring issues
From: Wei Fang @ 2026-04-13 7:52 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, chleroy
Cc: netdev, linux-kernel, imx, linuxppc-dev, linux-arm-kernel
Currently, the implementation of command BD ring has two issues, one is
that the driver may obtain wrong consumer index of the ring, because the
driver does not mask out the SBE bit of the CIR value, so a wrong index
will be obtained when a SBE error ouccrs. The other one is that the DMA
buffer may be used after free. If netc_xmit_ntmp_cmd() times out and
returns an error, the pending command is not explicitly aborted, while
ntmp_free_data_mem() unconditionally frees the DMA buffer. If the buffer
has already been reallocated elsewhere, this may lead to silent memory
corruption. Because the hardware eventually processes the pending command
and perform a DMA write of the response to the physical address of the
freed buffer. So this patch set is to fix these two issues.
Wei Fang (2):
net: enetc: correct the command BD ring consumer index
net: enetc: fix NTMP DMA use-after-free issue
drivers/net/ethernet/freescale/enetc/ntmp.c | 161 ++++++++++--------
.../ethernet/freescale/enetc/ntmp_private.h | 9 +-
include/linux/fsl/ntmp.h | 9 +-
3 files changed, 96 insertions(+), 83 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH net 1/2] net: enetc: correct the command BD ring consumer index
From: Wei Fang @ 2026-04-13 7:52 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, chleroy
Cc: netdev, linux-kernel, imx, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260413075250.281653-1-wei.fang@nxp.com>
The command BD ring cousumer index register has the consumer index as
the lower 10 bits, and the bit 31 is SBE, which indicates whether a
system bus error occurred during execution of the CBD command. So if a
system bus error occurs, reading the register will get the SBE bit set.
However, the current implementation directly uses the register value as
the consumer index without masking it. Therefore, if a system bus error
occurs, an incorrect consumer index will be obtained, causing errors in
the processing of the command BD ring. Thus, we need to mask out the
other bits to obtain the correct consumer index.
Fixes: 4701073c3deb ("net: enetc: add initial netc-lib driver to support NTMP")
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/ntmp.c | 7 ++++---
drivers/net/ethernet/freescale/enetc/ntmp_private.h | 1 +
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c
index 0c1d343253bf..1b1ff0446d0a 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp.c
+++ b/drivers/net/ethernet/freescale/enetc/ntmp.c
@@ -55,7 +55,7 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
spin_lock_init(&cbdr->ring_lock);
cbdr->next_to_use = netc_read(cbdr->regs.pir);
- cbdr->next_to_clean = netc_read(cbdr->regs.cir);
+ cbdr->next_to_clean = netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX;
/* Step 1: Configure the base address of the Control BD Ring */
netc_write(cbdr->regs.bar0, lower_32_bits(cbdr->dma_base_align));
@@ -98,7 +98,7 @@ static void ntmp_clean_cbdr(struct netc_cbdr *cbdr)
int i;
i = cbdr->next_to_clean;
- while (netc_read(cbdr->regs.cir) != i) {
+ while ((netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX) != i) {
cbd = ntmp_get_cbd(cbdr, i);
memset(cbd, 0, sizeof(*cbd));
i = (i + 1) % cbdr->bd_num;
@@ -135,7 +135,8 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
cbdr->next_to_use = i;
netc_write(cbdr->regs.pir, i);
- err = read_poll_timeout_atomic(netc_read, val, val == i,
+ err = read_poll_timeout_atomic(netc_read, val,
+ (val & NETC_CBDRCIR_INDEX) == i,
NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT,
true, cbdr->regs.cir);
if (unlikely(err))
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
index 34394e40fddd..7a53db8740db 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
+++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
@@ -12,6 +12,7 @@
#define NTMP_EID_REQ_LEN 8
#define NETC_CBDR_BD_NUM 256
+#define NETC_CBDRCIR_INDEX GENMASK(9, 0)
union netc_cbd {
struct {
--
2.34.1
^ permalink raw reply related
* [PATCH net 2/2] net: enetc: fix NTMP DMA use-after-free issue
From: Wei Fang @ 2026-04-13 7:52 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, chleroy
Cc: netdev, linux-kernel, imx, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260413075250.281653-1-wei.fang@nxp.com>
The AI-generated review reported a potential DMA use-after-free issue
[1]. If netc_xmit_ntmp_cmd() times out and returns an error, the pending
command is not explicitly aborted, while ntmp_free_data_mem()
unconditionally frees the DMA buffer. If the buffer has already been
reallocated elsewhere, this may lead to silent memory corruption. Because
the hardware eventually processes the pending command and perform a DMA
write of the response to the physical address of the freed buffer.
To resolve this issue, this patch does the following modifications:
1. Convert cbdr->ring_lock from a spinlock to a mutex
The lock was originally a spinlock in case NTMP operations might be
invoked from atomic context. After downstream support for all NTMP
tables, no such usage has materialized. A mutex lock is now required
because the driver now needs to reclaim used BDs and release associated
DMA memory within the lock's context, while dma_free_coherent() might
sleep.
2. Introduce software command BD (struct netc_swcbd)
The hardware write-back overwrites the addr and len fields of the BD,
so the driver cannot rely on the hardware BD to free the associated DMA
memory. The driver now maintains a software shadow BD storing the DMA
buffer pointer, DMA address, and size. And netc_xmit_ntmp_cmd() only
reclaims older BDs when the number of used BDs reaches
NETC_CBDR_CLEAN_WORK (16). The software BD enables correct DMA memory
release. With this, struct ntmp_dma_buf and ntmp_free_data_mem() are no
longer needed and are removed.
These changes eliminate the DMA use-after-free condition and ensure safe
and consistent BD reclamation and DMA buffer lifecycle management.
Fixes: 4701073c3deb ("net: enetc: add initial netc-lib driver to support NTMP")
Link: https://lore.kernel.org/netdev/20260403011729.1795413-1-kuba@kernel.org/ # [1]
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/ntmp.c | 158 ++++++++++--------
.../ethernet/freescale/enetc/ntmp_private.h | 8 +-
include/linux/fsl/ntmp.h | 9 +-
3 files changed, 93 insertions(+), 82 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c
index 1b1ff0446d0a..3efc65443113 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp.c
+++ b/drivers/net/ethernet/freescale/enetc/ntmp.c
@@ -7,6 +7,7 @@
#include <linux/dma-mapping.h>
#include <linux/fsl/netc_global.h>
#include <linux/iopoll.h>
+#include <linux/vmalloc.h>
#include "ntmp_private.h"
@@ -42,6 +43,12 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
if (!cbdr->addr_base)
return -ENOMEM;
+ cbdr->swcbd = vcalloc(cbd_num, sizeof(struct netc_swcbd));
+ if (!cbdr->swcbd) {
+ dma_free_coherent(dev, size, cbdr->addr_base, cbdr->dma_base);
+ return -ENOMEM;
+ }
+
cbdr->dma_size = size;
cbdr->bd_num = cbd_num;
cbdr->regs = *regs;
@@ -52,7 +59,7 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
cbdr->addr_base_align = PTR_ALIGN(cbdr->addr_base,
NTMP_BASE_ADDR_ALIGN);
- spin_lock_init(&cbdr->ring_lock);
+ mutex_init(&cbdr->ring_lock);
cbdr->next_to_use = netc_read(cbdr->regs.pir);
cbdr->next_to_clean = netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX;
@@ -71,10 +78,25 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
}
EXPORT_SYMBOL_GPL(ntmp_init_cbdr);
+static void ntmp_free_data_mem(struct device *dev, struct netc_swcbd *swcbd)
+{
+ dma_free_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN,
+ swcbd->buf, swcbd->dma);
+}
+
void ntmp_free_cbdr(struct netc_cbdr *cbdr)
{
/* Disable the Control BD Ring */
netc_write(cbdr->regs.mr, 0);
+
+ for (int i = 0; i < cbdr->bd_num; i++) {
+ struct netc_swcbd *swcbd = &cbdr->swcbd[i];
+
+ if (swcbd->dma)
+ ntmp_free_data_mem(cbdr->dev, swcbd);
+ }
+
+ vfree(cbdr->swcbd);
dma_free_coherent(cbdr->dev, cbdr->dma_size, cbdr->addr_base,
cbdr->dma_base);
memset(cbdr, 0, sizeof(*cbdr));
@@ -94,24 +116,28 @@ static union netc_cbd *ntmp_get_cbd(struct netc_cbdr *cbdr, int index)
static void ntmp_clean_cbdr(struct netc_cbdr *cbdr)
{
- union netc_cbd *cbd;
- int i;
+ int i = cbdr->next_to_clean;
- i = cbdr->next_to_clean;
while ((netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX) != i) {
- cbd = ntmp_get_cbd(cbdr, i);
+ union netc_cbd *cbd = ntmp_get_cbd(cbdr, i);
+ struct netc_swcbd *swcbd = &cbdr->swcbd[i];
+
+ ntmp_free_data_mem(cbdr->dev, swcbd);
+ memset(swcbd, 0, sizeof(*swcbd));
memset(cbd, 0, sizeof(*cbd));
i = (i + 1) % cbdr->bd_num;
}
+ dma_wmb();
cbdr->next_to_clean = i;
}
-static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
+static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd,
+ struct netc_swcbd *swcbd)
{
union netc_cbd *cur_cbd;
struct netc_cbdr *cbdr;
- int i, err;
+ int i, err, used_bds;
u16 status;
u32 val;
@@ -120,14 +146,21 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
*/
cbdr = &user->ring[0];
- spin_lock_bh(&cbdr->ring_lock);
+ mutex_lock(&cbdr->ring_lock);
- if (unlikely(!ntmp_get_free_cbd_num(cbdr)))
+ used_bds = cbdr->bd_num - ntmp_get_free_cbd_num(cbdr);
+ if (unlikely(used_bds >= NETC_CBDR_CLEAN_WORK)) {
ntmp_clean_cbdr(cbdr);
+ if (unlikely(!ntmp_get_free_cbd_num(cbdr))) {
+ err = -EBUSY;
+ goto cbdr_unlock;
+ }
+ }
i = cbdr->next_to_use;
cur_cbd = ntmp_get_cbd(cbdr, i);
*cur_cbd = *cbd;
+ cbdr->swcbd[i] = *swcbd;
dma_wmb();
/* Update producer index of both software and hardware */
@@ -135,10 +168,9 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
cbdr->next_to_use = i;
netc_write(cbdr->regs.pir, i);
- err = read_poll_timeout_atomic(netc_read, val,
- (val & NETC_CBDRCIR_INDEX) == i,
- NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT,
- true, cbdr->regs.cir);
+ err = read_poll_timeout(netc_read, val, (val & NETC_CBDRCIR_INDEX) == i,
+ NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT,
+ true, cbdr->regs.cir);
if (unlikely(err))
goto cbdr_unlock;
@@ -155,36 +187,28 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
dev_err(user->dev, "Command BD error: 0x%04x\n", status);
}
- ntmp_clean_cbdr(cbdr);
- dma_wmb();
-
cbdr_unlock:
- spin_unlock_bh(&cbdr->ring_lock);
+ mutex_unlock(&cbdr->ring_lock);
return err;
}
-static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void **buf_align)
+static int ntmp_alloc_data_mem(struct device *dev, struct netc_swcbd *swcbd,
+ void **buf_align)
{
void *buf;
- buf = dma_alloc_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
- &data->dma, GFP_KERNEL);
+ buf = dma_alloc_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN,
+ &swcbd->dma, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- data->buf = buf;
+ swcbd->buf = buf;
*buf_align = PTR_ALIGN(buf, NTMP_DATA_ADDR_ALIGN);
return 0;
}
-static void ntmp_free_data_mem(struct ntmp_dma_buf *data)
-{
- dma_free_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
- data->buf, data->dma);
-}
-
static void ntmp_fill_request_hdr(union netc_cbd *cbd, dma_addr_t dma,
int len, int table_id, int cmd,
int access_method)
@@ -235,37 +259,36 @@ static int ntmp_delete_entry_by_id(struct ntmp_user *user, int tbl_id,
u8 tbl_ver, u32 entry_id, u32 req_len,
u32 resp_len)
{
- struct ntmp_dma_buf data = {
- .dev = user->dev,
+ struct netc_swcbd swcbd = {
.size = max(req_len, resp_len),
};
struct ntmp_req_by_eid *req;
union netc_cbd cbd;
int err;
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
ntmp_fill_crd_eid(req, tbl_ver, 0, 0, entry_id);
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(req_len, resp_len),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(req_len, resp_len),
tbl_id, NTMP_CMD_DELETE, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ err = netc_xmit_ntmp_cmd(user, &cbd, &swcbd);
if (err)
dev_err(user->dev,
"Failed to delete entry 0x%x of %s, err: %pe",
entry_id, ntmp_table_name(tbl_id), ERR_PTR(err));
- ntmp_free_data_mem(&data);
-
return err;
}
static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
- u32 len, struct ntmp_req_by_eid *req,
- dma_addr_t dma, bool compare_eid)
+ struct ntmp_req_by_eid *req,
+ struct netc_swcbd *swcbd,
+ bool compare_eid)
{
+ u32 len = NTMP_LEN(sizeof(*req), swcbd->size);
struct ntmp_cmn_resp_query *resp;
int cmd = NTMP_CMD_QUERY;
union netc_cbd cbd;
@@ -277,8 +300,9 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
cmd = NTMP_CMD_QU;
/* Request header */
- ntmp_fill_request_hdr(&cbd, dma, len, tbl_id, cmd, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ ntmp_fill_request_hdr(&cbd, swcbd->dma, len, tbl_id, cmd,
+ NTMP_AM_ENTRY_ID);
+ err = netc_xmit_ntmp_cmd(user, &cbd, swcbd);
if (err) {
dev_err(user->dev,
"Failed to query entry 0x%x of %s, err: %pe\n",
@@ -306,15 +330,14 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id,
struct maft_entry_data *maft)
{
- struct ntmp_dma_buf data = {
- .dev = user->dev,
+ struct netc_swcbd swcbd = {
.size = sizeof(struct maft_req_add),
};
struct maft_req_add *req;
union netc_cbd cbd;
int err;
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
@@ -323,15 +346,13 @@ int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id,
req->keye = maft->keye;
req->cfge = maft->cfge;
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0),
NTMP_MAFT_ID, NTMP_CMD_ADD, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ err = netc_xmit_ntmp_cmd(user, &cbd, &swcbd);
if (err)
dev_err(user->dev, "Failed to add MAFT entry 0x%x, err: %pe\n",
entry_id, ERR_PTR(err));
- ntmp_free_data_mem(&data);
-
return err;
}
EXPORT_SYMBOL_GPL(ntmp_maft_add_entry);
@@ -339,33 +360,27 @@ EXPORT_SYMBOL_GPL(ntmp_maft_add_entry);
int ntmp_maft_query_entry(struct ntmp_user *user, u32 entry_id,
struct maft_entry_data *maft)
{
- struct ntmp_dma_buf data = {
- .dev = user->dev,
+ struct netc_swcbd swcbd = {
.size = sizeof(struct maft_resp_query),
};
struct maft_resp_query *resp;
struct ntmp_req_by_eid *req;
int err;
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
ntmp_fill_crd_eid(req, user->tbl.maft_ver, 0, 0, entry_id);
- err = ntmp_query_entry_by_id(user, NTMP_MAFT_ID,
- NTMP_LEN(sizeof(*req), data.size),
- req, data.dma, true);
+ err = ntmp_query_entry_by_id(user, NTMP_MAFT_ID, req, &swcbd, true);
if (err)
- goto end;
+ return err;
resp = (struct maft_resp_query *)req;
maft->keye = resp->keye;
maft->cfge = resp->cfge;
-end:
- ntmp_free_data_mem(&data);
-
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(ntmp_maft_query_entry);
@@ -379,8 +394,8 @@ EXPORT_SYMBOL_GPL(ntmp_maft_delete_entry);
int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
int count)
{
- struct ntmp_dma_buf data = {.dev = user->dev};
struct rsst_req_update *req;
+ struct netc_swcbd swcbd;
union netc_cbd cbd;
int err, i;
@@ -388,8 +403,8 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
/* HW only takes in a full 64 entry table */
return -EINVAL;
- data.size = struct_size(req, groups, count);
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ swcbd.size = struct_size(req, groups, count);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
@@ -399,24 +414,22 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
for (i = 0; i < count; i++)
req->groups[i] = (u8)(table[i]);
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0),
NTMP_RSST_ID, NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ err = netc_xmit_ntmp_cmd(user, &cbd, &swcbd);
if (err)
dev_err(user->dev, "Failed to update RSST entry, err: %pe\n",
ERR_PTR(err));
- ntmp_free_data_mem(&data);
-
return err;
}
EXPORT_SYMBOL_GPL(ntmp_rsst_update_entry);
int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
{
- struct ntmp_dma_buf data = {.dev = user->dev};
struct ntmp_req_by_eid *req;
+ struct netc_swcbd swcbd;
union netc_cbd cbd;
int err, i;
u8 *group;
@@ -425,21 +438,21 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
/* HW only takes in a full 64 entry table */
return -EINVAL;
- data.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
- RSST_CFGE_DATA_SIZE(count);
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ swcbd.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
+ RSST_CFGE_DATA_SIZE(count);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
/* Set the request data buffer */
ntmp_fill_crd_eid(req, user->tbl.rsst_ver, 0, 0, 0);
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(sizeof(*req), data.size),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(sizeof(*req), swcbd.size),
NTMP_RSST_ID, NTMP_CMD_QUERY, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ err = netc_xmit_ntmp_cmd(user, &cbd, &swcbd);
if (err) {
dev_err(user->dev, "Failed to query RSST entry, err: %pe\n",
ERR_PTR(err));
- goto end;
+ return err;
}
group = (u8 *)req;
@@ -447,10 +460,7 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
for (i = 0; i < count; i++)
table[i] = group[i];
-end:
- ntmp_free_data_mem(&data);
-
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(ntmp_rsst_query_entry);
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
index 7a53db8740db..5ae6f8b92700 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
+++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
@@ -13,6 +13,7 @@
#define NTMP_EID_REQ_LEN 8
#define NETC_CBDR_BD_NUM 256
#define NETC_CBDRCIR_INDEX GENMASK(9, 0)
+#define NETC_CBDR_CLEAN_WORK 16
union netc_cbd {
struct {
@@ -55,13 +56,6 @@ union netc_cbd {
} resp_hdr; /* NTMP Response Message Header Format */
};
-struct ntmp_dma_buf {
- struct device *dev;
- size_t size;
- void *buf;
- dma_addr_t dma;
-};
-
struct ntmp_cmn_req_data {
__le16 update_act;
u8 dbg_opt;
diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h
index 916dc4fe7de3..83a449b4d6ec 100644
--- a/include/linux/fsl/ntmp.h
+++ b/include/linux/fsl/ntmp.h
@@ -31,6 +31,12 @@ struct netc_tbl_vers {
u8 rsst_ver;
};
+struct netc_swcbd {
+ void *buf;
+ dma_addr_t dma;
+ size_t size;
+};
+
struct netc_cbdr {
struct device *dev;
struct netc_cbdr_regs regs;
@@ -44,9 +50,10 @@ struct netc_cbdr {
void *addr_base_align;
dma_addr_t dma_base;
dma_addr_t dma_base_align;
+ struct netc_swcbd *swcbd;
/* Serialize the order of command BD ring */
- spinlock_t ring_lock;
+ struct mutex ring_lock;
};
struct ntmp_user {
--
2.34.1
^ permalink raw reply related
* Re: [PATCH] pinctrl: mediatek: moore: implement gpio_chip::get_direction()
From: Linus Walleij @ 2026-04-13 8:01 UTC (permalink / raw)
To: Frank Wunderlich
Cc: bartosz.golaszewski, linux, sean.wang, matthias.bgg,
angelogioacchino.delregno, brgl, linux-mediatek, linux-gpio,
linux-kernel, linux-arm-kernel
In-Reply-To: <trinity-5e6f6a95-e576-4f97-9085-c6de21945eab-1775813076268@trinity-msg-rest-gmx-gmx-live-5cf7d7879b-qwfn5>
On Fri, Apr 10, 2026 at 11:24 AM Frank Wunderlich
<frank-w@public-files.de> wrote:
> > Gesendet: Freitag, 10. April 2026 um 09:09
> > Von: "Bartosz Golaszewski" <bartosz.golaszewski@oss.qualcomm.com>
> > An: "Frank Wunderlich" <linux@fw-web.de>, "Sean Wang" <sean.wang@kernel.org>, "Linus Walleij" <linusw@kernel.org>, "Matthias Brugger" <matthias.bgg@gmail.com>, "AngeloGioacchino Del Regno" <angelogioacchino.delregno@collabora.com>, "Bartosz Golaszewski" <brgl@kernel.org>
> > CC: linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, "Bartosz Golaszewski" <bartosz.golaszewski@oss.qualcomm.com>
> > Betreff: [PATCH] pinctrl: mediatek: moore: implement gpio_chip::get_direction()
> >
> > If the gpio_chip::get_direction() callback is not implemented by the GPIO
> > controller driver, GPIOLIB emits a warning.
> >
> > Implement get_direction() for the GPIO part of pinctrl-moore.
> >
> > Fixes: 471e998c0e31 ("gpiolib: remove redundant callback check")
> > Fixes: e623c4303ed1 ("gpiolib: sanitize the return value of gpio_chip::get_direction()")
> > Reported-by: Frank Wunderlich <linux@fw-web.de>
>
> please use the email i used for SoB in my linked patch (closes link below), the other email i use only for sending patches due to mail provider limitation.
I can't fix this up because the closes link isn't working right now.
Is it the same
as the one this mail came from frank-w@public-files.de?
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v6 0/4] KVM: arm64: PMU: Use multiple host PMUs
From: Akihiko Odaki @ 2026-04-13 8:07 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon, Kees Cook,
Gustavo A. R. Silva, Paolo Bonzini, Jonathan Corbet, Shuah Khan
Cc: linux-arm-kernel, kvmarm, linux-kernel, linux-hardening, devel,
kvm, linux-doc, linux-kselftest, Akihiko Odaki
On a heterogeneous arm64 system, KVM's PMU emulation is based on the
features of a single host PMU instance. When a vCPU is migrated to a
pCPU with an incompatible PMU, counters such as PMCCNTR_EL0 stop
incrementing.
Although this behavior is permitted by the architecture, Windows does
not handle it gracefully and may crash with a division-by-zero error.
The current workaround requires VMMs to pin vCPUs to a set of pCPUs
that share a compatible PMU. This is difficult to implement correctly in
QEMU/libvirt, where pinning occurs after vCPU initialization, and it
also restricts the guest to a subset of available pCPUs.
This patch introduces the KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY
attribute. If set, PMUv3 will be emulated without programmable event
counters. KVM will be able to run VCPUs on any physical CPUs with a
compatible hardware PMU.
This allows Windows guests to run reliably on heterogeneous systems
without crashing, even without vCPU pinning, and enables VMMs to
schedule vCPUs across all available pCPUs, making full use of the host
hardware.
A QEMU patch that demonstrates the usage of the new attribute is
available at:
https://lore.kernel.org/qemu-devel/20260225-kvm-v2-1-b8d743db0f73@rsg.ci.i.u-tokyo.ac.jp/
("[PATCH RFC v2] target/arm/kvm: Choose PMU backend")
Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
Changes in v6:
- Removed WARN_ON_ONCE() in kvm_pmu_create_perf_event(). It can be
triggered in kvm_arch_vcpu_load() before it checks supported_cpus.
- Removed an extra lockdep assertion in kvm_arm_pmu_v3_get_attr().
- Fixed error messages in test_fixed_counters_only().
- Fixed the vCPU run in test_fixed_counters_only().
- Link to v5: https://lore.kernel.org/r/20260411-hybrid-v5-0-b043b4d9f49e@rsg.ci.i.u-tokyo.ac.jp
Changes in v5:
- Rebased.
- Fixed the order to clear KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY in
kvm_arm_pmu_v3_set_pmu().
- Fixed the setting of KVM_ARM_VCPU_PMU_V3_IRQ in
test_fixed_counters_only().
- Changed to WARN_ON_ONCE() when kvm_pmu_probe_armpmu() returns NULL in
kvm_pmu_create_perf_event(), which is no longer supposed to happen.
- Link to v4: https://lore.kernel.org/r/20260317-hybrid-v4-0-bd62bcd48644@rsg.ci.i.u-tokyo.ac.jp
Changes in v4:
- Extracted kvm_pmu_enabled_counter_mask() into a separate patch.
- Added patch "KVM: arm64: PMU: Protect the list of PMUs with RCU".
- Merged KVM_REQ_CREATE_PMU into KVM_REQ_RELOAD_PMU.
- Added a check to avoid unnecessary KVM_REQ_RELOAD_PMU requests.
- Dropped the change to avoid setting kvm_arm_set_default_pmu() when
KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY is not set.
- Link to v3: https://lore.kernel.org/r/20260225-hybrid-v3-0-46e8fe220880@rsg.ci.i.u-tokyo.ac.jp
Changes in v3:
- Renamed the attribute to KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY.
- Changed to request the creation of perf counters when loading vCPU.
- Link to v2: https://lore.kernel.org/r/20250806-hybrid-v2-0-0661aec3af8c@rsg.ci.i.u-tokyo.ac.jp
Changes in v2:
- Added the KVM_ARM_VCPU_PMU_V3_COMPOSITION attribute to opt in the
feature.
- Added code to handle overflow.
- Link to v1: https://lore.kernel.org/r/20250319-hybrid-v1-1-4d1ada10e705@daynix.com
---
Akihiko Odaki (4):
KVM: arm64: PMU: Add kvm_pmu_enabled_counter_mask()
KVM: arm64: PMU: Protect the list of PMUs with RCU
KVM: arm64: PMU: Introduce FIXED_COUNTERS_ONLY
KVM: arm64: selftests: Test PMU_V3_FIXED_COUNTERS_ONLY
Documentation/virt/kvm/devices/vcpu.rst | 29 ++++
arch/arm64/include/asm/kvm_host.h | 2 +
arch/arm64/include/uapi/asm/kvm.h | 1 +
arch/arm64/kvm/arm.c | 1 +
arch/arm64/kvm/pmu-emul.c | 187 ++++++++++++++-------
include/kvm/arm_pmu.h | 2 +
.../selftests/kvm/arm64/vpmu_counter_access.c | 147 +++++++++++++---
7 files changed, 288 insertions(+), 81 deletions(-)
---
base-commit: 9a9c8ce300cd3859cc87b408ef552cd697cc2ab7
change-id: 20250224-hybrid-01d5ff47edd2
Best regards,
--
Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
^ permalink raw reply
* [PATCH v6 1/4] KVM: arm64: PMU: Add kvm_pmu_enabled_counter_mask()
From: Akihiko Odaki @ 2026-04-13 8:07 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon, Kees Cook,
Gustavo A. R. Silva, Paolo Bonzini, Jonathan Corbet, Shuah Khan
Cc: linux-arm-kernel, kvmarm, linux-kernel, linux-hardening, devel,
kvm, linux-doc, linux-kselftest, Akihiko Odaki
In-Reply-To: <20260413-hybrid-v6-0-e79d760f7f1b@rsg.ci.i.u-tokyo.ac.jp>
This function will be useful to enumerate enabled counters.
Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
arch/arm64/kvm/pmu-emul.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index b03dbda7f1ab..59ec96e09321 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -619,18 +619,24 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
}
}
-static bool kvm_pmu_counter_is_enabled(struct kvm_pmc *pmc)
+static u64 kvm_pmu_enabled_counter_mask(struct kvm_vcpu *vcpu)
{
- struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
- unsigned int mdcr = __vcpu_sys_reg(vcpu, MDCR_EL2);
+ u64 mask = 0;
- if (!(__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(pmc->idx)))
- return false;
+ if (__vcpu_sys_reg(vcpu, MDCR_EL2) & MDCR_EL2_HPME)
+ mask |= kvm_pmu_hyp_counter_mask(vcpu);
- if (kvm_pmu_counter_is_hyp(vcpu, pmc->idx))
- return mdcr & MDCR_EL2_HPME;
+ if (kvm_vcpu_read_pmcr(vcpu) & ARMV8_PMU_PMCR_E)
+ mask |= ~kvm_pmu_hyp_counter_mask(vcpu);
+
+ return __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
+}
+
+static bool kvm_pmu_counter_is_enabled(struct kvm_pmc *pmc)
+{
+ struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
- return kvm_vcpu_read_pmcr(vcpu) & ARMV8_PMU_PMCR_E;
+ return kvm_pmu_enabled_counter_mask(vcpu) & BIT(pmc->idx);
}
static bool kvm_pmc_counts_at_el0(struct kvm_pmc *pmc)
--
2.53.0
^ permalink raw reply related
* [PATCH v6 3/4] KVM: arm64: PMU: Introduce FIXED_COUNTERS_ONLY
From: Akihiko Odaki @ 2026-04-13 8:07 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon, Kees Cook,
Gustavo A. R. Silva, Paolo Bonzini, Jonathan Corbet, Shuah Khan
Cc: linux-arm-kernel, kvmarm, linux-kernel, linux-hardening, devel,
kvm, linux-doc, linux-kselftest, Akihiko Odaki
In-Reply-To: <20260413-hybrid-v6-0-e79d760f7f1b@rsg.ci.i.u-tokyo.ac.jp>
On a heterogeneous arm64 system, KVM's PMU emulation is based on the
features of a single host PMU instance. When a vCPU is migrated to a
pCPU with an incompatible PMU, counters such as PMCCNTR_EL0 stop
incrementing.
Although this behavior is permitted by the architecture, Windows does
not handle it gracefully and may crash with a division-by-zero error.
The current workaround requires VMMs to pin vCPUs to a set of pCPUs
that share a compatible PMU. This is difficult to implement correctly in
QEMU/libvirt, where pinning occurs after vCPU initialization, and it
also restricts the guest to a subset of available pCPUs.
Introduce the KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY attribute to
create a "fixed-counters-only" PMU. When set, KVM exposes a PMU that is
compatible with all pCPUs but that does not support programmable
event counters which may have different feature sets on different PMUs.
This allows Windows guests to run reliably on heterogeneous systems
without crashing, even without vCPU pinning, and enables VMMs to
schedule vCPUs across all available pCPUs, making full use of the host
hardware.
Much like KVM_ARM_VCPU_PMU_V3_IRQ and other read-write attributes, this
attribute provides a getter that facilitates kernel and userspace
debugging/testing.
Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
Documentation/virt/kvm/devices/vcpu.rst | 29 ++++++
arch/arm64/include/asm/kvm_host.h | 2 +
arch/arm64/include/uapi/asm/kvm.h | 1 +
arch/arm64/kvm/arm.c | 1 +
arch/arm64/kvm/pmu-emul.c | 155 +++++++++++++++++++++++---------
include/kvm/arm_pmu.h | 2 +
6 files changed, 147 insertions(+), 43 deletions(-)
diff --git a/Documentation/virt/kvm/devices/vcpu.rst b/Documentation/virt/kvm/devices/vcpu.rst
index 60bf205cb373..e0aeb1897d77 100644
--- a/Documentation/virt/kvm/devices/vcpu.rst
+++ b/Documentation/virt/kvm/devices/vcpu.rst
@@ -161,6 +161,35 @@ explicitly selected, or the number of counters is out of range for the
selected PMU. Selecting a new PMU cancels the effect of setting this
attribute.
+1.6 ATTRIBUTE: KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY
+------------------------------------------------------
+
+:Parameters: no additional parameter in kvm_device_attr.addr
+
+:Returns:
+
+ ======= =====================================================
+ -EBUSY Attempted to set after initializing PMUv3 or running
+ VCPU, or attempted to set for the first time after
+ setting an event filter
+ -ENXIO Attempted to get before setting
+ -ENODEV Attempted to set while PMUv3 not supported
+ ======= =====================================================
+
+If set, PMUv3 will be emulated without programmable event counters. The VCPU
+will use any compatible hardware PMU. This attribute is particularly useful on
+heterogeneous systems where different hardware PMUs cover different physical
+CPUs. The compatibility of hardware PMUs can be checked with
+KVM_ARM_VCPU_PMU_V3_SET_PMU. All VCPUs in a VM share this attribute. It isn't
+possible to set it for the first time if a PMU event filter is already present.
+
+Note that KVM will not make any attempts to run the VCPU on the physical CPUs
+with compatible hardware PMUs. This is entirely left to userspace. However,
+attempting to run the VCPU on an unsupported CPU will fail and KVM_RUN will
+return with exit_reason = KVM_EXIT_FAIL_ENTRY and populate the fail_entry struct
+by setting hardware_entry_failure_reason field to
+KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED and the cpu field to the processor id.
+
2. GROUP: KVM_ARM_VCPU_TIMER_CTRL
=================================
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 59f25b85be2b..b59e0182472c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -353,6 +353,8 @@ struct kvm_arch {
#define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS 10
/* Unhandled SEAs are taken to userspace */
#define KVM_ARCH_FLAG_EXIT_SEA 11
+ /* PMUv3 is emulated without progammable event counters */
+#define KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY 12
unsigned long flags;
/* VM-wide vCPU feature set */
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index a792a599b9d6..474c84fa757f 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -436,6 +436,7 @@ enum {
#define KVM_ARM_VCPU_PMU_V3_FILTER 2
#define KVM_ARM_VCPU_PMU_V3_SET_PMU 3
#define KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS 4
+#define KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY 5
#define KVM_ARM_VCPU_TIMER_CTRL 1
#define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0
#define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 620a465248d1..dca16ca26d32 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -634,6 +634,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
if (has_vhe())
kvm_vcpu_load_vhe(vcpu);
kvm_arch_vcpu_load_fp(vcpu);
+ kvm_vcpu_load_pmu(vcpu);
kvm_vcpu_pmu_restore_guest(vcpu);
if (kvm_arm_is_pvtime_enabled(&vcpu->arch))
kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index ef5140bbfe28..d1009c144581 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -326,7 +326,10 @@ u64 kvm_pmu_implemented_counter_mask(struct kvm_vcpu *vcpu)
static void kvm_pmc_enable_perf_event(struct kvm_pmc *pmc)
{
- if (!pmc->perf_event) {
+ struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
+
+ if (!pmc->perf_event ||
+ !cpumask_test_cpu(vcpu->cpu, &to_arm_pmu(pmc->perf_event->pmu)->supported_cpus)) {
kvm_pmu_create_perf_event(pmc);
return;
}
@@ -667,10 +670,8 @@ static bool kvm_pmc_counts_at_el2(struct kvm_pmc *pmc)
return kvm_pmc_read_evtreg(pmc) & ARMV8_PMU_INCLUDE_EL2;
}
-static int kvm_map_pmu_event(struct kvm *kvm, unsigned int eventsel)
+static int kvm_map_pmu_event(struct arm_pmu *pmu, unsigned int eventsel)
{
- struct arm_pmu *pmu = kvm->arch.arm_pmu;
-
/*
* The CPU PMU likely isn't PMUv3; let the driver provide a mapping
* for the guest's PMUv3 event ID.
@@ -681,6 +682,23 @@ static int kvm_map_pmu_event(struct kvm *kvm, unsigned int eventsel)
return eventsel;
}
+static struct arm_pmu *kvm_pmu_probe_armpmu(int cpu)
+{
+ struct arm_pmu_entry *entry;
+ struct arm_pmu *pmu;
+
+ guard(rcu)();
+
+ list_for_each_entry_rcu(entry, &arm_pmus, entry) {
+ pmu = entry->arm_pmu;
+
+ if (cpumask_test_cpu(cpu, &pmu->supported_cpus))
+ return pmu;
+ }
+
+ return NULL;
+}
+
/**
* kvm_pmu_create_perf_event - create a perf event for a counter
* @pmc: Counter context
@@ -694,6 +712,12 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
int eventsel;
u64 evtreg;
+ if (test_bit(KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY, &vcpu->kvm->arch.flags)) {
+ arm_pmu = kvm_pmu_probe_armpmu(vcpu->cpu);
+ if (!arm_pmu)
+ return;
+ }
+
evtreg = kvm_pmc_read_evtreg(pmc);
kvm_pmu_stop_counter(pmc);
@@ -722,7 +746,7 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
* Don't create an event if we're running on hardware that requires
* PMUv3 event translation and we couldn't find a valid mapping.
*/
- eventsel = kvm_map_pmu_event(vcpu->kvm, eventsel);
+ eventsel = kvm_map_pmu_event(arm_pmu, eventsel);
if (eventsel < 0)
return;
@@ -810,42 +834,6 @@ void kvm_host_pmu_init(struct arm_pmu *pmu)
list_add_tail_rcu(&entry->entry, &arm_pmus);
}
-static struct arm_pmu *kvm_pmu_probe_armpmu(void)
-{
- struct arm_pmu_entry *entry;
- struct arm_pmu *pmu;
- int cpu;
-
- guard(rcu)();
-
- /*
- * It is safe to use a stale cpu to iterate the list of PMUs so long as
- * the same value is used for the entirety of the loop. Given this, and
- * the fact that no percpu data is used for the lookup there is no need
- * to disable preemption.
- *
- * It is still necessary to get a valid cpu, though, to probe for the
- * default PMU instance as userspace is not required to specify a PMU
- * type. In order to uphold the preexisting behavior KVM selects the
- * PMU instance for the core during vcpu init. A dependent use
- * case would be a user with disdain of all things big.LITTLE that
- * affines the VMM to a particular cluster of cores.
- *
- * In any case, userspace should just do the sane thing and use the UAPI
- * to select a PMU type directly. But, be wary of the baggage being
- * carried here.
- */
- cpu = raw_smp_processor_id();
- list_for_each_entry_rcu(entry, &arm_pmus, entry) {
- pmu = entry->arm_pmu;
-
- if (cpumask_test_cpu(cpu, &pmu->supported_cpus))
- return pmu;
- }
-
- return NULL;
-}
-
static u64 __compute_pmceid(struct arm_pmu *pmu, bool pmceid1)
{
u32 hi[2], lo[2];
@@ -888,6 +876,9 @@ u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
u64 val, mask = 0;
int base, i, nr_events;
+ if (test_bit(KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY, &vcpu->kvm->arch.flags))
+ return 0;
+
if (!pmceid1) {
val = compute_pmceid0(cpu_pmu);
base = 0;
@@ -915,6 +906,26 @@ u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
return val & mask;
}
+void kvm_vcpu_load_pmu(struct kvm_vcpu *vcpu)
+{
+ unsigned long mask = kvm_pmu_enabled_counter_mask(vcpu);
+ struct kvm_pmc *pmc;
+ struct arm_pmu *cpu_pmu;
+ int i;
+
+ for_each_set_bit(i, &mask, 32) {
+ pmc = kvm_vcpu_idx_to_pmc(vcpu, i);
+ if (!pmc->perf_event)
+ continue;
+
+ cpu_pmu = to_arm_pmu(pmc->perf_event->pmu);
+ if (!cpumask_test_cpu(vcpu->cpu, &cpu_pmu->supported_cpus)) {
+ kvm_make_request(KVM_REQ_RELOAD_PMU, vcpu);
+ break;
+ }
+ }
+}
+
void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu)
{
u64 mask = kvm_pmu_implemented_counter_mask(vcpu);
@@ -1016,6 +1027,9 @@ u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm)
{
struct arm_pmu *arm_pmu = kvm->arch.arm_pmu;
+ if (test_bit(KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY, &kvm->arch.flags))
+ return 0;
+
/*
* PMUv3 requires that all event counters are capable of counting any
* event, though the same may not be true of non-PMUv3 hardware.
@@ -1070,7 +1084,24 @@ static void kvm_arm_set_pmu(struct kvm *kvm, struct arm_pmu *arm_pmu)
*/
int kvm_arm_set_default_pmu(struct kvm *kvm)
{
- struct arm_pmu *arm_pmu = kvm_pmu_probe_armpmu();
+ /*
+ * It is safe to use a stale cpu to iterate the list of PMUs so long as
+ * the same value is used for the entirety of the loop. Given this, and
+ * the fact that no percpu data is used for the lookup there is no need
+ * to disable preemption.
+ *
+ * It is still necessary to get a valid cpu, though, to probe for the
+ * default PMU instance as userspace is not required to specify a PMU
+ * type. In order to uphold the preexisting behavior KVM selects the
+ * PMU instance for the core during vcpu init. A dependent use
+ * case would be a user with disdain of all things big.LITTLE that
+ * affines the VMM to a particular cluster of cores.
+ *
+ * In any case, userspace should just do the sane thing and use the UAPI
+ * to select a PMU type directly. But, be wary of the baggage being
+ * carried here.
+ */
+ struct arm_pmu *arm_pmu = kvm_pmu_probe_armpmu(raw_smp_processor_id());
if (!arm_pmu)
return -ENODEV;
@@ -1098,6 +1129,7 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id)
break;
}
+ clear_bit(KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY, &kvm->arch.flags);
kvm_arm_set_pmu(kvm, arm_pmu);
cpumask_copy(kvm->arch.supported_cpus, &arm_pmu->supported_cpus);
ret = 0;
@@ -1108,11 +1140,42 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id)
return ret;
}
+static int kvm_arm_pmu_v3_set_pmu_fixed_counters_only(struct kvm_vcpu *vcpu)
+{
+ struct kvm *kvm = vcpu->kvm;
+ struct arm_pmu_entry *entry;
+ struct arm_pmu *arm_pmu;
+ struct cpumask *supported_cpus = kvm->arch.supported_cpus;
+
+ lockdep_assert_held(&kvm->arch.config_lock);
+
+ if (kvm_vm_has_ran_once(kvm) ||
+ (kvm->arch.pmu_filter &&
+ !test_bit(KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY, &kvm->arch.flags)))
+ return -EBUSY;
+
+ set_bit(KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY, &kvm->arch.flags);
+ kvm_arm_set_nr_counters(kvm, 0);
+ cpumask_clear(supported_cpus);
+
+ guard(rcu)();
+
+ list_for_each_entry_rcu(entry, &arm_pmus, entry) {
+ arm_pmu = entry->arm_pmu;
+ cpumask_or(supported_cpus, supported_cpus, &arm_pmu->supported_cpus);
+ }
+
+ return 0;
+}
+
static int kvm_arm_pmu_v3_set_nr_counters(struct kvm_vcpu *vcpu, unsigned int n)
{
struct kvm *kvm = vcpu->kvm;
- if (!kvm->arch.arm_pmu)
+ lockdep_assert_held(&kvm->arch.config_lock);
+
+ if (!kvm->arch.arm_pmu &&
+ !test_bit(KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY, &kvm->arch.flags))
return -EINVAL;
if (n > kvm_arm_pmu_get_max_counters(kvm))
@@ -1227,6 +1290,8 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
return kvm_arm_pmu_v3_set_nr_counters(vcpu, n);
}
+ case KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY:
+ return kvm_arm_pmu_v3_set_pmu_fixed_counters_only(vcpu);
case KVM_ARM_VCPU_PMU_V3_INIT:
return kvm_arm_pmu_v3_init(vcpu);
}
@@ -1253,6 +1318,9 @@ int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
irq = vcpu->arch.pmu.irq_num;
return put_user(irq, uaddr);
}
+ case KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY:
+ if (test_bit(KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY, &vcpu->kvm->arch.flags))
+ return 0;
}
return -ENXIO;
@@ -1266,6 +1334,7 @@ int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
case KVM_ARM_VCPU_PMU_V3_FILTER:
case KVM_ARM_VCPU_PMU_V3_SET_PMU:
case KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS:
+ case KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY:
if (kvm_vcpu_has_pmu(vcpu))
return 0;
}
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 96754b51b411..1375cbaf97b2 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -56,6 +56,7 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
u64 select_idx);
+void kvm_vcpu_load_pmu(struct kvm_vcpu *vcpu);
void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu);
int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu,
struct kvm_device_attr *attr);
@@ -161,6 +162,7 @@ static inline u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
static inline void kvm_pmu_update_vcpu_events(struct kvm_vcpu *vcpu) {}
static inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {}
static inline void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu) {}
+static inline void kvm_vcpu_load_pmu(struct kvm_vcpu *vcpu) {}
static inline void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu) {}
static inline u8 kvm_arm_pmu_get_pmuver_limit(void)
{
--
2.53.0
^ permalink raw reply related
* [PATCH v6 4/4] KVM: arm64: selftests: Test PMU_V3_FIXED_COUNTERS_ONLY
From: Akihiko Odaki @ 2026-04-13 8:07 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon, Kees Cook,
Gustavo A. R. Silva, Paolo Bonzini, Jonathan Corbet, Shuah Khan
Cc: linux-arm-kernel, kvmarm, linux-kernel, linux-hardening, devel,
kvm, linux-doc, linux-kselftest, Akihiko Odaki
In-Reply-To: <20260413-hybrid-v6-0-e79d760f7f1b@rsg.ci.i.u-tokyo.ac.jp>
Assert the following:
- KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY is unset at initialization.
- KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY can be set.
- Setting KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY for the first time
after setting an event filter results in EBUSY.
- KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY can be set again even if an
event filter has already been set.
- Setting KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY after running a VCPU
results in EBUSY.
- The existing test cases pass with
KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY set.
Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
.../selftests/kvm/arm64/vpmu_counter_access.c | 147 +++++++++++++++++----
1 file changed, 123 insertions(+), 24 deletions(-)
diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
index ae36325c022f..6e2bf3ad63b2 100644
--- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
+++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
@@ -403,12 +403,7 @@ static void create_vpmu_vm(void *guest_code)
{
struct kvm_vcpu_init init;
uint8_t pmuver, ec;
- uint64_t dfr0, irq = 23;
- struct kvm_device_attr irq_attr = {
- .group = KVM_ARM_VCPU_PMU_V3_CTRL,
- .attr = KVM_ARM_VCPU_PMU_V3_IRQ,
- .addr = (uint64_t)&irq,
- };
+ uint64_t dfr0;
/* The test creates the vpmu_vm multiple times. Ensure a clean state */
memset(&vpmu_vm, 0, sizeof(vpmu_vm));
@@ -434,8 +429,6 @@ static void create_vpmu_vm(void *guest_code)
TEST_ASSERT(pmuver != ID_AA64DFR0_EL1_PMUVer_IMP_DEF &&
pmuver >= ID_AA64DFR0_EL1_PMUVer_IMP,
"Unexpected PMUVER (0x%x) on the vCPU with PMUv3", pmuver);
-
- vcpu_ioctl(vpmu_vm.vcpu, KVM_SET_DEVICE_ATTR, &irq_attr);
}
static void destroy_vpmu_vm(void)
@@ -461,15 +454,25 @@ static void run_vcpu(struct kvm_vcpu *vcpu, uint64_t pmcr_n)
}
}
-static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool expect_fail)
+static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters,
+ bool fixed_counters_only,
+ bool expect_fail)
{
struct kvm_vcpu *vcpu;
unsigned int prev;
int ret;
+ uint64_t irq = 23;
create_vpmu_vm(guest_code);
vcpu = vpmu_vm.vcpu;
+ if (fixed_counters_only)
+ vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
+
+ vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_IRQ, &irq);
+
prev = get_pmcr_n(vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0)));
ret = __vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
@@ -489,15 +492,15 @@ static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool
* Create a guest with one vCPU, set the PMCR_EL0.N for the vCPU to @pmcr_n,
* and run the test.
*/
-static void run_access_test(uint64_t pmcr_n)
+static void run_access_test(uint64_t pmcr_n, bool fixed_counters_only)
{
uint64_t sp;
struct kvm_vcpu *vcpu;
struct kvm_vcpu_init init;
- pr_debug("Test with pmcr_n %lu\n", pmcr_n);
+ pr_debug("Test with pmcr_n %lu, fixed_counters_only %d\n", pmcr_n, fixed_counters_only);
- test_create_vpmu_vm_with_nr_counters(pmcr_n, false);
+ test_create_vpmu_vm_with_nr_counters(pmcr_n, fixed_counters_only, false);
vcpu = vpmu_vm.vcpu;
/* Save the initial sp to restore them later to run the guest again */
@@ -531,14 +534,14 @@ static struct pmreg_sets validity_check_reg_sets[] = {
* Create a VM, and check if KVM handles the userspace accesses of
* the PMU register sets in @validity_check_reg_sets[] correctly.
*/
-static void run_pmregs_validity_test(uint64_t pmcr_n)
+static void run_pmregs_validity_test(uint64_t pmcr_n, bool fixed_counters_only)
{
int i;
struct kvm_vcpu *vcpu;
uint64_t set_reg_id, clr_reg_id, reg_val;
uint64_t valid_counters_mask, max_counters_mask;
- test_create_vpmu_vm_with_nr_counters(pmcr_n, false);
+ test_create_vpmu_vm_with_nr_counters(pmcr_n, fixed_counters_only, false);
vcpu = vpmu_vm.vcpu;
valid_counters_mask = get_counters_mask(pmcr_n);
@@ -588,11 +591,11 @@ static void run_pmregs_validity_test(uint64_t pmcr_n)
* the vCPU to @pmcr_n, which is larger than the host value.
* The attempt should fail as @pmcr_n is too big to set for the vCPU.
*/
-static void run_error_test(uint64_t pmcr_n)
+static void run_error_test(uint64_t pmcr_n, bool fixed_counters_only)
{
pr_debug("Error test with pmcr_n %lu (larger than the host)\n", pmcr_n);
- test_create_vpmu_vm_with_nr_counters(pmcr_n, true);
+ test_create_vpmu_vm_with_nr_counters(pmcr_n, fixed_counters_only, true);
destroy_vpmu_vm();
}
@@ -622,22 +625,118 @@ static bool kvm_supports_nr_counters_attr(void)
return supported;
}
+static void test_config(uint64_t pmcr_n, bool fixed_counters_only)
+{
+ uint64_t i;
+
+ for (i = 0; i <= pmcr_n; i++) {
+ run_access_test(i, fixed_counters_only);
+ run_pmregs_validity_test(i, fixed_counters_only);
+ }
+
+ for (i = pmcr_n + 1; i < ARMV8_PMU_MAX_COUNTERS; i++)
+ run_error_test(i, fixed_counters_only);
+}
+
+static void test_fixed_counters_only(uint64_t pmcr_n)
+{
+ struct kvm_pmu_event_filter filter = { .nevents = 0 };
+ struct kvm_vm *vm;
+ struct kvm_vcpu *running_vcpu;
+ struct kvm_vcpu *stopped_vcpu;
+ struct kvm_vcpu_init init;
+ int ret;
+ uint64_t irq = 23;
+
+ create_vpmu_vm(guest_code);
+ ret = __vcpu_has_device_attr(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY);
+ if (ret) {
+ TEST_ASSERT(ret == -1 && errno == ENXIO,
+ KVM_IOCTL_ERROR(KVM_HAS_DEVICE_ATTR, ret));
+ destroy_vpmu_vm();
+ return;
+ }
+
+ /* Assert that FIXED_COUNTERS_ONLY is unset at initialization. */
+ ret = __vcpu_device_attr_get(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
+ TEST_ASSERT(ret == -1 && errno == ENXIO,
+ KVM_IOCTL_ERROR(KVM_GET_DEVICE_ATTR, ret));
+
+ /* Assert that setting FIXED_COUNTERS_ONLY succeeds. */
+ vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
+
+ /* Assert that getting FIXED_COUNTERS_ONLY succeeds. */
+ vcpu_device_attr_get(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
+
+ /*
+ * Assert that setting FIXED_COUNTERS_ONLY again succeeds even if an
+ * event filter has already been set.
+ */
+ vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_FILTER, &filter);
+
+ vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
+
+ destroy_vpmu_vm();
+
+ create_vpmu_vm(guest_code);
+
+ /*
+ * Assert that setting FIXED_COUNTERS_ONLY results in EBUSY if an event
+ * filter has already been set while FIXED_COUNTERS_ONLY has not.
+ */
+ vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_FILTER, &filter);
+
+ ret = __vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
+ TEST_ASSERT(ret == -1 && errno == EBUSY,
+ KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret));
+
+ destroy_vpmu_vm();
+
+ /*
+ * Assert that setting FIXED_COUNTERS_ONLY after running a VCPU results
+ * in EBUSY.
+ */
+ vm = vm_create(2);
+ vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init);
+ init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3);
+ running_vcpu = aarch64_vcpu_add(vm, 0, &init, guest_code);
+ stopped_vcpu = aarch64_vcpu_add(vm, 1, &init, guest_code);
+ kvm_arch_vm_finalize_vcpus(vm);
+ vcpu_device_attr_set(running_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_IRQ, &irq);
+ vcpu_device_attr_set(running_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_INIT, NULL);
+ run_vcpu(running_vcpu, pmcr_n);
+
+ ret = __vcpu_device_attr_set(stopped_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
+ KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
+ TEST_ASSERT(ret == -1 && errno == EBUSY,
+ KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret));
+
+ kvm_vm_free(vm);
+
+ test_config(0, true);
+}
+
int main(void)
{
- uint64_t i, pmcr_n;
+ uint64_t pmcr_n;
TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3));
TEST_REQUIRE(kvm_supports_vgic_v3());
TEST_REQUIRE(kvm_supports_nr_counters_attr());
pmcr_n = get_pmcr_n_limit();
- for (i = 0; i <= pmcr_n; i++) {
- run_access_test(i);
- run_pmregs_validity_test(i);
- }
-
- for (i = pmcr_n + 1; i < ARMV8_PMU_MAX_COUNTERS; i++)
- run_error_test(i);
+ test_config(pmcr_n, false);
+ test_fixed_counters_only(pmcr_n);
return 0;
}
--
2.53.0
^ permalink raw reply related
* [PATCH v6 2/4] KVM: arm64: PMU: Protect the list of PMUs with RCU
From: Akihiko Odaki @ 2026-04-13 8:07 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon, Kees Cook,
Gustavo A. R. Silva, Paolo Bonzini, Jonathan Corbet, Shuah Khan
Cc: linux-arm-kernel, kvmarm, linux-kernel, linux-hardening, devel,
kvm, linux-doc, linux-kselftest, Akihiko Odaki
In-Reply-To: <20260413-hybrid-v6-0-e79d760f7f1b@rsg.ci.i.u-tokyo.ac.jp>
Convert the list of PMUs to a RCU-protected list that has primitives to
avoid read-side contention.
Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
arch/arm64/kvm/pmu-emul.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index 59ec96e09321..ef5140bbfe28 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -7,9 +7,9 @@
#include <linux/cpu.h>
#include <linux/kvm.h>
#include <linux/kvm_host.h>
-#include <linux/list.h>
#include <linux/perf_event.h>
#include <linux/perf/arm_pmu.h>
+#include <linux/rculist.h>
#include <linux/uaccess.h>
#include <asm/kvm_emulate.h>
#include <kvm/arm_pmu.h>
@@ -26,7 +26,6 @@ static bool kvm_pmu_counter_is_enabled(struct kvm_pmc *pmc);
bool kvm_supports_guest_pmuv3(void)
{
- guard(mutex)(&arm_pmus_lock);
return !list_empty(&arm_pmus);
}
@@ -808,7 +807,7 @@ void kvm_host_pmu_init(struct arm_pmu *pmu)
return;
entry->arm_pmu = pmu;
- list_add_tail(&entry->entry, &arm_pmus);
+ list_add_tail_rcu(&entry->entry, &arm_pmus);
}
static struct arm_pmu *kvm_pmu_probe_armpmu(void)
@@ -817,7 +816,7 @@ static struct arm_pmu *kvm_pmu_probe_armpmu(void)
struct arm_pmu *pmu;
int cpu;
- guard(mutex)(&arm_pmus_lock);
+ guard(rcu)();
/*
* It is safe to use a stale cpu to iterate the list of PMUs so long as
@@ -837,7 +836,7 @@ static struct arm_pmu *kvm_pmu_probe_armpmu(void)
* carried here.
*/
cpu = raw_smp_processor_id();
- list_for_each_entry(entry, &arm_pmus, entry) {
+ list_for_each_entry_rcu(entry, &arm_pmus, entry) {
pmu = entry->arm_pmu;
if (cpumask_test_cpu(cpu, &pmu->supported_cpus))
@@ -1088,9 +1087,9 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id)
int ret = -ENXIO;
lockdep_assert_held(&kvm->arch.config_lock);
- mutex_lock(&arm_pmus_lock);
+ guard(rcu)();
- list_for_each_entry(entry, &arm_pmus, entry) {
+ list_for_each_entry_rcu(entry, &arm_pmus, entry) {
arm_pmu = entry->arm_pmu;
if (arm_pmu->pmu.type == pmu_id) {
if (kvm_vm_has_ran_once(kvm) ||
@@ -1106,7 +1105,6 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id)
}
}
- mutex_unlock(&arm_pmus_lock);
return ret;
}
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v6 4/4] KVM: arm64: selftests: Test PMU_V3_FIXED_COUNTERS_ONLY
From: Akihiko Odaki @ 2026-04-13 8:19 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon, Kees Cook,
Gustavo A. R. Silva, Paolo Bonzini, Jonathan Corbet, Shuah Khan
Cc: linux-arm-kernel, kvmarm, linux-kernel, linux-hardening, devel,
kvm, linux-doc, linux-kselftest
In-Reply-To: <20260413-hybrid-v6-4-e79d760f7f1b@rsg.ci.i.u-tokyo.ac.jp>
On 2026/04/13 17:07, Akihiko Odaki wrote:
> Assert the following:
> - KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY is unset at initialization.
> - KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY can be set.
> - Setting KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY for the first time
> after setting an event filter results in EBUSY.
> - KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY can be set again even if an
> event filter has already been set.
> - Setting KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY after running a VCPU
> results in EBUSY.
> - The existing test cases pass with
> KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY set.
>
> Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
> ---
> .../selftests/kvm/arm64/vpmu_counter_access.c | 147 +++++++++++++++++----
> 1 file changed, 123 insertions(+), 24 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
> index ae36325c022f..6e2bf3ad63b2 100644
> --- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
> +++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
> @@ -403,12 +403,7 @@ static void create_vpmu_vm(void *guest_code)
> {
> struct kvm_vcpu_init init;
> uint8_t pmuver, ec;
> - uint64_t dfr0, irq = 23;
> - struct kvm_device_attr irq_attr = {
> - .group = KVM_ARM_VCPU_PMU_V3_CTRL,
> - .attr = KVM_ARM_VCPU_PMU_V3_IRQ,
> - .addr = (uint64_t)&irq,
> - };
> + uint64_t dfr0;
>
> /* The test creates the vpmu_vm multiple times. Ensure a clean state */
> memset(&vpmu_vm, 0, sizeof(vpmu_vm));
> @@ -434,8 +429,6 @@ static void create_vpmu_vm(void *guest_code)
> TEST_ASSERT(pmuver != ID_AA64DFR0_EL1_PMUVer_IMP_DEF &&
> pmuver >= ID_AA64DFR0_EL1_PMUVer_IMP,
> "Unexpected PMUVER (0x%x) on the vCPU with PMUv3", pmuver);
> -
> - vcpu_ioctl(vpmu_vm.vcpu, KVM_SET_DEVICE_ATTR, &irq_attr);
> }
>
> static void destroy_vpmu_vm(void)
> @@ -461,15 +454,25 @@ static void run_vcpu(struct kvm_vcpu *vcpu, uint64_t pmcr_n)
> }
> }
>
> -static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool expect_fail)
> +static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters,
> + bool fixed_counters_only,
> + bool expect_fail)
> {
> struct kvm_vcpu *vcpu;
> unsigned int prev;
> int ret;
> + uint64_t irq = 23;
>
> create_vpmu_vm(guest_code);
> vcpu = vpmu_vm.vcpu;
>
> + if (fixed_counters_only)
> + vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
> +
> + vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_IRQ, &irq);
> +
> prev = get_pmcr_n(vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0)));
>
> ret = __vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> @@ -489,15 +492,15 @@ static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool
> * Create a guest with one vCPU, set the PMCR_EL0.N for the vCPU to @pmcr_n,
> * and run the test.
> */
> -static void run_access_test(uint64_t pmcr_n)
> +static void run_access_test(uint64_t pmcr_n, bool fixed_counters_only)
> {
> uint64_t sp;
> struct kvm_vcpu *vcpu;
> struct kvm_vcpu_init init;
>
> - pr_debug("Test with pmcr_n %lu\n", pmcr_n);
> + pr_debug("Test with pmcr_n %lu, fixed_counters_only %d\n", pmcr_n, fixed_counters_only);
>
> - test_create_vpmu_vm_with_nr_counters(pmcr_n, false);
> + test_create_vpmu_vm_with_nr_counters(pmcr_n, fixed_counters_only, false);
> vcpu = vpmu_vm.vcpu;
>
> /* Save the initial sp to restore them later to run the guest again */
> @@ -531,14 +534,14 @@ static struct pmreg_sets validity_check_reg_sets[] = {
> * Create a VM, and check if KVM handles the userspace accesses of
> * the PMU register sets in @validity_check_reg_sets[] correctly.
> */
> -static void run_pmregs_validity_test(uint64_t pmcr_n)
> +static void run_pmregs_validity_test(uint64_t pmcr_n, bool fixed_counters_only)
> {
> int i;
> struct kvm_vcpu *vcpu;
> uint64_t set_reg_id, clr_reg_id, reg_val;
> uint64_t valid_counters_mask, max_counters_mask;
>
> - test_create_vpmu_vm_with_nr_counters(pmcr_n, false);
> + test_create_vpmu_vm_with_nr_counters(pmcr_n, fixed_counters_only, false);
> vcpu = vpmu_vm.vcpu;
>
> valid_counters_mask = get_counters_mask(pmcr_n);
> @@ -588,11 +591,11 @@ static void run_pmregs_validity_test(uint64_t pmcr_n)
> * the vCPU to @pmcr_n, which is larger than the host value.
> * The attempt should fail as @pmcr_n is too big to set for the vCPU.
> */
> -static void run_error_test(uint64_t pmcr_n)
> +static void run_error_test(uint64_t pmcr_n, bool fixed_counters_only)
> {
> pr_debug("Error test with pmcr_n %lu (larger than the host)\n", pmcr_n);
>
> - test_create_vpmu_vm_with_nr_counters(pmcr_n, true);
> + test_create_vpmu_vm_with_nr_counters(pmcr_n, fixed_counters_only, true);
> destroy_vpmu_vm();
> }
>
> @@ -622,22 +625,118 @@ static bool kvm_supports_nr_counters_attr(void)
> return supported;
> }
>
> +static void test_config(uint64_t pmcr_n, bool fixed_counters_only)
> +{
> + uint64_t i;
> +
> + for (i = 0; i <= pmcr_n; i++) {
> + run_access_test(i, fixed_counters_only);
> + run_pmregs_validity_test(i, fixed_counters_only);
> + }
> +
> + for (i = pmcr_n + 1; i < ARMV8_PMU_MAX_COUNTERS; i++)
> + run_error_test(i, fixed_counters_only);
> +}
> +
> +static void test_fixed_counters_only(uint64_t pmcr_n)
> +{
> + struct kvm_pmu_event_filter filter = { .nevents = 0 };
> + struct kvm_vm *vm;
> + struct kvm_vcpu *running_vcpu;
> + struct kvm_vcpu *stopped_vcpu;
> + struct kvm_vcpu_init init;
> + int ret;
> + uint64_t irq = 23;
> +
> + create_vpmu_vm(guest_code);
> + ret = __vcpu_has_device_attr(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY);
> + if (ret) {
> + TEST_ASSERT(ret == -1 && errno == ENXIO,
> + KVM_IOCTL_ERROR(KVM_HAS_DEVICE_ATTR, ret));
> + destroy_vpmu_vm();
> + return;
> + }
> +
> + /* Assert that FIXED_COUNTERS_ONLY is unset at initialization. */
> + ret = __vcpu_device_attr_get(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
> + TEST_ASSERT(ret == -1 && errno == ENXIO,
> + KVM_IOCTL_ERROR(KVM_GET_DEVICE_ATTR, ret));
> +
> + /* Assert that setting FIXED_COUNTERS_ONLY succeeds. */
> + vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
> +
> + /* Assert that getting FIXED_COUNTERS_ONLY succeeds. */
> + vcpu_device_attr_get(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
> +
> + /*
> + * Assert that setting FIXED_COUNTERS_ONLY again succeeds even if an
> + * event filter has already been set.
> + */
> + vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_FILTER, &filter);
> +
> + vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
> +
> + destroy_vpmu_vm();
> +
> + create_vpmu_vm(guest_code);
> +
> + /*
> + * Assert that setting FIXED_COUNTERS_ONLY results in EBUSY if an event
> + * filter has already been set while FIXED_COUNTERS_ONLY has not.
> + */
> + vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_FILTER, &filter);
> +
> + ret = __vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
> + TEST_ASSERT(ret == -1 && errno == EBUSY,
> + KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret));
> +
> + destroy_vpmu_vm();
> +
> + /*
> + * Assert that setting FIXED_COUNTERS_ONLY after running a VCPU results
> + * in EBUSY.
> + */
> + vm = vm_create(2);
> + vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init);
> + init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3);
> + running_vcpu = aarch64_vcpu_add(vm, 0, &init, guest_code);
> + stopped_vcpu = aarch64_vcpu_add(vm, 1, &init, guest_code);
> + kvm_arch_vm_finalize_vcpus(vm);
> + vcpu_device_attr_set(running_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_IRQ, &irq);
> + vcpu_device_attr_set(running_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_INIT, NULL);
> + run_vcpu(running_vcpu, pmcr_n);
Sorry, I sent a series before testing by mistake. This hangs the test
and I'll send a fix later. Anything else is fine and ready for review.
Regards,
Akihiko Odaki
> +
> + ret = __vcpu_device_attr_set(stopped_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL);
> + TEST_ASSERT(ret == -1 && errno == EBUSY,
> + KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret));
> +
> + kvm_vm_free(vm);
> +
> + test_config(0, true);
> +}
> +
> int main(void)
> {
> - uint64_t i, pmcr_n;
> + uint64_t pmcr_n;
>
> TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3));
> TEST_REQUIRE(kvm_supports_vgic_v3());
> TEST_REQUIRE(kvm_supports_nr_counters_attr());
>
> pmcr_n = get_pmcr_n_limit();
> - for (i = 0; i <= pmcr_n; i++) {
> - run_access_test(i);
> - run_pmregs_validity_test(i);
> - }
> -
> - for (i = pmcr_n + 1; i < ARMV8_PMU_MAX_COUNTERS; i++)
> - run_error_test(i);
> + test_config(pmcr_n, false);
> + test_fixed_counters_only(pmcr_n);
>
> return 0;
> }
>
^ permalink raw reply
* Re: [PATCH 2/4] soc: amlogic: clk-measure: Add A1 and T7 support
From: Jian Hu @ 2026-04-13 8:21 UTC (permalink / raw)
To: Krzysztof Kozlowski, Neil Armstrong, Jerome Brunet, Kevin Hilman,
Michael Turquette, Martin Blumenstingl, robh+dt, Rob Herring
Cc: devicetree, linux-amlogic, linux-kernel, linux-arm-kernel
In-Reply-To: <9a4f69e7-838a-4992-af1d-46324e14eb48@kernel.org>
On 4/12/2026 5:55 PM, Krzysztof Kozlowski wrote:
> [ EXTERNAL EMAIL ]
>
> On 10/04/2026 12:03, Jian Hu wrote:
>> Add support for the A1 and T7 SoC family in amlogic clk measure.
>>
>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>> ---
>> drivers/soc/amlogic/meson-clk-measure.c | 272 ++++++++++++++++++++++++
>> 1 file changed, 272 insertions(+)
>>
>> diff --git a/drivers/soc/amlogic/meson-clk-measure.c b/drivers/soc/amlogic/meson-clk-measure.c
>> index d862e30a244e..083524671b76 100644
>> --- a/drivers/soc/amlogic/meson-clk-measure.c
>> +++ b/drivers/soc/amlogic/meson-clk-measure.c
>> @@ -787,6 +787,258 @@ static const struct meson_msr_id clk_msr_s4[] = {
>>
>> };
>>
>> +static struct meson_msr_id clk_msr_a1[] = {
> And existing code uses what sort of array? Seems you send us obsolete or
> downstream code.
Thanks for your review.
I have checked the previous Amlogic SoC's commits. Such as Amlogic AXG,
G12A, C3, S4.
The clk_msr_xx entry is added after last SoC's array, sorted by
submissin date rather than alphabetical order.
So I place A1 and T7 after S4 accordingly.
The A1 clock controller driver was already supported in
https://lore.kernel.org/all/20230523135351.19133-7-ddrokosov@sberdevices.ru/
It is also present in the mainline kernel:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/clk/meson/Kconfig#n113
This clock measure IP is used to measure the internal clock paths
frequencies, and A1 clock controller driver was supported.
Since the corresponding clock measure driver does not support A1 yet, So
add A1 clk msr here.
>
> Best regards,
> Krzysztof
^ permalink raw reply
* RE: [EXTERNAL] Re: [PATCH 1/8] hv: Select CONFIG_SYSFB only for CONFIG_HYPERV_VMBUS
From: Saurabh Singh Sengar @ 2026-04-13 8:22 UTC (permalink / raw)
To: Thomas Zimmermann, javierm@redhat.com, arnd@arndb.de,
ardb@kernel.org, ilias.apalodimas@linaro.org,
chenhuacai@kernel.org, kernel@xen0n.name,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
airlied@gmail.com, simona@ffwll.ch, KY Srinivasan, Haiyang Zhang,
wei.liu@kernel.org, Dexuan Cui, Long Li, deller@gmx.de
Cc: linux-arm-kernel@lists.infradead.org, loongarch@lists.linux.dev,
linux-efi@vger.kernel.org, linux-riscv@lists.infradead.org,
dri-devel@lists.freedesktop.org, linux-hyperv@vger.kernel.org,
linux-fbdev@vger.kernel.org, Michael Kelley, Saurabh Sengar,
stable@vger.kernel.org, Wei Liu
In-Reply-To: <2fe8ce91-2dc5-4cf2-b7cf-d495e5cff14b@suse.de>
> Hi
>
> Am 02.04.26 um 12:50 schrieb Saurabh Singh Sengar:
> >> Hyperv's sysfb access only exists in the VMBUS support. Therefore
> >> only select CONFIG_SYSFB for CONFIG_HYPERV_VMBUS. Avoids sysfb code
> >> on systems that don't need it.
> >>
> >> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> >> Fixes: 96959283a58d ("Drivers: hv: Always select CONFIG_SYSFB for
> >> Hyper-V
> >> guests")
> >> Cc: Michael Kelley <mhklinux@outlook.com>
> >> Cc: Saurabh Sengar <ssengar@linux.microsoft.com>
> >> Cc: Wei Liu <wei.liu@kernel.org>
> >> Cc: "K. Y. Srinivasan" <kys@microsoft.com>
> >> Cc: Haiyang Zhang <haiyangz@microsoft.com>
> >> Cc: Dexuan Cui <decui@microsoft.com>
> >> Cc: Long Li <longli@microsoft.com>
> >> Cc: linux-hyperv@vger.kernel.org
> >> Cc: <stable@vger.kernel.org> # v6.16+
> >> ---
> >> drivers/hv/Kconfig | 2 +-
> >> 1 file changed, 1 insertion(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index
> >> 7937ac0cbd0f..2d0b3fcb0ff8 100644
> >> --- a/drivers/hv/Kconfig
> >> +++ b/drivers/hv/Kconfig
> >> @@ -9,7 +9,6 @@ config HYPERV
> >> select PARAVIRT
> >> select X86_HV_CALLBACK_VECTOR if X86
> >> select OF_EARLY_FLATTREE if OF
> >> - select SYSFB if EFI && !HYPERV_VTL_MODE
> >> select IRQ_MSI_LIB if X86
> >> help
> >> Select this option to run Linux as a Hyper-V client operating @@
> >> -62,6
> >> +61,7 @@ config HYPERV_VMBUS
> >> tristate "Microsoft Hyper-V VMBus driver"
> >> depends on HYPERV
> >> default HYPERV
> >> + select SYSFB if EFI && !HYPERV_VTL_MODE
> >> help
> >> Select this option to enable Hyper-V Vmbus driver.
> >>
> >> --
> >> 2.53.0
> > Reviewed-by: Saurabh Sengar <ssengar@linux.microsoft.com>
>
> This fix is independent from the rest of the series. Do you want to merge it or
> can I take it into DRM trees?
Please feel free to take it via DRM tree.
CC : Wei Liu
- Saurabh
^ permalink raw reply
* [PATCH net] net: airoha: Fix possible TX queue stall in airoha_qdma_tx_napi_poll()
From: Lorenzo Bianconi @ 2026-04-13 8:29 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Lorenzo Bianconi
Cc: linux-arm-kernel, linux-mediatek, netdev
Since multiple net_device TX queues can share the same hw QDMA TX queue,
there is no guarantee we have inflight packets queued in hw belonging to a
net_device TX queue stopped in the xmit path because hw QDMA TX queue
can be full. In this corner case the net_device TX queue will never be
re-activated. In order to avoid any potential net_device TX queue stall,
we need to wake all the net_device TX queues feeding the same hw QDMA TX
queue in airoha_qdma_tx_napi_poll routine.
Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 30 ++++++++++++++++++++++++++----
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 9e995094c32a..e7610f36b8e4 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -855,6 +855,19 @@ static int airoha_qdma_init_rx(struct airoha_qdma *qdma)
return 0;
}
+static void airoha_qdma_wake_tx_queues(struct airoha_qdma *qdma)
+{
+ struct airoha_eth *eth = qdma->eth;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
+ struct airoha_gdm_port *port = eth->ports[i];
+
+ if (port && port->qdma == qdma)
+ netif_tx_wake_all_queues(port->dev);
+ }
+}
+
static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
{
struct airoha_tx_irq_queue *irq_q;
@@ -931,12 +944,21 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
txq = netdev_get_tx_queue(skb->dev, queue);
netdev_tx_completed_queue(txq, 1, skb->len);
- if (netif_tx_queue_stopped(txq) &&
- q->ndesc - q->queued >= q->free_thr)
- netif_tx_wake_queue(txq);
-
dev_kfree_skb_any(skb);
}
+
+ if (q->ndesc - q->queued == q->free_thr) {
+ /* Since multiple net_device TX queues can share the
+ * same hw QDMA TX queue, there is no guarantee we have
+ * inflight packets queued in hw belonging to a
+ * net_device TX queue stopped in the xmit path.
+ * In order to avoid any potential net_device TX queue
+ * stall, we need to wake all the net_device TX queues
+ * feeding the same hw QDMA TX queue.
+ */
+ airoha_qdma_wake_tx_queues(qdma);
+ }
+
unlock:
spin_unlock_bh(&q->lock);
}
---
base-commit: 2dddb34dd0d07b01fa770eca89480a4da4f13153
change-id: 20260407-airoha-txq-potential-stall-ad52c53094e8
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply related
* Re: [PATCH] firmware: raspberrypi: Change dependency to ARCH_BCM2835 and COMPILE_TEST
From: kernel test robot @ 2026-04-13 8:29 UTC (permalink / raw)
To: Chen-Yu Tsai, Florian Fainelli,
Broadcom internal kernel review list
Cc: llvm, oe-kbuild-all, Chen-Yu Tsai, linux-rpi-kernel,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260408081150.1710717-1-wenst@chromium.org>
Hi Chen-Yu,
kernel test robot noticed the following build errors:
[auto build test ERROR on soc/for-next]
[also build test ERROR on linus/master v7.0-rc7 next-20260410]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Chen-Yu-Tsai/firmware-raspberrypi-Change-dependency-to-ARCH_BCM2835-and-COMPILE_TEST/20260412-210604
base: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git for-next
patch link: https://lore.kernel.org/r/20260408081150.1710717-1-wenst%40chromium.org
patch subject: [PATCH] firmware: raspberrypi: Change dependency to ARCH_BCM2835 and COMPILE_TEST
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20260413/202604130409.fOhpgXN6-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260413/202604130409.fOhpgXN6-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604130409.fOhpgXN6-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:531:3: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
531 | dsb(sy);
| ^
>> drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:531:7: error: use of undeclared identifier 'sy'
531 | dsb(sy);
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:559:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
559 | dsb(sy); /* data barrier operation */
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:559:6: error: use of undeclared identifier 'sy'
559 | dsb(sy); /* data barrier operation */
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:1944:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
1944 | DEBUG_VALUE(PARSE_HEADER, (int)(long)header);
| ^
include/linux/raspberrypi/vchiq_core.h:71:37: note: expanded from macro 'DEBUG_VALUE'
71 | do { debug_ptr[DEBUG_ ## d] = (v); dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:1944:2: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:71:41: note: expanded from macro 'DEBUG_VALUE'
71 | do { debug_ptr[DEBUG_ ## d] = (v); dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:1946:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
1946 | DEBUG_VALUE(PARSE_MSGID, msgid);
| ^
include/linux/raspberrypi/vchiq_core.h:71:37: note: expanded from macro 'DEBUG_VALUE'
71 | do { debug_ptr[DEBUG_ ## d] = (v); dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:1946:2: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:71:41: note: expanded from macro 'DEBUG_VALUE'
71 | do { debug_ptr[DEBUG_ ## d] = (v); dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2059:4: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
2059 | DEBUG_TRACE(PARSE_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2059:4: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2062:5: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
2062 | DEBUG_TRACE(PARSE_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2062:5: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2097:4: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
2097 | DEBUG_TRACE(PARSE_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2097:4: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2099:5: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
2099 | DEBUG_TRACE(PARSE_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2099:5: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2132:4: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
2132 | DEBUG_TRACE(PARSE_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2132:4: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2137:4: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
2137 | DEBUG_TRACE(PARSE_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.
--
>> drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:665:3: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
665 | DEBUG_TRACE(SERVICE_CALLBACK_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
>> drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:665:3: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:667:3: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
667 | DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
| ^
include/linux/raspberrypi/vchiq_core.h:73:33: note: expanded from macro 'DEBUG_COUNT'
73 | do { debug_ptr[DEBUG_ ## d]++; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:667:3: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:73:37: note: expanded from macro 'DEBUG_COUNT'
73 | do { debug_ptr[DEBUG_ ## d]++; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:675:3: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
675 | DEBUG_TRACE(SERVICE_CALLBACK_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:675:3: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:769:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
769 | DEBUG_TRACE(SERVICE_CALLBACK_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:769:2: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:804:4: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
804 | DEBUG_TRACE(SERVICE_CALLBACK_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:804:4: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:805:4: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
805 | DEBUG_COUNT(MSG_QUEUE_FULL_COUNT);
| ^
include/linux/raspberrypi/vchiq_core.h:73:33: note: expanded from macro 'DEBUG_COUNT'
73 | do { debug_ptr[DEBUG_ ## d]++; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:805:4: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:73:37: note: expanded from macro 'DEBUG_COUNT'
73 | do { debug_ptr[DEBUG_ ## d]++; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:810:5: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
810 | DEBUG_TRACE(SERVICE_CALLBACK_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:810:5: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:814:4: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
814 | DEBUG_TRACE(SERVICE_CALLBACK_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:814:4: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:839:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
839 | DEBUG_TRACE(SERVICE_CALLBACK_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:839:2: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
18 errors generated.
--
>> drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:213:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
213 | DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
>> drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:213:2: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:228:4: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
228 | DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:228:4: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:236:4: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
236 | DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:236:4: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:279:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
279 | DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:279:2: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:454:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
454 | DEBUG_TRACE(AWAIT_COMPLETION_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:454:2: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:460:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
460 | DEBUG_TRACE(AWAIT_COMPLETION_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:460:2: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:464:3: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
464 | DEBUG_TRACE(AWAIT_COMPLETION_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:464:3: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:469:4: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
469 | DEBUG_TRACE(AWAIT_COMPLETION_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:469:4: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:475:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
475 | DEBUG_TRACE(AWAIT_COMPLETION_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:475:2: error: use of undeclared identifier 'sy'
include/linux/raspberrypi/vchiq_core.h:69:46: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:578:2: error: call to undeclared function 'dsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
578 | DEBUG_TRACE(AWAIT_COMPLETION_LINE);
| ^
include/linux/raspberrypi/vchiq_core.h:69:42: note: expanded from macro 'DEBUG_TRACE'
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.
vim +/dsb +531 drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 513
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 514 /*
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 515 * All the event waiting routines in VCHIQ used a custom semaphore
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 516 * implementation that filtered most signals. This achieved a behaviour similar
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 517 * to the "killable" family of functions. While cleaning up this code all the
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 518 * routines where switched to the "interruptible" family of functions, as the
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 519 * former was deemed unjustified and the use "killable" set all VCHIQ's
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 520 * threads in D state.
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 521 *
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 522 * Returns: 0 on success, a negative error code on failure
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 523 */
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 524 static inline int
4075fa9efc4ee6 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Dominic Braun 2018-12-14 525 remote_event_wait(wait_queue_head_t *wq, struct remote_event *event)
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 526 {
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 527 int ret = 0;
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 528
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 529 if (!event->fired) {
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 530 event->armed = 1;
35b7ebda57affc drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Michael Zoran 2016-10-19 @531 dsb(sy);
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 532 ret = wait_event_interruptible(*wq, event->fired);
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 533 if (ret) {
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 534 event->armed = 0;
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 535 return ret;
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 536 }
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 537 event->armed = 0;
f6c99d86246ad4 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Phil Elwell 2022-06-24 538 /* Ensure that the peer sees that we are not waiting (armed == 0). */
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 539 wmb();
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 540 }
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 541
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 542 event->fired = 0;
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 543 return ret;
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 544 }
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 545
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH] firmware: raspberrypi: Change dependency to ARCH_BCM2835 and COMPILE_TEST
From: kernel test robot @ 2026-04-13 8:29 UTC (permalink / raw)
To: Chen-Yu Tsai, Florian Fainelli,
Broadcom internal kernel review list
Cc: oe-kbuild-all, Chen-Yu Tsai, linux-rpi-kernel, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260408081150.1710717-1-wenst@chromium.org>
Hi Chen-Yu,
kernel test robot noticed the following build errors:
[auto build test ERROR on soc/for-next]
[also build test ERROR on linus/master v7.0-rc7 next-20260410]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Chen-Yu-Tsai/firmware-raspberrypi-Change-dependency-to-ARCH_BCM2835-and-COMPILE_TEST/20260412-210604
base: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git for-next
patch link: https://lore.kernel.org/r/20260408081150.1710717-1-wenst%40chromium.org
patch subject: [PATCH] firmware: raspberrypi: Change dependency to ARCH_BCM2835 and COMPILE_TEST
config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20260413/202604130727.sB8gZrr6-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260413/202604130727.sB8gZrr6-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604130727.sB8gZrr6-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c: In function 'remote_event_wait':
>> drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:531:17: error: implicit declaration of function 'dsb' [-Wimplicit-function-declaration]
531 | dsb(sy);
| ^~~
>> drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:531:21: error: 'sy' undeclared (first use in this function); did you mean 's8'?
531 | dsb(sy);
| ^~
| s8
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:531:21: note: each undeclared identifier is reported only once for each function it appears in
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c: In function 'remote_event_signal':
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:559:13: error: 'sy' undeclared (first use in this function); did you mean 's8'?
559 | dsb(sy); /* data barrier operation */
| ^~
| s8
In file included from include/linux/raspberrypi/vchiq_arm.h:14,
from drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:18:
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c: In function 'parse_message':
>> include/linux/raspberrypi/vchiq_core.h:71:48: error: 'sy' undeclared (first use in this function); did you mean 's8'?
71 | do { debug_ptr[DEBUG_ ## d] = (v); dsb(sy); } while (0)
| ^~
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:1944:9: note: in expansion of macro 'DEBUG_VALUE'
1944 | DEBUG_VALUE(PARSE_HEADER, (int)(long)header);
| ^~~~~~~~~~~
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c: In function 'parse_rx_slots':
include/linux/raspberrypi/vchiq_core.h:69:53: error: 'sy' undeclared (first use in this function); did you mean 's8'?
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^~
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2213:17: note: in expansion of macro 'DEBUG_TRACE'
2213 | DEBUG_TRACE(PARSE_LINE);
| ^~~~~~~~~~~
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c: In function 'slot_handler_func':
include/linux/raspberrypi/vchiq_core.h:73:44: error: 'sy' undeclared (first use in this function); did you mean 's8'?
73 | do { debug_ptr[DEBUG_ ## d]++; dsb(sy); } while (0)
| ^~
drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c:2314:17: note: in expansion of macro 'DEBUG_COUNT'
2314 | DEBUG_COUNT(SLOT_HANDLER_COUNT);
| ^~~~~~~~~~~
--
In file included from drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:33:
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c: In function 'add_completion':
>> include/linux/raspberrypi/vchiq_core.h:69:49: error: implicit declaration of function 'dsb' [-Wimplicit-function-declaration]
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^~~
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:665:17: note: in expansion of macro 'DEBUG_TRACE'
665 | DEBUG_TRACE(SERVICE_CALLBACK_LINE);
| ^~~~~~~~~~~
include/linux/raspberrypi/vchiq_core.h:69:53: error: 'sy' undeclared (first use in this function); did you mean 's8'?
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^~
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:665:17: note: in expansion of macro 'DEBUG_TRACE'
665 | DEBUG_TRACE(SERVICE_CALLBACK_LINE);
| ^~~~~~~~~~~
include/linux/raspberrypi/vchiq_core.h:69:53: note: each undeclared identifier is reported only once for each function it appears in
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^~
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:665:17: note: in expansion of macro 'DEBUG_TRACE'
665 | DEBUG_TRACE(SERVICE_CALLBACK_LINE);
| ^~~~~~~~~~~
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c: In function 'service_callback':
include/linux/raspberrypi/vchiq_core.h:69:53: error: 'sy' undeclared (first use in this function); did you mean 's8'?
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^~
drivers/platform/raspberrypi/vchiq-interface/vchiq_arm.c:769:9: note: in expansion of macro 'DEBUG_TRACE'
769 | DEBUG_TRACE(SERVICE_CALLBACK_LINE);
| ^~~~~~~~~~~
--
In file included from drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:14:
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c: In function 'vchiq_ioc_dequeue_message':
>> include/linux/raspberrypi/vchiq_core.h:69:49: error: implicit declaration of function 'dsb' [-Wimplicit-function-declaration]
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^~~
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:213:9: note: in expansion of macro 'DEBUG_TRACE'
213 | DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
| ^~~~~~~~~~~
include/linux/raspberrypi/vchiq_core.h:69:53: error: 'sy' undeclared (first use in this function); did you mean 's8'?
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^~
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:213:9: note: in expansion of macro 'DEBUG_TRACE'
213 | DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
| ^~~~~~~~~~~
include/linux/raspberrypi/vchiq_core.h:69:53: note: each undeclared identifier is reported only once for each function it appears in
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^~
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:213:9: note: in expansion of macro 'DEBUG_TRACE'
213 | DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
| ^~~~~~~~~~~
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c: In function 'vchiq_ioc_await_completion':
include/linux/raspberrypi/vchiq_core.h:69:53: error: 'sy' undeclared (first use in this function); did you mean 's8'?
69 | do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
| ^~
drivers/platform/raspberrypi/vchiq-interface/vchiq_dev.c:454:9: note: in expansion of macro 'DEBUG_TRACE'
454 | DEBUG_TRACE(AWAIT_COMPLETION_LINE);
| ^~~~~~~~~~~
vim +/dsb +531 drivers/platform/raspberrypi/vchiq-interface/vchiq_core.c
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 513
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 514 /*
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 515 * All the event waiting routines in VCHIQ used a custom semaphore
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 516 * implementation that filtered most signals. This achieved a behaviour similar
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 517 * to the "killable" family of functions. While cleaning up this code all the
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 518 * routines where switched to the "interruptible" family of functions, as the
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 519 * former was deemed unjustified and the use "killable" set all VCHIQ's
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 520 * threads in D state.
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 521 *
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 522 * Returns: 0 on success, a negative error code on failure
77cf3f5dcf35c8 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Nicolas Saenz Julienne 2019-05-09 523 */
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 524 static inline int
4075fa9efc4ee6 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Dominic Braun 2018-12-14 525 remote_event_wait(wait_queue_head_t *wq, struct remote_event *event)
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 526 {
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 527 int ret = 0;
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 528
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 529 if (!event->fired) {
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 530 event->armed = 1;
35b7ebda57affc drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Michael Zoran 2016-10-19 @531 dsb(sy);
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 532 ret = wait_event_interruptible(*wq, event->fired);
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 533 if (ret) {
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 534 event->armed = 0;
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 535 return ret;
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 536 }
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 537 event->armed = 0;
f6c99d86246ad4 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Phil Elwell 2022-06-24 538 /* Ensure that the peer sees that we are not waiting (armed == 0). */
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 539 wmb();
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 540 }
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 541
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 542 event->fired = 0;
c22502cb84d4c9 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c Umang Jain 2024-07-03 543 return ret;
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 544 }
71bad7f086419d drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c popcornmix 2013-07-02 545
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH] drm/bridge: stm_lvds: Do not fail atomic_check on disabled connector
From: Raphael Gallais-Pou @ 2026-04-13 8:30 UTC (permalink / raw)
To: Marek Vasut, dri-devel
Cc: Alexandre Torgue, David Airlie, Maarten Lankhorst,
Maxime Coquelin, Maxime Ripard, Philippe Cornu, Simona Vetter,
Thomas Zimmermann, Yannick Fertre, linux-arm-kernel, linux-kernel,
linux-stm32
In-Reply-To: <20260409024928.344010-1-marex@nabladev.com>
On 4/9/26 04:48, Marek Vasut wrote:
> If the connector is disabled, the new connector state has .crtc field
> set to NULL and there is nothing more to validate after that point.
> The .crtc field being NULL is not an error. Test for .crtc being NULL,
> and if it is NULL, exit early with return 0.
>
> This fixes a failure in suspend/resume path, where the connector is
> already disabled, but .atomic_check is called, fails, returns -EINVAL
> and blocks the suspend entry.
>
> Fixes: aca1cbc1c986 ("drm/stm: lvds: add new STM32 LVDS Display Interface Transmitter driver")
> Signed-off-by: Marek Vasut <marex@nabladev.com>
> ---
Hi Marek,
Acked-by: Raphaël Gallais-Pou <raphael.gallais-pou@foss.st.com>
Thanks,
Best regards,
Raphaël
> Cc: Alexandre Torgue <alexandre.torgue@foss.st.com>
> Cc: David Airlie <airlied@gmail.com>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> Cc: Maxime Ripard <mripard@kernel.org>
> Cc: Philippe Cornu <philippe.cornu@foss.st.com>
> Cc: Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
> Cc: Simona Vetter <simona@ffwll.ch>
> Cc: Thomas Zimmermann <tzimmermann@suse.de>
> Cc: Yannick Fertre <yannick.fertre@foss.st.com>
> Cc: dri-devel@lists.freedesktop.org
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> Cc: linux-stm32@st-md-mailman.stormreply.com
> ---
> drivers/gpu/drm/stm/lvds.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/stm/lvds.c b/drivers/gpu/drm/stm/lvds.c
> index fe38c0984b2b5..25e2ba98f36ae 100644
> --- a/drivers/gpu/drm/stm/lvds.c
> +++ b/drivers/gpu/drm/stm/lvds.c
> @@ -897,14 +897,14 @@ static int lvds_connector_atomic_check(struct drm_connector *connector,
> if (!conn_state)
> return -EINVAL;
>
> + if (!conn_state->crtc)
> + return 0;
> +
> if (list_empty(&connector->modes)) {
> drm_dbg(connector->dev, "connector: empty modes list\n");
> return -EINVAL;
> }
>
> - if (!conn_state->crtc)
> - return -EINVAL;
> -
> panel_mode = list_first_entry(&connector->modes,
> struct drm_display_mode, head);
>
^ permalink raw reply
* Re: [PATCH 1/1] virt: arm-cca-guest: fix error check for RSI_INCOMPLETE
From: Steven Price @ 2026-04-13 8:30 UTC (permalink / raw)
To: Sami Mujawar, linux-arm-kernel, linux-kernel
Cc: catalin.marinas, will, suzuki.poulose, gshan, YeoReum.Yun,
Jagdish Gediya
In-Reply-To: <20260410163636.259443-1-sami.mujawar@arm.com>
On 10/04/2026 17:36, Sami Mujawar wrote:
> The RSI interface can return RSI_INCOMPLETE when a report spans
> multiple granules. This is an expected condition and should not be
> treated as a fatal error.
>
> Currently, arm_cca_report_new() checks for `info.result != RSI_SUCCESS`
> and bails out, which incorrectly flags RSI_INCOMPLETE as a failure.
> Fix the check to only break out on results other than RSI_SUCCESS or
> RSI_INCOMPLETE.
>
> This ensures partial reports are handled correctly and avoids spurious
> -ENXIO errors when generating attestation reports.
>
> Fixes: 7999edc484ca ("virt: arm-cca-guest: TSM_REPORT support for realms")
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> Reported-by: Jagdish Gediya <Jagdish.Gediya@arm.com>
Reviewed-by: Steven Price <steven.price@arm.com>
> ---
> drivers/virt/coco/arm-cca-guest/arm-cca-guest.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
> index 0c9ea24a200c..66d00b6ceb78 100644
> --- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
> +++ b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
> @@ -157,7 +157,8 @@ static int arm_cca_report_new(struct tsm_report *report, void *data)
> } while (info.result == RSI_INCOMPLETE &&
> info.offset < RSI_GRANULE_SIZE);
>
> - if (info.result != RSI_SUCCESS) {
> + /* Break out in case of failure */
> + if (info.result != RSI_SUCCESS && info.result != RSI_INCOMPLETE) {
> ret = -ENXIO;
> token_size = 0;
> goto exit_free_granule_page;
^ permalink raw reply
* Re: [GIT PULL] firmware: arm_ffa: Fix for v7.1
From: Sudeep Holla @ 2026-04-13 8:32 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: Krzysztof Kozlowski, arm, SoC Team, Sudeep Holla, ALKML
In-Reply-To: <45bc09d9-33e0-48c4-92a3-9bf8e64ef80a@app.fastmail.com>
On Mon, Apr 13, 2026 at 08:23:58AM +0200, Arnd Bergmann wrote:
> On Sat, Apr 11, 2026, at 19:35, Sudeep Holla wrote:
> > On Sat, Apr 11, 2026 at 10:49:50AM +0200, Krzysztof Kozlowski wrote:
> >> On Tue, Apr 07, 2026 at 11:08:39AM +0100, Sudeep Holla wrote:
> >> > ----------------------------------------------------------------
> >> > Arm FF-A fix for v7.1
> >> >
> >> > Use the page aligned backing allocation size when computing the RXTX_MAP
> >> > page count. This fixes FF-A RX/TX buffer registration on kernels built
> >> > with 16K/64K PAGE_SIZE, where alloc_pages_exact() backs the buffer with a
> >> > larger aligned span than the discovered minimum buffer size.
> >>
> >> Can we avoid per-driver trees or pulls? You do maintain also ARM SCMI
> >> firmware driver, so this could be sent together? I think you also use
> >> the same Git tree, right?
> >
> > Sure, I can put all of the firmware drivers I maintain together. I had
> > for some reason assumed individual PR is preferred.
>
> To me, that's a function of how complex the changes are and how
> you describe them in the changelog text: If you have a lot of changes
> for the merge window, having one branch per firmware type probably
> works best, or even multiple ones if you have a series that implements
> something new and a number of random changes do existing code.
>
> If you have only a handful of bugfixes across multiple firmware
> subsystems, a single 'firmware fixes' is less work for all of
> us, with no loss of readability in the git history.
>
Understood, will try to follow something along these in the future.
--
Regards,
Sudeep
^ permalink raw reply
* [PING] Re: [PATCH v7 0/2] arm64: dts/defconfig: enable BST C1200 eMMC
From: Albert Yang @ 2026-04-13 8:34 UTC (permalink / raw)
To: krzk, arnd
Cc: krzk+dt, robh, conor+dt, gordon.ge, bst-upstream,
linux-arm-kernel, devicetree, linux-kernel, yangzh0906
In-Reply-To: <20260310091211.4171307-1-yangzh0906@thundersoft.com>
Hi Krzysztof, Arnd, Rob, and Conor,
Gentle ping for this v7 series posted on 2026-03-10:
https://lore.kernel.org/lkml/20260310091211.4171307-1-yangzh0906@thundersoft.com/
This series only contains the remaining DTS + defconfig parts for BST C1200 eMMC:
- 1/2 arm64: dts: bst: enable eMMC controller in C1200 CDCU1.0 board
- 2/2 arm64: defconfig: enable BST SDHCI controller
The MMC driver-side patches were already applied in mmc-next, so this series is for
arm64/DT review and merge path.
No functional code changes since v7. If preferred, I can send a rebase/refresh (v8)
on top of current mainline immediately.
Could you please help review and let me know if any changes are still needed?
Thanks for your time.
Best regards,
Albert
^ permalink raw reply
* Re: [PATCH V3 7/7] arm64/hw_breakpoint: Enable FEAT_Debugv8p9
From: Mark Rutland @ 2026-04-13 8:48 UTC (permalink / raw)
To: Rob Herring
Cc: Anshuman Khandual, linux-arm-kernel, linux-kernel,
Jonathan Corbet, Marc Zyngier, Oliver Upton, James Morse,
Suzuki K Poulose, Catalin Marinas, Will Deacon, Mark Brown,
kvmarm
In-Reply-To: <CAL_Jsq+=3CKrUDcdgSHFaSGgvnh9ZxTGEBTRLkwrYgzQ=frOdg@mail.gmail.com>
On Fri, Apr 10, 2026 at 02:55:55PM -0500, Rob Herring wrote:
> On Thu, Apr 9, 2026 at 5:52 AM Mark Rutland <mark.rutland@arm.com> wrote:
> > Both breakpoint and watchpoint exceptions are synchronous, meanning that
> > they can only be taken from the specific instruction that triggered
> > them. However, updates to the watchpoint control registers *do* need a
> > context synchronization event before they're guarnateed to take effect.
> >
> > For a sequence:
> >
> > // Initially:
> > // - MDSCR, MDCR, DAIF.D permit debug exceptions at CurrentEL
> > // - No watchpoints enabled
> >
> > 0x000: LDR <val>, [<addr>]
> > 0x004: MSR DBGWVR<n>_EL1, <addr>
> > 0x008: MSR DBGWCR<n>_EL1, <configure_and_enable>
> > 0x010: LDR <val>, [<addr>]
> > 0x014: ISB
> > 0x018: LDR <val>, [<addr>]
> >
> > ... we know:
> >
> > (a) The LDR at 0x000 *cannot* trigger the watchpoint.
>
> Why not?
Because:
(a) As noted above, both breakpoint and watchpoint exceptions are
synchronous. They can only be taken from the specific *instruction*
that triggered them, and the exception must be consistent with no
subsequent instructions having been executed.
In ARM DDI 0487 M.a.a, see:
- Section D1.4 ("Exceptions"), and in particular RFQHGR, RTNVSL.
- Section D2.8 ("Breakpoint exceptions")
- Section D2.9 ("Watchpoint exceptions")
(b) Generally, writes to system registers cannot affect earlier
instructions.
In ARM DDI 0487 M.a.a, see: Section D24.1.2.2 ("Synchronization
requirements for AArch64 System registers").
Note in particular the statement: "Direct writes to System registers
are not allowed to affect any instructions appearing in program
order before the direct write."
> Can't the LDR complete after the MSR?
The memory effects of the LDR at 0x000 could complete after the MSRs at
0x004 and 0x008 are executed.
However, any watchpoints/breakpoint triggered by the LDR at 0x000 must
be taken *before* the next instruction (i.e. the MSR at 0x004) can be
architecturally executed, and any such execption must be consistent with
th PE state prior to that next instruction being executed.
Note that this doesn't forbid the PE from speculating the MSR and other
subsequent instructions; it just has to maintain program order (so later
instructions can't affect earlier instructions), and must be able to
discard anything that was speculated past taking an exception.
> Is ordering ensured between those? Surely the watchpoint triggers on
> completion of the load and that wouldn't stall the PE from doing the
> MSR(s)?
Hopefully the above covers these concerns?
>
> > (b) The LDR at 0x010 *might* trigger the matchpoint.
> > (c) The LDR at 0x018 *must* trigger the watchpoint.
> >
> > For C code, we can enforce this order with barrier(), e.g.
> >
> > val = *addr;
> > barrier();
> > write_sysreg(addr, DBGWVR<n>_EL1);
> > write_sysreg(configure_and_enable, DBGWCR<n>_EL1);
> > isb();
> >
> > ... where the compiler cannot re-order the memory access (or
> > write_sysreg(), or isb()) across the barrier(), and as isb() has a
> > memory clobber, the same is true for isb().
> >
> > Likewise, for the inverse sequence:
> >
> > // Initially:
> > // - MDSCR, MDCR, DAIF.D permit debug exceptions at CurrentEL
> > // - Watchpoint configured and enabled for <addr>
> >
> > 0x100: LDR <val>, [<addr>]
> > 0x104: MSR DBGWCR<n>_EL1, <disable>
> > 0x108: LDR <val>, [<addr>]
> > 0x110: ISB
> > 0x114: LDR <val>, [<addr>]
> >
> > ... we know:
> >
> > (a) The LDR at 0x100 *must* trigger the watchpoint.
> > (b) The LDR at 0x108 *might* trigger the watchpoint.
> > (c) The LDR at 0x114 *cannot* trigger the watchpoint.
> >
> > > Any guidance on the flavor of dsb here? (And is there any guarantee
> > > that the access is visible to the watchpoint h/w after a dsb
> > > completes?)
> >
> > Hopefully the above was sufficient?
> >
> > As mentioned above, I think we have a latent issue where we can take a
> > breakpoint or watchpoint under arch_uninstall_hw_breakpoint(), where we
> > have:
> >
> > arch_uninstall_hw_breakpoint(bp) {
> > ...
> > hw_breakpoint_control(bp, HW_BREAKPOINT_UNINSTALL) {
> > ...
> > hw_breakpoint_slot_setup(slots, max_slots, bp, HW_BREAKPOINT_UNINSTALL) {
> > ...
> > *slot = NULL;
> > ...
> > }
> > ...
> > write_wb_reg(ctrl_reg, i, 0) {
> > ...
> > write_sysreg(0, ...);
> > isb();
> > ...
> > }
> > }
> > }
> >
> > The HW breakpoint/watchpoint associated with 'bp' could be triggered
> > between setting '*slot' to NULL and the ISB. If that happens, then
> > do_breakpoint() won't find 'bp', and will return *without* disabling the
> > HW breakpoint or attempting to step.
> >
> > If that first exception was taken *before* the MSR in write_sysreg(),
> > then nothing has changed, and the breakpoint/watchpoint will then be
> > taken again ad infinitum.
> >
> > If that first exception was taken *after* the MSR in write_sysreg(), the
> > context synchronization provided by exception entry/return will prevent
> > it from being taken again.
> >
> > Building v6.19 and testing (with pseudo-NMI enabled):
> >
> > | # grep write_wb_reg /proc/kallsyms
> > | ffff80008004b980 t write_wb_reg
> > | # ./perf-6.19 stat -a -C 1 -e 'mem:0xffff80008004b980/4:xk' true
>
> I'll give it a try with v4, but that should be prevented with my
> changes to exclude kprobe regions.
That'll work for breakpoints specifically, but not for watchpoints, and
I think for that we either have to dynamically disable
watchpoint/breakpoint exceptions (e.g. via DAIF.D), or write the code to
be race-aware. I strongly suspect that the latter will be simpler.
I think we can solve that with some wider cleanup, e.g. having
arch_uninstall_hw_breakpoint() disable the breakpoint/watchpoint
*before* setting its slot to NULL, but we'll need to take some care
(e.g. to save/restore MDSELR).
I strongly suspect that we can defer implementing support for EMBWE
until we've done a more general cleanup, but I'll need to go do some
reading first.
Mark.
^ permalink raw reply
* Re: [PATCH v10 16/20] coresight: Add PM callbacks for sink device
From: Leo Yan @ 2026-04-13 8:48 UTC (permalink / raw)
To: Jie Gan
Cc: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra, coresight,
linux-arm-kernel
In-Reply-To: <227b77b9-5232-4cff-b26a-458477e9eb32@oss.qualcomm.com>
On Mon, Apr 13, 2026 at 01:45:50PM +0800, Jie Gan wrote:
[...]
> > @@ -1787,15 +1808,32 @@ static int coresight_pm_save(struct coresight_path *path)
> > to = list_prev_entry(coresight_path_last_node(path), link);
> > coresight_disable_path_from_to(path, from, to);
> > + ret = coresight_pm_device_save(coresight_get_sink(path));
> > + if (ret)
> > + goto sink_failed;
> > +
> > return 0;
> > +
> > +sink_failed:
> > + if (!coresight_enable_path_from_to(path, coresight_get_mode(source),
> > + from, to))
> > + coresight_pm_device_restore(source);
>
> I have go through the history messages. I have a question about this point
> here:
>
> how can we handle the scenario if coresight_enable_path_from_to failed? It
> means we are never calling coresight_pm_device_restore for the ETM and
> leaving the ETM with OS lock state until CPU reset?
From a design perspective, if any failure occurs in the idle flow, the
priority is to avoid further mess, especially partial enable/disable
sequences that could lead to lockups.
The case you mentioned is a typical risk - if a path after source to
sink fails to be enabled, it is unsafe to arbitrarily enable the source
further. We rely on the per-CPU flag "percpu_pm_failed" to disable idle
states, if ETE/TRBE fails to be disabled, if CPU is turned off, this
also might cause lockup.
> Consider we are calling etm4_disable_hw with OS lock:
> etm4_disable_hw -> etm4_disable_trace_unit -> etm4x_wait_status (may timeout
> here?)
This is expected. I don't want to introduce a _recovery_ mechanism for
CPU PM failures, which is complex and over-engineering. CPU PM notifier
is low level code, and in my experience, PM issues can be easily
observed once CPU idle is enabled and should be resolved during the
development phase.
In many cases PM issues are often not caused by CoreSight drivers but by
other modules (e.g., clock or regulator drivers). The log "Failed in
coresight PM save ..." reminds developers the bugs. As said,
percpu_pm_failed is used as a last resort to prevent the platform from
locking up if there is a PM bug.
Thanks,
Leo
^ permalink raw reply
* [PATCH 0/3] arm64/virt: Add Arm CCA measurement register support
From: Sami Mujawar @ 2026-04-13 8:49 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: catalin.marinas, will, jgg, thuth, Suzuki.Poulose, steven.price,
gshan, YeoReum.Yun, Sami Mujawar
This series adds support for Arm Confidential Compute Architecture (CCA)
measurement registers in the Linux kernel, enabling guest Realms to
access, extend, and expose measurement values for attestation and runtime
integrity tracking.
The Realm Management Monitor (RMM) defines a set of measurement registers
consisting of a Realm Initial Measurement (RIM) and a number of Realm
Extensible Measurements (REMs). This series introduces the necessary
infrastructure to interact with these registers via the RSI interface
and exposes them to userspace through the TSM measurement framework.
At a high level, the series includes:
- Helper interfaces for reading and extending measurement
registers via RSI
- Definitions for Realm hash algorithms as defined by the
RMM specification
- Integration with the TSM measurement subsystem and sysfs
exposure for userspace visibility and interaction
After applying this series, measurement registers are exposed under:
/sys/devices/virtual/misc/arm_cca_guest/measurements/
Where:
- rim is read-only (initial measurement)
- rem[0-3] are read/write (extensible measurements)
- The hash algorithm reflects the Realm configuration
Patch summary:
1. arm64: rsi: Add helpers for Arm CCA measurement registers
- Introduces RSI helper APIs to read and extend RIM/REM registers
2. arm64: rsi: Add realm hash algorithm defines
- Adds definitions for SHA-256 and SHA-512 identifiers returned
by the RMM
3. virt: arm-cca-guest: Add support for measurement registers
- Integrates with TSM measurement framework
- Implements measurement register refresh and extend operations
- Exposes registers via sysfs using a misc device
- Dynamically configures hash algorithm and digest size per Realm
This enables a consistent mechanism for attestation-related measurements
in Arm CCA guests and aligns with the kernel TSM measurement abstraction.
Feedback is very welcome.
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Sami Mujawar (3):
arm64: rsi: Add helpers for Arm CCA measurement register operations
arm64: rsi: Add realm hash algorithm defines
virt: arm-cca-guest: Add support for measurement registers
.../sysfs-devices-virtual-misc-arm_cca_guest | 38 +++
arch/arm64/include/asm/rsi_cmds.h | 105 ++++++-
arch/arm64/include/asm/rsi_smc.h | 7 +
drivers/virt/coco/arm-cca-guest/Kconfig | 1 +
.../virt/coco/arm-cca-guest/arm-cca-guest.c | 296 +++++++++++++++++-
5 files changed, 442 insertions(+), 5 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-devices-virtual-misc-arm_cca_guest
--
SAMI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply
* [PATCH 1/3] arm64: rsi: Add helpers for Arm CCA measurement register operations
From: Sami Mujawar @ 2026-04-13 8:49 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: catalin.marinas, will, jgg, thuth, Suzuki.Poulose, steven.price,
gshan, YeoReum.Yun, Sami Mujawar
In-Reply-To: <20260413084957.327661-1-sami.mujawar@arm.com>
Add static inline helper functions to support reading the Realm
Initial Measurement (RIM) and reading/extending the Realm
Extensible Measurement (REM) registers.
The indices of the Arm CCA measurement registers, as defined by
the Realm Management Monitor specification, are as follows:
Index Register
0 RIM
1 - 4 REM[0 - 3]
The rsi_measurement_extend() function allows extending REM[0–3]
registers with a caller-provided digest (up to 64 bytes).
Index 0 (RIM) is read-only and cannot be extended.
The rsi_measurement_read() function allows reading measurement
values from RIM (index 0) or REM[0–3] (indices 1–4). The returned
digest is expected to be 64 bytes.
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
arch/arm64/include/asm/rsi_cmds.h | 105 +++++++++++++++++++++++++++++-
1 file changed, 104 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h
index 2c8763876dfb..cfd9bff88147 100644
--- a/arch/arm64/include/asm/rsi_cmds.h
+++ b/arch/arm64/include/asm/rsi_cmds.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2023 ARM Ltd.
+ * Copyright (C) 2023 - 2025 ARM Ltd.
*/
#ifndef __ASM_RSI_CMDS_H
@@ -15,6 +15,26 @@
#define RSI_GRANULE_SHIFT 12
#define RSI_GRANULE_SIZE (_AC(1, UL) << RSI_GRANULE_SHIFT)
+/*
+ * Maximum measurement data size in bytes.
+ * According to the RMM Specification, the width of the RmmRealmMeasurement type
+ * is 512 bits.
+ */
+#define RSI_MAX_MEASUREMENT_DATA_SIZE_BYTES 64
+
+/*
+ * Indices for the Realm Initial Measurement register (RIM) and the Realm
+ * Extensible Measurement registers (REMs).
+ * According to the RMM Specification, Realm attributes of a Realm include
+ * an array of measurement values. The first entry in this array is a RIM.
+ * The remaining entries in this array are REMs.
+ */
+#define RSI_INDEX_RIM 0
+#define RSI_INDEX_REM0 1
+#define RSI_INDEX_REM1 2
+#define RSI_INDEX_REM2 3
+#define RSI_INDEX_REM3 4
+
enum ripas {
RSI_RIPAS_EMPTY = 0,
RSI_RIPAS_RAM = 1,
@@ -159,4 +179,87 @@ static inline unsigned long rsi_attestation_token_continue(phys_addr_t granule,
return res.a0;
}
+/**
+ * rsi_measurement_extend - Extend the measurement value to the Realm Extensible
+ * Measurement (REM).
+ *
+ * @idx: Index of the REM register.
+ * Where:
+ * Index Register
+ * 1 - 4 REM[0-3]
+ * @digest: The digest data to be extended.
+ * @digest_size: Size of the digest data in bytes.
+ *
+ * Returns:
+ * On success, returns RSI_SUCCESS.
+ * Otherwise, -EINVAL
+ */
+static inline unsigned long rsi_measurement_extend(u32 idx,
+ const u8 *digest,
+ unsigned long digest_size)
+{
+ struct arm_smccc_1_2_regs regs = { 0 };
+
+ /*
+ * Index 0 is for RIM (which is Read Only), while
+ * REM[0-3] are indexed from 1 - 4.
+ * The digest size can be at the most 64 bytes.
+ */
+ if (!digest || idx < RSI_INDEX_REM0 || idx > RSI_INDEX_REM3 ||
+ digest_size == 0 || digest_size > RSI_MAX_MEASUREMENT_DATA_SIZE_BYTES)
+ return -EINVAL;
+
+ regs.a0 = SMC_RSI_MEASUREMENT_EXTEND;
+ regs.a1 = idx;
+ regs.a2 = digest_size;
+ memcpy(®s.a3, digest, digest_size);
+ arm_smccc_1_2_smc(®s, ®s);
+
+ if (regs.a0 != RSI_SUCCESS)
+ return -EINVAL;
+
+ return regs.a0;
+}
+
+/**
+ * rsi_measurement_read - Read the measurement value from the Realm Initial
+ * Measurement (RIM) or the Realm Extensible Measurement (REM) register.
+ *
+ * @idx: Index of the RIM or REM register.
+ * Where:
+ * Index Register
+ * 0 RIM
+ * 1 - 4 REM[0-3]
+ * @digest: The digest data to be returned.
+ * @digest_size: Size of the digest data buffer in bytes.
+ *
+ * Returns:
+ * On success, returns RSI_SUCCESS.
+ * Otherwise, -EINVAL
+ */
+static inline unsigned long rsi_measurement_read(u32 idx,
+ u8 *digest,
+ unsigned long digest_size)
+{
+ struct arm_smccc_1_2_regs regs = { 0 };
+
+ /*
+ * The digest size can be at the most 64 bytes, if less then 64 bytes
+ * it is zero padded.
+ */
+ if (!digest || idx > RSI_INDEX_REM3 ||
+ digest_size == 0 || digest_size > RSI_MAX_MEASUREMENT_DATA_SIZE_BYTES)
+ return -EINVAL;
+
+ regs.a0 = SMC_RSI_MEASUREMENT_READ;
+ regs.a1 = idx;
+ arm_smccc_1_2_smc(®s, ®s);
+
+ if (regs.a0 != RSI_SUCCESS)
+ return -EINVAL;
+
+ memcpy(digest, ®s.a1, digest_size);
+ return regs.a0;
+}
+
#endif /* __ASM_RSI_CMDS_H */
--
SAMI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related
* [PATCH 2/3] arm64: rsi: Add realm hash algorithm defines
From: Sami Mujawar @ 2026-04-13 8:49 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: catalin.marinas, will, jgg, thuth, Suzuki.Poulose, steven.price,
gshan, YeoReum.Yun, Sami Mujawar
In-Reply-To: <20260413084957.327661-1-sami.mujawar@arm.com>
Add macro definitions for the hash algorithm identifiers, as
specified in the Realm Management Monitor (RMM) specification.
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
arch/arm64/include/asm/rsi_smc.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm64/include/asm/rsi_smc.h b/arch/arm64/include/asm/rsi_smc.h
index e19253f96c94..dbcb98a6d5c9 100644
--- a/arch/arm64/include/asm/rsi_smc.h
+++ b/arch/arm64/include/asm/rsi_smc.h
@@ -144,6 +144,13 @@ struct realm_config {
#endif /* __ASSEMBLER__ */
+/*
+ * The RSI definition of the Hash Algorithm (as specified by the Secure
+ * Hash Standard) returned in the realm_config data structure.
+ */
+#define RSI_HASH_SHA_256 0
+#define RSI_HASH_SHA_512 1
+
/*
* Read configuration for the current Realm.
*
--
SAMI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related
* [PATCH 3/3] virt: arm-cca-guest: Add support for measurement registers
From: Sami Mujawar @ 2026-04-13 8:49 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: catalin.marinas, will, jgg, thuth, Suzuki.Poulose, steven.price,
gshan, YeoReum.Yun, Sami Mujawar
In-Reply-To: <20260413084957.327661-1-sami.mujawar@arm.com>
Add support for Arm CCA measurement registers (MRs), enabling attestation
and runtime integrity tracking from guest Realms.
This implementation registers a measurement configuration with the TSM
framework and exposes measurement register values via sysfs using a
misc device. The supported registers include the Realm Initial
Measurement (RIM) and four Runtime Extensible Measurement Registers
(REM0–REM3), each using SHA-256 or SHA-512 depending on Realm
configuration.
The measurement registers are located under the following sysfs node:
/sys/devices/virtual/misc/arm_cca_guest/measurements/
-rw-r--r-- 1 0 0 64 Jul 21 11:46 rem0:sha512
-rw-r--r-- 1 0 0 64 Jul 21 11:46 rem1:sha512
-rw-r--r-- 1 0 0 64 Jul 21 11:46 rem2:sha512
-rw-r--r-- 1 0 0 64 Jul 21 11:46 rem3:sha512
-r--r--r-- 1 0 0 64 Jul 21 11:46 rim:sha512
As seen above the attributes for the REMs are 'rw' indicating they can
be read or extended. While the attributes for RIM is 'r' indicating
that it can only be read and not extended.
The sysfs node suffix for the measurement register (i.e. ':sha512')
indicates the hash algorithm used is sha512. This also reflects
that the Realm was launched with SHA512 as the measurement algorithm.
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
.../sysfs-devices-virtual-misc-arm_cca_guest | 38 +++
drivers/virt/coco/arm-cca-guest/Kconfig | 1 +
.../virt/coco/arm-cca-guest/arm-cca-guest.c | 296 +++++++++++++++++-
3 files changed, 331 insertions(+), 4 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-devices-virtual-misc-arm_cca_guest
diff --git a/Documentation/ABI/testing/sysfs-devices-virtual-misc-arm_cca_guest b/Documentation/ABI/testing/sysfs-devices-virtual-misc-arm_cca_guest
new file mode 100644
index 000000000000..878dc54e48f8
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-virtual-misc-arm_cca_guest
@@ -0,0 +1,38 @@
+What: /sys/devices/virtual/misc/arm_cca_guest/measurements/MRNAME[:HASH]
+Date: July, 2025
+KernelVersion: v6.16
+Contact: linux-coco@lists.linux.dev
+Description:
+ Value of a Arm CCA Realm measurement register (MR). The optional
+ suffix :HASH is to represent the hash algorithms associated with
+ the MRs. See below for a complete list of Arm CCA Realm MRs exposed
+ via sysfs. Refer to the Arm Realm Management Monitor (RMM)
+ Specification for more information on the Realm Measurement registers.
+
+ The Arm Realm Management Monitor Specification can be found at:
+ https://developer.arm.com/documentation/den0137/latest/
+
+ See also:
+ https://docs.kernel.org/driver-api/coco/measurement-registers.html
+
+What: /sys/devices/virtual/misc/arm_cca_guest/measurements/rim:[sha256|sha512]
+Date: July, 2025
+KernelVersion: v6.16
+Contact: linux-coco@lists.linux.dev
+Description:
+ (RO) RIM - [32|64]-byte immutable storage typically used to represent
+ the Realm Initial Measurement (RIM) which is the measurement of
+ the configuration and contents of a Realm at the time of activation.
+
+What: /sys/devices/virtual/misc/arm_cca_guest/measurements/rem[0123]:[sha256|sha512]
+Date: July, 2025
+KernelVersion: v6.16
+Contact: linux-coco@lists.linux.dev
+Description:
+ (RW) REM[0123] - 4 Run-Time extendable Measurement Registers that
+ represent the Realm Extensible Measurement (REM) registers which
+ can be extended during the lifetime of a Realm.
+ Read from any of these returns the current value of the corresponding
+ REM. Write extends the written buffer to the REM. All writes must start
+ at offset 0 and be maximum 64 bytes in size. Attempting to write more
+ than 64 bytes will result in EINVAL returned by the write() syscall.
diff --git a/drivers/virt/coco/arm-cca-guest/Kconfig b/drivers/virt/coco/arm-cca-guest/Kconfig
index 3f0f013f03f1..62fcc6b16843 100644
--- a/drivers/virt/coco/arm-cca-guest/Kconfig
+++ b/drivers/virt/coco/arm-cca-guest/Kconfig
@@ -2,6 +2,7 @@ config ARM_CCA_GUEST
tristate "Arm CCA Guest driver"
depends on ARM64
select TSM_REPORTS
+ select TSM_MEASUREMENTS
help
The driver provides userspace interface to request and
attestation report from the Realm Management Monitor(RMM).
diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
index 0c9ea24a200c..2b5c5fa01cb3 100644
--- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
+++ b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
@@ -1,18 +1,286 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2023 ARM Ltd.
+ * Copyright (C) 2023 - 2025 ARM Ltd.
*/
#include <linux/arm-smccc.h>
#include <linux/cc_platform.h>
#include <linux/kernel.h>
+#include <linux/miscdevice.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/smp.h>
#include <linux/tsm.h>
+#include <linux/tsm-mr.h>
#include <linux/types.h>
#include <asm/rsi.h>
+#include <crypto/hash.h>
+
+/* MR buffer */
+static u8 *arm_cca_mr_buf;
+
+/**
+ * arm_cca_mrs - ARM CCA measurement register set.
+ *
+ * Defines a static array of measurement registers used by the ARM
+ * Confidential Compute Architecture (CCA). These registers are used
+ * for attestation and runtime integrity tracking.
+ *
+ * Register types:
+ * - rim: Realm initial measurement register (RIM)
+ * - rem0–rem3: Runtime extensible measurement registers (REMs)
+ */
+static struct tsm_measurement_register arm_cca_mrs[] = {
+ { TSM_MR_(rim, SHA256) | TSM_MR_F_READABLE },
+ { TSM_MR_(rem0, SHA256) | TSM_MR_F_RTMR },
+ { TSM_MR_(rem1, SHA256) | TSM_MR_F_RTMR },
+ { TSM_MR_(rem2, SHA256) | TSM_MR_F_RTMR },
+ { TSM_MR_(rem3, SHA256) | TSM_MR_F_RTMR }
+};
+
+/**
+ * arm_cca_mr_refresh - Refresh measurement registers for ARM CCA.
+ *
+ * @tm: Pointer to a struct tsm_measurements containing measurement registers.
+ *
+ * Iterates through all measurement registers in @tm and refreshes those
+ * marked with TSM_MR_F_LIVE or TSM_MR_F_READABLE by invoking
+ * rsi_measurement_read() for each.
+ *
+ * Return: 0 on success, or -EINVAL if @tm is NULL or a read operation fails.
+ */
+static int arm_cca_mr_refresh(const struct tsm_measurements *tm)
+{
+ int retval;
+ int index = 0;
+ const struct tsm_measurement_register *mr;
+
+ if (!tm)
+ return -EINVAL;
+
+ while (index < tm->nr_mrs) {
+ mr = &tm->mrs[index];
+
+ /* Skip if the MR is not Live or Readable. */
+ if ((mr->mr_flags & (TSM_MR_F_LIVE | TSM_MR_F_READABLE)) != 0) {
+ retval = rsi_measurement_read(index,
+ mr->mr_value,
+ mr->mr_size);
+ if (retval != 0)
+ return -EINVAL;
+ }
+
+ index++;
+ }
+
+ return 0;
+}
+
+/**
+ * arm_cca_mr_extend - Extend a measurement register with new data.
+ *
+ * @tm: Pointer to the tsm_measurements structure containing measurement
+ * registers.
+ * @mr: Pointer to the specific measurement register to extend.
+ * @data: Pointer to the data to be used for extension.
+ *
+ * This function extends a measurement register with new input data.
+ *
+ * Return: 0 on success, or a negative error code (e.g., -EINVAL for invalid
+ * arguments).
+ */
+static int arm_cca_mr_extend(const struct tsm_measurements *tm,
+ const struct tsm_measurement_register *mr,
+ const u8 *data)
+{
+ if (!tm || !mr || !data)
+ return -EINVAL;
+
+ return rsi_measurement_extend((mr - tm->mrs), data, mr->mr_size);
+}
+
+/**
+ * arm_cca_measurements - ARM CCA measurement configuration instance.
+ *
+ * This defines the measurement set and behavior for the ARM
+ * Confidential Compute Architecture, enabling measurements
+ * for attestation and runtime validation.
+ */
+static struct tsm_measurements arm_cca_measurements = {
+ .mrs = arm_cca_mrs,
+ .nr_mrs = ARRAY_SIZE(arm_cca_mrs),
+ .refresh = arm_cca_mr_refresh,
+ .write = arm_cca_mr_extend,
+};
+
+/**
+ * arm_cca_attr_groups - Attribute groups for the arm_cca_misc_dev miscellaneous
+ * device.
+ *
+ */
+static const struct attribute_group *arm_cca_attr_groups[] = {
+ NULL, /* measurements */
+ NULL
+};
+
+/**
+ * arm_cca_misc_dev - Miscellaneous device for ARM CCA functionality.
+ *
+ */
+static struct miscdevice arm_cca_misc_dev = {
+ .name = KBUILD_MODNAME,
+ .minor = MISC_DYNAMIC_MINOR,
+ .groups = arm_cca_attr_groups,
+};
+
+/**
+ * arm_cca_get_hash_algorithm - Get the hash algorithm and digest size for
+ * a Realm.
+ *
+ * @hash_algo: Pointer to an int to receive the internal hash algorithm ID
+ * (e.g., HASH_ALGO_SHA256 or HASH_ALGO_SHA512).
+ * @digest_size: Pointer to an int to receive the digest size in bytes
+ * (e.g., SHA256_DIGEST_SIZE or SHA512_DIGEST_SIZE).
+ *
+ * This function retrieves the hash algorithm used in a Realm's configuration
+ * by invoking the `rsi_get_realm_config()` interface.
+ *
+ * Return:
+ * * %0 - Success. The hash algorithm and digest size are returned.
+ * * %-ENOMEM - Memory allocation failed.
+ * * %-EINVAL - Configuration fetch failed or algorithm is unsupported.
+ *
+ */
+static int arm_cca_get_hash_algorithm(int *hash_algo, int *digest_size)
+{
+ int ret = 0;
+ unsigned long result;
+ struct realm_config *cfg = NULL;
+
+ cfg = alloc_pages_exact(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ result = rsi_get_realm_config(cfg);
+ if (result != RSI_SUCCESS) {
+ ret = -EINVAL;
+ goto exit_free_realm_config;
+ }
+
+ switch (cfg->hash_algo) {
+ case RSI_HASH_SHA_512:
+ *hash_algo = HASH_ALGO_SHA512;
+ *digest_size = SHA512_DIGEST_SIZE;
+ break;
+ case RSI_HASH_SHA_256:
+ *hash_algo = HASH_ALGO_SHA256;
+ *digest_size = SHA256_DIGEST_SIZE;
+ break;
+ default:
+ /* Unknown/unsupported algorithm. */
+ ret = -EINVAL;
+ break;
+ }
+
+exit_free_realm_config:
+ free_pages_exact(cfg, RSI_GRANULE_SIZE);
+ return ret;
+}
+
+/**
+ * arm_cca_mr_init - Initialize ARM CCA measurement register infrastructure.
+ *
+ * This function sets up the internal data structures for handling ARM CCA
+ * measurement registers (MRs) and creates a sysfs attribute group. It also
+ * registers a miscelaneous device for exposing the Arm CCA measurement
+ * registers to userspace.
+ *
+ * Return:
+ * * %0 - On success.
+ * * %-ENOMEM - if memory allocation fails.
+ * * %-EINVAL - On hash algorithm retrieval or attribute group creation
+ * failure.
+ */
+static int arm_cca_mr_init(void)
+{
+ const struct attribute_group *g;
+ int ret;
+ int hash_algo;
+ int digest_size;
+ int digest_buf_size;
+
+ /* Retrieve the hash algorithm and digest size. */
+ ret = arm_cca_get_hash_algorithm(&hash_algo, &digest_size);
+ if (ret)
+ return ret;
+
+ /*
+ * Allocate a single contiguous buffer to hold the digest values
+ * for all MRs.
+ */
+ digest_buf_size = ARRAY_SIZE(arm_cca_mrs) * digest_size;
+ u8 *digest_buf __free(kfree) = kzalloc(digest_buf_size, GFP_KERNEL);
+ if (!digest_buf)
+ return -ENOMEM;
+
+ arm_cca_mr_buf = digest_buf;
+
+ /* Initialise the mr_value storage and the mr_size. */
+ for (size_t i = 0; i < ARRAY_SIZE(arm_cca_mrs); ++i) {
+ arm_cca_mrs[i].mr_value = digest_buf + (digest_size * i);
+ arm_cca_mrs[i].mr_size = digest_size;
+ arm_cca_mrs[i].mr_hash = hash_algo;
+ }
+
+ /* Read the measurement registers. */
+ ret = arm_cca_mr_refresh(&arm_cca_measurements);
+ if (ret)
+ return ret;
+
+ /*
+ * Create a sysfs attribute group to expose the measurements
+ * to userspace.
+ */
+ g = tsm_mr_create_attribute_group(&arm_cca_measurements);
+ if (IS_ERR_OR_NULL(g))
+ return PTR_ERR(g);
+
+ /* Initialise the attribute group before registering the misc device. */
+ arm_cca_attr_groups[0] = g;
+
+ /*
+ * Register a miscelaneous device for exposing
+ * the Arm CCA measurement registers to userspace.
+ */
+ ret = misc_register(&arm_cca_misc_dev);
+ if (ret < 0) {
+ tsm_mr_free_attribute_group(g);
+ return ret;
+ }
+
+ arm_cca_mr_buf = no_free_ptr(digest_buf);
+
+ return 0;
+}
+
+/**
+ * arm_cca_mr_cleanup - Unregister sysfs attribute group and free the
+ * measurement digest buffer region.
+ *
+ * @mr_grp: Pointer to the sysfs attribute group.
+ *
+ * This function performs cleanup for the Arm CCA memory registers (MR).
+ *
+ * The function should be called during the teardown or cleanup phase
+ * to ensure proper resource deallocation.
+ */
+static void arm_cca_mr_cleanup(const struct attribute_group *mr_grp)
+{
+ misc_deregister(&arm_cca_misc_dev);
+ tsm_mr_free_attribute_group(mr_grp);
+ kfree(arm_cca_mr_buf);
+}
/**
* struct arm_cca_token_info - a descriptor for the token buffer.
@@ -188,12 +456,16 @@ static const struct tsm_report_ops arm_cca_tsm_ops = {
/**
* arm_cca_guest_init - Register with the Trusted Security Module (TSM)
- * interface.
+ * interface and also register a miscelaneous device used for exposing
+ * the Arm CCA measurement registers to userspace.
*
* Return:
* * %0 - Registered successfully with the TSM interface.
* * %-ENODEV - The execution context is not an Arm Realm.
* * %-EBUSY - Already registered.
+ * * %-ENOMEM - If memory allocation fails.
+ * * %-EINVAL - On hash algorithm retrieval or attribute group creation
+ * failure.
*/
static int __init arm_cca_guest_init(void)
{
@@ -202,9 +474,22 @@ static int __init arm_cca_guest_init(void)
if (!is_realm_world())
return -ENODEV;
+ ret = arm_cca_mr_init();
+ if (ret < 0) {
+ pr_err("Error %d initialising MRs\n", ret);
+ return ret;
+ }
+
ret = tsm_report_register(&arm_cca_tsm_ops, NULL);
- if (ret < 0)
+ if (ret < 0) {
pr_err("Error %d registering with TSM\n", ret);
+ goto cleanup_mr;
+ }
+
+ return ret;
+
+cleanup_mr:
+ arm_cca_mr_cleanup(arm_cca_attr_groups[0]);
return ret;
}
@@ -212,11 +497,14 @@ module_init(arm_cca_guest_init);
/**
* arm_cca_guest_exit - unregister with the Trusted Security Module (TSM)
- * interface.
+ * interface and deregister the miscelaneous device used for exposing the
+ * Arm CCA measurement registers to userspace.
+ *
*/
static void __exit arm_cca_guest_exit(void)
{
tsm_report_unregister(&arm_cca_tsm_ops);
+ arm_cca_mr_cleanup(arm_cca_attr_groups[0]);
}
module_exit(arm_cca_guest_exit);
--
SAMI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox