3
3
* Copyright © 2023 Intel Corporation
4
4
*/
5
5
6
+ #include <linux/device.h>
6
7
#include <linux/kobject.h>
7
8
#include <linux/pci.h>
8
9
#include <linux/sysfs.h>
9
10
10
- #include <drm/drm_managed.h>
11
-
12
11
#include "xe_device.h"
13
12
#include "xe_device_sysfs.h"
13
+ #include "xe_mmio.h"
14
+ #include "xe_pcode_api.h"
15
+ #include "xe_pcode.h"
14
16
#include "xe_pm.h"
15
17
16
18
/**
@@ -63,12 +65,93 @@ vram_d3cold_threshold_store(struct device *dev, struct device_attribute *attr,
63
65
64
66
static DEVICE_ATTR_RW (vram_d3cold_threshold );
65
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
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 ? true : false);
119
+ }
120
+ static DEVICE_ATTR_ADMIN_RO (auto_link_downgrade_capable );
121
+
122
+ static ssize_t
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
+ u32 val ;
128
+ int ret ;
129
+
130
+ xe_pm_runtime_get (xe );
131
+ ret = xe_pcode_read (xe_device_get_root_tile (xe ),
132
+ PCODE_MBOX (DGFX_PCODE_STATUS , DGFX_GET_INIT_STATUS , 0 ),
133
+ & val , NULL );
134
+ xe_pm_runtime_put (xe );
135
+
136
+ return ret ?: sysfs_emit (buf , "%u\n" , REG_FIELD_GET (DGFX_LINK_DOWNGRADE_STATUS , val ));
137
+ }
138
+ static DEVICE_ATTR_ADMIN_RO (auto_link_downgrade_status );
139
+
140
+ static const struct attribute * auto_link_downgrade_attrs [] = {
141
+ & dev_attr_auto_link_downgrade_capable .attr ,
142
+ & dev_attr_auto_link_downgrade_status .attr ,
143
+ NULL
144
+ };
145
+
66
146
static void xe_device_sysfs_fini (void * arg )
67
147
{
68
148
struct xe_device * xe = arg ;
69
149
70
150
if (xe -> d3cold .capable )
71
151
sysfs_remove_file (& xe -> drm .dev -> kobj , & dev_attr_vram_d3cold_threshold .attr );
152
+
153
+ if (xe -> info .platform == XE_BATTLEMAGE )
154
+ sysfs_remove_files (& xe -> drm .dev -> kobj , auto_link_downgrade_attrs );
72
155
}
73
156
74
157
int xe_device_sysfs_init (struct xe_device * xe )
@@ -82,5 +165,11 @@ int xe_device_sysfs_init(struct xe_device *xe)
82
165
return ret ;
83
166
}
84
167
168
+ if (xe -> info .platform == XE_BATTLEMAGE ) {
169
+ ret = sysfs_create_files (& dev -> kobj , auto_link_downgrade_attrs );
170
+ if (ret )
171
+ return ret ;
172
+ }
173
+
85
174
return devm_add_action_or_reset (dev , xe_device_sysfs_fini , xe );
86
175
}
0 commit comments