#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"
#include "xe_sriov_vf.h"
#include "xe_sriov_vf_ccs.h"
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;
}
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)) {
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 (IS_SRIOV(xe))
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;
}
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;
}
if (IS_SRIOV_VF(xe))
xe_sriov_vf_init_early(xe);
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);
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)));
}
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;
}
int xe_sriov_init_late(struct xe_device *xe)
{
if (IS_SRIOV_PF(xe))
return xe_sriov_pf_init_late(xe);
if (IS_SRIOV_VF(xe))
return xe_sriov_vf_init_late(xe);
return 0;
}