diff options
| author | Zeng Chi <zengchi@kylinos.cn> | 2026-09-21 18:24:42 +0800 |
|---|---|---|
| committer | Sean Christopherson <seanjc@google.com> | 2026-09-22 08:36:16 -0700 |
| commit | 119e9db233ad0f4cbd4cfb9f9385a7bca378b37d (patch) | |
| tree | 660d50d4139cb750fbde1ae3432452c20726c99d /drivers/dma/bestcomm/fec.c | |
| download | linux-stable-119e9db233ad0f4cbd4cfb9f9385a7bca378b37d.tar.gz linux-stable-119e9db233ad0f4cbd4cfb9f9385a7bca378b37d.zip | |
KVM: Don't pre-reserve xarray entries when storing empty/NULL attributesgrafted
Skip the xarray reservation loop when clearing all memory attributes, as
storing NULL only erases the entry and never needs to allocate, so no
reservation (and no cleanup of a failed one) is required in that case.
Suggested-by: Sean Christopherson <seanjc@google.com>
Cc: David Ballesteros <davimaba.v@proton.me>
Signed-off-by: Zeng Chi <zengchi@kylinos.cn>
Link: https://patch.msgid.link/20260921102442.1232375-1-zeng_chi911@163.com
[sean: split to separate patch]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Diffstat (limited to 'drivers/dma/bestcomm/fec.c')
| -rw-r--r-- | drivers/dma/bestcomm/fec.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/drivers/dma/bestcomm/fec.c b/drivers/dma/bestcomm/fec.c new file mode 100644 index 000000000..3a4a2f791 --- /dev/null +++ b/drivers/dma/bestcomm/fec.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Bestcomm FEC tasks driver + * + * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2003-2004 MontaVista, Software, Inc. + * ( by Dale Farnsworth <dfarnsworth@mvista.com> ) + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <asm/io.h> + +#include <linux/fsl/bestcomm/bestcomm.h> +#include <linux/fsl/bestcomm/bestcomm_priv.h> +#include <linux/fsl/bestcomm/fec.h> + + +/* ======================================================================== */ +/* Task image/var/inc */ +/* ======================================================================== */ + +/* fec tasks images */ +extern u32 bcom_fec_rx_task[]; +extern u32 bcom_fec_tx_task[]; + +/* rx task vars that need to be set before enabling the task */ +struct bcom_fec_rx_var { + u32 enable; /* (u16*) address of task's control register */ + u32 fifo; /* (u32*) address of fec's fifo */ + u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */ + u32 bd_last; /* (struct bcom_bd*) end of ring buffer */ + u32 bd_start; /* (struct bcom_bd*) current bd */ + u32 buffer_size; /* size of receive buffer */ +}; + +/* rx task incs that need to be set before enabling the task */ +struct bcom_fec_rx_inc { + u16 pad0; + s16 incr_bytes; + u16 pad1; + s16 incr_dst; + u16 pad2; + s16 incr_dst_ma; +}; + +/* tx task vars that need to be set before enabling the task */ +struct bcom_fec_tx_var { + u32 DRD; /* (u32*) address of self-modified DRD */ + u32 fifo; /* (u32*) address of fec's fifo */ + u32 enable; /* (u16*) address of task's control register */ + u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */ + u32 bd_last; /* (struct bcom_bd*) end of ring buffer */ + u32 bd_start; /* (struct bcom_bd*) current bd */ + u32 buffer_size; /* set by uCode for each packet */ +}; + +/* tx task incs that need to be set before enabling the task */ +struct bcom_fec_tx_inc { + u16 pad0; + s16 incr_bytes; + u16 pad1; + s16 incr_src; + u16 pad2; + s16 incr_src_ma; +}; + +/* private structure in the task */ +struct bcom_fec_priv { + phys_addr_t fifo; + int maxbufsize; +}; + + +/* ======================================================================== */ +/* Task support code */ +/* ======================================================================== */ + +struct bcom_task * +bcom_fec_rx_init(int queue_len, phys_addr_t fifo, int maxbufsize) +{ + struct bcom_task *tsk; + struct bcom_fec_priv *priv; + + tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd), + sizeof(struct bcom_fec_priv)); + if (!tsk) + return NULL; + + tsk->flags = BCOM_FLAGS_NONE; + + priv = tsk->priv; + priv->fifo = fifo; + priv->maxbufsize = maxbufsize; + + if (bcom_fec_rx_reset(tsk)) { + bcom_task_free(tsk); + return NULL; + } + + return tsk; +} +EXPORT_SYMBOL_GPL(bcom_fec_rx_init); + +int +bcom_fec_rx_reset(struct bcom_task *tsk) +{ + struct bcom_fec_priv *priv = tsk->priv; + struct bcom_fec_rx_var *var; + struct bcom_fec_rx_inc *inc; + + /* Shutdown the task */ + bcom_disable_task(tsk->tasknum); + + /* Reset the microcode */ + var = (struct bcom_fec_rx_var *) bcom_task_var(tsk->tasknum); + inc = (struct bcom_fec_rx_inc *) bcom_task_inc(tsk->tasknum); + + if (bcom_load_image(tsk->tasknum, bcom_fec_rx_task)) + return -1; + + var->enable = bcom_eng->regs_base + + offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]); + var->fifo = (u32) priv->fifo; + var->bd_base = tsk->bd_pa; + var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size); + var->bd_start = tsk->bd_pa; + var->buffer_size = priv->maxbufsize; + + inc->incr_bytes = -(s16)sizeof(u32); /* These should be in the */ + inc->incr_dst = sizeof(u32); /* task image, but we stick */ + inc->incr_dst_ma= sizeof(u8); /* to the official ones */ + + /* Reset the BDs */ + tsk->index = 0; + tsk->outdex = 0; + + memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size); + + /* Configure some stuff */ + bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_RX_BD_PRAGMA); + bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum); + + out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_RX], BCOM_IPR_FEC_RX); + + out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */ + + return 0; +} +EXPORT_SYMBOL_GPL(bcom_fec_rx_reset); + +void +bcom_fec_rx_release(struct bcom_task *tsk) +{ + /* Nothing special for the FEC tasks */ + bcom_task_free(tsk); +} +EXPORT_SYMBOL_GPL(bcom_fec_rx_release); + + + + /* Return 2nd to last DRD */ + /* This is an ugly hack, but at least it's only done + once at initialization */ +static u32 *self_modified_drd(int tasknum) +{ + u32 *desc; + int num_descs; + int drd_count; + int i; + + num_descs = bcom_task_num_descs(tasknum); + desc = bcom_task_desc(tasknum) + num_descs - 1; + drd_count = 0; + for (i=0; i<num_descs; i++, desc--) + if (bcom_desc_is_drd(*desc) && ++drd_count == 3) + break; + return desc; +} + +struct bcom_task * +bcom_fec_tx_init(int queue_len, phys_addr_t fifo) +{ + struct bcom_task *tsk; + struct bcom_fec_priv *priv; + + tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd), + sizeof(struct bcom_fec_priv)); + if (!tsk) + return NULL; + + tsk->flags = BCOM_FLAGS_ENABLE_TASK; + + priv = tsk->priv; + priv->fifo = fifo; + + if (bcom_fec_tx_reset(tsk)) { + bcom_task_free(tsk); + return NULL; + } + + return tsk; +} +EXPORT_SYMBOL_GPL(bcom_fec_tx_init); + +int +bcom_fec_tx_reset(struct bcom_task *tsk) +{ + struct bcom_fec_priv *priv = tsk->priv; + struct bcom_fec_tx_var *var; + struct bcom_fec_tx_inc *inc; + + /* Shutdown the task */ + bcom_disable_task(tsk->tasknum); + + /* Reset the microcode */ + var = (struct bcom_fec_tx_var *) bcom_task_var(tsk->tasknum); + inc = (struct bcom_fec_tx_inc *) bcom_task_inc(tsk->tasknum); + + if (bcom_load_image(tsk->tasknum, bcom_fec_tx_task)) + return -1; + + var->enable = bcom_eng->regs_base + + offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]); + var->fifo = (u32) priv->fifo; + var->DRD = bcom_sram_va2pa(self_modified_drd(tsk->tasknum)); + var->bd_base = tsk->bd_pa; + var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size); + var->bd_start = tsk->bd_pa; + + inc->incr_bytes = -(s16)sizeof(u32); /* These should be in the */ + inc->incr_src = sizeof(u32); /* task image, but we stick */ + inc->incr_src_ma= sizeof(u8); /* to the official ones */ + + /* Reset the BDs */ + tsk->index = 0; + tsk->outdex = 0; + + memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size); + + /* Configure some stuff */ + bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_TX_BD_PRAGMA); + bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum); + + out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_TX], BCOM_IPR_FEC_TX); + + out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */ + + return 0; +} +EXPORT_SYMBOL_GPL(bcom_fec_tx_reset); + +void +bcom_fec_tx_release(struct bcom_task *tsk) +{ + /* Nothing special for the FEC tasks */ + bcom_task_free(tsk); +} +EXPORT_SYMBOL_GPL(bcom_fec_tx_release); + + +MODULE_DESCRIPTION("BestComm FEC tasks driver"); +MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>"); +MODULE_LICENSE("GPL v2"); |
