mirror of
https://git.proxmox.com/git/fwupd
synced 2025-06-04 13:07:05 +00:00

An undiagnosed kernel issue is leading to a kernel crash involving DP aux reads with amdgpu involved. It's been reproduced in kernel 4.15 with a DKMS version of amdgpu as well as kernel 4.19 with amdgpu within the kernel. ``` [16862.519947] [drm:generic_reg_wait [amdgpu]] *ERROR* REG_WAIT timeout 10us * 160 tries - submit_channel_request line:246 [16862.519983] WARNING: CPU: 5 PID: 3015 at drivers/gpu/drm/amd/amdgpu/../display/dc/dc_helper.c:254 generic_reg_wait+0xe2/0x160 [amdgpu] [16862.519984] Modules linked in: rfcomm snd_hda_codec_realtek snd_hda_codec_generic cmac bnep arc4 nls_iso8859_1 amdkfd amd_iommu_v2 amdgpu i915 dell_rbtn iwlmvm snd_soc_skl wmi_bmof dell_wmi intel_rapl x86_pkg_temp_thermal dell_laptop intel_powerclamp snd_soc_skl_ipc dell_smbios coretemp snd_soc_sst_ipc dell_wmi_descriptor kvm_intel dcdbas snd_soc_sst_dsp snd_hda_ext_core kvmgt dell_smm_hwmon snd_soc_acpi_intel_match mac80211 vfio_mdev crct10dif_pclmul mdev vfio_iommu_type1 crc32_pclmul snd_soc_acpi vfio ghash_clmulni_intel snd_soc_core kvm pcbc snd_compress ac97_bus aesni_intel snd_hda_codec_hdmi snd_pcm_dmaengine chash gpu_sched aes_x86_64 snd_hda_intel crypto_simd snd_hda_codec cryptd ttm glue_helper pcmcia irqbypass snd_hda_core drm_kms_helper intel_cstate intel_rapl_perf snd_hwdep uvcvideo snd_pcm [16862.520008] drm cdc_ether iwlwifi cdc_mbim videobuf2_vmalloc snd_seq_midi videobuf2_memops cdc_ncm snd_seq_midi_event videobuf2_v4l2 snd_rawmidi videobuf2_common videodev input_leds serio_raw btusb qmi_wwan btrtl r8152 snd_seq btbcm media cdc_wdm btintel usbnet option mii usb_wwan bluetooth usbserial cdc_acm hid_multitouch joydev snd_seq_device snd_timer cfg80211 snd yenta_socket pcmcia_rsrc idma64 pcmcia_core soundcore virt_dma i2c_algo_bit fb_sys_fops syscopyarea mei_me sysfillrect ecdh_generic sysimgblt mei ucsi_acpi intel_lpss_pci processor_thermal_device typec_ucsi intel_lpss intel_soc_dts_iosf intel_pch_thermal typec wmi soc_button_array mac_hid intel_hid int3400_thermal video int3403_thermal dell_smo8800 sparse_keymap acpi_thermal_rel int340x_thermal_zone acpi_pad sch_fq_codel parport_pc [16862.520033] ppdev lp parport ip_tables x_tables autofs4 hid_generic usbhid uas usb_storage e1000e ahci libahci i2c_hid hid [16862.520040] CPU: 5 PID: 3015 Comm: fwupd Not tainted 4.19.0 #1 [16862.520040] Hardware name: Dell Inc. Latitude 7424 Rugged Extreme/, BIOS 1.0.0 09/12/2018 [16862.520062] RIP: 0010:generic_reg_wait+0xe2/0x160 [amdgpu] [16862.520063] Code: ab 44 8b 45 20 48 8b 4d 18 44 89 e6 8b 55 10 48 c7 c7 f0 bf 12 c1 44 89 4d d4 e8 79 1d 65 ff 41 83 7d 18 01 44 8b 4d d4 74 02 <0f> 0b 48 83 c4 18 44 89 c8 5b 41 5c 41 5d 41 5e 41 5f 5d c3 41 0f [16862.520064] RSP: 0018:ffffbdff831ffbe0 EFLAGS: 00010297 [16862.520065] RAX: 0000000000000000 RBX: 00000000000000a1 RCX: 0000000000000000 [16862.520065] RDX: 0000000000000000 RSI: ffff965fee356428 RDI: ffff965fee356428 [16862.520066] RBP: ffffbdff831ffc20 R08: 00000000000004d5 R09: 00000000ffffffff [16862.520066] R10: fffff464915dbd00 R11: ffffffff981923ed R12: 000000000000000a [16862.520067] R13: ffff965fdea5d480 R14: 0000000000000001 R15: 0000000000000000 [16862.520068] FS: 00007f17444485c0(0000) GS:ffff965fee340000(0000) knlGS:0000000000000000 [16862.520068] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [16862.520069] CR2: 00007f1732987150 CR3: 000000045f4fe006 CR4: 00000000003606e0 [16862.520070] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [16862.520070] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [16862.520070] Call Trace: [16862.520097] submit_channel_request+0x394/0x480 [amdgpu] [16862.520118] dc_link_aux_transfer+0xca/0x160 [amdgpu] [16862.520142] dm_dp_aux_transfer+0x59/0x120 [amdgpu] [16862.520146] drm_dp_dpcd_access+0x75/0x110 [drm_kms_helper] [16862.520148] drm_dp_dpcd_read+0x33/0xc0 [drm_kms_helper] [16862.520152] auxdev_read_iter+0x10f/0x1d0 [drm_kms_helper] [16862.520154] __vfs_read+0x106/0x180 [16862.520155] vfs_read+0x8e/0x130 [16862.520156] ksys_read+0x55/0xc0 [16862.520157] __x64_sys_read+0x1a/0x20 [16862.520159] do_syscall_64+0x5a/0x120 [16862.520161] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [16862.520162] RIP: 0033:0x7f1741b3a384 [16862.520163] Code: 84 00 00 00 00 00 41 54 55 49 89 d4 53 48 89 f5 89 fb 48 83 ec 10 e8 8b fc ff ff 4c 89 e2 41 89 c0 48 89 ee 89 df 31 c0 0f 05 <48> 3d 00 f0 ff ff 77 38 44 89 c7 48 89 44 24 08 e8 c7 fc ff ff 48 [16862.520163] RSP: 002b:00007fffadd980f0 EFLAGS: 00000246 ORIG_RAX: 0000000000000000 [16862.520164] RAX: ffffffffffffffda RBX: 0000000000000013 RCX: 00007f1741b3a384 [16862.520165] RDX: 0000000000000001 RSI: 00007fffadd98154 RDI: 0000000000000013 [16862.520165] RBP: 00007fffadd98154 R08: 0000000000000000 R09: 000055fd7e9c7010 [16862.520166] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000001 [16862.520166] R13: 00007fffadd981c0 R14: 00007fffadd98154 R15: 000055fd7eae35b0 [16862.520167] ---[ end trace 8e8b280a234718a5 ]--- [16862.520176] BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 [16862.520177] PGD 0 P4D 0 [16862.520179] Oops: 0000 [#1] SMP PTI [16862.520180] CPU: 5 PID: 3015 Comm: fwupd Tainted: G W 4.19.0 #1 [16862.520181] Hardware name: Dell Inc. Latitude 7424 Rugged Extreme/, BIOS 1.0.0 09/12/2018 [16862.520205] RIP: 0010:dal_ddc_close+0xd/0x30 [amdgpu] [16862.520207] Code: f1 00 e8 06 f5 ff ff 48 8b 55 f8 65 48 33 14 25 28 00 00 00 75 02 c9 c3 e8 70 09 65 d5 0f 1f 44 00 00 55 48 89 e5 53 48 89 fb <48> 8b 7f 08 e8 da f5 ff ff 48 8b 3b e8 d2 f5 ff ff 5b 5d c3 66 2e [16862.520208] RSP: 0018:ffffbdff831ffc58 EFLAGS: 00010246 [16862.520209] RAX: ffffffffc103f410 RBX: 0000000000000000 RCX: 0000000000000000 [16862.520210] RDX: ffffffffc10de660 RSI: 0000000000005c58 RDI: 0000000000000000 [16862.520211] RBP: ffffbdff831ffc60 R08: 0000000000000001 R09: 00000000ffffffff [16862.520211] R10: fffff464915dbd00 R11: 0000000000000001 R12: 0000000000000000 [16862.520212] R13: ffffbdff831ffdd0 R14: ffffbdff831ffd3d R15: 0000000000000000 [16862.520213] FS: 00007f17444485c0(0000) GS:ffff965fee340000(0000) knlGS:0000000000000000 [16862.520214] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [16862.520215] CR2: 0000000000000008 CR3: 000000045f4fe006 CR4: 00000000003606e0 [16862.520216] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [16862.520217] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [16862.520218] Call Trace: [16862.520242] release_engine+0x16/0x70 [amdgpu] [16862.520263] dc_link_aux_transfer+0xfd/0x160 [amdgpu] [16862.520287] dm_dp_aux_transfer+0x59/0x120 [amdgpu] [16862.520290] drm_dp_dpcd_access+0x75/0x110 [drm_kms_helper] [16862.520293] drm_dp_dpcd_read+0x33/0xc0 [drm_kms_helper] [16862.520296] auxdev_read_iter+0x10f/0x1d0 [drm_kms_helper] [16862.520298] __vfs_read+0x106/0x180 [16862.520300] vfs_read+0x8e/0x130 [16862.520301] ksys_read+0x55/0xc0 [16862.520302] __x64_sys_read+0x1a/0x20 [16862.520304] do_syscall_64+0x5a/0x120 [16862.520306] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [16862.520307] RIP: 0033:0x7f1741b3a384 [16862.520308] Code: 84 00 00 00 00 00 41 54 55 49 89 d4 53 48 89 f5 89 fb 48 83 ec 10 e8 8b fc ff ff 4c 89 e2 41 89 c0 48 89 ee 89 df 31 c0 0f 05 <48> 3d 00 f0 ff ff 77 38 44 89 c7 48 89 44 24 08 e8 c7 fc ff ff 48 [16862.520309] RSP: 002b:00007fffadd980f0 EFLAGS: 00000246 ORIG_RAX: 0000000000000000 [16862.520310] RAX: ffffffffffffffda RBX: 0000000000000013 RCX: 00007f1741b3a384 [16862.520311] RDX: 0000000000000001 RSI: 00007fffadd98154 RDI: 0000000000000013 [16862.520312] RBP: 00007fffadd98154 R08: 0000000000000000 R09: 000055fd7e9c7010 [16862.520312] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000001 [16862.520313] R13: 00007fffadd981c0 R14: 00007fffadd98154 R15: 000055fd7eae35b0 [16862.520314] Modules linked in: rfcomm snd_hda_codec_realtek snd_hda_codec_generic cmac bnep arc4 nls_iso8859_1 amdkfd amd_iommu_v2 amdgpu i915 dell_rbtn iwlmvm snd_soc_skl wmi_bmof dell_wmi intel_rapl x86_pkg_temp_thermal dell_laptop intel_powerclamp snd_soc_skl_ipc dell_smbios coretemp snd_soc_sst_ipc dell_wmi_descriptor kvm_intel dcdbas snd_soc_sst_dsp snd_hda_ext_core kvmgt dell_smm_hwmon snd_soc_acpi_intel_match mac80211 vfio_mdev crct10dif_pclmul mdev vfio_iommu_type1 crc32_pclmul snd_soc_acpi vfio ghash_clmulni_intel snd_soc_core kvm pcbc snd_compress ac97_bus aesni_intel snd_hda_codec_hdmi snd_pcm_dmaengine chash gpu_sched aes_x86_64 snd_hda_intel crypto_simd snd_hda_codec cryptd ttm glue_helper pcmcia irqbypass snd_hda_core drm_kms_helper intel_cstate intel_rapl_perf snd_hwdep uvcvideo snd_pcm [16862.520332] drm cdc_ether iwlwifi cdc_mbim videobuf2_vmalloc snd_seq_midi videobuf2_memops cdc_ncm snd_seq_midi_event videobuf2_v4l2 snd_rawmidi videobuf2_common videodev input_leds serio_raw btusb qmi_wwan btrtl r8152 snd_seq btbcm media cdc_wdm btintel usbnet option mii usb_wwan bluetooth usbserial cdc_acm hid_multitouch joydev snd_seq_device snd_timer cfg80211 snd yenta_socket pcmcia_rsrc idma64 pcmcia_core soundcore virt_dma i2c_algo_bit fb_sys_fops syscopyarea mei_me sysfillrect ecdh_generic sysimgblt mei ucsi_acpi intel_lpss_pci processor_thermal_device typec_ucsi intel_lpss intel_soc_dts_iosf intel_pch_thermal typec wmi soc_button_array mac_hid intel_hid int3400_thermal video int3403_thermal dell_smo8800 sparse_keymap acpi_thermal_rel int340x_thermal_zone acpi_pad sch_fq_codel parport_pc [16862.520351] ppdev lp parport ip_tables x_tables autofs4 hid_generic usbhid uas usb_storage e1000e ahci libahci i2c_hid hid [16862.520356] CR2: 0000000000000008 [16862.520357] ---[ end trace 8e8b280a234718a6 ]--- [16862.520380] RIP: 0010:dal_ddc_close+0xd/0x30 [amdgpu] [16862.520382] Code: f1 00 e8 06 f5 ff ff 48 8b 55 f8 65 48 33 14 25 28 00 00 00 75 02 c9 c3 e8 70 09 65 d5 0f 1f 44 00 00 55 48 89 e5 53 48 89 fb <48> 8b 7f 08 e8 da f5 ff ff 48 8b 3b e8 d2 f5 ff ff 5b 5d c3 66 2e [16862.520382] RSP: 0018:ffffbdff831ffc58 EFLAGS: 00010246 [16862.520384] RAX: ffffffffc103f410 RBX: 0000000000000000 RCX: 0000000000000000 [16862.520384] RDX: ffffffffc10de660 RSI: 0000000000005c58 RDI: 0000000000000000 [16862.520385] RBP: ffffbdff831ffc60 R08: 0000000000000001 R09: 00000000ffffffff [16862.520386] R10: fffff464915dbd00 R11: 0000000000000001 R12: 0000000000000000 [16862.520387] R13: ffffbdff831ffdd0 R14: ffffbdff831ffd3d R15: 0000000000000000 [16862.520388] FS: 00007f17444485c0(0000) GS:ffff965fee340000(0000) knlGS:0000000000000000 [16862.520389] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [16862.520390] CR2: 0000000000000008 CR3: 000000045f4fe006 CR4: 00000000003606e0 [16862.520391] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [16862.520392] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 ```
504 lines
15 KiB
C
504 lines
15 KiB
C
/*
|
|
* Copyright (C) 2017 Mario Limonciello <mario.limonciello@dell.com>
|
|
* Copyright (C) 2017 Peichen Huang <peichenhuang@tw.synaptics.com>
|
|
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "synapticsmst-device.h"
|
|
#include "synapticsmst-common.h"
|
|
#include "fu-plugin-vfuncs.h"
|
|
#include "fu-device-metadata.h"
|
|
|
|
#define SYNAPTICS_FLASH_MODE_DELAY 3
|
|
#define SYNAPTICS_UPDATE_ENUMERATE_TRIES 3
|
|
|
|
static gboolean
|
|
syanpticsmst_check_amdgpu_safe (GError **error)
|
|
{
|
|
gsize bufsz = 0;
|
|
g_autofree gchar *buf = NULL;
|
|
g_auto(GStrv) lines = NULL;
|
|
|
|
if (!g_file_get_contents ("/proc/modules", &buf, &bufsz, error))
|
|
return FALSE;
|
|
|
|
lines = g_strsplit (buf, "\n", -1);
|
|
for (guint i = 0; lines[i] != NULL; i++) {
|
|
if (g_str_has_prefix (lines[i], "amdgpu ")) {
|
|
g_set_error_literal (error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INTERNAL,
|
|
"amdgpu has known issues with synapticsmst");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
synapticsmst_common_check_supported_system (FuPlugin *plugin, GError **error)
|
|
{
|
|
|
|
if (g_getenv ("FWUPD_SYNAPTICSMST_FW_DIR") != NULL) {
|
|
g_debug ("Running Synaptics plugin in test mode");
|
|
return TRUE;
|
|
}
|
|
|
|
/* See https://github.com/hughsie/fwupd/issues/1121 for more details */
|
|
if (!syanpticsmst_check_amdgpu_safe (error))
|
|
return FALSE;
|
|
|
|
if (!g_file_test (SYSFS_DRM_DP_AUX, G_FILE_TEST_IS_DIR)) {
|
|
g_set_error (error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_INVALID_DATA,
|
|
"MST firmware updating not supported, missing kernel support.");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* creates MST-$str-$BOARDID */
|
|
static void
|
|
fu_plugin_synapticsmst_create_simple_guid (FuDevice *fu_device,
|
|
SynapticsMSTDevice *device,
|
|
const gchar *str)
|
|
{
|
|
guint16 board_id = synapticsmst_device_get_board_id (device);
|
|
g_autofree gchar *devid = g_strdup_printf ("MST-%s-%u", str, board_id);
|
|
fu_device_add_instance_id (fu_device, devid);
|
|
}
|
|
|
|
/* creates MST-$str-$chipid-$BOARDID */
|
|
static void
|
|
fu_plugin_synapticsmst_create_complex_guid (FuDevice *fu_device,
|
|
SynapticsMSTDevice *device,
|
|
const gchar *device_kind)
|
|
{
|
|
const gchar *chip_id_str = synapticsmst_device_get_chip_id_str (device);
|
|
g_autofree gchar *chip_id_down = g_ascii_strdown (chip_id_str, -1);
|
|
g_autofree gchar *tmp = g_strdup_printf ("%s-%s", device_kind, chip_id_down);
|
|
|
|
fu_plugin_synapticsmst_create_simple_guid (fu_device, device, tmp);
|
|
}
|
|
|
|
static gboolean
|
|
fu_plugin_synapticsmst_lookup_device (FuPlugin *plugin,
|
|
FuDevice *fu_device,
|
|
SynapticsMSTDevice *device,
|
|
GError **error)
|
|
{
|
|
const gchar *board_str;
|
|
const gchar *guid_template;
|
|
guint16 board_id = synapticsmst_device_get_board_id (device);
|
|
const gchar *chip_id_str = synapticsmst_device_get_chip_id_str (device);
|
|
g_autofree gchar *group = NULL;
|
|
g_autofree gchar *name = NULL;
|
|
|
|
/* GUIDs used only for test mode */
|
|
if (g_getenv ("FWUPD_SYNAPTICSMST_FW_DIR") != NULL) {
|
|
g_autofree gchar *tmp = NULL;
|
|
tmp = g_strdup_printf ("test-%s", chip_id_str);
|
|
fu_plugin_synapticsmst_create_simple_guid (fu_device, device, tmp);
|
|
return TRUE;
|
|
}
|
|
|
|
/* set up the device name via quirks */
|
|
group = g_strdup_printf ("SynapticsMSTBoardID=%u", board_id);
|
|
board_str = fu_plugin_lookup_quirk_by_id (plugin, group,
|
|
FU_QUIRKS_NAME);
|
|
if (board_str == NULL)
|
|
board_str = "Unknown Platform";
|
|
name = g_strdup_printf ("Synaptics %s inside %s", synapticsmst_device_get_chip_id_str (device),
|
|
board_str);
|
|
fu_device_set_name (fu_device, name);
|
|
|
|
/* build the GUIDs for the device */
|
|
guid_template = fu_plugin_lookup_quirk_by_id (plugin, group, "DeviceKind");
|
|
/* no quirks defined for this board */
|
|
if (guid_template == NULL) {
|
|
g_set_error (error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_NOT_SUPPORTED,
|
|
"Unknown board_id %x",
|
|
board_id);
|
|
return FALSE;
|
|
|
|
/* this is a host system, use system ID */
|
|
} else if (g_strcmp0 (guid_template, "system") == 0) {
|
|
const gchar *system_type = fu_plugin_get_dmi_value (plugin,
|
|
FU_HWIDS_KEY_PRODUCT_SKU);
|
|
fu_plugin_synapticsmst_create_simple_guid (fu_device, device,
|
|
system_type);
|
|
/* docks or something else */
|
|
} else {
|
|
g_auto(GStrv) templates = NULL;
|
|
templates = g_strsplit (guid_template, ",", -1);
|
|
for (guint i = 0; templates[i] != NULL; i++) {
|
|
fu_plugin_synapticsmst_create_complex_guid (fu_device,
|
|
device,
|
|
templates[i]);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_plugin_synaptics_add_device (FuPlugin *plugin,
|
|
SynapticsMSTDevice *device,
|
|
GError **error)
|
|
{
|
|
g_autoptr(FuDevice) dev = NULL;
|
|
const gchar *kind_str = NULL;
|
|
g_autofree gchar *dev_id_str = NULL;
|
|
g_autofree gchar *layer_str = NULL;
|
|
g_autofree gchar *rad_str = NULL;
|
|
const gchar *aux_node;
|
|
guint8 layer;
|
|
guint16 rad;
|
|
|
|
aux_node = synapticsmst_device_get_aux_node (device);
|
|
if (!synapticsmst_device_enumerate_device (device,
|
|
error)) {
|
|
g_prefix_error (error, "Error enumerating device at %s: ", aux_node);
|
|
return FALSE;
|
|
}
|
|
|
|
/* create the device */
|
|
dev = fu_device_new ();
|
|
/* Store $KIND-$AUXNODE-$LAYER-$RAD as device ID */
|
|
layer = synapticsmst_device_get_layer (device);
|
|
rad = synapticsmst_device_get_rad (device);
|
|
kind_str = synapticsmst_device_kind_to_string (synapticsmst_device_get_kind (device));
|
|
dev_id_str = g_strdup_printf ("MST-%s-%s-%u-%u",
|
|
kind_str, aux_node, layer, rad);
|
|
fu_device_set_id (dev, dev_id_str);
|
|
fu_device_set_physical_id (dev, aux_node);
|
|
fu_device_set_metadata (dev, "SynapticsMSTKind", kind_str);
|
|
fu_device_set_metadata (dev, "SynapticsMSTAuxNode", aux_node);
|
|
layer_str = g_strdup_printf ("%u", layer);
|
|
fu_device_set_metadata (dev, "SynapticsMSTLayer", layer_str);
|
|
rad_str = g_strdup_printf ("%u", rad);
|
|
fu_device_set_metadata (dev, "SynapticsMSTRad", rad_str);
|
|
fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE);
|
|
fu_device_set_vendor (dev, "Synaptics");
|
|
fu_device_set_summary (dev, "Multi-Stream Transport Device");
|
|
fu_device_add_icon (dev, "computer");
|
|
fu_device_set_version (dev, synapticsmst_device_get_version (device));
|
|
fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin));
|
|
|
|
/* create GUIDs and name */
|
|
if (!fu_plugin_synapticsmst_lookup_device (plugin, dev, device, error))
|
|
return FALSE;
|
|
|
|
fu_plugin_device_add (plugin, dev);
|
|
fu_plugin_cache_add (plugin, dev_id_str, dev);
|
|
|
|
/* inhibit the idle sleep of the daemon */
|
|
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE,
|
|
"SynapticsMST can cause the screen to flash when probing");
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_plugin_synaptics_scan_cascade (FuPlugin *plugin,
|
|
SynapticsMSTDevice *device,
|
|
GError **error)
|
|
{
|
|
g_autoptr(SynapticsMSTDevice) cascade_device = NULL;
|
|
FuDevice *fu_dev = NULL;
|
|
const gchar *aux_node;
|
|
|
|
aux_node = synapticsmst_device_get_aux_node (device);
|
|
if (!synapticsmst_device_open (device, error)) {
|
|
g_prefix_error (error,
|
|
"failed to open aux node %s again",
|
|
aux_node);
|
|
return FALSE;
|
|
}
|
|
|
|
for (guint8 j = 0; j < 2; j++) {
|
|
guint8 layer = synapticsmst_device_get_layer (device) + 1;
|
|
guint16 rad = synapticsmst_device_get_rad (device) | (j << (2 * (layer - 1)));
|
|
g_autofree gchar *dev_id_str = NULL;
|
|
dev_id_str = g_strdup_printf ("MST-REMOTE-%s-%u-%u",
|
|
aux_node, layer, rad);
|
|
fu_dev = fu_plugin_cache_lookup (plugin, dev_id_str);
|
|
|
|
/* run the scan */
|
|
if (!synapticsmst_device_scan_cascade_device (device, error, j))
|
|
return FALSE;
|
|
|
|
/* check if cascaded device was found */
|
|
if (!synapticsmst_device_get_cascade (device)) {
|
|
/* not found, nothing new to see here, move along */
|
|
if (fu_dev == NULL)
|
|
continue;
|
|
/* not found, but should have existed - remove it */
|
|
else {
|
|
fu_plugin_device_remove (plugin, fu_dev);
|
|
fu_plugin_cache_remove (plugin, dev_id_str);
|
|
/* don't scan any deeper on this node */
|
|
continue;
|
|
}
|
|
/* Found a device, add it */
|
|
} else {
|
|
cascade_device = synapticsmst_device_new (SYNAPTICSMST_DEVICE_KIND_REMOTE,
|
|
aux_node, layer, rad);
|
|
/* new device */
|
|
if (fu_dev == NULL) {
|
|
g_debug ("Adding remote device %s", dev_id_str);
|
|
if (!fu_plugin_synaptics_add_device (plugin, cascade_device, error))
|
|
return FALSE;
|
|
}
|
|
else
|
|
g_debug ("Skipping previously added device %s",
|
|
dev_id_str);
|
|
|
|
/* check recursively for more devices */
|
|
if (!fu_plugin_synaptics_scan_cascade (plugin, cascade_device, error))
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
fu_plugin_synapticsmst_remove_cascaded (FuPlugin *plugin, const gchar *aux_node)
|
|
{
|
|
FuDevice *fu_dev = NULL;
|
|
|
|
for (guint8 i = 0; i < 8; i++) {
|
|
for (guint16 j = 0; j < 256; j++) {
|
|
g_autofree gchar *dev_id_str = NULL;
|
|
dev_id_str = g_strdup_printf ("MST-REMOTE-%s-%u-%u",
|
|
aux_node, i, j);
|
|
fu_dev = fu_plugin_cache_lookup (plugin, dev_id_str);
|
|
if (fu_dev != NULL) {
|
|
fu_plugin_device_remove (plugin, fu_dev);
|
|
fu_plugin_cache_remove (plugin, dev_id_str);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
fu_plugin_synapticsmst_enumerate (FuPlugin *plugin,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GDir) dir = NULL;
|
|
const gchar *dp_aux_dir;
|
|
const gchar *aux_node = NULL;
|
|
|
|
dp_aux_dir = g_getenv ("FWUPD_SYNAPTICSMST_FW_DIR");
|
|
if (dp_aux_dir == NULL)
|
|
dp_aux_dir = SYSFS_DRM_DP_AUX;
|
|
else
|
|
g_debug ("Using %s to look for MST devices", dp_aux_dir);
|
|
dir = g_dir_open (dp_aux_dir, 0, NULL);
|
|
do {
|
|
g_autofree gchar *dev_id_str = NULL;
|
|
g_autoptr(GError) error_local = NULL;
|
|
g_autoptr(SynapticsMSTDevice) device = NULL;
|
|
FuDevice *fu_dev = NULL;
|
|
|
|
aux_node = g_dir_read_name (dir);
|
|
if (aux_node == NULL)
|
|
break;
|
|
|
|
dev_id_str = g_strdup_printf ("MST-DIRECT-%s-0-0", aux_node);
|
|
fu_dev = fu_plugin_cache_lookup (plugin, dev_id_str);
|
|
|
|
/* If we open succesfully a device exists here */
|
|
device = synapticsmst_device_new (SYNAPTICSMST_DEVICE_KIND_DIRECT, aux_node, 0, 0);
|
|
if (!synapticsmst_device_open (device, &error_local)) {
|
|
/* No device exists here, but was there - remove from DB */
|
|
if (fu_dev != NULL) {
|
|
g_debug ("Removing devices on %s", aux_node);
|
|
fu_plugin_device_remove (plugin, fu_dev);
|
|
fu_plugin_cache_remove (plugin, dev_id_str);
|
|
fu_plugin_synapticsmst_remove_cascaded (plugin,
|
|
aux_node);
|
|
} else {
|
|
/* Nothing to see here - move on*/
|
|
g_debug ("No device found on %s: %s", aux_node, error_local->message);
|
|
g_clear_error (&error_local);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* Add direct devices */
|
|
if (fu_dev == NULL) {
|
|
g_debug ("Adding direct device %s", dev_id_str);
|
|
if (!fu_plugin_synaptics_add_device (plugin, device, &error_local))
|
|
g_debug ("failed to add device: %s", error_local->message);
|
|
} else {
|
|
g_debug ("Skipping previously added device %s", dev_id_str);
|
|
}
|
|
|
|
/* recursively look for cascade devices */
|
|
if (!fu_plugin_synaptics_scan_cascade (plugin, device, error))
|
|
return FALSE;
|
|
} while(TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
fu_synapticsmst_write_progress_cb (goffset current, goffset total, gpointer user_data)
|
|
{
|
|
FuDevice *device = FU_DEVICE (user_data);
|
|
fu_device_set_progress_full (device, current, total);
|
|
}
|
|
|
|
gboolean
|
|
fu_plugin_update (FuPlugin *plugin,
|
|
FuDevice *dev,
|
|
GBytes *blob_fw,
|
|
FwupdInstallFlags flags,
|
|
GError **error)
|
|
{
|
|
g_autoptr(SynapticsMSTDevice) device = NULL;
|
|
SynapticsMSTDeviceKind kind;
|
|
const gchar *aux_node;
|
|
guint8 layer;
|
|
guint8 rad;
|
|
gboolean reboot;
|
|
gboolean install_force;
|
|
|
|
/* extract details to build a new device */
|
|
kind = synapticsmst_device_kind_from_string (fu_device_get_metadata (dev, "SynapticsMSTKind"));
|
|
aux_node = fu_device_get_metadata (dev, "SynapticsMSTAuxNode");
|
|
layer = g_ascii_strtoull (fu_device_get_metadata (dev, "SynapticsMSTLayer"), NULL, 0);
|
|
rad = g_ascii_strtoull (fu_device_get_metadata (dev, "SynapticsMSTRad"), NULL, 0);
|
|
|
|
|
|
/* sleep to allow device wakeup to complete */
|
|
g_debug ("waiting %d seconds for MST hub wakeup",
|
|
SYNAPTICS_FLASH_MODE_DELAY);
|
|
fu_device_set_status (dev, FWUPD_STATUS_DEVICE_BUSY);
|
|
g_usleep (SYNAPTICS_FLASH_MODE_DELAY * 1000000);
|
|
|
|
device = synapticsmst_device_new (kind, aux_node, layer, rad);
|
|
|
|
if (!synapticsmst_device_enumerate_device (device, error))
|
|
return FALSE;
|
|
reboot = !fu_device_has_custom_flag (dev, "skip-restart");
|
|
install_force = (flags & FWUPD_INSTALL_FLAG_FORCE) != 0 ||
|
|
fu_device_has_custom_flag (dev, "ignore-board-id");
|
|
fu_device_set_status (dev, FWUPD_STATUS_DEVICE_WRITE);
|
|
if (!synapticsmst_device_write_firmware (device, blob_fw,
|
|
fu_synapticsmst_write_progress_cb,
|
|
dev,
|
|
reboot,
|
|
install_force,
|
|
error)) {
|
|
g_prefix_error (error, "failed to flash firmware: ");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!reboot) {
|
|
g_debug ("Skipping device restart per quirk request");
|
|
return TRUE;
|
|
}
|
|
|
|
/* Re-run device enumeration to find the new device version */
|
|
fu_device_set_status (dev, FWUPD_STATUS_DEVICE_RESTART);
|
|
for (guint i = 1; i <= SYNAPTICS_UPDATE_ENUMERATE_TRIES; i++) {
|
|
g_autoptr(GError) error_local = NULL;
|
|
g_usleep (SYNAPTICS_FLASH_MODE_DELAY * 1000000);
|
|
if (!synapticsmst_device_enumerate_device (device,
|
|
&error_local)) {
|
|
g_warning ("Unable to find device after %u seconds: %s",
|
|
SYNAPTICS_FLASH_MODE_DELAY * i,
|
|
error_local->message);
|
|
if (i == SYNAPTICS_UPDATE_ENUMERATE_TRIES) {
|
|
g_set_error (error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INTERNAL,
|
|
"%s",
|
|
error_local->message);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
fu_device_set_version (dev, synapticsmst_device_get_version (device));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
fu_plugin_device_removed (FuPlugin *plugin, FuDevice *device, GError **error)
|
|
{
|
|
const gchar *aux_node;
|
|
const gchar *kind_str;
|
|
const gchar *layer_str;
|
|
const gchar *rad_str;
|
|
g_autofree gchar *dev_id_str = NULL;
|
|
|
|
aux_node = fu_device_get_metadata (device, "SynapticsMSTAuxNode");
|
|
if (aux_node == NULL)
|
|
return TRUE;
|
|
kind_str = fu_device_get_metadata (device, "SynapticsMSTKind");
|
|
if (kind_str == NULL)
|
|
return TRUE;
|
|
layer_str = fu_device_get_metadata (device, "SynapticsMSTLayer");
|
|
if (layer_str == NULL)
|
|
return TRUE;
|
|
rad_str = fu_device_get_metadata (device, "SynapticsMSTRad");
|
|
if (rad_str == NULL)
|
|
return TRUE;
|
|
dev_id_str = g_strdup_printf ("MST-%s-%s-%s-%s",
|
|
kind_str, aux_node, layer_str, rad_str);
|
|
if (fu_plugin_cache_lookup (plugin, dev_id_str) != NULL) {
|
|
g_debug ("Removing %s from cache", dev_id_str);
|
|
fu_plugin_cache_remove (plugin, dev_id_str);
|
|
} else {
|
|
g_debug ("%s constructed but not found in cache", dev_id_str);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_plugin_synapticsmst_coldplug (FuPlugin *plugin, GError **error)
|
|
{
|
|
g_autoptr(GError) error_local = NULL;
|
|
/* verify that this is a supported system */
|
|
if (!synapticsmst_common_check_supported_system (plugin, error))
|
|
return FALSE;
|
|
|
|
/* look for host devices or already plugged in dock devices */
|
|
if (!fu_plugin_synapticsmst_enumerate (plugin, &error_local))
|
|
g_debug ("error enumerating: %s", error_local->message);
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
fu_plugin_coldplug (FuPlugin *plugin, GError **error)
|
|
{
|
|
return fu_plugin_synapticsmst_coldplug (plugin, error);
|
|
}
|
|
|
|
gboolean
|
|
fu_plugin_recoldplug (FuPlugin *plugin, GError **error)
|
|
{
|
|
return fu_plugin_synapticsmst_coldplug (plugin, error);
|
|
}
|
|
|
|
|
|
void
|
|
fu_plugin_init (FuPlugin *plugin)
|
|
{
|
|
/* make sure dell is already coldplugged */
|
|
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "dell");
|
|
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.synaptics.mst");
|
|
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
|
|
}
|