mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
[Vblk]: Get vcpu affinity from the DT node
mpidr will not give the correct HRO VPU when it is floorswept. The Change contains: [1] Get the VCPU affinity from the DT rather from mpidr. [2] Remove the Mpidr Logic Bug 4856912 Change-Id: I4d21ed90a8effc94fd3b12a977752b56b3915548 Signed-off-by: Gokul Vasan L J <gokull@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3213689 GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com> Tested-by: Gokul Vasan L J <gokull@nvidia.com> Reviewed-by: Vipin Kumar <vipink@nvidia.com> Reviewed-by: Sreenivas Velpula <svelpula@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3262165 Tested-by: Manish Bhardwaj <mbhardwaj@nvidia.com> Reviewed-by: Sumeet Gupta <sumeetg@nvidia.com> Reviewed-by: Manish Bhardwaj <mbhardwaj@nvidia.com>
This commit is contained in:
@@ -64,11 +64,6 @@ static uint32_t total_instance_id;
|
|||||||
|
|
||||||
static int vblk_major;
|
static int vblk_major;
|
||||||
|
|
||||||
static uint32_t lcpu_to_vcpus[CPUS_PER_CLUSTER * MAX_NUM_CLUSTERS];
|
|
||||||
atomic_t vcpu_init_info;
|
|
||||||
static DEFINE_MUTEX(vcpu_lock);
|
|
||||||
static struct semaphore mpidr_sem;
|
|
||||||
|
|
||||||
static inline uint64_t _arch_counter_get_cntvct(void)
|
static inline uint64_t _arch_counter_get_cntvct(void)
|
||||||
{
|
{
|
||||||
uint64_t cval;
|
uint64_t cval;
|
||||||
@@ -102,27 +97,6 @@ exit:
|
|||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t convert_lcpu_to_vcpu(struct vblk_dev *vblkdev, uint32_t lcpu_affinity)
|
|
||||||
{
|
|
||||||
uint32_t cnt, vcpu = U32_MAX;
|
|
||||||
int adj_lcpu = -1;
|
|
||||||
|
|
||||||
/* search for vcpu corresponding to lcpu_affinity */
|
|
||||||
for (cnt = 0; cnt < MAX_NUM_CLUSTERS * CPUS_PER_CLUSTER; cnt++) {
|
|
||||||
if (lcpu_to_vcpus[cnt] != U32_MAX) {
|
|
||||||
/* calculating adjusted lcpu */
|
|
||||||
adj_lcpu++;
|
|
||||||
|
|
||||||
if (adj_lcpu == lcpu_affinity) {
|
|
||||||
vcpu = lcpu_to_vcpus[cnt];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vcpu;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct vsc_request *vblk_get_req_by_sr_num(struct vblk_dev *vblkdev,
|
static struct vsc_request *vblk_get_req_by_sr_num(struct vblk_dev *vblkdev,
|
||||||
uint32_t num)
|
uint32_t num)
|
||||||
{
|
{
|
||||||
@@ -1560,12 +1534,12 @@ static void vblk_init_device(struct work_struct *ws)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vblkdev->vcpu_affinity != U32_MAX) {
|
if (vblkdev->schedulable_vcpu_number != num_possible_cpus()) {
|
||||||
strncat(vblk_comm, ":%u", 3);
|
strncat(vblk_comm, ":%u", 3);
|
||||||
|
|
||||||
/* create partition specific worker thread */
|
/* create partition specific worker thread */
|
||||||
vblkdev->vblk_kthread = kthread_create_on_cpu(&vblk_request_worker, vblkdev,
|
vblkdev->vblk_kthread = kthread_create_on_cpu(&vblk_request_worker, vblkdev,
|
||||||
vblkdev->vcpu_affinity, vblk_comm);
|
vblkdev->schedulable_vcpu_number, vblk_comm);
|
||||||
} else {
|
} else {
|
||||||
/* create partition specific worker thread.
|
/* create partition specific worker thread.
|
||||||
* If the conversion is not successful
|
* If the conversion is not successful
|
||||||
@@ -1582,6 +1556,9 @@ static void vblk_init_device(struct work_struct *ws)
|
|||||||
|
|
||||||
/* set thread priority */
|
/* set thread priority */
|
||||||
attr.sched_policy = SCHED_RR;
|
attr.sched_policy = SCHED_RR;
|
||||||
|
/*
|
||||||
|
* FIXME: Need to review the priority level set currently <25.
|
||||||
|
*/
|
||||||
attr.sched_priority = VBLK_DEV_BASE_PRIORITY - vblkdev->config.priority;
|
attr.sched_priority = VBLK_DEV_BASE_PRIORITY - vblkdev->config.priority;
|
||||||
WARN_ON_ONCE(sched_setattr_nocheck(vblkdev->vblk_kthread, &attr) != 0);
|
WARN_ON_ONCE(sched_setattr_nocheck(vblkdev->vblk_kthread, &attr) != 0);
|
||||||
init_completion(&vblkdev->complete);
|
init_completion(&vblkdev->complete);
|
||||||
@@ -1599,13 +1576,15 @@ static void vblk_init_device(struct work_struct *ws)
|
|||||||
static irqreturn_t ivc_irq_handler(int irq, void *data)
|
static irqreturn_t ivc_irq_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct vblk_dev *vblkdev = (struct vblk_dev *)data;
|
struct vblk_dev *vblkdev = (struct vblk_dev *)data;
|
||||||
|
if (vblkdev->initialized) {
|
||||||
if (vblkdev->initialized)
|
|
||||||
/* wakeup worker thread */
|
/* wakeup worker thread */
|
||||||
complete(&vblkdev->complete);
|
complete(&vblkdev->complete);
|
||||||
else
|
} else {
|
||||||
schedule_work_on(vblkdev->vcpu_affinity, &vblkdev->init);
|
|
||||||
|
|
||||||
|
int vcpu = (vblkdev->schedulable_vcpu_number != num_possible_cpus()) ?
|
||||||
|
vblkdev->schedulable_vcpu_number : DEFAULT_INIT_VCPU;
|
||||||
|
schedule_work_on(vcpu, &vblkdev->init);
|
||||||
|
}
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1660,72 +1639,13 @@ static void tegra_create_timers(struct vblk_dev *vblkdev)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t read_mpidr(void)
|
|
||||||
{
|
|
||||||
uint64_t mpidr;
|
|
||||||
__asm volatile("MRS %0, MPIDR_EL1 " : "=r"(mpidr) :: "memory");
|
|
||||||
return mpidr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t read_mpidr_cluster(uint64_t mpidr)
|
|
||||||
{
|
|
||||||
return (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t read_mpidr_core(uint64_t mpidr)
|
|
||||||
{
|
|
||||||
return (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long get_cpu_info(void *data)
|
|
||||||
{
|
|
||||||
uint64_t l_mpidr, l_cluster, l_core;
|
|
||||||
uint32_t lcpu;
|
|
||||||
|
|
||||||
l_mpidr = read_mpidr();
|
|
||||||
l_cluster = read_mpidr_cluster(l_mpidr);
|
|
||||||
l_core = read_mpidr_core(l_mpidr);
|
|
||||||
|
|
||||||
lcpu = l_cluster * CPUS_PER_CLUSTER + l_core;
|
|
||||||
lcpu_to_vcpus[lcpu] = smp_processor_id();
|
|
||||||
|
|
||||||
up(&mpidr_sem);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void populate_lcpu_to_vcpu_info(struct vblk_dev *vblkdev)
|
|
||||||
{
|
|
||||||
uint32_t num_vcpus = num_present_cpus();
|
|
||||||
uint32_t cnt, lcpu;
|
|
||||||
|
|
||||||
/* initialize all clusters including holes */
|
|
||||||
for (lcpu = 0; lcpu < MAX_NUM_CLUSTERS * CPUS_PER_CLUSTER; lcpu++)
|
|
||||||
lcpu_to_vcpus[lcpu] = U32_MAX;
|
|
||||||
|
|
||||||
/* queuing API on each present vcpus serially
|
|
||||||
* by down and up semaphore operation
|
|
||||||
*/
|
|
||||||
for (cnt = 0; cnt < num_vcpus; cnt++) {
|
|
||||||
down(&mpidr_sem);
|
|
||||||
work_on_cpu(cnt, get_cpu_info, vblkdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* down and up operation to make sure get_cpu_info API
|
|
||||||
* gets exuected on last vcpu successfully before exiting function
|
|
||||||
*/
|
|
||||||
down(&mpidr_sem);
|
|
||||||
up(&mpidr_sem);
|
|
||||||
|
|
||||||
atomic_inc(&vcpu_init_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tegra_hv_vblk_probe(struct platform_device *pdev)
|
static int tegra_hv_vblk_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
static struct device_node *vblk_node;
|
static struct device_node *vblk_node;
|
||||||
|
struct device_node *schedulable_vcpu_number_node;
|
||||||
struct vblk_dev *vblkdev;
|
struct vblk_dev *vblkdev;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
uint32_t lcpu_affinity;
|
uint8_t is_cpu_bound = true;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!is_tegra_hypervisor_mode()) {
|
if (!is_tegra_hypervisor_mode()) {
|
||||||
@@ -1765,6 +1685,24 @@ static int tegra_hv_vblk_probe(struct platform_device *pdev)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
schedulable_vcpu_number_node = of_find_node_by_name(NULL, "virt-storage-request-submit-cpu-mapping");
|
||||||
|
/* read lcpu_affinity from dts */
|
||||||
|
if (schedulable_vcpu_number_node == NULL) {
|
||||||
|
dev_err(dev, "%s: virt-storage-request-submit-cpu-mapping DT not found\n",
|
||||||
|
__func__);
|
||||||
|
is_cpu_bound = false;
|
||||||
|
} else if (of_property_read_u32(schedulable_vcpu_number_node, "lcpu2tovcpu", &(vblkdev->schedulable_vcpu_number)) != 0) {
|
||||||
|
dev_err(dev, "%s: lcpu2tovcpu affinity is not found\n", __func__);
|
||||||
|
is_cpu_bound = false;
|
||||||
|
}
|
||||||
|
if (vblkdev->schedulable_vcpu_number >= num_online_cpus()) {
|
||||||
|
dev_err(dev, "%s: cpu affinity (%d) > online cpus (%d)\n", __func__, vblkdev->schedulable_vcpu_number, num_online_cpus());
|
||||||
|
is_cpu_bound = false;
|
||||||
|
}
|
||||||
|
if (false == is_cpu_bound) {
|
||||||
|
dev_err(dev, "%s: WARN: CPU is unbound\n", __func__);
|
||||||
|
vblkdev->schedulable_vcpu_number = num_possible_cpus();
|
||||||
|
}
|
||||||
|
|
||||||
vblkdev->initialized = false;
|
vblkdev->initialized = false;
|
||||||
|
|
||||||
@@ -1778,7 +1716,6 @@ static int tegra_hv_vblk_probe(struct platform_device *pdev)
|
|||||||
spin_lock_init(&vblkdev->queue_lock);
|
spin_lock_init(&vblkdev->queue_lock);
|
||||||
mutex_init(&vblkdev->ioctl_lock);
|
mutex_init(&vblkdev->ioctl_lock);
|
||||||
mutex_init(&vblkdev->ivc_lock);
|
mutex_init(&vblkdev->ivc_lock);
|
||||||
sema_init(&mpidr_sem, 1);
|
|
||||||
|
|
||||||
INIT_WORK(&vblkdev->init, vblk_init_device);
|
INIT_WORK(&vblkdev->init, vblk_init_device);
|
||||||
INIT_WORK(&vblkdev->rq_cfg, vblk_request_config);
|
INIT_WORK(&vblkdev->rq_cfg, vblk_request_config);
|
||||||
@@ -1788,25 +1725,10 @@ static int tegra_hv_vblk_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
/* Create timers for each request going to storage server*/
|
/* Create timers for each request going to storage server*/
|
||||||
tegra_create_timers(vblkdev);
|
tegra_create_timers(vblkdev);
|
||||||
|
schedule_work_on(((is_cpu_bound == false) ? DEFAULT_INIT_VCPU : vblkdev->schedulable_vcpu_number),
|
||||||
mutex_lock(&vcpu_lock);
|
&vblkdev->rq_cfg);
|
||||||
if (atomic_read(&vcpu_init_info) == 0)
|
|
||||||
populate_lcpu_to_vcpu_info(vblkdev);
|
|
||||||
mutex_unlock(&vcpu_lock);
|
|
||||||
|
|
||||||
/* read lcpu_affinity from dts */
|
|
||||||
if (of_property_read_u32_index(vblkdev->device->of_node, "lcpu_affinity", 0,
|
|
||||||
&lcpu_affinity)) {
|
|
||||||
/* pin thread to logical core 2 if dts property is missing */
|
|
||||||
lcpu_affinity = 2;
|
|
||||||
}
|
|
||||||
/* convert lcpu to vcpu */
|
|
||||||
vblkdev->vcpu_affinity = convert_lcpu_to_vcpu(vblkdev, lcpu_affinity);
|
|
||||||
|
|
||||||
schedule_work_on(vblkdev->vcpu_affinity, &vblkdev->rq_cfg);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#define DRV_NAME "tegra_hv_vblk"
|
#define DRV_NAME "tegra_hv_vblk"
|
||||||
|
|
||||||
|
#define DEFAULT_INIT_VCPU (0U)
|
||||||
|
|
||||||
/* Minor number and partition management. */
|
/* Minor number and partition management. */
|
||||||
#define VBLK_MINORS 32
|
#define VBLK_MINORS 32
|
||||||
|
|
||||||
@@ -96,7 +98,7 @@ struct vblk_dev {
|
|||||||
struct list_head req_list; /* List containing req */
|
struct list_head req_list; /* List containing req */
|
||||||
uint32_t ivc_id;
|
uint32_t ivc_id;
|
||||||
uint32_t ivm_id;
|
uint32_t ivm_id;
|
||||||
uint32_t vcpu_affinity;
|
uint32_t schedulable_vcpu_number; /* VCPU through which Req will be processed*/
|
||||||
struct tegra_hv_ivc_cookie *ivck;
|
struct tegra_hv_ivc_cookie *ivck;
|
||||||
struct tegra_hv_ivm_cookie *ivmk;
|
struct tegra_hv_ivm_cookie *ivmk;
|
||||||
uint32_t devnum;
|
uint32_t devnum;
|
||||||
|
|||||||
Reference in New Issue
Block a user