xref: /linux/drivers/gpu/drm/xe/xe_device_sysfs.c (revision e332935a540eb76dd656663ca908eb0544d96757)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2023 Intel Corporation
4  */
5 
6 #include <linux/device.h>
7 #include <linux/kobject.h>
8 #include <linux/pci.h>
9 #include <linux/sysfs.h>
10 
11 #include "xe_device.h"
12 #include "xe_device_sysfs.h"
13 #include "xe_mmio.h"
14 #include "xe_pcode_api.h"
15 #include "xe_pcode.h"
16 #include "xe_pm.h"
17 
18 /**
19  * DOC: Xe device sysfs
20  * Xe driver requires exposing certain tunable knobs controlled by user space for
21  * each graphics device. Considering this, we need to add sysfs attributes at device
22  * level granularity.
23  * These sysfs attributes will be available under pci device kobj directory.
24  *
25  * vram_d3cold_threshold - Report/change vram used threshold(in MB) below
26  * which vram save/restore is permissible during runtime D3cold entry/exit.
27  */
28 
29 static ssize_t
vram_d3cold_threshold_show(struct device * dev,struct device_attribute * attr,char * buf)30 vram_d3cold_threshold_show(struct device *dev,
31 			   struct device_attribute *attr, char *buf)
32 {
33 	struct pci_dev *pdev = to_pci_dev(dev);
34 	struct xe_device *xe = pdev_to_xe_device(pdev);
35 	int ret;
36 
37 	xe_pm_runtime_get(xe);
38 	ret = sysfs_emit(buf, "%d\n", xe->d3cold.vram_threshold);
39 	xe_pm_runtime_put(xe);
40 
41 	return ret;
42 }
43 
44 static ssize_t
vram_d3cold_threshold_store(struct device * dev,struct device_attribute * attr,const char * buff,size_t count)45 vram_d3cold_threshold_store(struct device *dev, struct device_attribute *attr,
46 			    const char *buff, size_t count)
47 {
48 	struct pci_dev *pdev = to_pci_dev(dev);
49 	struct xe_device *xe = pdev_to_xe_device(pdev);
50 	u32 vram_d3cold_threshold;
51 	int ret;
52 
53 	ret = kstrtou32(buff, 0, &vram_d3cold_threshold);
54 	if (ret)
55 		return ret;
56 
57 	drm_dbg(&xe->drm, "vram_d3cold_threshold: %u\n", vram_d3cold_threshold);
58 
59 	xe_pm_runtime_get(xe);
60 	ret = xe_pm_set_vram_threshold(xe, vram_d3cold_threshold);
61 	xe_pm_runtime_put(xe);
62 
63 	return ret ?: count;
64 }
65 
66 static DEVICE_ATTR_RW(vram_d3cold_threshold);
67 
68 /**
69  * DOC: PCIe Gen5 Limitations
70  *
71  * Default link speed of discrete GPUs is determined by configuration parameters
72  * stored in their flash memory, which are subject to override through user
73  * initiated firmware updates. It has been observed that devices configured with
74  * PCIe Gen5 as their default link speed can come across link quality issues due
75  * to host or motherboard limitations and may have to auto-downgrade their link
76  * to PCIe Gen4 speed when faced with unstable link at Gen5, which makes
77  * firmware updates rather risky on such setups. It is required to ensure that
78  * the device is capable of auto-downgrading its link to PCIe Gen4 speed before
79  * pushing the firmware image with PCIe Gen5 as default configuration. This can
80  * be done by reading ``auto_link_downgrade_capable`` sysfs entry, which will
81  * denote if the device is capable of auto-downgrading its link to PCIe Gen4
82  * speed with boolean output value of ``0`` or ``1``, meaning `incapable` or
83  * `capable` respectively.
84  *
85  * .. code-block:: shell
86  *
87  *    $ cat /sys/bus/pci/devices/<bdf>/auto_link_downgrade_capable
88  *
89  * Pushing the firmware image with PCIe Gen5 as default configuration on a auto
90  * link downgrade incapable device and facing link instability due to host or
91  * motherboard limitations can result in driver failing to bind to the device,
92  * making further firmware updates impossible with RMA being the only last
93  * resort.
94  *
95  * Link downgrade status of auto link downgrade capable devices is available
96  * through ``auto_link_downgrade_status`` sysfs entry with boolean output value
97  * of ``0`` or ``1``, where ``0`` means no auto-downgrading was required during
98  * link training (which is the optimal scenario) and ``1`` means the device has
99  * auto-downgraded its link to PCIe Gen4 speed due to unstable Gen5 link.
100  *
101  * .. code-block:: shell
102  *
103  *    $ cat /sys/bus/pci/devices/<bdf>/auto_link_downgrade_status
104  */
105 
106 static ssize_t
auto_link_downgrade_capable_show(struct device * dev,struct device_attribute * attr,char * buf)107 auto_link_downgrade_capable_show(struct device *dev, struct device_attribute *attr, char *buf)
108 {
109 	struct pci_dev *pdev = to_pci_dev(dev);
110 	struct xe_device *xe = pdev_to_xe_device(pdev);
111 	u32 cap, val;
112 
113 	xe_pm_runtime_get(xe);
114 	val = xe_mmio_read32(xe_root_tile_mmio(xe), BMG_PCIE_CAP);
115 	xe_pm_runtime_put(xe);
116 
117 	cap = REG_FIELD_GET(LINK_DOWNGRADE, val);
118 	return sysfs_emit(buf, "%u\n", cap == DOWNGRADE_CAPABLE);
119 }
120 static DEVICE_ATTR_ADMIN_RO(auto_link_downgrade_capable);
121 
122 static ssize_t
auto_link_downgrade_status_show(struct device * dev,struct device_attribute * attr,char * buf)123 auto_link_downgrade_status_show(struct device *dev, struct device_attribute *attr, char *buf)
124 {
125 	struct pci_dev *pdev = to_pci_dev(dev);
126 	struct xe_device *xe = pdev_to_xe_device(pdev);
127 	/* default the auto_link_downgrade status to 0 */
128 	u32 val = 0;
129 	int ret;
130 
131 	xe_pm_runtime_get(xe);
132 	ret = xe_pcode_read(xe_device_get_root_tile(xe),
133 			    PCODE_MBOX(DGFX_PCODE_STATUS, DGFX_GET_INIT_STATUS, 0),
134 			    &val, NULL);
135 	xe_pm_runtime_put(xe);
136 
137 	return ret ?: sysfs_emit(buf, "%u\n", REG_FIELD_GET(DGFX_LINK_DOWNGRADE_STATUS, val));
138 }
139 static DEVICE_ATTR_ADMIN_RO(auto_link_downgrade_status);
140 
141 static const struct attribute *auto_link_downgrade_attrs[] = {
142 	&dev_attr_auto_link_downgrade_capable.attr,
143 	&dev_attr_auto_link_downgrade_status.attr,
144 	NULL
145 };
146 
xe_device_sysfs_fini(void * arg)147 static void xe_device_sysfs_fini(void *arg)
148 {
149 	struct xe_device *xe = arg;
150 
151 	if (xe->d3cold.capable)
152 		sysfs_remove_file(&xe->drm.dev->kobj, &dev_attr_vram_d3cold_threshold.attr);
153 
154 	if (xe->info.platform == XE_BATTLEMAGE)
155 		sysfs_remove_files(&xe->drm.dev->kobj, auto_link_downgrade_attrs);
156 }
157 
xe_device_sysfs_init(struct xe_device * xe)158 int xe_device_sysfs_init(struct xe_device *xe)
159 {
160 	struct device *dev = xe->drm.dev;
161 	int ret;
162 
163 	if (xe->d3cold.capable) {
164 		ret = sysfs_create_file(&dev->kobj, &dev_attr_vram_d3cold_threshold.attr);
165 		if (ret)
166 			return ret;
167 	}
168 
169 	if (xe->info.platform == XE_BATTLEMAGE) {
170 		ret = sysfs_create_files(&dev->kobj, auto_link_downgrade_attrs);
171 		if (ret)
172 			return ret;
173 	}
174 
175 	return devm_add_action_or_reset(dev, xe_device_sysfs_fini, xe);
176 }
177