diff options
| author | Koichiro Den <den@valinux.co.jp> | 2026-07-21 15:28:15 +0900 |
|---|---|---|
| committer | Vinod Koul <vkoul@kernel.org> | 2026-07-21 16:00:36 +0530 |
| commit | 0613e7934ee233d726af8d8c89f251a1c4df738d (patch) | |
| tree | 898c9cfd79eaafa4506bcf2ff366d1848199f281 /drivers | |
| parent | 1d68178b3404737af2cee6c7b4395de3de6dccaa (diff) | |
| download | linux-next-0613e7934ee233d726af8d8c89f251a1c4df738d.tar.gz linux-next-0613e7934ee233d726af8d8c89f251a1c4df738d.zip | |
dmaengine: dw-edma: Program endpoint function numbers
The eDMA/HDMA transfers the driver issues carry a requester function
number in their TLPs, but nothing ever programs it: eDMA v0 leaves the
FUNC_NUM field of the channel control word zero and HDMA leaves the
per-channel func_num register at its reset value, so every transfer is
attributed to function 0. That is invisible in single-function setups,
but once the DMA block serves a non-zero endpoint function, its
requests must carry that function's number for the host to attribute
and translate them correctly.
Record the function number in the chip data (PCI_FUNC() of the probing
device for dw-edma-pcie) and program it per channel.
Endpoint-local chip instances keep func_no at 0, so transfers issued by
the endpoint-side driver remain PF0-attributed. Delegated channels are
programmed by the host-side dw-edma-pcie instance when it takes over the
channel, using that instance's PCI_FUNC().
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
Link: https://patch.msgid.link/20260721062815.4117887-15-den@valinux.co.jp
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/dma/dw-edma/dw-edma-core.c | 1 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-edma-core.h | 1 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-edma-pcie.c | 1 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-edma-v0-core.c | 10 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-hdma-v0-core.c | 3 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 |
6 files changed, 16 insertions, 1 deletions
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c index c9df5bbe2392..1f893dc54c79 100644 --- a/drivers/dma/dw-edma/dw-edma-core.c +++ b/drivers/dma/dw-edma/dw-edma-core.c @@ -931,6 +931,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc) chan = &dw->chan[i]; chan->dw = dw; + chan->func_no = chip->func_no; if (i < dw->wr_ch_cnt) { chan->id = i; diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h index bd3d532ebc89..f6a5ad317567 100644 --- a/drivers/dma/dw-edma/dw-edma-core.h +++ b/drivers/dma/dw-edma/dw-edma-core.h @@ -70,6 +70,7 @@ struct dw_edma_chan { struct dw_edma *dw; int id; enum dw_edma_dir dir; + u8 func_no; u32 ll_max; struct dw_edma_region ll_region; /* Linked list */ diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c index 64f2a80072bc..9f237ba916de 100644 --- a/drivers/dma/dw-edma/dw-edma-pcie.c +++ b/drivers/dma/dw-edma/dw-edma-pcie.c @@ -473,6 +473,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev, chip->mf = dma_data->mf; chip->flags = match->chip_flags; + chip->func_no = PCI_FUNC(pdev->devfn); chip->nr_irqs = nr_irqs; chip->ops = match->plat_ops; chip->cfg_non_ll = dma_data->cfg_non_ll; diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c index 13e69ce6c41d..abc1bd4c0be2 100644 --- a/drivers/dma/dw-edma/dw-edma-v0-core.c +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c @@ -26,6 +26,8 @@ enum dw_edma_control { DW_EDMA_V0_LLE = BIT(9), }; +#define EDMA_V0_FUNC_NUM_MASK GENMASK(16, 12) + static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw) { return dw->chip->reg_base; @@ -160,6 +162,11 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch, #define GET_CH_32(dw, dir, ch, name) \ readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name)) +static u32 dw_edma_v0_func_num(struct dw_edma_chan *chan) +{ + return FIELD_PREP(EDMA_V0_FUNC_NUM_MASK, chan->func_no); +} + /* eDMA management callbacks */ static void dw_edma_v0_core_ch_power(struct dw_edma *dw, enum dw_edma_dir dir, u16 id, bool enable) @@ -463,7 +470,8 @@ static void dw_edma_v0_core_ch_enable(struct dw_edma_chan *chan) /* Channel control */ SET_CH_32(dw, chan->dir, chan->id, ch_control1, - (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE)); + DW_EDMA_V0_CCS | DW_EDMA_V0_LLE | + dw_edma_v0_func_num(chan)); /* Linked list */ /* llp is not aligned on 64bit -> keep 32bit accesses */ SET_CH_32(dw, chan->dir, chan->id, llp.lsb, diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c index 8d20bb028b52..36ee72efcd31 100644 --- a/drivers/dma/dw-edma/dw-hdma-v0-core.c +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c @@ -345,6 +345,9 @@ static void dw_hdma_v0_core_ch_config(struct dw_edma_chan *chan) SET_CH_32(dw, chan->dir, chan->id, msi_abort.msb, chan->msi.address_hi); /* config MSI data */ SET_CH_32(dw, chan->dir, chan->id, msi_msgdata, chan->msi.data); + /* Configure the requester function number used by outbound TLPs. */ + SET_CH_32(dw, chan->dir, chan->id, func_num, + FIELD_PREP(HDMA_V0_FUNC_NUM_PF_MASK, chan->func_no)); } static void diff --git a/drivers/dma/dw-edma/dw-hdma-v0-regs.h b/drivers/dma/dw-edma/dw-hdma-v0-regs.h index 48e40efceb2e..2124c162a62f 100644 --- a/drivers/dma/dw-edma/dw-hdma-v0-regs.h +++ b/drivers/dma/dw-edma/dw-hdma-v0-regs.h @@ -24,6 +24,7 @@ #define HDMA_V0_CONSUMER_CYCLE_BIT BIT(0) #define HDMA_V0_DOORBELL_START BIT(0) #define HDMA_V0_CH_STATUS_MASK GENMASK(1, 0) +#define HDMA_V0_FUNC_NUM_PF_MASK GENMASK(7, 0) struct dw_hdma_v0_ch_regs { u32 ch_en; /* 0x0000 */ |
