Skip to content

Commit

Permalink
dmaengine: idxd: fix wq config registers offset programming
Browse files Browse the repository at this point in the history
DSA spec v1.1 [1] updated to include a stride size register for WQ
configuration that will specify how much space is reserved for the WQ
configuration register set. This change is expected to be in the final
gen1 DSA hardware. Fix the driver to use WQCFG_OFFSET() for all WQ
offset calculation and fixup WQCFG_OFFSET() to use the new calculated
wq size.

[1]: https://software.intel.com/content/www/us/en/develop/download/intel-data-streaming-accelerator-preliminary-architecture-specification.html

Fixes: bfe1d56 ("dmaengine: idxd: Init and probe for Intel data accelerators")
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/160383444959.48058.14249265538404901781.stgit@djiang5-desk3.ch.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
  • Loading branch information
Dave Jiang authored and Vinod Koul committed Oct 28, 2020
1 parent 3650b22 commit 484f910
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 17 deletions.
29 changes: 14 additions & 15 deletions drivers/dma/idxd/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
23 changes: 22 additions & 1 deletion drivers/dma/idxd/registers.h
Original file line number Diff line number Diff line change
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

0 comments on commit 484f910

Please sign in to comment.