Skip to content

Commit

Permalink
dlb: add scheduling domain configuration
Browse files Browse the repository at this point in the history
Add support for configuring a scheduling domain, creating the domain fd,
and reserving the domain's resources.

When a user requests to create a scheduling domain via configfs, the
requested resources are validated against the number currently available,
and then reserved for the scheduling domain. An anonymous file descriptor
for the domain is created and installed in the calling process's file
descriptor table.

The driver maintains a reference count for each scheduling domain,
incrementing it each time user-space requests a file descriptor for a dlb
port access and decrementing it in the file's release callback.

When the reference count transitions from 1->0 the driver automatically
resets the scheduling domain's resources and makes them available for use
by future applications. This ensures that applications that crash without
explicitly cleaning up do not orphan device resources. The code to perform
the domain reset will be added in subsequent commits.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
  • Loading branch information
mikexchen authored and intel-lab-lkp committed Dec 21, 2021
1 parent bb13186 commit 0eda6e7
Show file tree
Hide file tree
Showing 6 changed files with 808 additions and 2 deletions.
46 changes: 45 additions & 1 deletion drivers/misc/dlb/dlb_configfs.c
@@ -1,7 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2017-2020 Intel Corporation

#include <linux/anon_inodes.h>
#include <linux/version.h>
#include <linux/configfs.h>
#include <linux/fdtable.h>
#include "dlb_configfs.h"

