Skip to content

Commit

Permalink
Merge tag 'dmaengine-fix-5.10-rc5' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/kernel/git/vkoul/dmaengine

Pull dmaengine fixes from Vinod Koul:
 "A solitary core fix and a few driver fixes:

  Core:

   - channel_register error handling

  Driver fixes:

   - idxd: wq config registers programming and mapping of portal size

   - ioatdma: unused fn removal

   - pl330: fix burst size

   - ti: pm fix on busy and -Wenum-conversion warns

   - xilinx: SG capability check, usage of xilinx_aximcdma_tx_segment,
     readl_poll_timeout_atomic variant"

* tag 'dmaengine-fix-5.10-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine:
  dmaengine: fix error codes in channel_register()
  dmaengine: pl330: _prep_dma_memcpy: Fix wrong burst size
  dmaengine: ioatdma: remove unused function missed during dma_v2 removal
  dmaengine: idxd: fix mapping of portal size
  dmaengine: ti: omap-dma: Block PM if SDMA is busy to fix audio
  dmaengine: xilinx_dma: Fix SG capability check for MCDMA
  dmaengine: xilinx_dma: Fix usage of xilinx_aximcdma_tx_segment
  dmaengine: xilinx_dma: use readl_poll_timeout_atomic variant
  dmaengine: ti: k3-udma: fix -Wenum-conversion warning
  dmaengine: idxd: fix wq config registers offset programming
  • Loading branch information
