33 * Copyright © 2023 Intel Corporation
44 */
55
6+ #include <linux/device.h>
67#include <linux/kobject.h>
78#include <linux/pci.h>
89#include <linux/sysfs.h>
910
10- #include <drm/drm_managed.h>
11-
1211#include "xe_device.h"
1312#include "xe_device_sysfs.h"
13+ #include "xe_mmio.h"
14+ #include "xe_pcode_api.h"
15+ #include "xe_pcode.h"
1416#include "xe_pm.h"
1517
1618/**
@@ -63,12 +65,93 @@ vram_d3cold_threshold_store(struct device *dev, struct device_attribute *attr,
6365
6466static DEVICE_ATTR_RW (vram_d3cold_threshold );
6567
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+
66146static void xe_device_sysfs_fini (void * arg )
67147{
68148 struct xe_device * xe = arg ;
69149
70150 if (xe -> d3cold .capable )
71151 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 );
72155}
73156
74157int xe_device_sysfs_init (struct xe_device * xe )
@@ -82,5 +165,11 @@ int xe_device_sysfs_init(struct xe_device *xe)
82165 return ret ;
83166 }
84167
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+
85174 return devm_add_action_or_reset (dev , xe_device_sysfs_fini , xe );
86175}
0 commit comments