Contributors: 6
Author Tokens Token Proportion Commits Commit Proportion
Michal Wajdeczko 680 95.77% 14 73.68%
Matthew Brost 14 1.97% 1 5.26%
Lukasz Laguna 9 1.27% 1 5.26%
Rodrigo Vivi 3 0.42% 1 5.26%
Eric Anholt 3 0.42% 1 5.26%
Lucas De Marchi 1 0.14% 1 5.26%
Total 710 19


// SPDX-License-Identifier: MIT
/*
 * Copyright © 2025 Intel Corporation
 */

#include <linux/debugfs.h>
#include <drm/drm_debugfs.h>

#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_gt_sriov_pf_config.h"
#include "xe_gt_sriov_pf_debugfs.h"
#include "xe_pm.h"
#include "xe_tile_debugfs.h"
#include "xe_tile_sriov_pf_debugfs.h"
#include "xe_sriov.h"
#include "xe_sriov_pf.h"
#include "xe_sriov_pf_provision.h"

/*
 *      /sys/kernel/debug/dri/BDF/
 *      ├── sriov		# d_inode->i_private = (xe_device*)
 *      │   ├── pf		# d_inode->i_private = (xe_device*)
 *      │   │   ├── tile0	# d_inode->i_private = (xe_tile*)
 *      │   │   ├── tile1
 *      │   │   :   :
 *      │   ├── vf1		# d_inode->i_private = VFID(1)
 *      │   │   ├── tile0	# d_inode->i_private = (xe_tile*)
 *      │   │   ├── tile1
 *      │   │   :   :
 *      │   ├── vfN		# d_inode->i_private = VFID(N)
 *      │   │   ├── tile0	# d_inode->i_private = (xe_tile*)
 *      │   │   ├── tile1
 *      :   :   :   :
 */

static void *extract_priv(struct dentry *d)
{
	return d->d_inode->i_private;
}

__maybe_unused
static struct xe_tile *extract_tile(struct dentry *d)
{
	return extract_priv(d);
}

static struct xe_device *extract_xe(struct dentry *d)
{
	return extract_priv(d->d_parent->d_parent);
}

__maybe_unused
static unsigned int extract_vfid(struct dentry *d)
{
	void *pp = extract_priv(d->d_parent);

	return pp == extract_xe(d) ? PFID : (uintptr_t)pp;
}

/*
 *      /sys/kernel/debug/dri/BDF/
 *      ├── sriov
 *      :   ├── pf
 *          :   ├── tile0
 *              :   ├── ggtt_available
 *                  ├── ggtt_provisioned
 */

static int pf_config_print_available_ggtt(struct xe_tile *tile, struct drm_printer *p)
{
	return xe_gt_sriov_pf_config_print_available_ggtt(tile->primary_gt, p);
}

static int pf_config_print_ggtt(struct xe_tile *tile, struct drm_printer *p)
{
	return xe_gt_sriov_pf_config_print_ggtt(tile->primary_gt, p);
}

static const struct drm_info_list pf_ggtt_info[] = {
	{
		"ggtt_available",
		.show = xe_tile_debugfs_simple_show,
		.data = pf_config_print_available_ggtt,
	},
	{
		"ggtt_provisioned",
		.show = xe_tile_debugfs_simple_show,
		.data = pf_config_print_ggtt,
	},
};

/*
 *      /sys/kernel/debug/dri/BDF/
 *      ├── sriov
 *      :   ├── pf
 *          :   ├── tile0
 *              :   ├── vram_provisioned
 */

static int pf_config_print_vram(struct xe_tile *tile, struct drm_printer *p)
{
	return xe_gt_sriov_pf_config_print_lmem(tile->primary_gt, p);
}

static const struct drm_info_list pf_vram_info[] = {
	{
		"vram_provisioned",
		.show = xe_tile_debugfs_simple_show,
		.data = pf_config_print_vram,
	},
};

/*
 *      /sys/kernel/debug/dri/BDF/
 *      ├── sriov
 *      │   ├── pf
 *      │   │   ├── tile0
 *      │   │   │   ├── ggtt_spare
 *      │   │   │   ├── vram_spare
 *      │   │   ├── tile1
 *      │   │   :   :
 *      │   ├── vf1
 *      │   :   ├── tile0
 *      │       │   ├── ggtt_quota
 *      │       │   ├── vram_quota
 *      │       ├── tile1
 *      │       :   :
 */

#define DEFINE_SRIOV_TILE_CONFIG_DEBUGFS_ATTRIBUTE(NAME, CONFIG, TYPE, FORMAT)	\
										\
