Re: [PATCH v7] net: airoha: npu: use aligned streaming DMA for mailbox messages

Lorenzo Bianconi <[email protected]>
Newsgroups org.infradead.lists.linux-mediatek,org.infradead.lists.linux-arm-kernel,org.kernel.vger.netdev
Message-ID <aoJqU7G9xIoAQfXA@lore-qca>
> On EN7581 + MT7996 (Gemtek W1700K), mapping small caller buffers with
> DMA_BIDIRECTIONAL regresses NPU version probe: the mailbox completes
> successfully but WLAN_FUNC_GET_WAIT_NPU_VERSION reads as 0.0 instead of
> 0.1111.

IIUC you are suggesting the issue is if we allocate a small buffer it could fit
in the same cacheline of a neighbour object so if the DMA reads/writes the same
cacheline, it could invalidate data, right? (I am not sure if this device is
DMA-coherent or not).
If so, in the airoha_npu_send_msg() callers, I guess it is enough to allocate
something like:

	kzalloc(max(len, SMP_CACHE_BYTES))

and avoid the extra copy in __airoha_npu_send_msg(). What do you think?
IIRC kzalloc() aligns to SMP_CACHE_BYTES is len >= SMP_CACHE_BYTES.

Regards,
Lorenzo

> 
> Bounce mailbox traffic through a per-core cacheline-aligned buffer
> allocated at probe. Map ALIGN(len, SMP_CACHE_BYTES) with
> DMA_BIDIRECTIONAL while programming the original payload length into the
> mailbox length register. Copy the reply only after dma_unmap_single() so
> the CPU sees the NPU-written payload on non-coherent DMA.
> 
> Introduce __airoha_npu_send_msg() with an optional reply pointer so GET
> callers can copy the trailing response payload once. Keep
> airoha_npu_send_msg() as a wrapper that copies the full response back
> into the caller buffer, matching the old bidirectional mapping.
> 
> Tested on Quantum Fiber / Gemtek W1700K (EN7581 + MT7996), kernel
> 6.18.44, including two cold reboots and sustained WiFi use.
> 
> Fixes: 6f884eb87a79 ("net: airoha: Fix DMA direction for NPU mailbox buffer")
> Link: https://patchwork.kernel.org/project/linux-mediatek/patch/[email protected]/
> Assisted-by: Cursor:composer-2
> Signed-off-by: Daniel Pawlik <[email protected]>
> ---
>  drivers/net/ethernet/airoha/airoha_npu.c  | 62 ++++++++++++++++++-----
>  include/linux/soc/airoha/airoha_offload.h |  1 +
>  2 files changed, 49 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c
> index b679bed952de..2ba78bf0e97b 100644
> --- a/drivers/net/ethernet/airoha/airoha_npu.c
> +++ b/drivers/net/ethernet/airoha/airoha_npu.c
> @@ -5,6 +5,7 @@
>   */
>  
>  #include <linux/devcoredump.h>
> +#include <linux/dma-mapping.h>
>  #include <linux/firmware.h>
>  #include <linux/platform_device.h>
>  #include <linux/of_net.h>
> @@ -23,6 +24,8 @@
>  #define NPU_EN7581_FIRMWARE_RV32_MAX_SIZE	0x200000
>  #define NPU_EN7581_FIRMWARE_DATA_MAX_SIZE	0x10000
>  #define NPU_DUMP_SIZE				512
> +/* Maximum mailbox DMA payload (PPE ~28 bytes, WLAN TLV up to 24). */
> +#define AIROHA_NPU_MBOX_SIZE			256
>  
>  #define REG_NPU_LOCAL_SRAM		0x0
>  
> @@ -160,23 +163,33 @@ struct wlan_mbox_data {
>  	DECLARE_FLEX_ARRAY(u8, d);
>  };
>  
> -static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id,
> -			       void *p, int size)
> +static int __airoha_npu_send_msg(struct airoha_npu *npu, int func_id,
> +				 const void *data, int len, void *reply,
> +				 u16 reply_len)
>  {
> -	u16 core = 0; /* FIXME */
> -	u32 val, offset = core << 4;
> +	struct airoha_npu_core *core = &npu->cores[0]; /* FIXME: core */
>  	dma_addr_t dma_addr;
> +	unsigned int map_len = ALIGN(len, SMP_CACHE_BYTES);
> +	u32 val, offset = 0;
>  	int ret;
>  
> -	dma_addr = dma_map_single(npu->dev, p, size, DMA_BIDIRECTIONAL);
> +	if (len <= 0 || len > AIROHA_NPU_MBOX_SIZE)
> +		return -EINVAL;
> +
> +	if (reply && reply_len > len)
> +		return -EINVAL;
> +
> +	spin_lock_bh(&core->lock);
> +
> +	memcpy(core->buf, data, len);
> +
> +	dma_addr = dma_map_single(npu->dev, core->buf, map_len, DMA_BIDIRECTIONAL);
>  	ret = dma_mapping_error(npu->dev, dma_addr);
>  	if (ret)
> -		return ret;
> -
> -	spin_lock_bh(&npu->cores[core].lock);
> +		goto unlock;
>  
>  	regmap_write(npu->regmap, REG_CR_MBQ0_CTRL(0) + offset, dma_addr);
> -	regmap_write(npu->regmap, REG_CR_MBQ0_CTRL(1) + offset, size);
> +	regmap_write(npu->regmap, REG_CR_MBQ0_CTRL(1) + offset, len);
>  	regmap_read(npu->regmap, REG_CR_MBQ0_CTRL(2) + offset, &val);
>  	regmap_write(npu->regmap, REG_CR_MBQ0_CTRL(2) + offset, val + 1);
>  	val = FIELD_PREP(MBOX_MSG_FUNC_ID, func_id) | MBOX_MSG_WAIT_RSP;
> @@ -189,13 +202,23 @@ static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id,
>  	if (!ret && FIELD_GET(MBOX_MSG_STATUS, val) != NPU_MBOX_SUCCESS)
>  		ret = -EINVAL;
>  
> -	spin_unlock_bh(&npu->cores[core].lock);
> +	dma_unmap_single(npu->dev, dma_addr, map_len, DMA_BIDIRECTIONAL);
>  
> -	dma_unmap_single(npu->dev, dma_addr, size, DMA_BIDIRECTIONAL);
> +	/* Copy the trailing reply_len bytes of the response. */
> +	if (!ret && reply)
> +		memcpy(reply, core->buf + len - reply_len, reply_len);
> +unlock:
> +	spin_unlock_bh(&core->lock);
>  
>  	return ret;
>  }
>  
> +static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id,
> +			       void *data, int len)
> +{
> +	return __airoha_npu_send_msg(npu, func_id, data, len, data, len);
> +}
> +
>  static int airoha_npu_load_firmware(struct device *dev, void __iomem *addr,
>  				    const char *fw_name, int fw_max_size)
>  {
> @@ -497,9 +520,8 @@ static int airoha_npu_wlan_msg_get(struct airoha_npu *npu, int ifindex,
>  	wlan_data->func_type = NPU_OP_GET;
>  	wlan_data->func_id = func_id;
>  
> -	err = airoha_npu_send_msg(npu, NPU_FUNC_WIFI, wlan_data, len);
> -	if (!err)
> -		memcpy(data, wlan_data->d, data_len);
> +	err = __airoha_npu_send_msg(npu, NPU_FUNC_WIFI, wlan_data, len,
> +				    data, data_len);
>  	kfree(wlan_data);
>  
>  	return err;
> @@ -770,6 +792,18 @@ static int airoha_npu_probe(struct platform_device *pdev)
>  	if (err)
>  		return err;
>  
> +	for (i = 0; i < ARRAY_SIZE(npu->cores); i++) {
> +		struct airoha_npu_core *core = &npu->cores[i];
> +		void *raw;
> +
> +		raw = devm_kmalloc(dev, AIROHA_NPU_MBOX_SIZE + SMP_CACHE_BYTES,
> +				   GFP_KERNEL);
> +		if (!raw)
> +			return -ENOMEM;
> +
> +		core->buf = PTR_ALIGN(raw, SMP_CACHE_BYTES);
> +	}
> +
>  	err = airoha_npu_run_firmware(dev, base, &res);
>  	if (err)
>  		return dev_err_probe(dev, err, "failed to run npu firmware\n");
> diff --git a/include/linux/soc/airoha/airoha_offload.h b/include/linux/soc/airoha/airoha_offload.h
> index 7589fccfeef6..f635766e3dba 100644
> --- a/include/linux/soc/airoha/airoha_offload.h
> +++ b/include/linux/soc/airoha/airoha_offload.h
> @@ -173,6 +173,7 @@ struct airoha_npu {
>  		/* protect concurrent npu memory accesses */
>  		spinlock_t lock;
>  		struct work_struct wdt_work;
> +		void *buf; /* mailbox DMA bounce buffer */
>  	} cores[NPU_NUM_CORES];
>  
>  	int irqs[NPU_NUM_IRQ];
> -- 
> 2.55.0
>
signature.asc (application/pgp-signature, 228 B)
-----BEGIN PGP SIGNATURE-----

iHUEABYKAB0WIQTquNwa3Txd3rGGn7Y6cBh0uS2trAUCaoJqUwAKCRA6cBh0uS2t
rJKHAQCxbJO+swWF67vpy0YipmSukJEskcpf4E5FlW4+fsqZ7AEAkI8UQNvU/9WD
52cI/EuNY2zC2edZWZkbH7TmFi/ZFgs=
=SfV1
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.