Files
linux/drivers/gpu/drm/xe/xe_sriov.c
Michal Wajdeczko 9a54b5127f drm/xe/pf: Make the late-initialization really late
While the late PF per-GT initialization is done quite late in the
single GT initialization flow, in case of multi-GT platforms, it
may still be done before other GT early initialization. That leads
to some issues during unwind, when there are cross-GT dependencies,
like resource cleanup that is shared by both GTs, but the other GT
may already be sanitized or disabled.

The following errors could be observed when trying to unload the PF
driver with some LMEM/VRAM already provisioned for few VFs:

 [ ] xe 0000:03:00.0: DEVRES REL ffff88814708f240 fini_config (16 bytes)
 [ ] xe 0000:03:00.0: [drm:lmtt_write_pte [xe]] PF: LMTT: WRITE level=2 index=1 pte=0x0
 [ ] xe 0000:03:00.0: [drm:lmtt_invalidate_hw [xe]] PF: LMTT: num_fences=2 err=-19
 [ ] xe 0000:03:00.0: [drm:lmtt_pt_free [xe]] PF: LMTT: level=0 addr=53a470000
 [ ] xe 0000:03:00.0: [drm:lmtt_pt_free [xe]] PF: LMTT: level=1 addr=53a4b0000
 [ ] xe 0000:03:00.0: [drm:lmtt_invalidate_hw [xe]] PF: LMTT: num_fences=2 err=-19
 [ ] xe 0000:03:00.0: [drm] PF: LMTT0 invalidation failed (-ENODEV)
 [ ] xe 0000:03:00.0: [drm:lmtt_write_pte [xe]] PF: LMTT: WRITE level=2 index=2 pte=0x0
 [ ] xe 0000:03:00.0: [drm:lmtt_invalidate_hw [xe]] PF: LMTT: num_fences=2 err=-19
 [ ] xe 0000:03:00.0: [drm:lmtt_pt_free [xe]] PF: LMTT: level=0 addr=539b70000
 [ ] xe 0000:03:00.0: [drm:lmtt_pt_free [xe]] PF: LMTT: level=1 addr=539bf0000
 [ ] xe 0000:03:00.0: [drm:lmtt_invalidate_hw [xe]] PF: LMTT: num_fences=2 err=-19
 [ ] xe 0000:03:00.0: [drm] PF: LMTT0 invalidation failed (-ENODEV)

Move all PF per-GT late initialization to the already defined late
SR-IOV initialization function to allow proper order of the cleanup
actions.

While around, format all PF function stubs as one-liners, like many
other stubs are defined in the Xe driver.

Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
Reviewed-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
Link: https://lore.kernel.org/r/20251004162008.1782-1-michal.wajdeczko@intel.com
2025-10-06 19:30:17 +02:00

177 lines
4.4 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"
#include "xe_sriov_vf.h"
#include "xe_sriov_vf_ccs.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 (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;
}
/**
* 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;
}
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); /* 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;
}
/**
* xe_sriov_init_late() - SR-IOV late initialization functions.
* @xe: the &xe_device to initialize
*
* Return: 0 on success or a negative error code on failure.
*/
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;
}