static int NAME##_set(void *data, u64 val)					\
{										\
	struct xe_tile *tile = extract_tile(data);				\
	unsigned int vfid = extract_vfid(data);					\
	struct xe_gt *gt = tile->primary_gt;					\
	struct xe_device *xe = tile->xe;					\
	int err;								\
										\
	if (val > (TYPE)~0ull)							\
		return -EOVERFLOW;						\
										\
	xe_pm_runtime_get(xe);							\
	err = xe_sriov_pf_wait_ready(xe) ?:					\
	      xe_gt_sriov_pf_config_set_##CONFIG(gt, vfid, val);		\
	if (!err)								\
		xe_sriov_pf_provision_set_custom_mode(xe);			\
	xe_pm_runtime_put(xe);							\
										\
	return err;								\
}										\
										\
static int NAME##_get(void *data, u64 *val)					\
{										\
	struct xe_tile *tile = extract_tile(data);				\
	unsigned int vfid = extract_vfid(data);					\
	struct xe_gt *gt = tile->primary_gt;					\
										\
	*val = xe_gt_sriov_pf_config_get_##CONFIG(gt, vfid);			\
	return 0;								\
}										\
										\
DEFINE_DEBUGFS_ATTRIBUTE(NAME##_fops, NAME##_get, NAME##_set, FORMAT)

DEFINE_SRIOV_TILE_CONFIG_DEBUGFS_ATTRIBUTE(ggtt, ggtt, u64, "%llu\n");
DEFINE_SRIOV_TILE_CONFIG_DEBUGFS_ATTRIBUTE(vram, lmem, u64, "%llu\n");

static void pf_add_config_attrs(struct xe_tile *tile, struct dentry *dent, unsigned int vfid)
{
	struct xe_device *xe = tile->xe;

	xe_tile_assert(tile, tile == extract_tile(dent));
	xe_tile_assert(tile, vfid == extract_vfid(dent));

	debugfs_create_file_unsafe(vfid ? "ggtt_quota" : "ggtt_spare",
				   0644, dent, dent, &ggtt_fops);
	if (IS_DGFX(xe))
		debugfs_create_file_unsafe(vfid ? "vram_quota" : "vram_spare",
					   xe_device_has_lmtt(xe) ? 0644 : 0444,
					   dent, dent, &vram_fops);
}

static void pf_populate_tile(struct xe_tile *tile, struct dentry *dent, unsigned int vfid)
{
	struct xe_device *xe = tile->xe;
	struct drm_minor *minor = xe->drm.primary;
	struct xe_gt *gt;
	unsigned int id;

	pf_add_config_attrs(tile, dent, vfid);

	if (!vfid) {
		drm_debugfs_create_files(pf_ggtt_info,
					 ARRAY_SIZE(pf_ggtt_info),
					 dent, minor);
		if (IS_DGFX(xe))
			drm_debugfs_create_files(pf_vram_info,
						 ARRAY_SIZE(pf_vram_info),
						 dent, minor);
	}

	for_each_gt_on_tile(gt, tile, id)
		xe_gt_sriov_pf_debugfs_populate(gt, dent, vfid);
}

/**
 * xe_tile_sriov_pf_debugfs_populate() - Populate SR-IOV debugfs tree with tile files.
 * @tile: the &xe_tile to register
 * @parent: the parent &dentry that represents the SR-IOV @vfid function
 * @vfid: the VF identifier
 *
 * Add to the @parent directory new debugfs directory that will represent a @tile and
 * populate it with files that are related to the SR-IOV @vfid function.
 *
 * This function can only be called on PF.
 */
void xe_tile_sriov_pf_debugfs_populate(struct xe_tile *tile, struct dentry *parent,
				       unsigned int vfid)
{
	struct xe_device *xe = tile->xe;
	struct dentry *dent;
	char name[10]; /* should be enough up to "tile%u\0" for 2^16 - 1 */

	xe_tile_assert(tile, IS_SRIOV_PF(xe));
	xe_tile_assert(tile, extract_priv(parent->d_parent) == xe);
	xe_tile_assert(tile, extract_priv(parent) == tile->xe ||
		       (uintptr_t)extract_priv(parent) == vfid);

	/*
	 *      /sys/kernel/debug/dri/BDF/
	 *      ├── sriov
	 *      │   ├── pf		# parent, d_inode->i_private = (xe_device*)
	 *      │   │   ├── tile0	# d_inode->i_private = (xe_tile*)
	 *      │   │   ├── tile1
	 *      │   │   :   :
	 *      │   ├── vf1		# parent, d_inode->i_private = VFID(1)
	 *      │   │   ├── tile0	# d_inode->i_private = (xe_tile*)
	 *      │   │   ├── tile1
	 *      :   :   :   :
	 */
	snprintf(name, sizeof(name), "tile%u", tile->id);
	dent = debugfs_create_dir(name, parent);
	if (IS_ERR(dent))
		return;
	dent->d_inode->i_private = tile;

	xe_tile_assert(tile, extract_tile(dent) == tile);
	xe_tile_assert(tile, extract_vfid(dent) == vfid);
	xe_tile_assert(tile, extract_xe(dent) == xe);

	pf_populate_tile(tile, dent, vfid);
}