struct dlb_device_configfs dlb_dev_configfs[16];
Expand All @@ -11,12 +14,38 @@ static int dlb_configfs_create_sched_domain(struct dlb *dlb,
{
struct dlb_create_sched_domain_args *arg = karg;
struct dlb_cmd_response response = {0};
int ret;
struct dlb_domain *domain;
u32 flags = O_RDONLY;
int ret, fd;

mutex_lock(&dlb->resource_mutex);

ret = dlb_hw_create_sched_domain(&dlb->hw, arg, &response);
if (ret)
goto unlock;

ret = dlb_init_domain(dlb, response.id);
if (ret)
goto unlock;

domain = dlb->sched_domains[response.id];

if (dlb->f->f_mode & FMODE_WRITE)
flags = O_RDWR;

fd = anon_inode_getfd("[dlbdomain]", &dlb_domain_fops,
domain, flags);

if (fd < 0) {
dev_err(dlb->dev, "Failed to get anon fd.\n");
kref_put(&domain->refcnt, dlb_free_domain);
ret = fd;
goto unlock;
}

arg->domain_fd = fd;

unlock:
mutex_unlock(&dlb->resource_mutex);

memcpy(karg, &response, sizeof(response));
Expand Down Expand Up @@ -84,6 +113,7 @@ static ssize_t dlb_cfs_domain_##name##_store( \
return count; \
} \

DLB_CONFIGFS_DOMAIN_SHOW(domain_fd)
DLB_CONFIGFS_DOMAIN_SHOW(status)
DLB_CONFIGFS_DOMAIN_SHOW(domain_id)
DLB_CONFIGFS_DOMAIN_SHOW(num_ldb_queues)
Expand Down Expand Up @@ -137,6 +167,7 @@ static ssize_t dlb_cfs_domain_create_store(struct config_item *item,

dlb_cfs_domain->status = args.response.status;
dlb_cfs_domain->domain_id = args.response.id;
dlb_cfs_domain->domain_fd = args.domain_fd;

if (ret) {
dev_err(dlb->dev,
Expand All @@ -145,11 +176,23 @@ static ssize_t dlb_cfs_domain_create_store(struct config_item *item,
}

dlb_cfs_domain->create = 1;
} else if (create_in == 0 && dlb_cfs_domain->create == 1) {
dev_dbg(dlb->dev,
"Close domain: %s\n",
dlb_cfs_domain->group.cg_item.ci_namebuf);

ret = close_fd(dlb_cfs_domain->domain_fd);
if (ret)
dev_err(dlb->dev,
"close sched domain failed: ret=%d\n", ret);

dlb_cfs_domain->create = 0;
}

return count;
}

CONFIGFS_ATTR_RO(dlb_cfs_domain_, domain_fd);
CONFIGFS_ATTR_RO(dlb_cfs_domain_, status);
CONFIGFS_ATTR_RO(dlb_cfs_domain_, domain_id);
CONFIGFS_ATTR(dlb_cfs_domain_, num_ldb_queues);
Expand All @@ -162,6 +205,7 @@ CONFIGFS_ATTR(dlb_cfs_domain_, num_dir_credits);
CONFIGFS_ATTR(dlb_cfs_domain_, create);

static struct configfs_attribute *dlb_cfs_domain_attrs[] = {
&dlb_cfs_domain_attr_domain_fd,
&dlb_cfs_domain_attr_status,
&dlb_cfs_domain_attr_domain_id,
&dlb_cfs_domain_attr_num_ldb_queues,
Expand Down
68 changes: 68 additions & 0 deletions drivers/misc/dlb/dlb_main.c
Expand Up @@ -61,8 +61,76 @@ static int dlb_device_create(struct dlb *dlb, struct pci_dev *pdev)
/****** Char dev callbacks ******/
/********************************/

static int dlb_open(struct inode *i, struct file *f)
{
struct dlb *dlb;

mutex_lock(&dlb_ids_lock);
dlb = idr_find(&dlb_ids, iminor(i));
mutex_unlock(&dlb_ids_lock);

f->private_data = dlb;
dlb->f = f;

return 0;
}

static const struct file_operations dlb_fops = {
.owner = THIS_MODULE,
.open = dlb_open,
};

int dlb_init_domain(struct dlb *dlb, u32 domain_id)
{
struct dlb_domain *domain;

domain = kzalloc(sizeof(*domain), GFP_KERNEL);
if (!domain)
return -ENOMEM;

domain->id = domain_id;

kref_init(&domain->refcnt);
domain->dlb = dlb;

dlb->sched_domains[domain_id] = domain;

return 0;
}

static int __dlb_free_domain(struct dlb_domain *domain)
{
struct dlb *dlb = domain->dlb;

dlb->sched_domains[domain->id] = NULL;

kfree(domain);

return 0;
}

void dlb_free_domain(struct kref *kref)
{
__dlb_free_domain(container_of(kref, struct dlb_domain, refcnt));
}

static int dlb_domain_close(struct inode *i, struct file *f)
{
struct dlb_domain *domain = f->private_data;
struct dlb *dlb = domain->dlb;

mutex_lock(&dlb->resource_mutex);

kref_put(&domain->refcnt, dlb_free_domain);

mutex_unlock(&dlb->resource_mutex);

return 0;
}

const struct file_operations dlb_domain_fops = {
.owner = THIS_MODULE,
.release = dlb_domain_close,
};

/**********************************/
Expand Down
128 changes: 128 additions & 0 deletions drivers/misc/dlb/dlb_main.h
Expand Up @@ -13,6 +13,7 @@
#include <linux/types.h>
#include <linux/bitfield.h>

#include <uapi/linux/dlb.h>
#include "dlb_args.h"

/*
Expand Down Expand Up @@ -248,10 +249,20 @@ int dlb_pf_init_driver_state(struct dlb *dlb);
void dlb_pf_enable_pm(struct dlb *dlb);
int dlb_pf_wait_for_device_ready(struct dlb *dlb, struct pci_dev *pdev);

extern const struct file_operations dlb_domain_fops;

struct dlb_domain {
struct dlb *dlb;
struct kref refcnt;
u8 id;
};

struct dlb {
struct pci_dev *pdev;
struct dlb_hw hw;
struct device *dev;
struct dlb_domain *sched_domains[DLB_MAX_NUM_DOMAINS];
struct file *f;
/*
* The resource mutex serializes access to driver data structures and
* hardware registers.
Expand Down Expand Up @@ -326,6 +337,123 @@ static inline void dlb_bitmap_free(struct dlb_bitmap *bitmap)
kfree(bitmap);
}

/**
* dlb_bitmap_clear_range() - clear a range of bitmap entries
* @bitmap: pointer to dlb_bitmap structure.
* @bit: starting bit index.
* @len: length of the range.
*
* Return:
* Returns 0 upon success, < 0 otherwise.
*
* Errors:
* EINVAL - bitmap is NULL or is uninitialized, or the range exceeds the bitmap
* length.
*/
static inline int dlb_bitmap_clear_range(struct dlb_bitmap *bitmap,
unsigned int bit,
unsigned int len)
{
if (!bitmap || !bitmap->map)
return -EINVAL;

if (bitmap->len <= bit)
return -EINVAL;

bitmap_clear(bitmap->map, bit, len);

return 0;
}

/**
* dlb_bitmap_find_set_bit_range() - find an range of set bits
* @bitmap: pointer to dlb_bitmap structure.
* @len: length of the range.
*
* This function looks for a range of set bits of length @len.
*
* Return:
* Returns the base bit index upon success, < 0 otherwise.
*
* Errors:
* ENOENT - unable to find a length *len* range of set bits.
* EINVAL - bitmap is NULL or is uninitialized, or len is invalid.
*/
static inline int dlb_bitmap_find_set_bit_range(struct dlb_bitmap *bitmap,
unsigned int len)
{
struct dlb_bitmap *complement_mask = NULL;
int ret;

if (!bitmap || !bitmap->map || len == 0)
return -EINVAL;

if (bitmap->len < len)
return -ENOENT;

ret = dlb_bitmap_alloc(&complement_mask, bitmap->len);
if (ret)
return ret;

bitmap_zero(complement_mask->map, complement_mask->len);

bitmap_complement(complement_mask->map, bitmap->map, bitmap->len);

ret = bitmap_find_next_zero_area(complement_mask->map,
complement_mask->len,
0,
len,
0);

dlb_bitmap_free(complement_mask);

/* No set bit range of length len? */
return (ret >= (int)bitmap->len) ? -ENOENT : ret;
}

/**
* dlb_bitmap_longest_set_range() - returns longest contiguous range of set
* bits
* @bitmap: pointer to dlb_bitmap structure.
*
* Return:
* Returns the bitmap's longest contiguous range of set bits upon success,
* <0 otherwise.
*
* Errors:
* EINVAL - bitmap is NULL or is uninitialized.
*/
static inline int dlb_bitmap_longest_set_range(struct dlb_bitmap *bitmap)
{
int max_len, len;
int start, end;

if (!bitmap || !bitmap->map)
return -EINVAL;

if (bitmap_weight(bitmap->map, bitmap->len) == 0)
return 0;

max_len = 0;
bitmap_for_each_set_region(bitmap->map, start, end, 0, bitmap->len) {
len = end - start;
if (max_len < len)
max_len = len;
}
return max_len;
}

int dlb_init_domain(struct dlb *dlb, u32 domain_id);
void dlb_free_domain(struct kref *kref);

static inline struct device *hw_to_dev(struct dlb_hw *hw)
{
struct dlb *dlb;

dlb = container_of(hw, struct dlb, hw);
return dlb->dev;
}

/* Prototypes for dlb_resource.c */
int dlb_resource_init(struct dlb_hw *hw);
void dlb_resource_free(struct dlb_hw *hw);
Expand Down
18 changes: 18 additions & 0 deletions drivers/misc/dlb/dlb_regs.h
Expand Up @@ -6,6 +6,24 @@

#include <linux/types.h>

#define CHP_CFG_DIR_VAS_CRD(x) \
(0x40000000 + (x) * 0x1000)
#define CHP_CFG_DIR_VAS_CRD_RST 0x0

#define CHP_CFG_DIR_VAS_CRD_COUNT 0x00003FFF
#define CHP_CFG_DIR_VAS_CRD_RSVD0 0xFFFFC000
#define CHP_CFG_DIR_VAS_CRD_COUNT_LOC 0
#define CHP_CFG_DIR_VAS_CRD_RSVD0_LOC 14

#define CHP_CFG_LDB_VAS_CRD(x) \
(0x40080000 + (x) * 0x1000)
#define CHP_CFG_LDB_VAS_CRD_RST 0x0

#define CHP_CFG_LDB_VAS_CRD_COUNT 0x00007FFF
#define CHP_CFG_LDB_VAS_CRD_RSVD0 0xFFFF8000
#define CHP_CFG_LDB_VAS_CRD_COUNT_LOC 0
#define CHP_CFG_LDB_VAS_CRD_RSVD0_LOC 15

#define CM_CFG_DIAGNOSTIC_IDLE_STATUS 0xb4000004
#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_RST 0x9d0fffff

Expand Down

0 comments on commit 0eda6e7

Please sign in to comment.