Skip to content

Commit b0325ae

Browse files
davejiangvinodkoul
authored andcommitted
dmaengine: idxd: add WQ operation cap restriction support
DSA 2.0 add the capability of configuring DMA ops on a per workqueue basis. This means that certain ops can be disabled by the system administrator for certain wq. By default, all ops are available. A bitmap is used to store the ops due to total op size of 256 bits and it is more convenient to use a range list to specify which bits are enabled. One of the usage to support this is for VM migration between different iteration of devices. The newer ops are disabled in order to allow guest to migrate to a host that only support older ops. Another usage is to restrict the WQ to certain operations for QoS of performance. A sysfs of ops_config attribute is added per wq. It is only usable when the ops_config bit is set under WQ_CAP register. This means that this attribute will return -EOPNOTSUPP on DSA 1.x devices. The expected input is a range list for the bits per operation the WQ supports. Signed-off-by: Dave Jiang <[email protected]> Co-developed-by: Fenghua Yu <[email protected]> Signed-off-by: Fenghua Yu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent a8563a3 commit b0325ae

File tree

6 files changed

+128
-3
lines changed

6 files changed

+128
-3
lines changed

Documentation/ABI/stable/sysfs-driver-dma-idxd

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,17 @@ Contact: [email protected]
227227
Description: Indicate the number of retires for an enqcmds submission on a sharedwq.
228228
A max value to set attribute is capped at 64.
229229

230+
What: /sys/bus/dsa/devices/wq<m>.<n>/op_config
231+
Date: Sept 14, 2022
232+
KernelVersion: 6.0.0
233+
234+
Description: Shows the operation capability bits displayed in bitmap format
235+
presented by %*pb printk() output format specifier.
236+
The attribute can be configured when the WQ is disabled in
237+
order to configure the WQ to accept specific bits that
238+
correlates to the operations allowed. It's visible only
239+
on platforms that support the capability.
240+
230241
What: /sys/bus/dsa/devices/engine<m>.<n>/group_id
231242
Date: Oct 25, 2019
232243
KernelVersion: 5.6.0

drivers/dma/idxd/device.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ static void idxd_wq_disable_cleanup(struct idxd_wq *wq)
391391
memset(wq->name, 0, WQ_NAME_SIZE);
392392
wq->max_xfer_bytes = WQ_DEFAULT_MAX_XFER;
393393
wq->max_batch_size = WQ_DEFAULT_MAX_BATCH;
394+
if (wq->opcap_bmap)
395+
bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS);
394396
}
395397

396398
static void idxd_wq_device_reset_cleanup(struct idxd_wq *wq)
@@ -809,7 +811,7 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
809811
struct idxd_device *idxd = wq->idxd;
810812
struct device *dev = &idxd->pdev->dev;
811813
u32 wq_offset;
812-
int i;
814+
int i, n;
813815

814816
if (!wq->group)
815817
return 0;
@@ -867,6 +869,17 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
867869
wq->wqcfg->max_xfer_shift = ilog2(wq->max_xfer_bytes);
868870
wq->wqcfg->max_batch_shift = ilog2(wq->max_batch_size);
869871

872+
/* bytes 32-63 */
873+
if (idxd->hw.wq_cap.op_config && wq->opcap_bmap) {
874+
memset(wq->wqcfg->op_config, 0, IDXD_MAX_OPCAP_BITS / 8);
875+
for_each_set_bit(n, wq->opcap_bmap, IDXD_MAX_OPCAP_BITS) {
876+
int pos = n % BITS_PER_LONG_LONG;
877+
int idx = n / BITS_PER_LONG_LONG;
878+
879+
wq->wqcfg->op_config[idx] |= BIT(pos);
880+
}
881+
}
882+
870883
dev_dbg(dev, "WQ %d CFGs\n", wq->id);
871884
for (i = 0; i < WQCFG_STRIDES(idxd); i++) {
872885
wq_offset = WQCFG_OFFSET(idxd, wq->id, i);

drivers/dma/idxd/idxd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ struct idxd_wq {
196196
enum idxd_wq_state state;
197197
unsigned long flags;
198198
union wqcfg *wqcfg;
199+
unsigned long *opcap_bmap;
200+
199201
struct dsa_hw_desc **hw_descs;
200202
int num_descs;
201203
union {

drivers/dma/idxd/init.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,16 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
191191
rc = -ENOMEM;
192192
goto err;
193193
}
194+
195+
if (idxd->hw.wq_cap.op_config) {
196+
wq->opcap_bmap = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL);
197+
if (!wq->opcap_bmap) {
198+
put_device(conf_dev);
199+
rc = -ENOMEM;
200+
goto err;
201+
}
202+
bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS);
203+
}
194204
idxd->wqs[i] = wq;
195205
}
196206

drivers/dma/idxd/registers.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ union wq_cap_reg {
5454
u64 priority:1;
5555
u64 occupancy:1;
5656
u64 occupancy_int:1;
57-
u64 rsvd3:10;
57+
u64 op_config:1;
58+
u64 rsvd3:9;
5859
};
5960
u64 bits;
6061
} __packed;
@@ -350,8 +351,11 @@ union wqcfg {
350351

351352
/* bytes 28-31 */
352353
u32 rsvd8;
354+
355+
/* bytes 32-63 */
356+
u64 op_config[4];
353357
};
354-
u32 bits[8];
358+
u32 bits[16];
355359
} __packed;
356360

