21
21
#include <linux/delay.h>
22
22
#include <linux/kfifo.h>
23
23
#include <linux/slab.h>
24
+ #include <acpi/apei.h>
24
25
#include <ras/ras_event.h>
25
26
26
27
#include "aerdrv.h"
@@ -38,6 +39,127 @@ bool pci_aer_available(void)
38
39
return !pcie_aer_disable && pci_msi_enabled ();
39
40
}
40
41
42
+ #ifdef CONFIG_ACPI_APEI
43
+ static inline int hest_match_pci (struct acpi_hest_aer_common * p ,
44
+ struct pci_dev * pci )
45
+ {
46
+ return ACPI_HEST_SEGMENT (p -> bus ) == pci_domain_nr (pci -> bus ) &&
47
+ ACPI_HEST_BUS (p -> bus ) == pci -> bus -> number &&
48
+ p -> device == PCI_SLOT (pci -> devfn ) &&
49
+ p -> function == PCI_FUNC (pci -> devfn );
50
+ }
51
+
52
+ static inline bool hest_match_type (struct acpi_hest_header * hest_hdr ,
53
+ struct pci_dev * dev )
54
+ {
55
+ u16 hest_type = hest_hdr -> type ;
56
+ u8 pcie_type = pci_pcie_type (dev );
57
+
58
+ if ((hest_type == ACPI_HEST_TYPE_AER_ROOT_PORT &&
59
+ pcie_type == PCI_EXP_TYPE_ROOT_PORT ) ||
60
+ (hest_type == ACPI_HEST_TYPE_AER_ENDPOINT &&
61
+ pcie_type == PCI_EXP_TYPE_ENDPOINT ) ||
62
+ (hest_type == ACPI_HEST_TYPE_AER_BRIDGE &&
63
+ (dev -> class >> 16 ) == PCI_BASE_CLASS_BRIDGE ))
64
+ return true;
65
+ return false;
66
+ }
67
+
68
+ struct aer_hest_parse_info {
69
+ struct pci_dev * pci_dev ;
70
+ int firmware_first ;
71
+ };
72
+
73
+ static int hest_source_is_pcie_aer (struct acpi_hest_header * hest_hdr )
74
+ {
75
+ if (hest_hdr -> type == ACPI_HEST_TYPE_AER_ROOT_PORT ||
76
+ hest_hdr -> type == ACPI_HEST_TYPE_AER_ENDPOINT ||
77
+ hest_hdr -> type == ACPI_HEST_TYPE_AER_BRIDGE )
78
+ return 1 ;
79
+ return 0 ;
80
+ }
81
+
82
+ static int aer_hest_parse (struct acpi_hest_header * hest_hdr , void * data )
83
+ {
84
+ struct aer_hest_parse_info * info = data ;
85
+ struct acpi_hest_aer_common * p ;
86
+ int ff ;
87
+
88
+ if (!hest_source_is_pcie_aer (hest_hdr ))
89
+ return 0 ;
90
+
91
+ p = (struct acpi_hest_aer_common * )(hest_hdr + 1 );
92
+ ff = !!(p -> flags & ACPI_HEST_FIRMWARE_FIRST );
93
+
94
+ /*
95
+ * If no specific device is supplied, determine whether
96
+ * FIRMWARE_FIRST is set for *any* PCIe device.
97
+ */
98
+ if (!info -> pci_dev ) {
99
+ info -> firmware_first |= ff ;
100
+ return 0 ;
101
+ }
102
+
103
+ /* Otherwise, check the specific device */
104
+ if (p -> flags & ACPI_HEST_GLOBAL ) {
105
+ if (hest_match_type (hest_hdr , info -> pci_dev ))
106
+ info -> firmware_first = ff ;
107
+ } else
108
+ if (hest_match_pci (p , info -> pci_dev ))
109
+ info -> firmware_first = ff ;
110
+
111
+ return 0 ;
112
+ }
113
+
114
+ static void aer_set_firmware_first (struct pci_dev * pci_dev )
115
+ {
116
+ int rc ;
117
+ struct aer_hest_parse_info info = {
118
+ .pci_dev = pci_dev ,
119
+ .firmware_first = 0 ,
120
+ };
121
+
122
+ rc = apei_hest_parse (aer_hest_parse , & info );
123
+
124
+ if (rc )
125
+ pci_dev -> __aer_firmware_first = 0 ;
126
+ else
127
+ pci_dev -> __aer_firmware_first = info .firmware_first ;
128
+ pci_dev -> __aer_firmware_first_valid = 1 ;
129
+ }
130
+
131
+ int pcie_aer_get_firmware_first (struct pci_dev * dev )
132
+ {
133
+ if (!pci_is_pcie (dev ))
134
+ return 0 ;
135
+
136
+ if (!dev -> __aer_firmware_first_valid )
137
+ aer_set_firmware_first (dev );
138
+ return dev -> __aer_firmware_first ;
139
+ }
140
+
141
+ static bool aer_firmware_first ;
142
+
143
+ /**
144
+ * aer_acpi_firmware_first - Check if APEI should control AER.
145
+ */
146
+ bool aer_acpi_firmware_first (void )
147
+ {
148
+ static bool parsed = false;
149
+ struct aer_hest_parse_info info = {
150
+ .pci_dev = NULL , /* Check all PCIe devices */
151
+ .firmware_first = 0 ,
152
+ };
153
+
154
+ if (!parsed ) {
155
+ apei_hest_parse (aer_hest_parse , & info );
156
+ aer_firmware_first = info .firmware_first ;
157
+ parsed = true;
158
+ }
159
+ return aer_firmware_first ;
160
+ }
161
+ #endif
162
+
41
163
#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \
42
164
PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)
43
165
0 commit comments