drivers/accel/ivpu/ivpu_ms.c

Source file repositories/reference/linux-study-clean/drivers/accel/ivpu/ivpu_ms.c

File Facts

System
Linux kernel
Corpus path
drivers/accel/ivpu/ivpu_ms.c
Extension
.c
Size
8723 bytes
Lines
350
Domain
Driver Families
Bucket
drivers/accel
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only OR MIT
/*
 * Copyright (C) 2020-2024 Intel Corporation
 */

#include <drm/drm_file.h>
#include <linux/pm_runtime.h>

#include "ivpu_drv.h"
#include "ivpu_gem.h"
#include "ivpu_hw.h"
#include "ivpu_jsm_msg.h"
#include "ivpu_ms.h"
#include "ivpu_pm.h"

#define MS_INFO_BUFFER_SIZE	  SZ_64K
#define MS_NUM_BUFFERS		  2
#define MS_READ_PERIOD_MULTIPLIER 2
#define MS_MIN_SAMPLE_PERIOD_NS   1000000

static struct ivpu_ms_instance *
get_instance_by_mask(struct ivpu_file_priv *file_priv, u64 metric_mask)
{
	struct ivpu_ms_instance *ms;

	lockdep_assert_held(&file_priv->ms_lock);

	list_for_each_entry(ms, &file_priv->ms_instance_list, ms_instance_node)
		if (ms->mask == metric_mask)
			return ms;

	return NULL;
}

int ivpu_ms_start_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
{
	struct ivpu_file_priv *file_priv = file->driver_priv;
	struct drm_ivpu_metric_streamer_start *args = data;
	struct ivpu_device *vdev = file_priv->vdev;
	struct ivpu_ms_instance *ms;
	u32 sample_size;
	u64 buf_size;
	int ret;

	if (!args->metric_group_mask || !args->read_period_samples ||
	    args->sampling_period_ns < MS_MIN_SAMPLE_PERIOD_NS)
		return -EINVAL;

	ret = ivpu_rpm_get(vdev);
	if (ret < 0)
		return ret;

	mutex_lock(&file_priv->ms_lock);

	if (get_instance_by_mask(file_priv, args->metric_group_mask)) {
		ivpu_dbg(vdev, IOCTL, "Instance already exists (mask %#llx)\n",
			 args->metric_group_mask);
		ret = -EALREADY;
		goto unlock;
	}

	ms = kzalloc_obj(*ms);
	if (!ms) {
		ret = -ENOMEM;
		goto unlock;
	}

	ms->mask = args->metric_group_mask;

	ret = ivpu_jsm_metric_streamer_info(vdev, ms->mask, 0, 0, &sample_size, NULL);
	if (ret)
		goto err_free_ms;

	buf_size = PAGE_ALIGN((u64)args->read_period_samples * sample_size *
			      MS_READ_PERIOD_MULTIPLIER * MS_NUM_BUFFERS);
	if (buf_size > ivpu_hw_range_size(&vdev->hw->ranges.global)) {
		ivpu_dbg(vdev, IOCTL, "Requested MS buffer size %llu exceeds range size %llu\n",
			 buf_size, ivpu_hw_range_size(&vdev->hw->ranges.global));
		ret = -EINVAL;
		goto err_free_ms;
	}

	ms->bo = ivpu_bo_create_global(vdev, buf_size, DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE);
	if (!ms->bo) {
		ivpu_dbg(vdev, IOCTL, "Failed to allocate MS buffer (size %llu)\n", buf_size);
		ret = -ENOMEM;
		goto err_free_ms;
	}

	ms->buff_size = ivpu_bo_size(ms->bo) / MS_NUM_BUFFERS;

Annotation

Implementation Notes