357361
#define WQCFG_PASID_IDX 2

drivers/dma/idxd/sysfs.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,68 @@ static ssize_t wq_enqcmds_retries_store(struct device *dev, struct device_attrib
10581058
static struct device_attribute dev_attr_wq_enqcmds_retries =
10591059
__ATTR(enqcmds_retries, 0644, wq_enqcmds_retries_show, wq_enqcmds_retries_store);
10601060

1061+
static ssize_t wq_op_config_show(struct device *dev,
1062+
struct device_attribute *attr, char *buf)
1063+
{
1064+
struct idxd_wq *wq = confdev_to_wq(dev);
1065+
1066+
return sysfs_emit(buf, "%*pb\n", IDXD_MAX_OPCAP_BITS, wq->opcap_bmap);
1067+
}
1068+
1069+
static int idxd_verify_supported_opcap(struct idxd_device *idxd, unsigned long *opmask)
1070+
{
1071+
int bit;
1072+
1073+
/*
1074+
* The OPCAP is defined as 256 bits that represents each operation the device
1075+
* supports per bit. Iterate through all the bits and check if the input mask
1076+
* is set for bits that are not set in the OPCAP for the device. If no OPCAP
1077+
* bit is set and input mask has the bit set, then return error.
1078+
*/
1079+
for_each_set_bit(bit, opmask, IDXD_MAX_OPCAP_BITS) {
1080+
if (!test_bit(bit, idxd->opcap_bmap))
1081+
return -EINVAL;
1082+
}
1083+
1084+
return 0;
1085+
}
1086+
1087+
static ssize_t wq_op_config_store(struct device *dev, struct device_attribute *attr,
1088+
const char *buf, size_t count)
1089+
{
1090+
struct idxd_wq *wq = confdev_to_wq(dev);
1091+
struct idxd_device *idxd = wq->idxd;
1092+
unsigned long *opmask;
1093+
int rc;
1094+
1095+
if (wq->state != IDXD_WQ_DISABLED)
1096+
return -EPERM;
1097+
1098+
opmask = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL);
1099+
if (!opmask)
1100+
return -ENOMEM;
1101+
1102+
rc = bitmap_parse(buf, count, opmask, IDXD_MAX_OPCAP_BITS);
1103+
if (rc < 0)
1104+
goto err;
1105+
1106+
rc = idxd_verify_supported_opcap(idxd, opmask);
1107+
if (rc < 0)
1108+
goto err;
1109+
1110+
bitmap_copy(wq->opcap_bmap, opmask, IDXD_MAX_OPCAP_BITS);
1111+
1112+
bitmap_free(opmask);
1113+
return count;
1114+
1115+
err:
1116+
bitmap_free(opmask);
1117+
return rc;
1118+
}
1119+
1120+
static struct device_attribute dev_attr_wq_op_config =
1121+
__ATTR(op_config, 0644, wq_op_config_show, wq_op_config_store);
1122+
10611123
static struct attribute *idxd_wq_attributes[] = {
10621124
&dev_attr_wq_clients.attr,
10631125
&dev_attr_wq_state.attr,
@@ -1075,11 +1137,33 @@ static struct attribute *idxd_wq_attributes[] = {
10751137
&dev_attr_wq_ats_disable.attr,
10761138
&dev_attr_wq_occupancy.attr,
10771139
&dev_attr_wq_enqcmds_retries.attr,
1140+
&dev_attr_wq_op_config.attr,
10781141
NULL,
10791142
};
10801143

1144+
static bool idxd_wq_attr_op_config_invisible(struct attribute *attr,
1145+
struct idxd_device *idxd)
1146+
{
1147+
return attr == &dev_attr_wq_op_config.attr &&
1148+
!idxd->hw.wq_cap.op_config;
1149+
}
1150+
1151+
static umode_t idxd_wq_attr_visible(struct kobject *kobj,
1152+
struct attribute *attr, int n)
1153+
{
1154+
struct device *dev = container_of(kobj, struct device, kobj);
1155+
struct idxd_wq *wq = confdev_to_wq(dev);
1156+
struct idxd_device *idxd = wq->idxd;
1157+
1158+
if (idxd_wq_attr_op_config_invisible(attr, idxd))
1159+
return 0;
1160+
1161+
return attr->mode;
1162+
}
1163+
10811164
static const struct attribute_group idxd_wq_attribute_group = {
10821165
.attrs = idxd_wq_attributes,
1166+
.is_visible = idxd_wq_attr_visible,
10831167
};
10841168

10851169
static const struct attribute_group *idxd_wq_attribute_groups[] = {
@@ -1091,6 +1175,7 @@ static void idxd_conf_wq_release(struct device *dev)
10911175
{
10921176
struct idxd_wq *wq = confdev_to_wq(dev);
10931177

1178+
bitmap_free(wq->opcap_bmap);
10941179
kfree(wq->wqcfg);
10951180
kfree(wq);
10961181
}

0 commit comments

Comments
 (0)