1  // SPDX-License-Identifier: MIT
2  /*
3   * Copyright © 2023 Intel Corporation
4   */
5  
6  #include <drm/drm_managed.h>
7  
8  #include "regs/xe_regs.h"
9  
10  #include "xe_assert.h"
11  #include "xe_device.h"
12  #include "xe_mmio.h"
13  #include "xe_sriov.h"
14  #include "xe_sriov_pf.h"
15  
16  /**
17   * xe_sriov_mode_to_string - Convert enum value to string.
18   * @mode: the &xe_sriov_mode to convert
19   *
20   * Returns: SR-IOV mode as a user friendly string.
21   */
xe_sriov_mode_to_string(enum xe_sriov_mode mode)22  const char *xe_sriov_mode_to_string(enum xe_sriov_mode mode)
23  {
24  	switch (mode) {
25  	case XE_SRIOV_MODE_NONE:
26  		return "none";
27  	case XE_SRIOV_MODE_PF:
28  		return "SR-IOV PF";
29  	case XE_SRIOV_MODE_VF:
30  		return "SR-IOV VF";
31  	default:
32  		return "<invalid>";
33  	}
34  }
35  
test_is_vf(struct xe_device * xe)36  static bool test_is_vf(struct xe_device *xe)
37  {
38  	u32 value = xe_mmio_read32(xe_root_mmio_gt(xe), VF_CAP_REG);
39  
40  	return value & VF_CAP;
41  }
42  
43  /**
44   * xe_sriov_probe_early - Probe a SR-IOV mode.
45   * @xe: the &xe_device to probe mode on
46   *
47   * This function should be called only once and as soon as possible during
48   * driver probe to detect whether we are running a SR-IOV Physical Function
49   * (PF) or a Virtual Function (VF) device.
50   *
51   * SR-IOV PF mode detection is based on PCI @dev_is_pf() function.
52   * SR-IOV VF mode detection is based on dedicated MMIO register read.
53   */
xe_sriov_probe_early(struct xe_device * xe)54  void xe_sriov_probe_early(struct xe_device *xe)
55  {
56  	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
57  	enum xe_sriov_mode mode = XE_SRIOV_MODE_NONE;
58  	bool has_sriov = xe->info.has_sriov;
59  
60  	if (has_sriov) {
61  		if (test_is_vf(xe))
62  			mode = XE_SRIOV_MODE_VF;
63  		else if (xe_sriov_pf_readiness(xe))
64  			mode = XE_SRIOV_MODE_PF;
65  	} else if (pci_sriov_get_totalvfs(pdev)) {
66  		/*
67  		 * Even if we have not enabled SR-IOV support using the
68  		 * platform specific has_sriov flag, the hardware may still
69  		 * report SR-IOV capability and the PCI layer may wrongly
70  		 * advertise driver support to enable VFs. Explicitly reset
71  		 * the number of supported VFs to zero to avoid confusion.
72  		 */
73  		drm_info(&xe->drm, "Support for SR-IOV is not available\n");
74  		pci_sriov_set_totalvfs(pdev, 0);
75  	}
76  
77  	xe_assert(xe, !xe->sriov.__mode);
78  	xe->sriov.__mode = mode;
79  	xe_assert(xe, xe->sriov.__mode);
80  
81  	if (has_sriov)
82  		drm_info(&xe->drm, "Running in %s mode\n",
83  			 xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
84  }
85  
fini_sriov(struct drm_device * drm,void * arg)86  static void fini_sriov(struct drm_device *drm, void *arg)
87  {
88  	struct xe_device *xe = arg;
89  
90  	destroy_workqueue(xe->sriov.wq);
91  	xe->sriov.wq = NULL;
92  }
93  
94  /**
95   * xe_sriov_init - Initialize SR-IOV specific data.
96   * @xe: the &xe_device to initialize
97   *
98   * In this function we create dedicated workqueue that will be used
99   * by the SR-IOV specific workers.
100   *
101   * Return: 0 on success or a negative error code on failure.
102   */
xe_sriov_init(struct xe_device * xe)103  int xe_sriov_init(struct xe_device *xe)
104  {
105  	if (!IS_SRIOV(xe))
106  		return 0;
107  
108  	if (IS_SRIOV_PF(xe)) {
109  		int err = xe_sriov_pf_init_early(xe);
110  
111  		if (err)
112  			return err;
113  	}
114  
115  	xe_assert(xe, !xe->sriov.wq);
116  	xe->sriov.wq = alloc_workqueue("xe-sriov-wq", 0, 0);
117  	if (!xe->sriov.wq)
118  		return -ENOMEM;
119  
120  	return drmm_add_action_or_reset(&xe->drm, fini_sriov, xe);
121  }
122  
123  /**
124   * xe_sriov_print_info - Print basic SR-IOV information.
125   * @xe: the &xe_device to print info from
126   * @p: the &drm_printer
127   *
128   * Print SR-IOV related information into provided DRM printer.
129   */
xe_sriov_print_info(struct xe_device * xe,struct drm_printer * p)130  void xe_sriov_print_info(struct xe_device *xe, struct drm_printer *p)
131  {
132  	drm_printf(p, "supported: %s\n", str_yes_no(xe_device_has_sriov(xe)));
133  	drm_printf(p, "enabled: %s\n", str_yes_no(IS_SRIOV(xe)));
134  	drm_printf(p, "mode: %s\n", xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
135  }
136  
137  /**
138   * xe_sriov_function_name() - Get SR-IOV Function name.
139   * @n: the Function number (identifier) to get name of
140   * @buf: the buffer to format to
141   * @size: size of the buffer (shall be at least 5 bytes)
142   *
143   * Return: formatted function name ("PF" or "VF%u").
144   */
xe_sriov_function_name(unsigned int n,char * buf,size_t size)145  const char *xe_sriov_function_name(unsigned int n, char *buf, size_t size)
146  {
147  	if (n)
148  		snprintf(buf, size, "VF%u", n);
149  	else
150  		strscpy(buf, "PF", size);
151  	return buf;
152  }
153