]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/pci/pcie/aer/aerdrv_acpi.c
Merge branch 'fix/asoc' into for-linus
[net-next-2.6.git] / drivers / pci / pcie / aer / aerdrv_acpi.c
CommitLineData
6c2b374d
ZY
1/*
2 * Access ACPI _OSC method
3 *
4 * Copyright (C) 2006 Intel Corp.
5 * Tom Long Nguyen (tom.l.nguyen@intel.com)
6 * Zhang Yanmin (yanmin.zhang@intel.com)
7 *
8 */
9
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>
affb72c3 19#include <acpi/apei.h>
6c2b374d
ZY
20#include "aerdrv.h"
21
affb72c3
HY
22#ifdef CONFIG_ACPI_APEI
23static inline int hest_match_pci(struct acpi_hest_aer_common *p,
24 struct pci_dev *pci)
25{
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));
30}
31
32struct aer_hest_parse_info {
33 struct pci_dev *pci_dev;
34 int firmware_first;
35};
36
37static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data)
38{
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;
44
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;
58 }
59
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;
69
70 return 0;
71}
72
73static void aer_set_firmware_first(struct pci_dev *pci_dev)
74{
75 int rc;
76 struct aer_hest_parse_info info = {
77 .pci_dev = pci_dev,
78 .firmware_first = 0,
79 };
80
81 rc = apei_hest_parse(aer_hest_parse, &info);
82
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;
88}
89
90int pcie_aer_get_firmware_first(struct pci_dev *dev)
91{
92 if (!dev->__aer_firmware_first_valid)
93 aer_set_firmware_first(dev);
94 return dev->__aer_firmware_first;
95}
96#endif