2 * Access ACPI _OSC method
4 * Copyright (C) 2006 Intel Corp.
5 * Tom Long Nguyen (tom.l.nguyen@intel.com)
6 * Zhang Yanmin (yanmin.zhang@intel.com)
10 #include <linux/module.h>
11 #include <linux/pci.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
15 #include <linux/suspend.h>
16 #include <linux/acpi.h>
17 #include <linux/pci-acpi.h>
18 #include <linux/delay.h>
19 #include <acpi/apei.h>
22 #ifdef CONFIG_ACPI_APEI
23 static inline int hest_match_pci(struct acpi_hest_aer_common *p,
26 return (0 == pci_domain_nr(pci->bus) &&
27 p->bus == pci->bus->number &&
28 p->device == PCI_SLOT(pci->devfn) &&
29 p->function == PCI_FUNC(pci->devfn));
32 static inline bool hest_match_type(struct acpi_hest_header *hest_hdr,
35 u16 hest_type = hest_hdr->type;
36 u8 pcie_type = pci_pcie_type(dev);
38 if ((hest_type == ACPI_HEST_TYPE_AER_ROOT_PORT &&
39 pcie_type == PCI_EXP_TYPE_ROOT_PORT) ||
40 (hest_type == ACPI_HEST_TYPE_AER_ENDPOINT &&
41 pcie_type == PCI_EXP_TYPE_ENDPOINT) ||
42 (hest_type == ACPI_HEST_TYPE_AER_BRIDGE &&
43 (dev->class >> 16) == PCI_BASE_CLASS_BRIDGE))
48 struct aer_hest_parse_info {
49 struct pci_dev *pci_dev;
53 static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data)
55 struct aer_hest_parse_info *info = data;
56 struct acpi_hest_aer_common *p;
59 p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
60 ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
61 if (p->flags & ACPI_HEST_GLOBAL) {
62 if (hest_match_type(hest_hdr, info->pci_dev))
63 info->firmware_first = ff;
65 if (hest_match_pci(p, info->pci_dev))
66 info->firmware_first = ff;
71 static void aer_set_firmware_first(struct pci_dev *pci_dev)
74 struct aer_hest_parse_info info = {
79 rc = apei_hest_parse(aer_hest_parse, &info);
82 pci_dev->__aer_firmware_first = 0;
84 pci_dev->__aer_firmware_first = info.firmware_first;
85 pci_dev->__aer_firmware_first_valid = 1;
88 int pcie_aer_get_firmware_first(struct pci_dev *dev)
90 if (!pci_is_pcie(dev))
93 if (!dev->__aer_firmware_first_valid)
94 aer_set_firmware_first(dev);
95 return dev->__aer_firmware_first;
98 static bool aer_firmware_first;
100 static int aer_hest_parse_aff(struct acpi_hest_header *hest_hdr, void *data)
102 struct acpi_hest_aer_common *p;
104 if (aer_firmware_first)
107 switch (hest_hdr->type) {
108 case ACPI_HEST_TYPE_AER_ROOT_PORT:
109 case ACPI_HEST_TYPE_AER_ENDPOINT:
110 case ACPI_HEST_TYPE_AER_BRIDGE:
111 p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
112 aer_firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
119 * aer_acpi_firmware_first - Check if APEI should control AER.
121 bool aer_acpi_firmware_first(void)
123 static bool parsed = false;
126 apei_hest_parse(aer_hest_parse_aff, NULL);
129 return aer_firmware_first;