Commit cba99807 authored by wanghaibin's avatar wanghaibin Committed by Dongxu Sun
Browse files

irqchip/gic-v3-its: Alloc/Free device id from pools for virtual devices

virt inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8K8HP


CVE: NA

--------------------------------

Alloc/Free device id from pools for virtual devices
and plug the helpers into its_msi_prepare()/its_free_device().

Signed-off-by: default avatarwanghaibin <wanghaibin.wang@huawei.com>
Signed-off-by: default avatarZenghui Yu <yuzenghui@huawei.com>
Signed-off-by: default avatarKunkun Jiang <jiangkunkun@huawei.com>
Signed-off-by: default avatarDongxu Sun <sundongxu3@huawei.com>
parent 6544e9e9
Loading
Loading
Loading
Loading
+84 −0
Original line number Diff line number Diff line
@@ -282,6 +282,10 @@ struct its_device {
	u32			nr_ites;
	u32			device_id;
	bool			shared;

	/* For virtual devices which needed the devid managed */
	bool			is_vdev;
	struct rsv_devid_pool	*devid_pool;
};

static struct {
@@ -309,6 +313,58 @@ static DEFINE_RAW_SPINLOCK(vmovp_lock);

static DEFINE_IDA(its_vpeid_ida);

static void free_devid_to_rsv_pools(struct its_device *its_dev)
{
	struct rsv_devid_pool *pool = its_dev->devid_pool;
	u32 id, size;

	WARN_ON(!pool);

	id = its_dev->device_id - pool->start;
	size = pool->end - pool->start;
	WARN_ON(id >= size);

	raw_spin_lock(&pool->devid_bm_lock);
	clear_bit(id, pool->devid_bm);
	raw_spin_unlock(&pool->devid_bm_lock);

	pr_debug("ITS: free devid (%u) to rsv_devid_pools\n", its_dev->device_id);
}

static int alloc_devid_from_rsv_pools(struct rsv_devid_pool **devid_pool,
				      u32 *dev_id)
{
	struct rsv_devid_pool *pool;
	int err = -ENOSPC;

	raw_spin_lock(&rsv_devid_pools_lock);
	list_for_each_entry(pool, &rsv_devid_pools, entry) {
		u32 size, id;

		size = pool->end - pool->start;

		raw_spin_lock(&pool->devid_bm_lock);
		id = find_first_zero_bit(pool->devid_bm, size);
		if (id >= size) {
			/* No usable device id in this pool, try next. */
			raw_spin_unlock(&pool->devid_bm_lock);
			continue;
		}

		*dev_id = pool->start + id;
		set_bit(id, pool->devid_bm);
		raw_spin_unlock(&pool->devid_bm_lock);

		*devid_pool = pool;
		err = 0;
		break;
	}
	raw_spin_unlock(&rsv_devid_pools_lock);

	pr_debug("ITS: alloc devid (%u) from rsv_devid_pools\n", *dev_id);
	return err;
}

#ifdef CONFIG_ASCEND_INIT_ALL_GICR
static bool init_all_gicr;
static int nr_gicr;
@@ -3843,6 +3899,12 @@ static void its_free_device(struct its_device *its_dev)
	raw_spin_unlock_irqrestore(&its_dev->its->lock, flags);
	kfree(its_dev->event_map.col_map);
	kfree(its_dev->itt);

	if (its_dev->is_vdev) {
		WARN_ON(!rsv_devid_pool_cap);
		free_devid_to_rsv_pools(its_dev);
	}

	kfree(its_dev);
}

@@ -3870,6 +3932,8 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
	struct msi_domain_info *msi_info;
	u32 dev_id;
	int err = 0;
	int use_devid_pool = false;
	struct rsv_devid_pool *pool = NULL;

	/*
	 * We ignore "dev" entirely, and rely on the dev_id that has
@@ -3879,6 +3943,18 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
	 */
	dev_id = info->scratchpad[0].ul;

	if (rsv_devid_pool_cap && !dev->of_node && !dev->fwnode &&
	    info->scratchpad[0].ul == -1)
		use_devid_pool = true;

	if (use_devid_pool) {
		err = alloc_devid_from_rsv_pools(&pool, &dev_id);
		if (err) {
			pr_warn("ITS: No remaining device id\n");
			return err;
		}
	}

	msi_info = msi_get_domain_info(domain);
	its = msi_info->data;

@@ -3895,6 +3971,9 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
	mutex_lock(&its->dev_alloc_lock);
	its_dev = its_find_device(its, dev_id);
	if (its_dev) {
		/* Impossible ...*/
		WARN_ON_ONCE(use_devid_pool);

		/*
		 * We already have seen this ID, probably through
		 * another alias (PCI bridge of some sort). No need to
@@ -3912,6 +3991,11 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
	}

	pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec));

	if (use_devid_pool) {
		its_dev->is_vdev = true;
		its_dev->devid_pool = pool;
	}
out:
	mutex_unlock(&its->dev_alloc_lock);
	info->scratchpad[0].ptr = its_dev;