Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: trace: Add generic RAS tracepoint for hotplug event

Hotplug events are critical indicators for analyzing hardware health, and
surprise link downs can significantly impact system performance and
reliability.

Define a new TRACING_SYSTEM named "pci", add a generic RAS tracepoint
for hotplug event to help health checks. Add enum pci_hotplug_event in
include/uapi/linux/pci.h so applications like rasdaemon can register
tracepoint event handlers for it.

The following output is generated when a device is hotplugged:

$ echo 1 > /sys/kernel/debug/tracing/events/pci/pci_hp_event/enable
$ cat /sys/kernel/debug/tracing/trace_pipe
irq/51-pciehp-88 [001] ..... 1311.177459: pci_hp_event: 0000:00:02.0 slot:10, event:CARD_PRESENT

irq/51-pciehp-88 [001] ..... 1311.177566: pci_hp_event: 0000:00:02.0 slot:10, event:LINK_UP

Suggested-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Lukas Wunner <lukas@wunner.de>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org> # for trace event
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://patch.msgid.link/20251210132907.58799-2-xueshuai@linux.alibaba.com

authored by

Shuai Xue and committed by
Bjorn Helgaas
9e541b3c 8f0b4cce

+118 -6
+3
drivers/pci/Makefile
··· 47 47 obj-y += switch/ 48 48 49 49 subdir-ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG 50 + 51 + CFLAGS_trace.o := -I$(src) 52 + obj-$(CONFIG_TRACING) += trace.o
+25 -6
drivers/pci/hotplug/pciehp_ctrl.c
··· 19 19 #include <linux/types.h> 20 20 #include <linux/pm_runtime.h> 21 21 #include <linux/pci.h> 22 + #include <trace/events/pci.h> 22 23 23 24 #include "../pci.h" 24 25 #include "pciehp.h" ··· 245 244 case ON_STATE: 246 245 ctrl->state = POWEROFF_STATE; 247 246 mutex_unlock(&ctrl->state_lock); 248 - if (events & PCI_EXP_SLTSTA_DLLSC) 247 + if (events & PCI_EXP_SLTSTA_DLLSC) { 249 248 ctrl_info(ctrl, "Slot(%s): Link Down\n", 250 249 slot_name(ctrl)); 251 - if (events & PCI_EXP_SLTSTA_PDC) 250 + trace_pci_hp_event(pci_name(ctrl->pcie->port), 251 + slot_name(ctrl), 252 + PCI_HOTPLUG_LINK_DOWN); 253 + } 254 + if (events & PCI_EXP_SLTSTA_PDC) { 252 255 ctrl_info(ctrl, "Slot(%s): Card not present\n", 253 256 slot_name(ctrl)); 257 + trace_pci_hp_event(pci_name(ctrl->pcie->port), 258 + slot_name(ctrl), 259 + PCI_HOTPLUG_CARD_NOT_PRESENT); 260 + } 254 261 pciehp_disable_slot(ctrl, SURPRISE_REMOVAL); 255 262 break; 256 263 default: ··· 278 269 INDICATOR_NOOP); 279 270 ctrl_info(ctrl, "Slot(%s): Card not present\n", 280 271 slot_name(ctrl)); 272 + trace_pci_hp_event(pci_name(ctrl->pcie->port), 273 + slot_name(ctrl), 274 + PCI_HOTPLUG_CARD_NOT_PRESENT); 281 275 } 282 276 mutex_unlock(&ctrl->state_lock); 283 277 return; ··· 293 281 case OFF_STATE: 294 282 ctrl->state = POWERON_STATE; 295 283 mutex_unlock(&ctrl->state_lock); 296 - if (present) 284 + if (present) { 297 285 ctrl_info(ctrl, "Slot(%s): Card present\n", 298 286 slot_name(ctrl)); 299 - if (link_active) 300 - ctrl_info(ctrl, "Slot(%s): Link Up\n", 301 - slot_name(ctrl)); 287 + trace_pci_hp_event(pci_name(ctrl->pcie->port), 288 + slot_name(ctrl), 289 + PCI_HOTPLUG_CARD_PRESENT); 290 + } 291 + if (link_active) { 292 + ctrl_info(ctrl, "Slot(%s): Link Up\n", slot_name(ctrl)); 293 + trace_pci_hp_event(pci_name(ctrl->pcie->port), 294 + slot_name(ctrl), 295 + PCI_HOTPLUG_LINK_UP); 296 + } 302 297 ctrl->request_result = pciehp_enable_slot(ctrl); 303 298 break; 304 299 default:
+11
drivers/pci/trace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Tracepoints for PCI system 4 + * 5 + * Copyright (C) 2025 Alibaba Corporation 6 + */ 7 + 8 + #include <linux/pci.h> 9 + 10 + #define CREATE_TRACE_POINTS 11 + #include <trace/events/pci.h>
+72
include/trace/events/pci.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #undef TRACE_SYSTEM 3 + #define TRACE_SYSTEM pci 4 + 5 + #if !defined(_TRACE_HW_EVENT_PCI_H) || defined(TRACE_HEADER_MULTI_READ) 6 + #define _TRACE_HW_EVENT_PCI_H 7 + 8 + #include <linux/tracepoint.h> 9 + 10 + #define PCI_HOTPLUG_EVENT \ 11 + EM(PCI_HOTPLUG_LINK_UP, "LINK_UP") \ 12 + EM(PCI_HOTPLUG_LINK_DOWN, "LINK_DOWN") \ 13 + EM(PCI_HOTPLUG_CARD_PRESENT, "CARD_PRESENT") \ 14 + EMe(PCI_HOTPLUG_CARD_NOT_PRESENT, "CARD_NOT_PRESENT") 15 + 16 + /* Enums require being exported to userspace, for user tool parsing */ 17 + #undef EM 18 + #undef EMe 19 + #define EM(a, b) TRACE_DEFINE_ENUM(a); 20 + #define EMe(a, b) TRACE_DEFINE_ENUM(a); 21 + 22 + PCI_HOTPLUG_EVENT 23 + 24 + /* 25 + * Now redefine the EM() and EMe() macros to map the enums to the strings 26 + * that will be printed in the output. 27 + */ 28 + #undef EM 29 + #undef EMe 30 + #define EM(a, b) {a, b}, 31 + #define EMe(a, b) {a, b} 32 + 33 + /* 34 + * Note: For generic PCI hotplug events, we pass already-resolved strings 35 + * (port_name, slot) instead of driver-specific structures like 'struct 36 + * controller'. This is because different PCI hotplug drivers (pciehp, cpqphp, 37 + * ibmphp, shpchp) define their own versions of 'struct controller' with 38 + * different fields and helper functions. Using driver-specific structures would 39 + * make the tracepoint interface non-generic and cause compatibility issues 40 + * across different drivers. 41 + */ 42 + TRACE_EVENT(pci_hp_event, 43 + 44 + TP_PROTO(const char *port_name, 45 + const char *slot, 46 + const int event), 47 + 48 + TP_ARGS(port_name, slot, event), 49 + 50 + TP_STRUCT__entry( 51 + __string( port_name, port_name ) 52 + __string( slot, slot ) 53 + __field( int, event ) 54 + ), 55 + 56 + TP_fast_assign( 57 + __assign_str(port_name); 58 + __assign_str(slot); 59 + __entry->event = event; 60 + ), 61 + 62 + TP_printk("%s slot:%s, event:%s\n", 63 + __get_str(port_name), 64 + __get_str(slot), 65 + __print_symbolic(__entry->event, PCI_HOTPLUG_EVENT) 66 + ) 67 + ); 68 + 69 + #endif /* _TRACE_HW_EVENT_PCI_H */ 70 + 71 + /* This part must be outside protection */ 72 + #include <trace/define_trace.h>
+7
include/uapi/linux/pci.h
··· 39 39 #define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02) /* Set mmap state to MEM space. */ 40 40 #define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03) /* Enable/disable write-combining. */ 41 41 42 + enum pci_hotplug_event { 43 + PCI_HOTPLUG_LINK_UP, 44 + PCI_HOTPLUG_LINK_DOWN, 45 + PCI_HOTPLUG_CARD_PRESENT, 46 + PCI_HOTPLUG_CARD_NOT_PRESENT, 47 + }; 48 + 42 49 #endif /* _UAPILINUX_PCI_H */