* [PATCH v19 11/14] crypto: qce - Use existing devres APIs in devm_qce_dma_request()
From: Bartosz Golaszewski @ 2026-05-26 13:10 UTC (permalink / raw)
To: Vinod Koul, Jonathan Corbet, Thara Gopinath, Herbert Xu,
David S. Miller, Udit Tiwari, Md Sadre Alam, Dmitry Baryshkov,
Manivannan Sadhasivam, Stephan Gerhold, Bjorn Andersson,
Peter Ujfalusi, Michal Simek, Frank Li, Andy Gross,
Neil Armstrong
Cc: dmaengine, linux-doc, linux-kernel, linux-arm-msm, linux-crypto,
linux-arm-kernel, brgl, Bartosz Golaszewski, Bartosz Golaszewski,
Konrad Dybcio
In-Reply-To: <20260526-qcom-qce-cmd-descr-v19-0-08472fdcbf4a@oss.qualcomm.com>
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Switch to devm_kmalloc() and devm_dma_alloc_chan() in
devm_qce_dma_request(). This allows us to drop two labels and shrink the
function.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/crypto/qce/dma.c | 34 +++++++++++-----------------------
1 file changed, 11 insertions(+), 23 deletions(-)
diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
index d60efb5c26d88f8b0259b1dccc8724d0f75571c6..c2602d35baa6ad3ca5de734de7ff6160ff29567c 100644
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -12,7 +12,7 @@
#define QCE_IGNORE_BUF_SZ (2 * QCE_BAM_BURST_SIZE)
-static void qce_dma_release(void *data)
+static void qce_dma_terminate(void *data)
{
struct qce_dma_data *dma = data;
@@ -27,34 +27,22 @@ int devm_qce_dma_request(struct qce_device *qce)
{
struct qce_dma_data *dma = &qce->dma;
struct device *dev = qce->dev;
- int ret;
- dma->txchan = dma_request_chan(dev, "tx");
+ dma->result_buf = devm_kmalloc(dev, QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ, GFP_KERNEL);
+ if (!dma->result_buf)
+ return -ENOMEM;
+
+ dma->txchan = devm_dma_request_chan(dev, "tx");
if (IS_ERR(dma->txchan))
return dev_err_probe(dev, PTR_ERR(dma->txchan),
"Failed to get TX DMA channel\n");
- dma->rxchan = dma_request_chan(dev, "rx");
- if (IS_ERR(dma->rxchan)) {
- ret = dev_err_probe(dev, PTR_ERR(dma->rxchan),
- "Failed to get RX DMA channel\n");
- goto error_rx;
- }
-
- dma->result_buf = kmalloc(QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ,
- GFP_KERNEL);
- if (!dma->result_buf) {
- ret = -ENOMEM;
- goto error_nomem;
- }
-
- return devm_add_action_or_reset(dev, qce_dma_release, dma);
+ dma->rxchan = devm_dma_request_chan(dev, "rx");
+ if (IS_ERR(dma->rxchan))
+ return dev_err_probe(dev, PTR_ERR(dma->rxchan),
+ "Failed to get RX DMA channel\n");
-error_nomem:
- dma_release_channel(dma->rxchan);
-error_rx:
- dma_release_channel(dma->txchan);
- return ret;
+ return devm_add_action_or_reset(dev, qce_dma_terminate, dma);
}
struct scatterlist *
--
2.47.3
^ permalink raw reply related
* [PATCH v19 12/14] crypto: qce - Map crypto memory for DMA
From: Bartosz Golaszewski @ 2026-05-26 13:11 UTC (permalink / raw)
To: Vinod Koul, Jonathan Corbet, Thara Gopinath, Herbert Xu,
David S. Miller, Udit Tiwari, Md Sadre Alam, Dmitry Baryshkov,
Manivannan Sadhasivam, Stephan Gerhold, Bjorn Andersson,
Peter Ujfalusi, Michal Simek, Frank Li, Andy Gross,
Neil Armstrong
Cc: dmaengine, linux-doc, linux-kernel, linux-arm-msm, linux-crypto,
linux-arm-kernel, brgl, Bartosz Golaszewski, Bartosz Golaszewski
In-Reply-To: <20260526-qcom-qce-cmd-descr-v19-0-08472fdcbf4a@oss.qualcomm.com>
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
As the first step in converting the driver to using DMA for register
I/O, let's map the crypto memory range.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/crypto/qce/core.c | 23 ++++++++++++++++++++++-
drivers/crypto/qce/core.h | 6 ++++++
2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
index a0e2eadc3afd5f83e46724c8bc3e3690146b86ba..d7b7a3dda464964afe6a6893bb329d5bd5759dcd 100644
--- a/drivers/crypto/qce/core.c
+++ b/drivers/crypto/qce/core.c
@@ -192,10 +192,19 @@ static void qce_cancel_work(void *data)
cancel_work_sync(work);
}
+static void qce_crypto_unmap_dma(void *data)
+{
+ struct qce_device *qce = data;
+
+ dma_unmap_resource(qce->dev, qce->base_dma, qce->dma_size,
+ DMA_BIDIRECTIONAL, 0);
+}
+
static int qce_crypto_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct qce_device *qce;
+ struct resource *res;
int ret;
qce = devm_kzalloc(dev, sizeof(*qce), GFP_KERNEL);
@@ -205,7 +214,7 @@ static int qce_crypto_probe(struct platform_device *pdev)
qce->dev = dev;
platform_set_drvdata(pdev, qce);
- qce->base = devm_platform_ioremap_resource(pdev, 0);
+ qce->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(qce->base))
return PTR_ERR(qce->base);
@@ -255,6 +264,18 @@ static int qce_crypto_probe(struct platform_device *pdev)
qce->async_req_enqueue = qce_async_request_enqueue;
qce->async_req_done = qce_async_request_done;
+ qce->dma_size = resource_size(res);
+ qce->base_dma = dma_map_resource(dev, res->start, qce->dma_size,
+ DMA_BIDIRECTIONAL, 0);
+ qce->base_phys = res->start;
+ ret = dma_mapping_error(dev, qce->base_dma);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(qce->dev, qce_crypto_unmap_dma, qce);
+ if (ret)
+ return ret;
+
return devm_qce_register_algs(qce);
}
diff --git a/drivers/crypto/qce/core.h b/drivers/crypto/qce/core.h
index f092ce2d3b04a936a37805c20ac5ba78d8fdd2df..a80e12eac6c87e5321cce16c56a4bf5003474ef0 100644
--- a/drivers/crypto/qce/core.h
+++ b/drivers/crypto/qce/core.h
@@ -27,6 +27,9 @@
* @dma: pointer to dma data
* @burst_size: the crypto burst size
* @pipe_pair_id: which pipe pair id the device using
+ * @base_dma: base DMA address
+ * @base_phys: base physical address
+ * @dma_size: size of memory mapped for DMA
* @async_req_enqueue: invoked by every algorithm to enqueue a request
* @async_req_done: invoked by every algorithm to finish its request
*/
@@ -43,6 +46,9 @@ struct qce_device {
struct qce_dma_data dma;
int burst_size;
unsigned int pipe_pair_id;
+ dma_addr_t base_dma;
+ phys_addr_t base_phys;
+ size_t dma_size;
int (*async_req_enqueue)(struct qce_device *qce,
struct crypto_async_request *req);
void (*async_req_done)(struct qce_device *qce, int ret);
--
2.47.3
^ permalink raw reply related
* [PATCH v19 13/14] crypto: qce - Add BAM DMA support for crypto register I/O
From: Bartosz Golaszewski @ 2026-05-26 13:11 UTC (permalink / raw)
To: Vinod Koul, Jonathan Corbet, Thara Gopinath, Herbert Xu,
David S. Miller, Udit Tiwari, Md Sadre Alam, Dmitry Baryshkov,
Manivannan Sadhasivam, Stephan Gerhold, Bjorn Andersson,
Peter Ujfalusi, Michal Simek, Frank Li, Andy Gross,
Neil Armstrong
Cc: dmaengine, linux-doc, linux-kernel, linux-arm-msm, linux-crypto,
linux-arm-kernel, brgl, Bartosz Golaszewski, Bartosz Golaszewski
In-Reply-To: <20260526-qcom-qce-cmd-descr-v19-0-08472fdcbf4a@oss.qualcomm.com>
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Switch to using BAM DMA for register I/O in addition to passing data. To
that end: provide the necessary infrastructure in the driver, modify the
ordering of operations as required and replace all direct register writes
with wrappers queueing DMA command descriptors.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/crypto/qce/aead.c | 10 ++--
drivers/crypto/qce/common.c | 20 ++++---
drivers/crypto/qce/dma.c | 120 ++++++++++++++++++++++++++++++++++++++++--
drivers/crypto/qce/dma.h | 5 ++
drivers/crypto/qce/sha.c | 10 ++--
drivers/crypto/qce/skcipher.c | 10 ++--
6 files changed, 144 insertions(+), 31 deletions(-)
diff --git a/drivers/crypto/qce/aead.c b/drivers/crypto/qce/aead.c
index 03b8042da9a1b4aebdc775ad8ab912abc7b2383d..e271ecbcbb4a33c405fbec85c458cf1daa7e2c55 100644
--- a/drivers/crypto/qce/aead.c
+++ b/drivers/crypto/qce/aead.c
@@ -463,17 +463,17 @@ qce_aead_async_req_handle(struct crypto_async_request *async_req)
src_nents = dst_nents - 1;
}
- ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, src_nents, rctx->dst_sg, dst_nents,
- qce_aead_done, async_req);
+ ret = qce_start(async_req, tmpl->crypto_alg_type);
if (ret)
goto error_unmap_src;
- qce_dma_issue_pending(&qce->dma);
-
- ret = qce_start(async_req, tmpl->crypto_alg_type);
+ ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, src_nents, rctx->dst_sg, dst_nents,
+ qce_aead_done, async_req);
if (ret)
goto error_terminate;
+ qce_dma_issue_pending(&qce->dma);
+
return 0;
error_terminate:
diff --git a/drivers/crypto/qce/common.c b/drivers/crypto/qce/common.c
index 54a78a57f63028f01870a3edeb8e390f523bb190..37bb6f03244d317a887aeb0aa10cefe327b4ce05 100644
--- a/drivers/crypto/qce/common.c
+++ b/drivers/crypto/qce/common.c
@@ -25,7 +25,7 @@ static inline u32 qce_read(struct qce_device *qce, u32 offset)
static inline void qce_write(struct qce_device *qce, u32 offset, u32 val)
{
- writel(val, qce->base + offset);
+ qce_write_dma(qce, offset, val);
}
static inline void qce_write_array(struct qce_device *qce, u32 offset,
@@ -82,6 +82,8 @@ static void qce_setup_config(struct qce_device *qce)
{
u32 config;
+ qce_clear_bam_transaction(qce);
+
/* get big endianness */
config = qce_config_reg(qce, 0);
@@ -90,12 +92,14 @@ static void qce_setup_config(struct qce_device *qce)
qce_write(qce, REG_CONFIG, config);
}
-static inline void qce_crypto_go(struct qce_device *qce, bool result_dump)
+static inline int qce_crypto_go(struct qce_device *qce, bool result_dump)
{
if (result_dump)
qce_write(qce, REG_GOPROC, BIT(GO_SHIFT) | BIT(RESULTS_DUMP_SHIFT));
else
qce_write(qce, REG_GOPROC, BIT(GO_SHIFT));
+
+ return qce_submit_cmd_desc(qce);
}
#if defined(CONFIG_CRYPTO_DEV_QCE_SHA) || defined(CONFIG_CRYPTO_DEV_QCE_AEAD)
@@ -223,9 +227,7 @@ static int qce_setup_regs_ahash(struct crypto_async_request *async_req)
config = qce_config_reg(qce, 1);
qce_write(qce, REG_CONFIG, config);
- qce_crypto_go(qce, true);
-
- return 0;
+ return qce_crypto_go(qce, true);
}
#endif
@@ -386,9 +388,7 @@ static int qce_setup_regs_skcipher(struct crypto_async_request *async_req)
config = qce_config_reg(qce, 1);
qce_write(qce, REG_CONFIG, config);
- qce_crypto_go(qce, true);
-
- return 0;
+ return qce_crypto_go(qce, true);
}
#endif
@@ -535,9 +535,7 @@ static int qce_setup_regs_aead(struct crypto_async_request *async_req)
qce_write(qce, REG_CONFIG, config);
/* Start the process */
- qce_crypto_go(qce, !IS_CCM(flags));
-
- return 0;
+ return qce_crypto_go(qce, !IS_CCM(flags));
}
#endif
diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
index c2602d35baa6ad3ca5de734de7ff6160ff29567c..769cc71da90076be446cbdf7ec7db27f628fa2ac 100644
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -4,6 +4,8 @@
*/
#include <linux/device.h>
+#include <linux/dma/qcom_bam_dma.h>
+#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <crypto/scatterwalk.h>
@@ -11,6 +13,96 @@
#include "dma.h"
#define QCE_IGNORE_BUF_SZ (2 * QCE_BAM_BURST_SIZE)
+#define QCE_BAM_CMD_SGL_SIZE 128
+#define QCE_BAM_CMD_ELEMENT_SIZE 128
+
+struct qce_desc_info {
+ struct dma_async_tx_descriptor *dma_desc;
+ enum dma_data_direction dir;
+};
+
+struct qce_bam_transaction {
+ struct bam_cmd_element bam_ce[QCE_BAM_CMD_ELEMENT_SIZE];
+ struct scatterlist wr_sgl[QCE_BAM_CMD_SGL_SIZE];
+ struct qce_desc_info *desc;
+ u32 bam_ce_idx;
+ u32 pre_bam_ce_idx;
+ u32 wr_sgl_cnt;
+};
+
+void qce_clear_bam_transaction(struct qce_device *qce)
+{
+ struct qce_bam_transaction *bam_txn = qce->dma.bam_txn;
+
+ bam_txn->bam_ce_idx = 0;
+ bam_txn->wr_sgl_cnt = 0;
+ bam_txn->pre_bam_ce_idx = 0;
+}
+
+int qce_submit_cmd_desc(struct qce_device *qce)
+{
+ struct qce_desc_info *qce_desc = qce->dma.bam_txn->desc;
+ struct qce_bam_transaction *bam_txn = qce->dma.bam_txn;
+ struct dma_async_tx_descriptor *dma_desc;
+ struct dma_chan *chan = qce->dma.rxchan;
+ unsigned long attrs = DMA_PREP_CMD;
+ dma_cookie_t cookie;
+ unsigned int mapped;
+ int ret;
+
+ mapped = dma_map_sg(qce->dev, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt, DMA_TO_DEVICE);
+ if (!mapped)
+ return -ENOMEM;
+
+ dma_desc = dmaengine_prep_slave_sg(chan, bam_txn->wr_sgl, mapped, DMA_MEM_TO_DEV, attrs);
+ if (!dma_desc) {
+ ret = -ENOMEM;
+ goto err_unmap_sg;
+ }
+
+ qce_desc->dma_desc = dma_desc;
+ cookie = dmaengine_submit(qce_desc->dma_desc);
+
+ ret = dma_submit_error(cookie);
+ if (ret)
+ goto err_unmap_sg;
+
+ return 0;
+
+err_unmap_sg:
+ dma_unmap_sg(qce->dev, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt, DMA_TO_DEVICE);
+ return ret;
+}
+
+static void qce_prep_dma_cmd_desc(struct qce_device *qce, struct qce_dma_data *dma,
+ unsigned int addr, void *buf)
+{
+ struct qce_bam_transaction *bam_txn = dma->bam_txn;
+ struct bam_cmd_element *bam_ce_buf;
+ int bam_ce_size, cnt, idx;
+
+ idx = bam_txn->bam_ce_idx;
+ bam_ce_buf = &bam_txn->bam_ce[idx];
+ bam_prep_ce_le32(bam_ce_buf, addr, BAM_WRITE_COMMAND, *((__le32 *)buf));
+
+ bam_ce_buf = &bam_txn->bam_ce[bam_txn->pre_bam_ce_idx];
+ bam_txn->bam_ce_idx++;
+ bam_ce_size = (bam_txn->bam_ce_idx - bam_txn->pre_bam_ce_idx) * sizeof(*bam_ce_buf);
+
+ cnt = bam_txn->wr_sgl_cnt;
+
+ sg_set_buf(&bam_txn->wr_sgl[cnt], bam_ce_buf, bam_ce_size);
+
+ ++bam_txn->wr_sgl_cnt;
+ bam_txn->pre_bam_ce_idx = bam_txn->bam_ce_idx;
+}
+
+void qce_write_dma(struct qce_device *qce, unsigned int offset, u32 val)
+{
+ unsigned int reg_addr = ((unsigned int)(qce->base_phys) + offset);
+
+ qce_prep_dma_cmd_desc(qce, &qce->dma, reg_addr, &val);
+}
static void qce_dma_terminate(void *data)
{
@@ -42,6 +134,16 @@ int devm_qce_dma_request(struct qce_device *qce)
return dev_err_probe(dev, PTR_ERR(dma->rxchan),
"Failed to get RX DMA channel\n");
+ dma->bam_txn = devm_kzalloc(dev, sizeof(*dma->bam_txn), GFP_KERNEL);
+ if (!dma->bam_txn)
+ return -ENOMEM;
+
+ dma->bam_txn->desc = devm_kzalloc(dev, sizeof(*dma->bam_txn->desc), GFP_KERNEL);
+ if (!dma->bam_txn->desc)
+ return -ENOMEM;
+
+ sg_init_table(dma->bam_txn->wr_sgl, QCE_BAM_CMD_SGL_SIZE);
+
return devm_add_action_or_reset(dev, qce_dma_terminate, dma);
}
@@ -101,28 +203,36 @@ int qce_dma_prep_sgs(struct qce_dma_data *dma, struct scatterlist *rx_sg,
{
struct dma_chan *rxchan = dma->rxchan;
struct dma_chan *txchan = dma->txchan;
- unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+ unsigned long txflags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+ unsigned long rxflags = txflags | DMA_PREP_FENCE;
int ret;
- ret = qce_dma_prep_sg(rxchan, rx_sg, rx_nents, flags, DMA_MEM_TO_DEV,
+ ret = qce_dma_prep_sg(rxchan, rx_sg, rx_nents, rxflags, DMA_MEM_TO_DEV,
NULL, NULL);
if (ret)
return ret;
- return qce_dma_prep_sg(txchan, tx_sg, tx_nents, flags, DMA_DEV_TO_MEM,
+ return qce_dma_prep_sg(txchan, tx_sg, tx_nents, txflags, DMA_DEV_TO_MEM,
cb, cb_param);
}
void qce_dma_issue_pending(struct qce_dma_data *dma)
{
- dma_async_issue_pending(dma->rxchan);
dma_async_issue_pending(dma->txchan);
+ dma_async_issue_pending(dma->rxchan);
}
int qce_dma_terminate_all(struct qce_dma_data *dma)
{
+ struct qce_device *qce = container_of(dma, struct qce_device, dma);
+ struct qce_bam_transaction *bam_txn = dma->bam_txn;
int ret;
ret = dmaengine_terminate_all(dma->rxchan);
- return ret ?: dmaengine_terminate_all(dma->txchan);
+ if (ret)
+ return ret;
+
+ dma_unmap_sg(qce->dev, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt, DMA_TO_DEVICE);
+
+ return dmaengine_terminate_all(dma->txchan);
}
diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h
index 483789d9fa98e79d1283de8297bf2fc2a773f3a7..f05dfa9e6b25bd60e32f45079a8bc7e6a4cf81f9 100644
--- a/drivers/crypto/qce/dma.h
+++ b/drivers/crypto/qce/dma.h
@@ -8,6 +8,7 @@
#include <linux/dmaengine.h>
+struct qce_bam_transaction;
struct qce_device;
/* maximum data transfer block size between BAM and CE */
@@ -32,6 +33,7 @@ struct qce_dma_data {
struct dma_chan *txchan;
struct dma_chan *rxchan;
struct qce_result_dump *result_buf;
+ struct qce_bam_transaction *bam_txn;
};
int devm_qce_dma_request(struct qce_device *qce);
@@ -43,5 +45,8 @@ int qce_dma_terminate_all(struct qce_dma_data *dma);
struct scatterlist *
qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add,
unsigned int max_len);
+void qce_write_dma(struct qce_device *qce, unsigned int offset, u32 val);
+int qce_submit_cmd_desc(struct qce_device *qce);
+void qce_clear_bam_transaction(struct qce_device *qce);
#endif /* _DMA_H_ */
diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
index a3a1a205aaf8559a04809936e2a3b7d564c16c53..5be82b345753f49202797852cec09dbc7f0a1e03 100644
--- a/drivers/crypto/qce/sha.c
+++ b/drivers/crypto/qce/sha.c
@@ -109,17 +109,17 @@ static int qce_ahash_async_req_handle(struct crypto_async_request *async_req)
goto error_unmap_src;
}
- ret = qce_dma_prep_sgs(&qce->dma, req->src, rctx->src_nents,
- &rctx->result_sg, 1, qce_ahash_done, async_req);
+ ret = qce_start(async_req, tmpl->crypto_alg_type);
if (ret)
goto error_unmap_dst;
- qce_dma_issue_pending(&qce->dma);
-
- ret = qce_start(async_req, tmpl->crypto_alg_type);
+ ret = qce_dma_prep_sgs(&qce->dma, req->src, rctx->src_nents,
+ &rctx->result_sg, 1, qce_ahash_done, async_req);
if (ret)
goto error_terminate;
+ qce_dma_issue_pending(&qce->dma);
+
return 0;
error_terminate:
diff --git a/drivers/crypto/qce/skcipher.c b/drivers/crypto/qce/skcipher.c
index 1fef315a7105c869e7fc6a60719087b721e78bb3..6535336a2c57c39db94999011890b8bdad5c58c2 100644
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -142,18 +142,18 @@ qce_skcipher_async_req_handle(struct crypto_async_request *async_req)
src_nents = dst_nents - 1;
}
+ ret = qce_start(async_req, tmpl->crypto_alg_type);
+ if (ret)
+ goto error_unmap_src;
+
ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, src_nents,
rctx->dst_sg, dst_nents,
qce_skcipher_done, async_req);
if (ret)
- goto error_unmap_src;
+ goto error_terminate;
qce_dma_issue_pending(&qce->dma);
- ret = qce_start(async_req, tmpl->crypto_alg_type);
- if (ret)
- goto error_terminate;
-
return 0;
error_terminate:
--
2.47.3
^ permalink raw reply related
* [PATCH v19 14/14] crypto: qce - Communicate the base physical address to the dmaengine
From: Bartosz Golaszewski @ 2026-05-26 13:11 UTC (permalink / raw)
To: Vinod Koul, Jonathan Corbet, Thara Gopinath, Herbert Xu,
David S. Miller, Udit Tiwari, Md Sadre Alam, Dmitry Baryshkov,
Manivannan Sadhasivam, Stephan Gerhold, Bjorn Andersson,
Peter Ujfalusi, Michal Simek, Frank Li, Andy Gross,
Neil Armstrong
Cc: dmaengine, linux-doc, linux-kernel, linux-arm-msm, linux-crypto,
linux-arm-kernel, brgl, Bartosz Golaszewski, Bartosz Golaszewski
In-Reply-To: <20260526-qcom-qce-cmd-descr-v19-0-08472fdcbf4a@oss.qualcomm.com>
In order to communicate to the BAM DMA engine which address should be
used as a scratchpad for dummy writes related to BAM pipe locking,
fill out and attach the provided metadata struct to the descriptor.
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/crypto/qce/dma.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
index 769cc71da90076be446cbdf7ec7db27f628fa2ac..349c1d9ce9a2f4628087aa4ed5f8dda2bd9eaedb 100644
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -11,6 +11,7 @@
#include "core.h"
#include "dma.h"
+#include "regs-v5.h"
#define QCE_IGNORE_BUF_SZ (2 * QCE_BAM_BURST_SIZE)
#define QCE_BAM_CMD_SGL_SIZE 128
@@ -41,6 +42,10 @@ void qce_clear_bam_transaction(struct qce_device *qce)
int qce_submit_cmd_desc(struct qce_device *qce)
{
+ struct bam_desc_metadata meta = {
+ .scratchpad_addr = qce->base_phys + REG_VERSION,
+ .direction = DMA_MEM_TO_DEV,
+ };
struct qce_desc_info *qce_desc = qce->dma.bam_txn->desc;
struct qce_bam_transaction *bam_txn = qce->dma.bam_txn;
struct dma_async_tx_descriptor *dma_desc;
@@ -60,6 +65,10 @@ int qce_submit_cmd_desc(struct qce_device *qce)
goto err_unmap_sg;
}
+ ret = dmaengine_desc_attach_metadata(dma_desc, &meta, sizeof(meta));
+ if (ret)
+ goto err_unmap_sg;
+
qce_desc->dma_desc = dma_desc;
cookie = dmaengine_submit(qce_desc->dma_desc);
--
2.47.3
^ permalink raw reply related
* Re: [PATCH RFC v8 01/24] mm: Introduce kpkeys
From: Linus Walleij @ 2026-05-26 13:17 UTC (permalink / raw)
To: Kevin Brodsky
Cc: linux-hardening, Andrew Morton, Andy Lutomirski, Catalin Marinas,
Dave Hansen, David Hildenbrand (Arm), Ira Weiny, Jann Horn,
Jeff Xu, Joey Gouly, Kees Cook, Marc Zyngier, Mark Brown,
Matthew Wilcox, Maxwell Bland, Mike Rapoport (IBM),
Peter Zijlstra, Pierre Langlois, Quentin Perret, Rick Edgecombe,
Ryan Roberts, Vlastimil Babka, Will Deacon, Yang Shi, Yeoreum Yun,
linux-arm-kernel, linux-mm, x86, Lorenzo Stoakes, Thomas Gleixner
In-Reply-To: <20260526-kpkeys-v8-1-eaaacdacc67c@arm.com>
Hi Kevin,
here is just a few drive-by review comments pertaining to the
API which will be used for all architectures wanting to use
pkeys.
On Tue, May 26, 2026 at 1:17 PM Kevin Brodsky <kevin.brodsky@arm.com> wrote:
> kpkeys is a simple framework to enable the use of protection keys
> (pkeys) to harden the kernel itself. This patch introduces the basic
> API in <linux/kpkeys.h>: a couple of functions to set and restore
> the pkey register and macros to define guard objects.
Itäs a nice idea to use guards for this!
> kpkeys introduces a new concept on top of pkeys: the kpkeys context.
> Each context is associated to a set of permissions for the pkeys
> managed by the kpkeys framework. kpkeys_set_context(ctx) sets those
> permissions according to ctx, and returns the original pkey
> register, to be later restored by kpkeys_restore_pkey_reg(). To
> start with, only KPKEYS_CTX_DEFAULT is available, which is meant to
> grant RW access to KPKEYS_PKEY_DEFAULT (i.e. all memory since this
> is the only available pkey for now).
OK!
> Because each architecture implementing pkeys uses a different
> representation for the pkey register, and may reserve certain pkeys
> for specific uses, support for kpkeys must be explicitly indicated
> by selecting ARCH_HAS_KPKEYS and defining the following functions in
> <asm/kpkeys.h>, in addition to the macros provided in
> <asm-generic/kpkeys.h>:
>
> - arch_kpkeys_set_context()
> - arch_kpkeys_restore_pkey_reg()
> - arch_supports_kpkeys()
>
> Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
I'm following so far.
Is there no need for something like
ctx = arch_kpkeys_request_context(KEY_TYPE) ?
I'm just thinking of the scenario that e.g. two architectures want
to request the same type of key for some generic resource, but
the underlying implementation is vastly different for the two
architectures, so relying on hard-coded arch-specific constants
may not work. I'm also thinking about archs supporting different
versions/types of kpkeys in a multi-platform executable kernel
that may execute on several different silicon with the same ISA.
Maybe this is too much upfront design, I understand it needs to
be kept simple.
> +#ifndef KPKEYS_PKEY_DEFAULT
> +#define KPKEYS_PKEY_DEFAULT 0
> +#endif
(...)
> +#define KPKEYS_CTX_DEFAULT 0
> +
> +#define KPKEYS_CTX_MIN KPKEYS_CTX_DEFAULT
> +#define KPKEYS_CTX_MAX KPKEYS_CTX_DEFAULT
I was thinking an enum:
enum kpkey_type {
KPKEY_DEFAULT = 0,
KPKEY_MMU_TABLE = 1,
....
};
since this is what is used later.
> +/**
> + * kpkeys_set_context() - switch kpkeys context
> + * @ctx: the context to switch to
> + *
> + * Switches to specified kpkeys context. @ctx must be a compile-time
> + * constant. The arch-specific pkey register will be updated accordingly, and
> + * the original value returned.
> + *
> + * Return: the original pkey register value if the register was written to, or
> + * KPKEYS_PKEY_REG_INVAL otherwise (no write to the register was
> + * required).
> + */
> +static __always_inline u64 kpkeys_set_context(int ctx)
Should ctx be unsigned here? I'm nor sure what a negativ context
would mean.
kpkeys_set_context(unsigned int ctx)
And then I was thinking:
unsigned int kpkeys_request_context(enum kpkey_type type) {}...
+ arch_ -prefixed version of the same.
unsigned int ctx;
ctx = kpkeys_request_context(KPKEY_MMU_TABLE);
(...)
Constant sinking in the compiler will optimize the arch
function to a constant in the object code so it will still
be fast just a bit more talkative in source form.
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v19 05/14] dmaengine: qcom: bam_dma: Add pipe_lock_supported flag support
From: Bartosz Golaszewski @ 2026-05-26 13:10 UTC (permalink / raw)
To: Vinod Koul, Jonathan Corbet, Thara Gopinath, Herbert Xu,
David S. Miller, Udit Tiwari, Md Sadre Alam, Dmitry Baryshkov,
Manivannan Sadhasivam, Stephan Gerhold, Bjorn Andersson,
Peter Ujfalusi, Michal Simek, Frank Li, Andy Gross,
Neil Armstrong
Cc: dmaengine, linux-doc, linux-kernel, linux-arm-msm, linux-crypto,
linux-arm-kernel, brgl, Bartosz Golaszewski, Bartosz Golaszewski,
Dmitry Baryshkov
In-Reply-To: <20260526-qcom-qce-cmd-descr-v19-0-08472fdcbf4a@oss.qualcomm.com>
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Extend the device match data with a flag indicating whether the IP
supports the BAM lock/unlock feature. Set it to true on BAM IP versions
1.4.0 and above.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/dma/qcom/bam_dma.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 2129ff5261571581a2c086c13dd657dc63e16f90..04fe1d546be73f074c66c4a5712ad65717e10929 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -115,6 +115,7 @@ struct reg_offset_data {
struct bam_device_data {
const struct reg_offset_data *reg_info;
+ bool pipe_lock_supported;
};
static const struct reg_offset_data bam_v1_3_reg_info[] = {
@@ -181,6 +182,7 @@ static const struct reg_offset_data bam_v1_4_reg_info[] = {
static const struct bam_device_data bam_v1_4_data = {
.reg_info = bam_v1_4_reg_info,
+ .pipe_lock_supported = true,
};
static const struct reg_offset_data bam_v1_7_reg_info[] = {
@@ -214,6 +216,7 @@ static const struct reg_offset_data bam_v1_7_reg_info[] = {
static const struct bam_device_data bam_v1_7_data = {
.reg_info = bam_v1_7_reg_info,
+ .pipe_lock_supported = true,
};
/* BAM CTRL */
--
2.47.3
^ permalink raw reply related
* [PATCH v19 04/14] dmaengine: qcom: bam_dma: Extend the driver's device match data
From: Bartosz Golaszewski @ 2026-05-26 13:10 UTC (permalink / raw)
To: Vinod Koul, Jonathan Corbet, Thara Gopinath, Herbert Xu,
David S. Miller, Udit Tiwari, Md Sadre Alam, Dmitry Baryshkov,
Manivannan Sadhasivam, Stephan Gerhold, Bjorn Andersson,
Peter Ujfalusi, Michal Simek, Frank Li, Andy Gross,
Neil Armstrong
Cc: dmaengine, linux-doc, linux-kernel, linux-arm-msm, linux-crypto,
linux-arm-kernel, brgl, Bartosz Golaszewski, Bartosz Golaszewski
In-Reply-To: <20260526-qcom-qce-cmd-descr-v19-0-08472fdcbf4a@oss.qualcomm.com>
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
In preparation for supporting the pipe locking feature flag, extend the
amount of information we can carry in device match data: create a
separate structure and make the register information one of its fields.
This way, in subsequent patches, it will be just a matter of adding a
new field to the device data.
Reviewed-by: Dmitry Baryshkov <lumag@kernel.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/dma/qcom/bam_dma.c | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 1c62f845ac0b956e311857b93f5b504086662f45..2129ff5261571581a2c086c13dd657dc63e16f90 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -113,6 +113,10 @@ struct reg_offset_data {
unsigned int pipe_mult, evnt_mult, ee_mult;
};
+struct bam_device_data {
+ const struct reg_offset_data *reg_info;
+};
+
static const struct reg_offset_data bam_v1_3_reg_info[] = {
[BAM_CTRL] = { 0x0F80, 0x00, 0x00, 0x00 },
[BAM_REVISION] = { 0x0F84, 0x00, 0x00, 0x00 },
@@ -142,6 +146,10 @@ static const struct reg_offset_data bam_v1_3_reg_info[] = {
[BAM_P_FIFO_SIZES] = { 0x1020, 0x00, 0x40, 0x00 },
};
+static const struct bam_device_data bam_v1_3_data = {
+ .reg_info = bam_v1_3_reg_info,
+};
+
static const struct reg_offset_data bam_v1_4_reg_info[] = {
[BAM_CTRL] = { 0x0000, 0x00, 0x00, 0x00 },
[BAM_REVISION] = { 0x0004, 0x00, 0x00, 0x00 },
@@ -171,6 +179,10 @@ static const struct reg_offset_data bam_v1_4_reg_info[] = {
[BAM_P_FIFO_SIZES] = { 0x1820, 0x00, 0x1000, 0x00 },
};
+static const struct bam_device_data bam_v1_4_data = {
+ .reg_info = bam_v1_4_reg_info,
+};
+
static const struct reg_offset_data bam_v1_7_reg_info[] = {
[BAM_CTRL] = { 0x00000, 0x00, 0x00, 0x00 },
[BAM_REVISION] = { 0x01000, 0x00, 0x00, 0x00 },
@@ -200,6 +212,10 @@ static const struct reg_offset_data bam_v1_7_reg_info[] = {
[BAM_P_FIFO_SIZES] = { 0x13820, 0x00, 0x1000, 0x00 },
};
+static const struct bam_device_data bam_v1_7_data = {
+ .reg_info = bam_v1_7_reg_info,
+};
+
/* BAM CTRL */
#define BAM_SW_RST BIT(0)
#define BAM_EN BIT(1)
@@ -393,7 +409,7 @@ struct bam_device {
bool powered_remotely;
u32 active_channels;
- const struct reg_offset_data *layout;
+ const struct bam_device_data *dev_data;
struct clk *bamclk;
int irq;
@@ -411,7 +427,7 @@ struct bam_device {
static inline void __iomem *bam_addr(struct bam_device *bdev, u32 pipe,
enum bam_reg reg)
{
- const struct reg_offset_data r = bdev->layout[reg];
+ const struct reg_offset_data r = bdev->dev_data->reg_info[reg];
return bdev->regs + r.base_offset +
r.pipe_mult * pipe +
@@ -1205,9 +1221,9 @@ static void bam_channel_init(struct bam_device *bdev, struct bam_chan *bchan,
}
static const struct of_device_id bam_of_match[] = {
- { .compatible = "qcom,bam-v1.3.0", .data = &bam_v1_3_reg_info },
- { .compatible = "qcom,bam-v1.4.0", .data = &bam_v1_4_reg_info },
- { .compatible = "qcom,bam-v1.7.0", .data = &bam_v1_7_reg_info },
+ { .compatible = "qcom,bam-v1.3.0", .data = &bam_v1_3_data },
+ { .compatible = "qcom,bam-v1.4.0", .data = &bam_v1_4_data },
+ { .compatible = "qcom,bam-v1.7.0", .data = &bam_v1_7_data },
{}
};
@@ -1231,7 +1247,7 @@ static int bam_dma_probe(struct platform_device *pdev)
return -ENODEV;
}
- bdev->layout = match->data;
+ bdev->dev_data = match->data;
bdev->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(bdev->regs))
--
2.47.3
^ permalink raw reply related
* Re: [PATCH v10 02/30] arm64/fpsimd: Update FA64 and ZT0 enables when loading SME state
From: Mark Brown @ 2026-05-26 13:25 UTC (permalink / raw)
To: Mark Rutland
Cc: Marc Zyngier, Joey Gouly, Catalin Marinas, Suzuki K Poulose,
Will Deacon, Paolo Bonzini, Jonathan Corbet, Shuah Khan,
Oliver Upton, Dave Martin, Fuad Tabba, Ben Horgan,
linux-arm-kernel, kvmarm, linux-kernel, kvm, linux-doc,
linux-kselftest, Peter Maydell, Eric Auger
In-Reply-To: <ahWWqU51Zffmhlo5@J2N7QTR9R3>
[-- Attachment #1: Type: text/plain, Size: 1273 bytes --]
On Tue, May 26, 2026 at 01:48:41PM +0100, Mark Rutland wrote:
> On Fri, Mar 06, 2026 at 05:00:54PM +0000, Mark Brown wrote:
> > We provide a helper which does the configuration as part of a
> > read/modify/write operation along with the configuration of the task VL,
> > then update the floating point state load and SME access trap to use it.
> > + if (fa64) \
> > + __new |= SMCR_ELx_FA64; \
> > + if (zt0) \
> > + __new |= SMCR_ELx_EZT0; \
> I'd strongly prefer that we make it the caller's responsiblity to track
> all the bits within SMCR, rather than requiring each caller to pass a
> bag of booleans.
I was explicitly going for the opposite of that in order to make it
harder for someone implementing a future extension to miss a place where
an update is required, having the callers independently constructing the
register values feels like it's asking for trouble.
> unsigned long __task_smcr(const struct task_struct *tsk)
> {
> unsigned long vq = sve_vq_from_vl(task_get_sme_vl(tsk));
> unsigned long smcr = vq - 1;
I agree that's a better pattern for the main kernel - we could also do
something similar with a task_set_smcr() which wraps the explicitly
specifed version. That would I think avoid most of the issue you're
seeing?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v3 11/11] iio: dac: add mcf54415 DAC
From: Jonathan Cameron @ 2026-05-26 13:30 UTC (permalink / raw)
To: Angelo Dureghello
Cc: Greg Ungerer, Geert Uytterhoeven, Steven King, Arnd Bergmann,
Maxime Coquelin, Alexandre Torgue, David Lechner, Nuno Sá,
Andy Shevchenko, Greg Ungerer, linux-m68k, linux-kernel,
linux-stm32, linux-arm-kernel, linux-iio
In-Reply-To: <20260522-wip-stmark2-dac-v3-11-16be0ad35a67@baylibre.com>
On Fri, 22 May 2026 23:20:39 +0200
Angelo Dureghello <adureghello@baylibre.com> wrote:
> From: Angelo Dureghello <adureghello@baylibre.com>
>
> Add basic version of mcf54415 DAC driver. DAC is embedded in the cpu and
> DAC configuration registers are mapped in the internal IO address space.
>
> The DAC accepts a 12-bit digital signal and creates a monotonic 12-bit
> analog output varying from DAC_VREFL to DAC_VREFH. The DAC module
> consists of a conversion unit, an output amplifier, and the associated
> digital control blocks. Default register values for DAC_VREFL and DAC_VREFH
> are respectively 0 and 0xfff, left untouched in this initial version.
>
> This initial version of the driver is minimalistic, "output raw" only, to
> be extended in the future. DMA and external sync are disabled, default mode
> is high speed, default format is right-justified 12bit on 16bit word.
>
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
https://sashiko.dev/#/patchset/20260522-wip-stmark2-dac-v3-0-16be0ad35a67%40baylibre.com
Given there were only a couple of comments I've included them below alongside
my review. All minor stuff.
Thanks,
Jonathan
> ---
> Changes in v2:
> - remove tests from commit message, moved to patch 0
> - remove additional blank lines
> - remove dead code and unused definitions
> - use regmap
> - add limit check on raw write
> - non functional style fixes
> - add COMPILE_TEST to Kconfig
> Changes in v3:
> - add comments where needed
> - code style changes
> - remove unneeded variables
> - use regmap_set_bits where possible
> - remove macro not needed to define a single channel
> - set up regmap to big_endian accesses for next patches that will come,
> that will adjust ColdFire readx/writex as standard LE (links in 0/x).
> - add return value check on regmap calls
> - sashiko: remove unneeded .io_port from regmap init.
> - sashiko: add select REGMAP_MMIO in Kconfig
Looks like you missed or disagreed with the previous sashiko comment on v2 about
type passed to regmap_read()
> ---
> drivers/iio/dac/Kconfig | 11 +++
> drivers/iio/dac/Makefile | 1 +
> drivers/iio/dac/mcf54415_dac.c | 207 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 219 insertions(+)
>
> diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
> index cd4870b65415..b1a578076188 100644
> --- a/drivers/iio/dac/Kconfig
> +++ b/drivers/iio/dac/Kconfig
> @@ -516,6 +516,17 @@ config MAX5821
> Say yes here to build support for Maxim MAX5821
> 10 bits DAC.
>
> +config MCF54415_DAC
> + tristate "NXP MCF54415 DAC driver"
> + depends on M5441x || COMPILE_TEST
> + select REGMAP_MMIO
> + help
> + Say yes here to build support for NXP MCF54415
> + 12bit DAC.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called mcf54415_dac.
> +
> diff --git a/drivers/iio/dac/mcf54415_dac.c b/drivers/iio/dac/mcf54415_dac.c
> new file mode 100644
> index 000000000000..c8c87572d43d
> --- /dev/null
> +++ b/drivers/iio/dac/mcf54415_dac.c
> @@ -0,0 +1,207 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * NXP mcf54415 DAC driver
> + *
> + * Copyright 2026 BayLibre - adureghello@baylibre.com
> + */
> +
> +#include <linux/array_size.h>
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/compiler_types.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
not seeing any use of this. I guess it 'evolved' away.
Anyhow, please sanity check these all one more time for v4.
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +#include <linux/iio/iio.h>
> +
> +#define MCF54415_DAC_CR 0x00
> +#define MCF54415_DAC_CR_PDN BIT(0)
> +#define MCF54415_DAC_CR_HSLS BIT(6)
> +#define MCF54415_DAC_CR_WMLVL GENMASK(9, 8)
> +#define MCF54415_DAC_CR_FILT BIT(12)
> +
> +#define MCF54415_DAC_DATA 0x02
> +
> +struct mcf54415_dac {
> + struct regmap *map;
> + struct clk *clk;
> +};
> +
> +static const struct regmap_config mcf54415_dac_regmap_config = {
> + .reg_bits = 16,
> + .reg_stride = 2,
> + .val_bits = 16,
> + .max_register = 0x0c, /* DACX_FILTCNT, R.M. Table 30-2 */
> + .val_format_endian = REGMAP_ENDIAN_BIG,
> + .reg_format_endian = REGMAP_ENDIAN_BIG,
> +};
> +
> +static int mcf54415_dac_init(struct mcf54415_dac *info)
> +{
> + int ret;
> +
> + /* Keeping defaults and enable DAC (bit 0 set to 0) */
> + ret = regmap_write(info->map, MCF54415_DAC_CR, MCF54415_DAC_CR_FILT |
> + FIELD_PREP(MCF54415_DAC_CR_WMLVL, 1));
Perhaps use a local variable. It is a tiny bit too easy to miss that
parameter being split over two lines.
u16 val = MCF54415_DAC_CR_FILT | FIELD_PREP(MCF54415_DAC_CR_WMLVL, 1);
would avoid that.
Alternatively perhaps just reflowing as:
ret = regmap_write(info->map, MCF54415_DAC_CR,
MCF54415_DAC_CR_FILT |
FIELD_PREP(MCF54415_DAC_CR_WMLVL, 1));
avoids that reading issue (I read it wrong ;)
> + if (ret)
> + return ret;
> +
> + /* DAC is ready after 12us, from RM table 40-3 */
> + fsleep(12);
> +
> + return 0;
> +}
> +
> +static int mcf54415_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + struct mcf54415_dac *info = iio_priv(indio_dev);
> + int ret;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + ret = regmap_read(info->map, MCF54415_DAC_DATA, val);
Sashiko pointed out that regmap_read() expects a u32* so this should use
a local variable for the read.
> + if (ret)
> + return -EIO;
Another one sashiko got. Why is this eating the possibly more useful error
code from regmap_read()?
> + *val &= 0xfff;
> + return IIO_VAL_INT;
> + case IIO_CHAN_INFO_SCALE:
> + /* Reference voltage as per ColdFire datasheet is 3.3V */
> + *val = 3300 /* mV */;
> + *val2 = 12;
> + return IIO_VAL_FRACTIONAL_LOG2;
> + default:
> + return -EINVAL;
> + }
> +}
> +static int mcf54415_dac_resume(struct device *dev)
> +{
> + struct mcf54415_dac *info = iio_priv(dev_get_drvdata(dev));
> + int ret;
> +
> + ret = clk_prepare_enable(info->clk);
> + if (ret)
> + return ret;
> +
> + mcf54415_dac_init(info);
If this fails should we report it? I think you'd at least want
some print to help with debug. (Sashiko got this)
> +
> + return 0;
> +}
^ permalink raw reply
* Re: [PATCH v2 29/39] KVM: arm64: gic-v5: Support SPI injection
From: Vladimir Murzin @ 2026-05-26 13:41 UTC (permalink / raw)
To: Sascha Bischoff, linux-arm-kernel@lists.infradead.org,
kvmarm@lists.linux.dev, kvm@vger.kernel.org
Cc: nd, maz@kernel.org, oliver.upton@linux.dev, Joey Gouly,
Suzuki Poulose, yuzenghui@huawei.com, peter.maydell@linaro.org,
lpieralisi@kernel.org, Timothy Hayes
In-Reply-To: <20260521144846.1899475-30-sascha.bischoff@arm.com>
Hi Sascha,
On 5/21/26 15:59, Sascha Bischoff wrote:
> /* SPIs */
> - if (intid >= VGIC_NR_PRIVATE_IRQS &&
> - intid < (kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS)) {
> - intid = array_index_nospec(intid, kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS);
> - return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
> + if (__irq_is_spi(type, intid)) {
> + switch (type) {
> + case KVM_DEV_TYPE_ARM_VGIC_V5:
> + intid = vgic_v5_get_hwirq_id(intid);
> +
> + if (intid >= kvm->arch.vgic.nr_spis)
> + return NULL;
> +
> + intid = array_index_nospec(intid, kvm->arch.vgic.nr_spis);
> + return &kvm->arch.vgic.spis[intid];
> + default:
> + u32 max_intid = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +
> + if (intid < max_intid) {
> + intid = array_index_nospec(intid, max_intid);
> + return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
> + }
> + }
> }
Just quick update to save everybody's time. That hunk causes my build fail with:
arch/arm64/kvm/vgic/vgic.c: In function 'vgic_get_irq':
arch/arm64/kvm/vgic/vgic.c:103:4: error: a label can only be part of a statement and a declaration is not a statement
103 | u32 max_intid = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
| ^~~
make[4]: *** [scripts/Makefile.build:289: arch/arm64/kvm/vgic/vgic.o] Error 1
make[3]: *** [scripts/Makefile.build:548: arch/arm64/kvm] Error 2
make[2]: *** [scripts/Makefile.build:548: arch/arm64] Error 2
Obvious fix-up would be wrap default case into curly braces.
Cheers
Vladimir
^ permalink raw reply
* [PATCH v19 03/14] dmaengine: qcom: bam_dma: convert tasklet to a BH workqueue
From: Bartosz Golaszewski @ 2026-05-26 13:10 UTC (permalink / raw)
To: Vinod Koul, Jonathan Corbet, Thara Gopinath, Herbert Xu,
David S. Miller, Udit Tiwari, Md Sadre Alam, Dmitry Baryshkov,
Manivannan Sadhasivam, Stephan Gerhold, Bjorn Andersson,
Peter Ujfalusi, Michal Simek, Frank Li, Andy Gross,
Neil Armstrong
Cc: dmaengine, linux-doc, linux-kernel, linux-arm-msm, linux-crypto,
linux-arm-kernel, brgl, Bartosz Golaszewski, Bartosz Golaszewski,
Dmitry Baryshkov
In-Reply-To: <20260526-qcom-qce-cmd-descr-v19-0-08472fdcbf4a@oss.qualcomm.com>
BH workqueues are a modern mechanism, aiming to replace legacy tasklets.
Let's convert the BAM DMA driver to using the high-priority variant of
the BH workqueue.
[Vinod: suggested using the BG workqueue instead of the regular one
running in process context]
Suggested-by: Vinod Koul <vkoul@kernel.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Bjorn Andersson <andersson@kernel.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/dma/qcom/bam_dma.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index b3d36ea79984385fe0d05ce56042d3e6e3030c5a..1c62f845ac0b956e311857b93f5b504086662f45 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -42,6 +42,7 @@
#include <linux/pm_runtime.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include "../dmaengine.h"
#include "../virt-dma.h"
@@ -397,8 +398,8 @@ struct bam_device {
struct clk *bamclk;
int irq;
- /* dma start transaction tasklet */
- struct tasklet_struct task;
+ /* dma start transaction workqueue */
+ struct work_struct work;
};
/**
@@ -863,7 +864,7 @@ static u32 process_channel_irqs(struct bam_device *bdev)
/*
* if complete, process cookie. Otherwise
* push back to front of desc_issued so that
- * it gets restarted by the tasklet
+ * it gets restarted by the work queue.
*/
if (!async_desc->num_desc) {
vchan_cookie_complete(&async_desc->vd);
@@ -893,9 +894,9 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
srcs |= process_channel_irqs(bdev);
- /* kick off tasklet to start next dma transfer */
+ /* kick off the work queue to start next dma transfer */
if (srcs & P_IRQ)
- tasklet_schedule(&bdev->task);
+ queue_work(system_bh_highpri_wq, &bdev->work);
ret = pm_runtime_get_sync(bdev->dev);
if (ret < 0)
@@ -1091,14 +1092,14 @@ static void bam_start_dma(struct bam_chan *bchan)
}
/**
- * dma_tasklet - DMA IRQ tasklet
- * @t: tasklet argument (bam controller structure)
+ * bam_dma_work() - DMA interrupt work queue callback
+ * @work: work queue struct embedded in the BAM controller device struct
*
* Sets up next DMA operation and then processes all completed transactions
*/
-static void dma_tasklet(struct tasklet_struct *t)
+static void bam_dma_work(struct work_struct *work)
{
- struct bam_device *bdev = from_tasklet(bdev, t, task);
+ struct bam_device *bdev = from_work(bdev, work, work);
struct bam_chan *bchan;
unsigned int i;
@@ -1111,14 +1112,13 @@ static void dma_tasklet(struct tasklet_struct *t)
if (!list_empty(&bchan->vc.desc_issued) && !IS_BUSY(bchan))
bam_start_dma(bchan);
}
-
}
/**
* bam_issue_pending - starts pending transactions
* @chan: dma channel
*
- * Calls tasklet directly which in turn starts any pending transactions
+ * Calls work queue directly which in turn starts any pending transactions
*/
static void bam_issue_pending(struct dma_chan *chan)
{
@@ -1286,14 +1286,14 @@ static int bam_dma_probe(struct platform_device *pdev)
if (ret)
goto err_disable_clk;
- tasklet_setup(&bdev->task, dma_tasklet);
+ INIT_WORK(&bdev->work, bam_dma_work);
bdev->channels = devm_kcalloc(bdev->dev, bdev->num_channels,
sizeof(*bdev->channels), GFP_KERNEL);
if (!bdev->channels) {
ret = -ENOMEM;
- goto err_tasklet_kill;
+ goto err_workqueue_cancel;
}
/* allocate and initialize channels */
@@ -1359,8 +1359,8 @@ static int bam_dma_probe(struct platform_device *pdev)
err_bam_channel_exit:
for (i = 0; i < bdev->num_channels; i++)
tasklet_kill(&bdev->channels[i].vc.task);
-err_tasklet_kill:
- tasklet_kill(&bdev->task);
+err_workqueue_cancel:
+ cancel_work_sync(&bdev->work);
err_disable_clk:
clk_disable_unprepare(bdev->bamclk);
@@ -1394,7 +1394,7 @@ static void bam_dma_remove(struct platform_device *pdev)
bdev->channels[i].fifo_phys);
}
- tasklet_kill(&bdev->task);
+ cancel_work_sync(&bdev->work);
clk_disable_unprepare(bdev->bamclk);
}
--
2.47.3
^ permalink raw reply related
* Re: [PATCH 1/2] gfp_types: Introduce a new GFP_ATOMIC_RT gfp flag
From: Vlastimil Babka (SUSE) @ 2026-05-26 13:55 UTC (permalink / raw)
To: Michal Hocko, Waiman Long
Cc: Marc Zyngier, Thomas Gleixner, Sebastian Andrzej Siewior,
Clark Williams, Steven Rostedt, Andrew Morton, David Hildenbrand,
Lorenzo Stoakes, Liam R. Howlett, Mike Rapoport,
Suren Baghdasaryan, linux-arm-kernel, linux-kernel, linux-mm,
linux-rt-devel
In-Reply-To: <ahQLVgj8zV4xQRh9@tiehlicka>
On 5/25/26 10:41 AM, Michal Hocko wrote:
> On Wed 20-05-26 16:46:27, Waiman Long wrote:
>> The GFP_ATOMIC flag is to be used in atomic context where user cannot
>> sleep and need the allocation to succeed. However, it does not support
>> contexts where preemption or interrupt is disabled under PREEMPT_RT
>> like raw_spin_lock_irqsave() or plain preempt_disable().
>>
>> With the advance of the ALLOC_TRYLOCK allocation flag in the v7.1
>> kernel, it is possible to allocate memory under such contexts by using
>> spin_trylock to acquire the spinlock in the memory allocation path. This
>> does increase the chance that the allocation can fail due to the presence
>> of concurrent memory allocation requests. So its users must be able to
>> handle such memory allocation failure gracefully.
>>
>> The ALLOC_TRYLOCK flag will only be enabled if none of the
>> ___GFP_DIRECT_RECLAIM and ___GFP_KSWAPD_RECLAIM flags are set.
>>
>> Introduce a new GFP_ATOMIC_RT gfp flag for those PREEMPT_RT
>> atomic contexts. This new flag will fall back to GFP_ATOMIC in
>> non-PREEMPT_RT kernel. GFP_ATOMIC can continue to be used in contexts
>> where preemption and interrupt are not disabled in PREEMPT_RT kernel
>> like spin_lock_irqsave().
>
> Before we go this way we need to really be clear we do want to support
> raw_spinlock (aka RT) contexts. This is a big commitment because it
> dictates internal allocator locking that would have potentially a much
> bigger impact long term. I would go this way only after/when we conclude
> there is absolutely no other way and we need to have allocator in those
> critical sections. Now you have a single place which complains ATM
We already have alloc_pages_nolock() which uses ALLOC_TRYLOCK internally
for these limited contexts. So the support and commitment exist. This
just exposes it via a new gfp flag alias. But if there's a single user
and it's already disputed, we don't have to expose it that way indeed.
> without much of an explanation why this cannot be really handled in
> other way. Have you even considered any options to pull the allocation
> from within the raw spin lock section?
^ permalink raw reply
* [PATCH RFT] tty: serial: fsl_lpuart: Add register dump
From: Stefan Wahren @ 2026-05-26 14:01 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Sherry Sun
Cc: Christophe JAILLET, Ingo Molnar, Frank Li, linux-serial,
linux-arm-kernel, Stefan Wahren
Dumping the registers from userspace for debug purposes isn't trivial,
because runtime PM can gate the required clocks and any read access
to these registers would result in a lockup.
So implement a register dump via debugfs, which deals with the
runtime PM.
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
Hi, I only have access to a board (i.MX93) with 32 bit registers, so it
would be great if someone could test it for 8 bit registers.
Thanks
drivers/tty/serial/fsl_lpuart.c | 69 +++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 1bd7ec9c81ea..7e4b3e59414a 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -10,6 +10,7 @@
#include <linux/circ_buf.h>
#include <linux/clk.h>
#include <linux/console.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
@@ -23,6 +24,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/seq_file.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/tty_flip.h>
@@ -291,6 +293,8 @@ struct lpuart_port {
bool is_cs7; /* Set to true when character size is 7 */
/* and the parity is enabled */
bool dma_idle_int;
+
+ struct dentry *debugfs_dir;
};
struct lpuart_soc_data {
@@ -1031,6 +1035,7 @@ static void lpuart32_rxint(struct lpuart_port *sport)
}
out:
+
uart_unlock_and_check_sysrq(&sport->port);
tty_flip_buffer_push(port);
@@ -2860,6 +2865,67 @@ static int lpuart_global_reset(struct lpuart_port *sport)
return 0;
}
+#ifdef CONFIG_DEBUG_FS
+
+#define dump_register_hex(_seq, _reg, _sport) \
+seq_printf((_seq), "%-12s: 0x%02x\n", #_reg, readb((_sport)->port.membase + (_reg)))
+
+#define dump_register32_hex(_seq, _reg, _sport) \
+seq_printf((_seq), "%-12s: 0x%08x\n", #_reg, lpuart32_read(&(_sport)->port, _reg))
+
+static int regs_show(struct seq_file *s, void *p)
+{
+ struct lpuart_port *sport = s->private;
+
+ pm_runtime_get_sync(sport->port.dev);
+
+ if (lpuart_is_32(sport)) {
+ dump_register32_hex(s, UARTBAUD, sport);
+ dump_register32_hex(s, UARTSTAT, sport);
+ dump_register32_hex(s, UARTCTRL, sport);
+ dump_register32_hex(s, UARTMATCH, sport);
+ dump_register32_hex(s, UARTMODIR, sport);
+ dump_register32_hex(s, UARTFIFO, sport);
+ dump_register32_hex(s, UARTWATER, sport);
+ } else {
+ dump_register_hex(s, UARTBDH, sport);
+ dump_register_hex(s, UARTBDL, sport);
+ dump_register_hex(s, UARTCR1, sport);
+ dump_register_hex(s, UARTCR2, sport);
+ dump_register_hex(s, UARTSR1, sport);
+ dump_register_hex(s, UARTCR3, sport);
+ dump_register_hex(s, UARTDR, sport);
+ dump_register_hex(s, UARTCR4, sport);
+ dump_register_hex(s, UARTCR5, sport);
+ dump_register_hex(s, UARTMODEM, sport);
+ dump_register_hex(s, UARTPFIFO, sport);
+ dump_register_hex(s, UARTCFIFO, sport);
+ dump_register_hex(s, UARTSFIFO, sport);
+ dump_register_hex(s, UARTTWFIFO, sport);
+ dump_register_hex(s, UARTTCFIFO, sport);
+ dump_register_hex(s, UARTRWFIFO, sport);
+ }
+
+ pm_runtime_mark_last_busy(sport->port.dev);
+ pm_runtime_put_autosuspend(sport->port.dev);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(regs);
+
+static void lpuart_init_debugfs(struct lpuart_port *sport)
+{
+ sport->debugfs_dir = debugfs_create_dir(dev_name(sport->port.dev),
+ NULL);
+
+ debugfs_create_file("regs", 0400, sport->debugfs_dir, sport, ®s_fops);
+}
+
+#else
+static inline void lpuart_init_debugfs(struct lpuart_port *sport) {}
+#endif
+
static int lpuart_probe(struct platform_device *pdev)
{
const struct lpuart_soc_data *sdata = of_device_get_match_data(&pdev->dev);
@@ -2969,6 +3035,8 @@ static int lpuart_probe(struct platform_device *pdev)
if (ret)
goto failed_irq_request;
+ lpuart_init_debugfs(sport);
+
return 0;
failed_irq_request:
@@ -2987,6 +3055,7 @@ static void lpuart_remove(struct platform_device *pdev)
{
struct lpuart_port *sport = platform_get_drvdata(pdev);
+ debugfs_remove_recursive(sport->debugfs_dir);
uart_remove_one_port(&lpuart_reg, &sport->port);
lpuart_disable_clks(sport);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 17/18] arm64: fpsimd: Move SME save/restore inline
From: Mark Rutland @ 2026-05-26 14:08 UTC (permalink / raw)
To: linux-arm-kernel, kvmarm
Cc: broonie, catalin.marinas, james.morse, maz, oupton, tabba, will
In-Reply-To: <20260521132556.584676-18-mark.rutland@arm.com>
On Thu, May 21, 2026 at 02:25:55PM +0100, Mark Rutland wrote:
> +static inline void __sme_save_za(struct sme_state *state, unsigned long svl)
> +{
> + /* The <Wv> argument to STR (array vector) can only encode W12-W15 */
> + register unsigned long v asm ("12");
Sorry, I had meant to put "x12" here, but evidently GCC and LLVM accept
"12" on its own.
For clarity (e.g. to match the comment) I'll change that to "w12" and
make the type unsigned int. Likewise in __sme_load_za().
Mark.
^ permalink raw reply
* Re: [PATCH 01/18] KVM: arm64: Don't include <asm/fpsimdmacros.h>
From: Mark Brown @ 2026-05-26 14:18 UTC (permalink / raw)
To: Mark Rutland
Cc: linux-arm-kernel, kvmarm, catalin.marinas, james.morse, maz,
oupton, tabba, will
In-Reply-To: <20260521132556.584676-2-mark.rutland@arm.com>
[-- Attachment #1: Type: text/plain, Size: 338 bytes --]
On Thu, May 21, 2026 at 02:25:39PM +0100, Mark Rutland wrote:
> There's no need for hyp/entry.S to include <asm/fpsimdmacros.h>.
>
> The fpsimd macros have never been used by code in hyp/entry.S, and were
> instead used by code in hyp/fpsimd.S.
>
> Remove the unnecessary include.
Reviewed-by: Mark Brown <broonie@kernel.org>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v10 02/30] arm64/fpsimd: Update FA64 and ZT0 enables when loading SME state
From: Mark Rutland @ 2026-05-26 14:20 UTC (permalink / raw)
To: Mark Brown
Cc: Marc Zyngier, Joey Gouly, Catalin Marinas, Suzuki K Poulose,
Will Deacon, Paolo Bonzini, Jonathan Corbet, Shuah Khan,
Oliver Upton, Dave Martin, Fuad Tabba, Ben Horgan,
linux-arm-kernel, kvmarm, linux-kernel, kvm, linux-doc,
linux-kselftest, Peter Maydell, Eric Auger
In-Reply-To: <d8074c6b-9bc9-496e-8a74-94ac18ce9a55@sirena.org.uk>
On Tue, May 26, 2026 at 02:25:56PM +0100, Mark Brown wrote:
> On Tue, May 26, 2026 at 01:48:41PM +0100, Mark Rutland wrote:
> > On Fri, Mar 06, 2026 at 05:00:54PM +0000, Mark Brown wrote:
>
> > > We provide a helper which does the configuration as part of a
> > > read/modify/write operation along with the configuration of the task VL,
> > > then update the floating point state load and SME access trap to use it.
>
> > > + if (fa64) \
> > > + __new |= SMCR_ELx_FA64; \
> > > + if (zt0) \
> > > + __new |= SMCR_ELx_EZT0; \
>
> > I'd strongly prefer that we make it the caller's responsiblity to track
> > all the bits within SMCR, rather than requiring each caller to pass a
> > bag of booleans.
>
> I was explicitly going for the opposite of that in order to make it
> harder for someone implementing a future extension to miss a place where
> an update is required, having the callers independently constructing the
> register values feels like it's asking for trouble.
I didn't say callers should *construct* the value independently, and I
showed how to centralize the construction in a __task_smcr() function.
I think callers should pass the entire value around rather than a
collection of discrete booleans: constructing a collection of discrete
booleans is functionally equivalent to construction the entire value,
and we can more easily manage the construction and passing of the entire
value.
> > unsigned long __task_smcr(const struct task_struct *tsk)
> > {
> > unsigned long vq = sve_vq_from_vl(task_get_sme_vl(tsk));
> > unsigned long smcr = vq - 1;
>
> I agree that's a better pattern for the main kernel - we could also do
> something similar with a task_set_smcr() which wraps the explicitly
> specifed version.
I don't think a task_set_smcr() function would gain much vs
using sysreg_cond_update_s(). I expect that we'd use the SMCR value as
the source of truth (and hence that would need to be generated outside
of task_set_smcr()), at which point either task_set_smcr() would be a
thin wrapper that just hides the register name, or it would generate the
value independently and obscure the connection.
I expect that what we should have eventually is something like:
unsigned long smcr = __task_smcr(task);
sysreg_cond_update_s(SYS_SMCR_EL1, smcr);
if (za) {
__sme load_za(sme_state);
if (smcr & SMCR_ELx_EZT0)
__sme_load_zt(sme_state);
}
... or:
const unsigned long smcr = __task_smcr(task);
const bool zt0 = smcr & SMCR_ELx_EZT0;
sysreg_cond_update_s(SYS_SMCR_EL1, smcr);
if (za) {
__sme load_za(sme_state);
if (zt0)
__sme_load_zt(sme_state);
}
... where in either case it's clear at the function level that the value
programmed into SMCR matches what we're using for boolean decisions, and
it's clear at a higher level that functions are consistent given
consistent usage of __task_smcr().
> That would I think avoid most of the issue you're seeing?
I'm not sure what you mean here.
I don't think we need task_set_smcr(), and I'd prefer what I suggested.
Mark.
^ permalink raw reply
* Re: [PATCH 02/18] KVM: arm64: Don't override FFR save/restore argument
From: Mark Brown @ 2026-05-26 14:27 UTC (permalink / raw)
To: Mark Rutland
Cc: linux-arm-kernel, kvmarm, catalin.marinas, james.morse, maz,
oupton, tabba, will
In-Reply-To: <20260521132556.584676-3-mark.rutland@arm.com>
[-- Attachment #1: Type: text/plain, Size: 428 bytes --]
On Thu, May 21, 2026 at 02:25:40PM +0100, Mark Rutland wrote:
> The __sve_save_state() and __sve_restore_state() functions take a
> parameter describing whether to save/restore the FFR, but both functions
> silently override this with '1'. This has always been benign (and
> callers have all passed 'true' since the parameter was introduced), but
> clearly this is not intentional.
Reviewed-by: Mark Brown <broonie@kernel.org>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v2] remoteproc: imx_rproc: Use device node name as processor name
From: Mathieu Poirier @ 2026-05-26 14:37 UTC (permalink / raw)
To: Jiafei Pan
Cc: daniel.baluta, Frank.Li, andersson, festevam, imx, kernel,
linux-arm-kernel, linux-kernel, linux-remoteproc, peng.fan,
s.hauer
In-Reply-To: <20260508032016.27716-1-Jiafei.Pan@nxp.com>
On Fri, May 08, 2026 at 11:20:16AM +0800, Jiafei Pan wrote:
> As currently there are maybe multiple remote processors, so change from
> using fixed name to using device node name as remote processor name in
> order to make them can be distinguished by through of name in sys
> filesystem.
>
> Signed-off-by: Jiafei Pan <Jiafei.Pan@nxp.com>
> ---
> Fixes sine v1:
> * Update patch subject to aligin prefix name with existing patches
>
> drivers/remoteproc/imx_rproc.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
Applied.
Thanks,
Mathieu
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index e8d239bef5c9..38713f6f1c50 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -1356,8 +1356,7 @@ static int imx_rproc_probe(struct platform_device *pdev)
> unsigned long cpus_bits;
> int ret;
>
> - /* set some other name then imx */
> - rproc = devm_rproc_alloc(dev, "imx-rproc", &imx_rproc_ops,
> + rproc = devm_rproc_alloc(dev, np->name, &imx_rproc_ops,
> NULL, sizeof(*priv));
> if (!rproc)
> return -ENOMEM;
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH 17/18] arm64: fpsimd: Move SME save/restore inline
From: Vladimir Murzin @ 2026-05-26 14:39 UTC (permalink / raw)
To: Mark Rutland, linux-arm-kernel, kvmarm
Cc: broonie, catalin.marinas, james.morse, maz, oupton, tabba, will
In-Reply-To: <ahWpST4K3rbMbjWK@J2N7QTR9R3>
Hi Mark,
On 5/26/26 15:08, Mark Rutland wrote:
> On Thu, May 21, 2026 at 02:25:55PM +0100, Mark Rutland wrote:
>> +static inline void __sme_save_za(struct sme_state *state, unsigned long svl)
>> +{
>> + /* The <Wv> argument to STR (array vector) can only encode W12-W15 */
>> + register unsigned long v asm ("12");
> Sorry, I had meant to put "x12" here, but evidently GCC and LLVM accept
> "12" on its own.
>
> For clarity (e.g. to match the comment) I'll change that to "w12" and
> make the type unsigned int. Likewise in __sme_load_za().
>
I suspect you are intentionally not using "Ucj" constrain to limit register allocator,
if so I'm wondering why?
Cheers
Vladimir
> Mark.
>
^ permalink raw reply
* [PATCH v2 0/6] iommu/arm-smmu: Add interconnect bandwidth voting support
From: Bibek Kumar Patro @ 2026-05-26 14:42 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro
On some Qualcomm SoCs the SMMU register space is gated behind an
interconnect fabric that requires an active bandwidth vote before
registers can be accessed. In the common case this vote is held
implicitly by other clients (e.g. the GMU device holds a GEM_NOC
vote whenever the GPU is active), so the SMMU works without any
explicit vote from the driver.
However, during certain power transitions — specifically sleep/wakeup
sequences — the interconnect vote can be dropped before the SMMU is
powered down. If the SMMU is then accessed (e.g. during runtime
resume) while the vote is absent, register reads fail intermittently.
The precise ordering makes this difficult to reproduce consistently.
This series adds support for an optional interconnect path in the
arm-smmu driver. When an 'interconnects' property is present in the
SMMU device node, the driver acquires the path and votes for bandwidth
before any register access, releasing the vote on runtime suspend and
on error paths. Platforms that do not describe an interconnect path
are unaffected.
Changes in v2:
- dt-bindings: Cleaned up 'interconnects' property description —
removed "Optional" prefix and driver implementation details as
flagged by Krzysztof Kozlowski.
- dt-bindings: Added allOf conditional using 'items' to restrict the
'interconnects' property to Adreno SMMU nodes only (qcom,adreno-smmu
with qcom,qcs615-smmu-500, qcom,qcs8300-smmu-500,
qcom,sa8775p-smmu-500 or qcom,sc7280-smmu-500 compatible), so
non-Adreno SMMU nodes on the same SoC cannot use this property.
- Added DTS patches for kodiak, lemans, monaco and talos to add
the GEM_NOC interconnect path for the adreno_smmu node on each
platform.
Link to v1:
https://lore.kernel.org/all/20260516-smmu_interconnect_addition-v1-0-f889d933f5c1@oss.qualcomm.com/
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
Bibek Kumar Patro (6):
dt-bindings: iommu: arm,smmu: Document interconnects property
iommu/arm-smmu: Add interconnect bandwidth voting support
arm64: dts: qcom: kodiak: Add GEM_NOC interconnect for adreno SMMU
arm64: dts: qcom: lemans: Add GEM_NOC interconnect for adreno SMMU
arm64: dts: qcom: monaco: Add GEM_NOC interconnect for adreno SMMU
arm64: dts: qcom: talos: Add GEM_NOC interconnect for adreno SMMU
.../devicetree/bindings/iommu/arm,smmu.yaml | 27 ++++++++++
arch/arm64/boot/dts/qcom/kodiak.dtsi | 2 +
arch/arm64/boot/dts/qcom/lemans.dtsi | 2 +
arch/arm64/boot/dts/qcom/monaco.dtsi | 2 +
arch/arm64/boot/dts/qcom/talos.dtsi | 2 +
drivers/iommu/arm/arm-smmu/arm-smmu.c | 57 +++++++++++++++++++++-
drivers/iommu/arm/arm-smmu/arm-smmu.h | 2 +
7 files changed, 92 insertions(+), 2 deletions(-)
---
base-commit: c1ecb239fa3456529a32255359fc78b69eb9d847
change-id: 20260516-smmu_interconnect_addition-d9567535e9d7
Best regards,
--
Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
^ permalink raw reply
* [PATCH v2 1/6] dt-bindings: iommu: arm,smmu: Document interconnects property
From: Bibek Kumar Patro @ 2026-05-26 14:42 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro
In-Reply-To: <20260526-smmu_interconnect_addition-v2-0-2a6d8ca30d63@oss.qualcomm.com>
Some SoC implementations require a bandwidth vote on an interconnect
path before the SMMU register space is accessible. Add the optional
'interconnects' property to the binding to allow platform DT nodes
to describe this path.
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
.../devicetree/bindings/iommu/arm,smmu.yaml | 27 ++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
index 06fb5c8e7547cb7a92823adc2772b94f747376a6..3a677ff1a18fcdf5c0ca9ec8a017d41f9eb5ff09 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
@@ -243,6 +243,13 @@ properties:
minItems: 1
maxItems: 3
+ interconnects:
+ maxItems: 1
+ description:
+ Interconnect path to the SMMU register space. Required on SoCs
+ where the SMMU registers are only accessible after a bandwidth
+ vote has been placed on the interconnect fabric.
+
nvidia,memory-controller:
description: |
A phandle to the memory controller on NVIDIA Tegra186 and later SoCs.
@@ -602,6 +609,26 @@ allOf:
clock-names: false
clocks: false
+ - if:
+ properties:
+ compatible:
+ items:
+ - enum:
+ - qcom,qcs615-smmu-500
+ - qcom,qcs8300-smmu-500
+ - qcom,sa8775p-smmu-500
+ - qcom,sc7280-smmu-500
+ - const: qcom,adreno-smmu
+ - const: qcom,smmu-500
+ - const: arm,mmu-500
+ then:
+ properties:
+ interconnects:
+ maxItems: 1
+ else:
+ properties:
+ interconnects: false
+
- if:
properties:
compatible:
--
2.34.1
^ permalink raw reply related
* [PATCH v2 2/6] iommu/arm-smmu: Add interconnect bandwidth voting support
From: Bibek Kumar Patro @ 2026-05-26 14:42 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro
In-Reply-To: <20260526-smmu_interconnect_addition-v2-0-2a6d8ca30d63@oss.qualcomm.com>
On some SoCs the SMMU registers require an active interconnect
bandwidth vote to be accessible. While other clients typically
satisfy this requirement implicitly, certain corner cases (e.g.
during sleep/wakeup transitions) can leave the SMMU without a
vote, causing intermittent register access failures.
Add support for an optional interconnect path to the arm-smmu
driver and vote for bandwidth while the SMMU is active. The path
is acquired from DT if present and ignored otherwise.
The bandwidth vote is enabled before accessing SMMU registers
during probe and runtime resume, and released during runtime
suspend and on error paths.
Generally, from an architectural perspective, GEM_NOC and DDR are
expected to have an active vote whenever the adreno_smmu block is
powered on. In most common use cases, this requirement is implicitly
satisfied because other GPU-related clients (for example, the GMU
device) already hold a GEM_NOC vote when adreno_smmu is enabled.
However, there are certain corner cases, such as during sleep/wakeup
transitions, where the GEM_NOC vote can be removed before adreno_smmu
is powered down. If adreno_smmu is then accessed while the interconnect
vote is missing, it can lead to the observed failures. Because of the
precise ordering involved, this scenario is difficult to reproduce
consistently.
(also GDSC is involved in adreno usecases can have an independent vote)
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
drivers/iommu/arm/arm-smmu/arm-smmu.c | 57 +++++++++++++++++++++++++++++++++--
drivers/iommu/arm/arm-smmu/arm-smmu.h | 2 ++
2 files changed, 57 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 0bd21d206eb3e75c3b9fb1364cdc92e82c5aa499..07c7e44ec6a5bd1488f00f87d859a20495e46601 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -53,6 +53,11 @@
#define MSI_IOVA_BASE 0x8000000
#define MSI_IOVA_LENGTH 0x100000
+/* Interconnect bandwidth vote values for the SMMU register access path */
+#define ARM_SMMU_ICC_AVG_BW 0
+#define ARM_SMMU_ICC_PEAK_BW_HIGH 1000
+#define ARM_SMMU_ICC_PEAK_BW_LOW 0
+
static int force_stage;
module_param(force_stage, int, S_IRUGO);
MODULE_PARM_DESC(force_stage,
@@ -86,6 +91,36 @@ static inline void arm_smmu_rpm_put(struct arm_smmu_device *smmu)
}
}
+static int arm_smmu_icc_get(struct arm_smmu_device *smmu)
+{
+ smmu->icc_path = devm_of_icc_get(smmu->dev, NULL);
+ if (IS_ERR(smmu->icc_path)) {
+ int err = PTR_ERR(smmu->icc_path);
+
+ if (err == -ENODEV) {
+ smmu->icc_path = NULL;
+ return 0;
+ }
+ return dev_err_probe(smmu->dev, err,
+ "failed to get interconnect path\n");
+ }
+ return 0;
+}
+
+static void arm_smmu_icc_enable(struct arm_smmu_device *smmu)
+{
+ if (smmu->icc_path)
+ WARN_ON(icc_set_bw(smmu->icc_path, ARM_SMMU_ICC_AVG_BW,
+ ARM_SMMU_ICC_PEAK_BW_HIGH));
+}
+
+static void arm_smmu_icc_disable(struct arm_smmu_device *smmu)
+{
+ if (smmu->icc_path)
+ WARN_ON(icc_set_bw(smmu->icc_path, ARM_SMMU_ICC_AVG_BW,
+ ARM_SMMU_ICC_PEAK_BW_LOW));
+}
+
static void arm_smmu_rpm_use_autosuspend(struct arm_smmu_device *smmu)
{
/*
@@ -2189,6 +2224,17 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
if (err)
return err;
+ /*
+ * Acquire and vote the interconnect path before accessing any SMMU
+ * registers (including ARM_SMMU_GR0_ID0 in arm_smmu_device_cfg_probe).
+ */
+ err = arm_smmu_icc_get(smmu);
+ if (err) {
+ clk_bulk_disable_unprepare(smmu->num_clks, smmu->clks);
+ return err;
+ }
+ arm_smmu_icc_enable(smmu);
+
err = arm_smmu_device_cfg_probe(smmu);
if (err)
return err;
@@ -2273,8 +2319,10 @@ static void arm_smmu_device_shutdown(struct platform_device *pdev)
if (pm_runtime_enabled(smmu->dev))
pm_runtime_force_suspend(smmu->dev);
- else
+ else {
clk_bulk_disable(smmu->num_clks, smmu->clks);
+ arm_smmu_icc_disable(smmu);
+ }
clk_bulk_unprepare(smmu->num_clks, smmu->clks);
}
@@ -2294,9 +2342,13 @@ static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
struct arm_smmu_device *smmu = dev_get_drvdata(dev);
int ret;
+ arm_smmu_icc_enable(smmu);
+
ret = clk_bulk_enable(smmu->num_clks, smmu->clks);
- if (ret)
+ if (ret) {
+ arm_smmu_icc_disable(smmu);
return ret;
+ }
arm_smmu_device_reset(smmu);
@@ -2308,6 +2360,7 @@ static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
struct arm_smmu_device *smmu = dev_get_drvdata(dev);
clk_bulk_disable(smmu->num_clks, smmu->clks);
+ arm_smmu_icc_disable(smmu);
return 0;
}
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h b/drivers/iommu/arm/arm-smmu/arm-smmu.h
index 26d2e33cd328b8278888585fc07a31485d9397e2..c00606a416b2f4bb44a35e5d67f6ef801df68e1c 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h
@@ -15,6 +15,7 @@
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/device.h>
+#include <linux/interconnect.h>
#include <linux/io-64-nonatomic-hi-lo.h>
#include <linux/io-pgtable.h>
#include <linux/iommu.h>
@@ -335,6 +336,7 @@ struct arm_smmu_device {
int num_clks;
unsigned int *irqs;
struct clk_bulk_data *clks;
+ struct icc_path *icc_path;
spinlock_t global_sync_lock;
--
2.34.1
^ permalink raw reply related
* [PATCH v2 3/6] arm64: dts: qcom: kodiak: Add GEM_NOC interconnect for adreno SMMU
From: Bibek Kumar Patro @ 2026-05-26 14:42 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro
In-Reply-To: <20260526-smmu_interconnect_addition-v2-0-2a6d8ca30d63@oss.qualcomm.com>
On Kodiak platforms, the Adreno SMMU requires a bandwidth vote on
the GEM_NOC path (MASTER_GPU_TCU -> SLAVE_EBI1) before its registers
are accessible. Without this vote, the SMMU may become unreachable,
leading to intermittent probe failures and runtime issues.
Add the required interconnect to ensure reliable register access.
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/kodiak.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
index fa540d8c2615dc02d941eb16bc7253204c2750bd..eefa4b836a81374ff437ab4bbcbc3fecc1590ab6 100644
--- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
+++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
@@ -3386,6 +3386,8 @@ adreno_smmu: iommu@3da0000 {
power-domains = <&gpucc GPU_CC_CX_GDSC>;
dma-coherent;
+ interconnects = <&gem_noc MASTER_GPU_TCU QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
};
gfx_0_tbu: tbu@3dd9000 {
--
2.34.1
^ permalink raw reply related
* [PATCH v2 4/6] arm64: dts: qcom: lemans: Add GEM_NOC interconnect for adreno SMMU
From: Bibek Kumar Patro @ 2026-05-26 14:42 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro
In-Reply-To: <20260526-smmu_interconnect_addition-v2-0-2a6d8ca30d63@oss.qualcomm.com>
On Lemans platforms, the Adreno SMMU requires a bandwidth vote on
the GEM_NOC path (MASTER_GPU_TCU -> SLAVE_EBI1) before its registers
are accessible. Without this vote, the SMMU may become unreachable,
leading to intermittent probe failures and runtime issues.
Add the required interconnect to ensure reliable register access.
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/lemans.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index 522ba43836a2425a8612506f5f7113f291f34706..ac9f529d2719105609d997874a6319c7d04e1655 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -4796,6 +4796,8 @@ adreno_smmu: iommu@3da0000 {
<GIC_SPI 685 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 686 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 687 IRQ_TYPE_LEVEL_HIGH>;
+ interconnects = <&gem_noc MASTER_GPU_TCU QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
};
serdes0: phy@8901000 {
--
2.34.1
^ permalink raw reply related
* [PATCH v2 5/6] arm64: dts: qcom: monaco: Add GEM_NOC interconnect for adreno SMMU
From: Bibek Kumar Patro @ 2026-05-26 14:42 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro
In-Reply-To: <20260526-smmu_interconnect_addition-v2-0-2a6d8ca30d63@oss.qualcomm.com>
On Monaco platforms, the Adreno SMMU requires a bandwidth vote on
the GEM_NOC path (MASTER_GPU_TCU -> SLAVE_EBI1) before its registers
are accessible. Without this vote, the SMMU may become unreachable,
leading to intermittent probe failures and runtime issues.
Add the required interconnect to ensure reliable register access.
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/monaco.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 2660c161c3d74f4002aebff40634509e885fb3b3..00183ed67ebf0645e1da0c4674248354fa2af941 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -5088,6 +5088,8 @@ adreno_smmu: iommu@3da0000 {
"gpu_cc_hub_aon_clk";
power-domains = <&gpucc GPU_CC_CX_GDSC>;
dma-coherent;
+ interconnects = <&gem_noc MASTER_GPU_TCU QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
};
pmu@9091000 {
--
2.34.1
^ 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