Skip to content

Commit d87d457

Browse files
committed
dmaengine: dw-axi-dmac: Add DMA channel selection
Add a mechanism to allow clients to prefer some DMA channels over others. This is required to allow high-bandwidth clients to request one of the two "heavy" channels, but could also be used to prevent some clients from hogging all channels. Signed-off-by: Phil Elwell <[email protected]>
1 parent 29b478e commit d87d457

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,19 +1476,46 @@ static int __maybe_unused axi_dma_runtime_resume(struct device *dev)
14761476
return axi_dma_resume(chip);
14771477
}
14781478

1479+
static bool dw_axi_dma_filter_fn(struct dma_chan *dchan, void *filter_param)
1480+
{
1481+
struct axi_dma_chan *chan = dchan_to_axi_dma_chan(dchan);
1482+
uint32_t selector = *(const uint32_t *)filter_param;
1483+
1484+
return !!(selector & (1 << chan->id));
1485+
}
1486+
14791487
static struct dma_chan *dw_axi_dma_of_xlate(struct of_phandle_args *dma_spec,
14801488
struct of_dma *ofdma)
14811489
{
14821490
struct dw_axi_dma *dw = ofdma->of_dma_data;
14831491
struct axi_dma_chan *chan;
14841492
struct dma_chan *dchan;
1493+
uint32_t chan_mask = 0;
1494+
uint32_t chan_sel;
1495+
dma_cap_mask_t mask;
1496+
int i;
1497+
1498+
/*
1499+
* Walk through all channels looking for the best match.
1500+
* Starting from 0, choose the first available slave channel which isn't precluded.
1501+
*/
1502+
chan_sel = dma_spec->args[0];
14851503

1486-
dchan = dma_get_any_slave_channel(&dw->dma);
1504+
for (i = 0; i < dw->hdata->nr_channels; i++) {
1505+
if (((dw->sel_precluded[i] & chan_sel) == 0) &&
1506+
((dw->sel_required[i] & chan_sel) == dw->sel_required[i]))
1507+
chan_mask |= (1 << i);
1508+
}
1509+
1510+
dma_cap_zero(mask);
1511+
dma_cap_set(DMA_SLAVE, mask);
1512+
1513+
dchan = __dma_request_channel(&mask, dw_axi_dma_filter_fn, &chan_mask, ofdma->of_node);
14871514
if (!dchan)
14881515
return NULL;
14891516

14901517
chan = dchan_to_axi_dma_chan(dchan);
1491-
chan->hw_handshake_num = dma_spec->args[0];
1518+
chan->hw_handshake_num = (u8)chan_sel;
14921519
return dchan;
14931520
}
14941521

@@ -1570,6 +1597,18 @@ static int parse_device_properties(struct axi_dma_chip *chip)
15701597
}
15711598
}
15721599

1600+
/* sel-require is optional */
1601+
memset(chip->dw->sel_required, 0, sizeof(chip->dw->sel_required));
1602+
device_property_read_u32_array(dev, "snps,sel-require",
1603+
chip->dw->sel_required,
1604+
chip->dw->hdata->nr_channels);
1605+
1606+
/* sel-preclude is optional */
1607+
memset(chip->dw->sel_precluded, 0, sizeof(chip->dw->sel_precluded));
1608+
device_property_read_u32_array(dev, "snps,sel-preclude",
1609+
chip->dw->sel_precluded,
1610+
chip->dw->hdata->nr_channels);
1611+
15731612
return 0;
15741613
}
15751614

drivers/dma/dw-axi-dmac/dw-axi-dmac.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ struct dw_axi_dma {
5858
struct dma_device dma;
5959
struct dw_axi_dma_hcfg *hdata;
6060
struct device_dma_parameters dma_parms;
61+
u32 sel_required[DMAC_MAX_CHANNELS];
62+
u32 sel_precluded[DMAC_MAX_CHANNELS];
6163

6264
/* channels */
6365
struct axi_dma_chan *chan;

0 commit comments

Comments
 (0)