MIPS: Yosemite, Emma: Fix off-by-two in arcs_cmdline buffer size check
[linux-2.6/linux-mips.git] / drivers / pci / pcie / aer / aerdrv_acpi.c
blob275bf158ffa7184978e33fb23124888e25570cc2
1 /*
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)
8 */
10 #include <linux/module.h>
11 #include <linux/pci.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/pm.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>
20 #include "aerdrv.h"
22 #ifdef CONFIG_ACPI_APEI
23 static inline int hest_match_pci(struct acpi_hest_aer_common *p,
24 struct pci_dev *pci)
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 struct aer_hest_parse_info {
33 struct pci_dev *pci_dev;
34 int firmware_first;
37 static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data)
39 struct aer_hest_parse_info *info = data;
40 struct acpi_hest_aer_common *p;
41 u8 pcie_type = 0;
42 u8 bridge = 0;
43 int ff = 0;
45 switch (hest_hdr->type) {
46 case ACPI_HEST_TYPE_AER_ROOT_PORT:
47 pcie_type = PCI_EXP_TYPE_ROOT_PORT;
48 break;
49 case ACPI_HEST_TYPE_AER_ENDPOINT:
50 pcie_type = PCI_EXP_TYPE_ENDPOINT;
51 break;
52 case ACPI_HEST_TYPE_AER_BRIDGE:
53 if ((info->pci_dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
54 bridge = 1;
55 break;
56 default:
57 return 0;
60 p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
61 if (p->flags & ACPI_HEST_GLOBAL) {
62 if ((info->pci_dev->is_pcie &&
63 info->pci_dev->pcie_type == pcie_type) || bridge)
64 ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
65 } else
66 if (hest_match_pci(p, info->pci_dev))
67 ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
68 info->firmware_first = ff;
70 return 0;
73 static void aer_set_firmware_first(struct pci_dev *pci_dev)
75 int rc;
76 struct aer_hest_parse_info info = {
77 .pci_dev = pci_dev,
78 .firmware_first = 0,
81 rc = apei_hest_parse(aer_hest_parse, &info);
83 if (rc)
84 pci_dev->__aer_firmware_first = 0;
85 else
86 pci_dev->__aer_firmware_first = info.firmware_first;
87 pci_dev->__aer_firmware_first_valid = 1;
90 int pcie_aer_get_firmware_first(struct pci_dev *dev)
92 if (!dev->__aer_firmware_first_valid)
93 aer_set_firmware_first(dev);
94 return dev->__aer_firmware_first;
97 static bool aer_firmware_first;
99 static int aer_hest_parse_aff(struct acpi_hest_header *hest_hdr, void *data)
101 struct acpi_hest_aer_common *p;
103 if (aer_firmware_first)
104 return 0;
106 switch (hest_hdr->type) {
107 case ACPI_HEST_TYPE_AER_ROOT_PORT:
108 case ACPI_HEST_TYPE_AER_ENDPOINT:
109 case ACPI_HEST_TYPE_AER_BRIDGE:
110 p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
111 aer_firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
112 default:
113 return 0;
118 * aer_acpi_firmware_first - Check if APEI should control AER.
120 bool aer_acpi_firmware_first(void)
122 static bool parsed = false;
124 if (!parsed) {
125 apei_hest_parse(aer_hest_parse_aff, NULL);
126 parsed = true;
128 return aer_firmware_first;
130 #endif