Linus Torvalds committed Nov 20, 2020
2 parents fc8299f + 7e4be12 commit bd4d74e
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 63 deletions.
17 changes: 9 additions & 8 deletions drivers/dma/dmaengine.c
Original file line number Diff line number Diff line change
Expand Up @@ -1039,16 +1039,15 @@ static int get_dma_id(struct dma_device *device)
static int __dma_async_device_channel_register(struct dma_device *device,
struct dma_chan *chan)
{
int rc = 0;
int rc;

chan->local = alloc_percpu(typeof(*chan->local));
if (!chan->local)
goto err_out;
return -ENOMEM;
chan->dev = kzalloc(sizeof(*chan->dev), GFP_KERNEL);
if (!chan->dev) {
free_percpu(chan->local);
chan->local = NULL;
goto err_out;
rc = -ENOMEM;
goto err_free_local;
}

/*
Expand All @@ -1061,7 +1060,8 @@ static int __dma_async_device_channel_register(struct dma_device *device,
if (chan->chan_id < 0) {
pr_err("%s: unable to alloc ida for chan: %d\n",
__func__, chan->chan_id);
goto err_out;
rc = chan->chan_id;
goto err_free_dev;
}

chan->dev->device.class = &dma_devclass;
Expand All @@ -1082,9 +1082,10 @@ static int __dma_async_device_channel_register(struct dma_device *device,
mutex_lock(&device->chan_mutex);
ida_free(&device->chan_ida, chan->chan_id);
mutex_unlock(&device->chan_mutex);
err_out:
free_percpu(chan->local);
err_free_dev:
kfree(chan->dev);
err_free_local:
free_percpu(chan->local);
return rc;
}

Expand Down
31 changes: 15 additions & 16 deletions drivers/dma/idxd/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ int idxd_wq_map_portal(struct idxd_wq *wq)
resource_size_t start;

start = pci_resource_start(pdev, IDXD_WQ_BAR);
start = start + wq->id * IDXD_PORTAL_SIZE;
start += idxd_get_wq_portal_full_offset(wq->id, IDXD_PORTAL_LIMITED);

wq->dportal = devm_ioremap(dev, start, IDXD_PORTAL_SIZE);
if (!wq->dportal)
Expand All @@ -295,7 +295,7 @@ void idxd_wq_disable_cleanup(struct idxd_wq *wq)
int i, wq_offset;

lockdep_assert_held(&idxd->dev_lock);
memset(&wq->wqcfg, 0, sizeof(wq->wqcfg));
memset(wq->wqcfg, 0, idxd->wqcfg_size);
wq->type = IDXD_WQT_NONE;
wq->size = 0;
wq->group = NULL;
Expand All @@ -304,8 +304,8 @@ void idxd_wq_disable_cleanup(struct idxd_wq *wq)
clear_bit(WQ_FLAG_DEDICATED, &wq->flags);
memset(wq->name, 0, WQ_NAME_SIZE);

for (i = 0; i < 8; i++) {
wq_offset = idxd->wqcfg_offset + wq->id * 32 + i * sizeof(u32);
for (i = 0; i < WQCFG_STRIDES(idxd); i++) {
wq_offset = WQCFG_OFFSET(idxd, wq->id, i);
iowrite32(0, idxd->reg_base + wq_offset);
dev_dbg(dev, "WQ[%d][%d][%#x]: %#x\n",
wq->id, i, wq_offset,
Expand Down Expand Up @@ -539,33 +539,32 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
if (!wq->group)
return 0;

memset(&wq->wqcfg, 0, sizeof(union wqcfg));
memset(wq->wqcfg, 0, idxd->wqcfg_size);

/* byte 0-3 */
wq->wqcfg.wq_size = wq->size;
wq->wqcfg->wq_size = wq->size;

if (wq->size == 0) {
dev_warn(dev, "Incorrect work queue size: 0\n");
return -EINVAL;
}

/* bytes 4-7 */
wq->wqcfg.wq_thresh = wq->threshold;
wq->wqcfg->wq_thresh = wq->threshold;

/* byte 8-11 */
wq->wqcfg.priv = !!(wq->type == IDXD_WQT_KERNEL);
wq->wqcfg.mode = 1;

wq->wqcfg.priority = wq->priority;
wq->wqcfg->priv = !!(wq->type == IDXD_WQT_KERNEL);
wq->wqcfg->mode = 1;
wq->wqcfg->priority = wq->priority;

/* bytes 12-15 */
wq->wqcfg.max_xfer_shift = ilog2(wq->max_xfer_bytes);
wq->wqcfg.max_batch_shift = ilog2(wq->max_batch_size);
wq->wqcfg->max_xfer_shift = ilog2(wq->max_xfer_bytes);
wq->wqcfg->max_batch_shift = ilog2(wq->max_batch_size);

dev_dbg(dev, "WQ %d CFGs\n", wq->id);
for (i = 0; i < 8; i++) {
wq_offset = idxd->wqcfg_offset + wq->id * 32 + i * sizeof(u32);
iowrite32(wq->wqcfg.bits[i], idxd->reg_base + wq_offset);
for (i = 0; i < WQCFG_STRIDES(idxd); i++) {
wq_offset = WQCFG_OFFSET(idxd, wq->id, i);
iowrite32(wq->wqcfg->bits[i], idxd->reg_base + wq_offset);
dev_dbg(dev, "WQ[%d][%d][%#x]: %#x\n",
wq->id, i, wq_offset,
ioread32(idxd->reg_base + wq_offset));
Expand Down
3 changes: 2 additions & 1 deletion drivers/dma/idxd/idxd.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ struct idxd_wq {
u32 priority;
enum idxd_wq_state state;
unsigned long flags;
union wqcfg wqcfg;
union wqcfg *wqcfg;
u32 vec_ptr; /* interrupt steering */
struct dsa_hw_desc **hw_descs;
int num_descs;
Expand Down Expand Up @@ -183,6 +183,7 @@ struct idxd_device {
int max_wq_size;
int token_limit;
int nr_tokens; /* non-reserved tokens */
unsigned int wqcfg_size;

union sw_err_reg sw_err;
wait_queue_head_t cmd_waitq;
Expand Down
5 changes: 5 additions & 0 deletions drivers/dma/idxd/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ static int idxd_setup_internals(struct idxd_device *idxd)
wq->idxd_cdev.minor = -1;
wq->max_xfer_bytes = idxd->max_xfer_bytes;
wq->max_batch_size = idxd->max_batch_size;
wq->wqcfg = devm_kzalloc(dev, idxd->wqcfg_size, GFP_KERNEL);
if (!wq->wqcfg)
return -ENOMEM;
}

for (i = 0; i < idxd->max_engines; i++) {
Expand Down Expand Up @@ -251,6 +254,8 @@ static void idxd_read_caps(struct idxd_device *idxd)
dev_dbg(dev, "total workqueue size: %u\n", idxd->max_wq_size);
idxd->max_wqs = idxd->hw.wq_cap.num_wqs;
dev_dbg(dev, "max workqueues: %u\n", idxd->max_wqs);
idxd->wqcfg_size = 1 << (idxd->hw.wq_cap.wqcfg_size + IDXD_WQCFG_MIN);
dev_dbg(dev, "wqcfg size: %u\n", idxd->wqcfg_size);

/* reading operation capabilities */
for (i = 0; i < 4; i++) {
Expand Down
25 changes: 23 additions & 2 deletions drivers/dma/idxd/registers.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#define IDXD_MMIO_BAR 0
#define IDXD_WQ_BAR 2
#define IDXD_PORTAL_SIZE 0x4000
#define IDXD_PORTAL_SIZE PAGE_SIZE

/* MMIO Device BAR0 Registers */
#define IDXD_VER_OFFSET 0x00
Expand Down Expand Up @@ -43,7 +43,8 @@ union wq_cap_reg {
struct {
u64 total_wq_size:16;
u64 num_wqs:8;
u64 rsvd:24;
u64 wqcfg_size:4;
u64 rsvd:20;
u64 shared_mode:1;
u64 dedicated_mode:1;
u64 rsvd2:1;
Expand All @@ -55,6 +56,7 @@ union wq_cap_reg {
u64 bits;
} __packed;
#define IDXD_WQCAP_OFFSET 0x20
#define IDXD_WQCFG_MIN 5

union group_cap_reg {
struct {
Expand Down Expand Up @@ -333,4 +335,23 @@ union wqcfg {
};
u32 bits[8];
} __packed;

/*
* This macro calculates the offset into the WQCFG register
* idxd - struct idxd *
* n - wq id
* ofs - the index of the 32b dword for the config register
*
* The WQCFG register block is divided into groups per each wq. The n index
* allows us to move to the register group that's for that particular wq.
* Each register is 32bits. The ofs gives us the number of register to access.
*/
#define WQCFG_OFFSET(_idxd_dev, n, ofs) \
({\
typeof(_idxd_dev) __idxd_dev = (_idxd_dev); \
(__idxd_dev)->wqcfg_offset + (n) * (__idxd_dev)->wqcfg_size + sizeof(u32) * (ofs); \
})

#define WQCFG_STRIDES(_idxd_dev) ((_idxd_dev)->wqcfg_size / sizeof(u32))

#endif
2 changes: 1 addition & 1 deletion drivers/dma/idxd/submit.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc)
if (idxd->state != IDXD_DEV_ENABLED)
return -EIO;

portal = wq->dportal + idxd_get_wq_portal_offset(IDXD_PORTAL_UNLIMITED);
portal = wq->dportal;
/*
* The wmb() flushes writes to coherent DMA data before possibly
* triggering a DMA read. The wmb() is necessary even on UP because
Expand Down
10 changes: 0 additions & 10 deletions drivers/dma/ioat/dca.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,6 @@
#define DCA2_TAG_MAP_BYTE3 0x82
#define DCA2_TAG_MAP_BYTE4 0x82

/* verify if tag map matches expected values */
static inline int dca2_tag_map_valid(u8 *tag_map)
{
return ((tag_map[0] == DCA2_TAG_MAP_BYTE0) &&
(tag_map[1] == DCA2_TAG_MAP_BYTE1) &&
(tag_map[2] == DCA2_TAG_MAP_BYTE2) &&
(tag_map[3] == DCA2_TAG_MAP_BYTE3) &&
(tag_map[4] == DCA2_TAG_MAP_BYTE4));
}

/*
* "Legacy" DCA systems do not implement the DCA register set in the
* I/OAT device. Software needs direct support for their tag mappings.
Expand Down
2 changes: 1 addition & 1 deletion drivers/dma/pl330.c
Original file line number Diff line number Diff line change
Expand Up @@ -2799,7 +2799,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
* If burst size is smaller than bus width then make sure we only
* transfer one at a time to avoid a burst stradling an MFIFO entry.
*/
if (desc->rqcfg.brst_size * 8 < pl330->pcfg.data_bus_width)
if (burst * 8 < pl330->pcfg.data_bus_width)
desc->rqcfg.brst_len = 1;

desc->bytes_requested = len;
Expand Down
2 changes: 1 addition & 1 deletion drivers/dma/ti/k3-udma-private.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ EXPORT_SYMBOL(xudma_rflow_is_gp);
#define XUDMA_GET_PUT_RESOURCE(res) \
struct udma_##res *xudma_##res##_get(struct udma_dev *ud, int id) \
{ \
return __udma_reserve_##res(ud, false, id); \
return __udma_reserve_##res(ud, UDMA_TP_NORMAL, id); \
} \
EXPORT_SYMBOL(xudma_##res##_get); \
\
Expand Down
37 changes: 24 additions & 13 deletions drivers/dma/ti/omap-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1522,29 +1522,38 @@ static void omap_dma_free(struct omap_dmadev *od)
}
}

/* Currently used by omap2 & 3 to block deeper SoC idle states */
static bool omap_dma_busy(struct omap_dmadev *od)
{
struct omap_chan *c;
int lch = -1;

while (1) {
lch = find_next_bit(od->lch_bitmap, od->lch_count, lch + 1);
if (lch >= od->lch_count)
break;
c = od->lch_map[lch];
if (!c)
continue;
if (omap_dma_chan_read(c, CCR) & CCR_ENABLE)
return true;
}

return false;
}

/* Currently only used for omap2. For omap1, also a check for lcd_dma is needed */
static int omap_dma_busy_notifier(struct notifier_block *nb,
unsigned long cmd, void *v)
{
struct omap_dmadev *od;
struct omap_chan *c;
int lch = -1;

od = container_of(nb, struct omap_dmadev, nb);

switch (cmd) {
case CPU_CLUSTER_PM_ENTER:
while (1) {
lch = find_next_bit(od->lch_bitmap, od->lch_count,
lch + 1);
if (lch >= od->lch_count)
break;
c = od->lch_map[lch];
if (!c)
continue;
if (omap_dma_chan_read(c, CCR) & CCR_ENABLE)
return NOTIFY_BAD;
}
if (omap_dma_busy(od))
return NOTIFY_BAD;
break;
case CPU_CLUSTER_PM_ENTER_FAILED:
case CPU_CLUSTER_PM_EXIT:
Expand Down Expand Up @@ -1595,6 +1604,8 @@ static int omap_dma_context_notifier(struct notifier_block *nb,

switch (cmd) {
case CPU_CLUSTER_PM_ENTER:
if (omap_dma_busy(od))
return NOTIFY_BAD;
omap_dma_context_save(od);
break;
case CPU_CLUSTER_PM_ENTER_FAILED:
Expand Down
Loading

0 comments on commit bd4d74e

Please sign in to comment.