]>
Commit | Line | Data |
---|---|---|
05843961 MD |
1 | #include <linux/acpi.h> |
2 | #include <linux/pci.h> | |
3 | ||
4 | #define PREFIX "ACPI: " | |
5 | ||
6 | static inline unsigned long parse_acpi_hest_ia_machine_check(struct acpi_hest_ia_machine_check *p) | |
7 | { | |
8 | return sizeof(*p) + | |
9 | (sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks); | |
10 | } | |
11 | ||
12 | static inline unsigned long parse_acpi_hest_ia_corrected(struct acpi_hest_ia_corrected *p) | |
13 | { | |
14 | return sizeof(*p) + | |
15 | (sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks); | |
16 | } | |
17 | ||
18 | static inline unsigned long parse_acpi_hest_ia_nmi(struct acpi_hest_ia_nmi *p) | |
19 | { | |
20 | return sizeof(*p); | |
21 | } | |
22 | ||
23 | static inline unsigned long parse_acpi_hest_generic(struct acpi_hest_generic *p) | |
24 | { | |
25 | return sizeof(*p); | |
26 | } | |
27 | ||
28 | static inline unsigned int hest_match_pci(struct acpi_hest_aer_common *p, struct pci_dev *pci) | |
29 | { | |
30 | return (0 == pci_domain_nr(pci->bus) && | |
31 | p->bus == pci->bus->number && | |
32 | p->device == PCI_SLOT(pci->devfn) && | |
33 | p->function == PCI_FUNC(pci->devfn)); | |
34 | } | |
35 | ||
36 | static unsigned long parse_acpi_hest_aer(void *hdr, int type, struct pci_dev *pci, int *firmware_first) | |
37 | { | |
38 | struct acpi_hest_aer_common *p = hdr + sizeof(struct acpi_hest_header); | |
39 | unsigned long rc=0; | |
40 | u8 pcie_type = 0; | |
41 | u8 bridge = 0; | |
42 | switch (type) { | |
43 | case ACPI_HEST_TYPE_AER_ROOT_PORT: | |
44 | rc = sizeof(struct acpi_hest_aer_root); | |
45 | pcie_type = PCI_EXP_TYPE_ROOT_PORT; | |
46 | break; | |
47 | case ACPI_HEST_TYPE_AER_ENDPOINT: | |
48 | rc = sizeof(struct acpi_hest_aer); | |
49 | pcie_type = PCI_EXP_TYPE_ENDPOINT; | |
50 | break; | |
51 | case ACPI_HEST_TYPE_AER_BRIDGE: | |
52 | rc = sizeof(struct acpi_hest_aer_bridge); | |
53 | if ((pci->class >> 16) == PCI_BASE_CLASS_BRIDGE) | |
54 | bridge = 1; | |
55 | break; | |
56 | } | |
57 | ||
58 | if (p->flags & ACPI_HEST_GLOBAL) { | |
59 | if ((pci->is_pcie && (pci->pcie_type == pcie_type)) || bridge) | |
60 | *firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); | |
61 | } | |
62 | else | |
63 | if (hest_match_pci(p, pci)) | |
64 | *firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); | |
65 | return rc; | |
66 | } | |
67 | ||
68 | static int acpi_hest_firmware_first(struct acpi_table_header *stdheader, struct pci_dev *pci) | |
69 | { | |
70 | struct acpi_table_hest *hest = (struct acpi_table_hest *)stdheader; | |
71 | void *p = (void *)hest + sizeof(*hest); /* defined by the ACPI 4.0 spec */ | |
72 | struct acpi_hest_header *hdr = p; | |
73 | ||
74 | int i; | |
75 | int firmware_first = 0; | |
76 | static unsigned char printed_unused = 0; | |
77 | static unsigned char printed_reserved = 0; | |
78 | ||
79 | for (i=0, hdr=p; p < (((void *)hest) + hest->header.length) && i < hest->error_source_count; i++) { | |
80 | switch (hdr->type) { | |
81 | case ACPI_HEST_TYPE_IA32_CHECK: | |
82 | p += parse_acpi_hest_ia_machine_check(p); | |
83 | break; | |
84 | case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: | |
85 | p += parse_acpi_hest_ia_corrected(p); | |
86 | break; | |
87 | case ACPI_HEST_TYPE_IA32_NMI: | |
88 | p += parse_acpi_hest_ia_nmi(p); | |
89 | break; | |
90 | /* These three should never appear */ | |
91 | case ACPI_HEST_TYPE_NOT_USED3: | |
92 | case ACPI_HEST_TYPE_NOT_USED4: | |
93 | case ACPI_HEST_TYPE_NOT_USED5: | |
94 | if (!printed_unused) { | |
95 | printk(KERN_DEBUG PREFIX | |
96 | "HEST Error Source list contains an obsolete type (%d).\n", hdr->type); | |
97 | printed_unused = 1; | |
98 | } | |
99 | break; | |
100 | case ACPI_HEST_TYPE_AER_ROOT_PORT: | |
101 | case ACPI_HEST_TYPE_AER_ENDPOINT: | |
102 | case ACPI_HEST_TYPE_AER_BRIDGE: | |
103 | p += parse_acpi_hest_aer(p, hdr->type, pci, &firmware_first); | |
104 | break; | |
105 | case ACPI_HEST_TYPE_GENERIC_ERROR: | |
106 | p += parse_acpi_hest_generic(p); | |
107 | break; | |
108 | /* These should never appear either */ | |
109 | case ACPI_HEST_TYPE_RESERVED: | |
110 | default: | |
111 | if (!printed_reserved) { | |
112 | printk(KERN_DEBUG PREFIX | |
113 | "HEST Error Source list contains a reserved type (%d).\n", hdr->type); | |
114 | printed_reserved = 1; | |
115 | } | |
116 | break; | |
117 | } | |
118 | } | |
119 | return firmware_first; | |
120 | } | |
121 | ||
122 | int acpi_hest_firmware_first_pci(struct pci_dev *pci) | |
123 | { | |
124 | acpi_status status = AE_NOT_FOUND; | |
125 | struct acpi_table_header *hest = NULL; | |
4bdae98f SL |
126 | |
127 | if (acpi_disabled) | |
128 | return 0; | |
129 | ||
05843961 MD |
130 | status = acpi_get_table(ACPI_SIG_HEST, 1, &hest); |
131 | ||
132 | if (ACPI_SUCCESS(status)) { | |
133 | if (acpi_hest_firmware_first(hest, pci)) { | |
134 | return 1; | |
135 | } | |
136 | } | |
137 | return 0; | |
138 | } | |
139 | EXPORT_SYMBOL_GPL(acpi_hest_firmware_first_pci); |