156 lines
3.9 KiB
C
156 lines
3.9 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2023 Intel Corporation
|
|
*/
|
|
|
|
#include <linux/fault-inject.h>
|
|
|
|
#include <drm/drm_managed.h>
|
|
|
|
#include "regs/xe_regs.h"
|
|
|
|
#include "xe_assert.h"
|
|
#include "xe_device.h"
|
|
#include "xe_mmio.h"
|
|
#include "xe_sriov.h"
|
|
#include "xe_sriov_pf.h"
|
|
|
|
/**
|
|
* xe_sriov_mode_to_string - Convert enum value to string.
|
|
* @mode: the &xe_sriov_mode to convert
|
|
*
|
|
* Returns: SR-IOV mode as a user friendly string.
|
|
*/
|
|
const char *xe_sriov_mode_to_string(enum xe_sriov_mode mode)
|
|
{
|
|
switch (mode) {
|
|
case XE_SRIOV_MODE_NONE:
|
|
return "none";
|
|
case XE_SRIOV_MODE_PF:
|
|
return "SR-IOV PF";
|
|
case XE_SRIOV_MODE_VF:
|
|
return "SR-IOV VF";
|
|
default:
|
|
return "<invalid>";
|
|
}
|
|
}
|
|
|
|
static bool test_is_vf(struct xe_device *xe)
|
|
{
|
|
u32 value = xe_mmio_read32(xe_root_tile_mmio(xe), VF_CAP_REG);
|
|
|
|
return value & VF_CAP;
|
|
}
|
|
|
|
/**
|
|
* xe_sriov_probe_early - Probe a SR-IOV mode.
|
|
* @xe: the &xe_device to probe mode on
|
|
*
|
|
* This function should be called only once and as soon as possible during
|
|
* driver probe to detect whether we are running a SR-IOV Physical Function
|
|
* (PF) or a Virtual Function (VF) device.
|
|
*
|
|
* SR-IOV PF mode detection is based on PCI @dev_is_pf() function.
|
|
* SR-IOV VF mode detection is based on dedicated MMIO register read.
|
|
*/
|
|
void xe_sriov_probe_early(struct xe_device *xe)
|
|
{
|
|
struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
|
|
enum xe_sriov_mode mode = XE_SRIOV_MODE_NONE;
|
|
bool has_sriov = xe->info.has_sriov;
|
|
|
|
if (has_sriov) {
|
|
if (test_is_vf(xe))
|
|
mode = XE_SRIOV_MODE_VF;
|
|
else if (xe_sriov_pf_readiness(xe))
|
|
mode = XE_SRIOV_MODE_PF;
|
|
} else if (pci_sriov_get_totalvfs(pdev)) {
|
|
/*
|
|
* Even if we have not enabled SR-IOV support using the
|
|
* platform specific has_sriov flag, the hardware may still
|
|
* report SR-IOV capability and the PCI layer may wrongly
|
|
* advertise driver support to enable VFs. Explicitly reset
|
|
* the number of supported VFs to zero to avoid confusion.
|
|
*/
|
|
drm_info(&xe->drm, "Support for SR-IOV is not available\n");
|
|
pci_sriov_set_totalvfs(pdev, 0);
|
|
}
|
|
|
|
xe_assert(xe, !xe->sriov.__mode);
|
|
xe->sriov.__mode = mode;
|
|
xe_assert(xe, xe->sriov.__mode);
|
|
|
|
if (has_sriov)
|
|
drm_info(&xe->drm, "Running in %s mode\n",
|
|
xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
|
|
}
|
|
|
|
static void fini_sriov(struct drm_device *drm, void *arg)
|
|
{
|
|
struct xe_device *xe = arg;
|
|
|
|
destroy_workqueue(xe->sriov.wq);
|
|
xe->sriov.wq = NULL;
|
|
}
|
|
|
|
/**
|
|
* xe_sriov_init - Initialize SR-IOV specific data.
|
|
* @xe: the &xe_device to initialize
|
|
*
|
|
* In this function we create dedicated workqueue that will be used
|
|
* by the SR-IOV specific workers.
|
|
*
|
|
* Return: 0 on success or a negative error code on failure.
|
|
*/
|
|
int xe_sriov_init(struct xe_device *xe)
|
|
{
|
|
if (!IS_SRIOV(xe))
|
|
return 0;
|
|
|
|
if (IS_SRIOV_PF(xe)) {
|
|
int err = xe_sriov_pf_init_early(xe);
|
|
|
|
if (err)
|
|
return err;
|
|
}
|
|
|
|
xe_assert(xe, !xe->sriov.wq);
|
|
xe->sriov.wq = alloc_workqueue("xe-sriov-wq", 0, 0);
|
|
if (!xe->sriov.wq)
|
|
return -ENOMEM;
|
|
|
|
return drmm_add_action_or_reset(&xe->drm, fini_sriov, xe);
|
|
}
|
|
ALLOW_ERROR_INJECTION(xe_sriov_init, ERRNO); /* See xe_pci_probe() */
|
|
|
|
/**
|
|
* xe_sriov_print_info - Print basic SR-IOV information.
|
|
* @xe: the &xe_device to print info from
|
|
* @p: the &drm_printer
|
|
*
|
|
* Print SR-IOV related information into provided DRM printer.
|
|
*/
|
|
void xe_sriov_print_info(struct xe_device *xe, struct drm_printer *p)
|
|
{
|
|
drm_printf(p, "supported: %s\n", str_yes_no(xe_device_has_sriov(xe)));
|
|
drm_printf(p, "enabled: %s\n", str_yes_no(IS_SRIOV(xe)));
|
|
drm_printf(p, "mode: %s\n", xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
|
|
}
|
|
|
|
/**
|
|
* xe_sriov_function_name() - Get SR-IOV Function name.
|
|
* @n: the Function number (identifier) to get name of
|
|
* @buf: the buffer to format to
|
|
* @size: size of the buffer (shall be at least 5 bytes)
|
|
*
|
|
* Return: formatted function name ("PF" or "VF%u").
|
|
*/
|
|
const char *xe_sriov_function_name(unsigned int n, char *buf, size_t size)
|
|
{
|
|
if (n)
|
|
snprintf(buf, size, "VF%u", n);
|
|
else
|
|
strscpy(buf, "PF", size);
|
|
return buf;
|
|
}
|