lkml.org 
[lkml]   [2020]   [Oct]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH v4 04/17] dmaengine: idxd: add support for readonly config devices
    From
    Date
    The VFIO mediated device for idxd driver will provide a virtual DSA
    device by backing it with a workqueue. The virtual device will be limited
    with the wq configuration registers set to read-only. Add support and
    helper functions for the handling of a DSA device with the configuration
    registers marked as read-only.

    Signed-off-by: Dave Jiang <dave.jiang@intel.com>
    ---
    drivers/dma/idxd/device.c | 116 +++++++++++++++++++++++++++++++++++++++++++++
    drivers/dma/idxd/idxd.h | 1
    drivers/dma/idxd/init.c | 8 +++
    drivers/dma/idxd/sysfs.c | 20 +++++---
    4 files changed, 137 insertions(+), 8 deletions(-)

    diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
    index d6f551dcbcb6..7003884cd8ad 100644
    --- a/drivers/dma/idxd/device.c
    +++ b/drivers/dma/idxd/device.c
    @@ -778,3 +778,119 @@ int idxd_device_config(struct idxd_device *idxd)

    return 0;
    }
    +
    +static int idxd_wq_load_config(struct idxd_wq *wq)
    +{
    + struct idxd_device *idxd = wq->idxd;
    + struct device *dev = &idxd->pdev->dev;
    + int wqcfg_offset;
    + int i;
    +
    + wqcfg_offset = WQCFG_OFFSET(idxd, wq->id, 0);
    + memcpy_fromio(wq->wqcfg, idxd->reg_base + wqcfg_offset, idxd->wqcfg_size);
    +
    + wq->size = wq->wqcfg->wq_size;
    + wq->threshold = wq->wqcfg->wq_thresh;
    + if (wq->wqcfg->priv)
    + wq->type = IDXD_WQT_KERNEL;
    +
    + /* The driver does not support shared WQ mode in read-only config yet */
    + if (wq->wqcfg->mode == 0 || wq->wqcfg->pasid_en)
    + return -EOPNOTSUPP;
    +
    + set_bit(WQ_FLAG_DEDICATED, &wq->flags);
    +
    + wq->priority = wq->wqcfg->priority;
    +
    + for (i = 0; i < WQCFG_STRIDES(idxd); i++) {
    + wqcfg_offset = WQCFG_OFFSET(idxd, wq->id, i);
    + dev_dbg(dev, "WQ[%d][%d][%#x]: %#x\n", wq->id, i, wqcfg_offset, wq->wqcfg->bits[i]);
    + }
    +
    + return 0;
    +}
    +
    +static void idxd_group_load_config(struct idxd_group *group)
    +{
    + struct idxd_device *idxd = group->idxd;
    + struct device *dev = &idxd->pdev->dev;
    + int i, j, grpcfg_offset;
    +
    + /*
    + * Load WQS bit fields
    + * Iterate through all 256 bits 64 bits at a time
    + */
    + for (i = 0; i < GRPWQCFG_STRIDES; i++) {
    + struct idxd_wq *wq;
    +
    + grpcfg_offset = GRPWQCFG_OFFSET(idxd, group->id, i);
    + group->grpcfg.wqs[i] = ioread64(idxd->reg_base + grpcfg_offset);
    + dev_dbg(dev, "GRPCFG wq[%d:%d: %#x]: %#llx\n",
    + group->id, i, grpcfg_offset, group->grpcfg.wqs[i]);
    +
    + if (i * 64 >= idxd->max_wqs)
    + break;
    +
    + /* Iterate through all 64 bits and check for wq set */
    + for (j = 0; j < 64; j++) {
    + int id = i * 64 + j;
    +
    + /* No need to check beyond max wqs */
    + if (id >= idxd->max_wqs)
    + break;
    +
    + /* Set group assignment for wq if wq bit is set */
    + if (group->grpcfg.wqs[i] & BIT(j)) {
    + wq = &idxd->wqs[id];
    + wq->group = group;
    + }
    + }
    + }
    +
    + grpcfg_offset = GRPENGCFG_OFFSET(idxd, group->id);
    + group->grpcfg.engines = ioread64(idxd->reg_base + grpcfg_offset);
    + dev_dbg(dev, "GRPCFG engs[%d: %#x]: %#llx\n", group->id,
    + grpcfg_offset, group->grpcfg.engines);
    +
    + /* Iterate through all 64 bits to check engines set */
    + for (i = 0; i < 64; i++) {
    + if (i >= idxd->max_engines)
    + break;
    +
    + if (group->grpcfg.engines & BIT(i)) {
    + struct idxd_engine *engine = &idxd->engines[i];
    +
    + engine->group = group;
    + }
    + }
    +
    + grpcfg_offset = GRPFLGCFG_OFFSET(idxd, group->id);
    + group->grpcfg.flags.bits = ioread32(idxd->reg_base + grpcfg_offset);
    + dev_dbg(dev, "GRPFLAGS flags[%d: %#x]: %#x\n",
    + group->id, grpcfg_offset, group->grpcfg.flags.bits);
    +}
    +
    +int idxd_device_load_config(struct idxd_device *idxd)
    +{
    + union gencfg_reg reg;
    + int i, rc;
    +
    + reg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET);
    + idxd->token_limit = reg.token_limit;
    +
    + for (i = 0; i < idxd->max_groups; i++) {
    + struct idxd_group *group = &idxd->groups[i];
    +
    + idxd_group_load_config(group);
    + }
    +
    + for (i = 0; i < idxd->max_wqs; i++) {
    + struct idxd_wq *wq = &idxd->wqs[i];
    +
    + rc = idxd_wq_load_config(wq);
    + if (rc < 0)
    + return rc;
    + }
    +
    + return 0;
    +}
    diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h
    index 7e54209c433a..1afc34be4ed0 100644
    --- a/drivers/dma/idxd/idxd.h
    +++ b/drivers/dma/idxd/idxd.h
    @@ -317,6 +317,7 @@ void idxd_device_cleanup(struct idxd_device *idxd);
    int idxd_device_config(struct idxd_device *idxd);
    void idxd_device_wqs_clear_state(struct idxd_device *idxd);
    void idxd_device_drain_pasid(struct idxd_device *idxd, int pasid);
    +int idxd_device_load_config(struct idxd_device *idxd);

    /* work queue control */
    int idxd_wq_alloc_resources(struct idxd_wq *wq);
    diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
    index 45b0eac640c3..98b1091181bb 100644
    --- a/drivers/dma/idxd/init.c
    +++ b/drivers/dma/idxd/init.c
    @@ -349,6 +349,14 @@ static int idxd_probe(struct idxd_device *idxd)
    if (rc)
    goto err_setup;

    + /* If the configs are readonly, then load them from device */
    + if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) {
    + dev_dbg(dev, "Loading RO device config\n");
    + rc = idxd_device_load_config(idxd);
    + if (rc < 0)
    + goto err_setup;
    + }
    +
    rc = idxd_setup_interrupts(idxd);
    if (rc)
    goto err_setup;
    diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c
    index 6d292eb79bf3..304eb2cf532e 100644
    --- a/drivers/dma/idxd/sysfs.c
    +++ b/drivers/dma/idxd/sysfs.c
    @@ -102,7 +102,7 @@ static int idxd_config_bus_match(struct device *dev,

    static int idxd_config_bus_probe(struct device *dev)
    {
    - int rc;
    + int rc = 0;
    unsigned long flags;

    dev_dbg(dev, "%s called\n", __func__);
    @@ -120,7 +120,8 @@ static int idxd_config_bus_probe(struct device *dev)

    /* Perform IDXD configuration and enabling */
    spin_lock_irqsave(&idxd->dev_lock, flags);
    - rc = idxd_device_config(idxd);
    + if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
    + rc = idxd_device_config(idxd);
    spin_unlock_irqrestore(&idxd->dev_lock, flags);
    if (rc < 0) {
    module_put(THIS_MODULE);
    @@ -207,7 +208,8 @@ static int idxd_config_bus_probe(struct device *dev)
    }

    spin_lock_irqsave(&idxd->dev_lock, flags);
    - rc = idxd_device_config(idxd);
    + if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
    + rc = idxd_device_config(idxd);
    spin_unlock_irqrestore(&idxd->dev_lock, flags);
    if (rc < 0) {
    mutex_unlock(&wq->wq_lock);
    @@ -328,12 +330,14 @@ static int idxd_config_bus_remove(struct device *dev)

    idxd_unregister_dma_device(idxd);
    rc = idxd_device_disable(idxd);
    - for (i = 0; i < idxd->max_wqs; i++) {
    - struct idxd_wq *wq = &idxd->wqs[i];
    + if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) {
    + for (i = 0; i < idxd->max_wqs; i++) {
    + struct idxd_wq *wq = &idxd->wqs[i];

    - mutex_lock(&wq->wq_lock);
    - idxd_wq_disable_cleanup(wq);
    - mutex_unlock(&wq->wq_lock);
    + mutex_lock(&wq->wq_lock);
    + idxd_wq_disable_cleanup(wq);
    + mutex_unlock(&wq->wq_lock);
    + }
    }
    module_put(THIS_MODULE);
    if (rc < 0)

    \
     
     \ /
      Last update: 2020-10-30 19:53    [W:4.346 / U:1.972 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site