aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2010-05-18 02:35:16 -0400
committerLen Brown <len.brown@intel.com>2010-05-19 22:40:14 -0400
commitaffb72c3a8984ba55e055b0a0228c3ea1a056758 (patch)
treea6d4c9051110c03f9222bde9c3dcea7822f8570c
parentea8c071cad789b1919355fc7a67182a5c9994e6b (diff)
ACPI, APEI, PCIE AER, use general HEST table parsing in AER firmware_first setup
Now, a dedicated HEST tabling parsing code is used for PCIE AER firmware_first setup. It is rebased on general HEST tabling parsing code of APEI. The firmware_first setup code is moved from PCI core to AER driver too, because it is only AER related. Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Andi Kleen <ak@linux.intel.com> Reviewed-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com> Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/hest.c139
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h17
-rw-r--r--drivers/pci/pcie/aer/aerdrv_acpi.c77
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c8
-rw-r--r--drivers/pci/probe.c8
-rw-r--r--include/acpi/acpi_hest.h12
-rw-r--r--include/linux/pci.h3
8 files changed, 100 insertions, 165 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index d90af7fe8b98..e7cd919548e9 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -20,7 +20,6 @@ obj-y += acpi.o \
20# All the builtin files are in the "acpi." module_param namespace. 20# All the builtin files are in the "acpi." module_param namespace.
21acpi-y += osl.o utils.o reboot.o 21acpi-y += osl.o utils.o reboot.o
22acpi-y += atomicio.o 22acpi-y += atomicio.o
23acpi-y += hest.o
24 23
25# sleep related files 24# sleep related files
26acpi-y += wakeup.o 25acpi-y += wakeup.o
diff --git a/drivers/acpi/hest.c b/drivers/acpi/hest.c
deleted file mode 100644
index 1c527a192872..000000000000
--- a/drivers/acpi/hest.c
+++ /dev/null
@@ -1,139 +0,0 @@
1#include <linux/acpi.h>
2#include <linux/pci.h>
3
4#define PREFIX "ACPI: "
5
6static 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
12static 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
18static inline unsigned long parse_acpi_hest_ia_nmi(struct acpi_hest_ia_nmi *p)
19{
20 return sizeof(*p);
21}
22
23static inline unsigned long parse_acpi_hest_generic(struct acpi_hest_generic *p)
24{
25 return sizeof(*p);
26}
27
28static 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
36static 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
68static 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
122int acpi_hest_firmware_first_pci(struct pci_dev *pci)
123{
124 acpi_status status = AE_NOT_FOUND;
125 struct acpi_table_header *hest = NULL;
126
127 if (acpi_disabled)
128 return 0;
129
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}
139EXPORT_SYMBOL_GPL(acpi_hest_firmware_first_pci);
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index bd833ea3ba49..7182c337aef1 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -134,4 +134,21 @@ static inline int aer_osc_setup(struct pcie_device *pciedev)
134} 134}
135#endif 135#endif
136 136
137#ifdef CONFIG_ACPI_APEI
138extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
139#else
140static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
141{
142 if (pci_dev->__aer_firmware_first_valid)
143 return pci_dev->__aer_firmware_first;
144 return 0;
145}
146#endif
147
148static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev,
149 int enable)
150{
151 pci_dev->__aer_firmware_first = !!enable;
152 pci_dev->__aer_firmware_first_valid = 1;
153}
137#endif /* _AERDRV_H_ */ 154#endif /* _AERDRV_H_ */
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
index 04814087658d..f278d7b0d95d 100644
--- a/drivers/pci/pcie/aer/aerdrv_acpi.c
+++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
@@ -16,6 +16,7 @@
16#include <linux/acpi.h> 16#include <linux/acpi.h>
17#include <linux/pci-acpi.h> 17#include <linux/pci-acpi.h>
18#include <linux/delay.h> 18#include <linux/delay.h>
19#include <acpi/apei.h>
19#include "aerdrv.h" 20#include "aerdrv.h"
20 21
21/** 22/**
@@ -53,3 +54,79 @@ int aer_osc_setup(struct pcie_device *pciedev)
53 54
54 return 0; 55 return 0;
55} 56}
57
58#ifdef CONFIG_ACPI_APEI
59static inline int hest_match_pci(struct acpi_hest_aer_common *p,
60 struct pci_dev *pci)
61{
62 return (0 == pci_domain_nr(pci->bus) &&
63 p->bus == pci->bus->number &&
64 p->device == PCI_SLOT(pci->devfn) &&
65 p->function == PCI_FUNC(pci->devfn));
66}
67
68struct aer_hest_parse_info {
69 struct pci_dev *pci_dev;
70 int firmware_first;
71};
72
73static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data)
74{
75 struct aer_hest_parse_info *info = data;
76 struct acpi_hest_aer_common *p;
77 u8 pcie_type = 0;
78 u8 bridge = 0;
79 int ff = 0;
80
81 switch (hest_hdr->type) {
82 case ACPI_HEST_TYPE_AER_ROOT_PORT:
83 pcie_type = PCI_EXP_TYPE_ROOT_PORT;
84 break;
85 case ACPI_HEST_TYPE_AER_ENDPOINT:
86 pcie_type = PCI_EXP_TYPE_ENDPOINT;
87 break;
88 case ACPI_HEST_TYPE_AER_BRIDGE:
89 if ((info->pci_dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
90 bridge = 1;
91 break;
92 default:
93 return 0;
94 }
95
96 p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
97 if (p->flags & ACPI_HEST_GLOBAL) {
98 if ((info->pci_dev->is_pcie &&
99 info->pci_dev->pcie_type == pcie_type) || bridge)
100 ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
101 } else
102 if (hest_match_pci(p, info->pci_dev))
103 ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
104 info->firmware_first = ff;
105
106 return 0;
107}
108
109static void aer_set_firmware_first(struct pci_dev *pci_dev)
110{
111 int rc;
112 struct aer_hest_parse_info info = {
113 .pci_dev = pci_dev,
114 .firmware_first = 0,
115 };
116
117 rc = apei_hest_parse(aer_hest_parse, &info);
118
119 if (rc)
120 pci_dev->__aer_firmware_first = 0;
121 else
122 pci_dev->__aer_firmware_first = info.firmware_first;
123 pci_dev->__aer_firmware_first_valid = 1;
124}
125
126int pcie_aer_get_firmware_first(struct pci_dev *dev)
127{
128 if (!dev->__aer_firmware_first_valid)
129 aer_set_firmware_first(dev);
130 return dev->__aer_firmware_first;
131}
132#endif
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index aceb04b67b60..586b6713e417 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -36,7 +36,7 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev)
36 u16 reg16 = 0; 36 u16 reg16 = 0;
37 int pos; 37 int pos;
38 38
39 if (dev->aer_firmware_first) 39 if (pcie_aer_get_firmware_first(dev))
40 return -EIO; 40 return -EIO;
41 41
42 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 42 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
@@ -64,7 +64,7 @@ int pci_disable_pcie_error_reporting(struct pci_dev *dev)
64 u16 reg16 = 0; 64 u16 reg16 = 0;
65 int pos; 65 int pos;
66 66
67 if (dev->aer_firmware_first) 67 if (pcie_aer_get_firmware_first(dev))
68 return -EIO; 68 return -EIO;
69 69
70 pos = pci_pcie_cap(dev); 70 pos = pci_pcie_cap(dev);
@@ -859,7 +859,7 @@ void aer_delete_rootport(struct aer_rpc *rpc)
859 */ 859 */
860int aer_init(struct pcie_device *dev) 860int aer_init(struct pcie_device *dev)
861{ 861{
862 if (dev->port->aer_firmware_first) { 862 if (pcie_aer_get_firmware_first(dev->port)) {
863 dev_printk(KERN_DEBUG, &dev->device, 863 dev_printk(KERN_DEBUG, &dev->device,
864 "PCIe errors handled by platform firmware.\n"); 864 "PCIe errors handled by platform firmware.\n");
865 goto out; 865 goto out;
@@ -873,7 +873,7 @@ out:
873 if (forceload) { 873 if (forceload) {
874 dev_printk(KERN_DEBUG, &dev->device, 874 dev_printk(KERN_DEBUG, &dev->device,
875 "aerdrv forceload requested.\n"); 875 "aerdrv forceload requested.\n");
876 dev->port->aer_firmware_first = 0; 876 pcie_aer_force_firmware_first(dev->port, 0);
877 return 0; 877 return 0;
878 } 878 }
879 return -ENXIO; 879 return -ENXIO;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c82548afcd5c..f4adba2d1dd3 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -10,7 +10,6 @@
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/cpumask.h> 11#include <linux/cpumask.h>
12#include <linux/pci-aspm.h> 12#include <linux/pci-aspm.h>
13#include <acpi/acpi_hest.h>
14#include "pci.h" 13#include "pci.h"
15 14
16#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ 15#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
@@ -904,12 +903,6 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev)
904 pdev->is_hotplug_bridge = 1; 903 pdev->is_hotplug_bridge = 1;
905} 904}
906 905
907static void set_pci_aer_firmware_first(struct pci_dev *pdev)
908{
909 if (acpi_hest_firmware_first_pci(pdev))
910 pdev->aer_firmware_first = 1;
911}
912
913#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) 906#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
914 907
915/** 908/**
@@ -939,7 +932,6 @@ int pci_setup_device(struct pci_dev *dev)
939 dev->multifunction = !!(hdr_type & 0x80); 932 dev->multifunction = !!(hdr_type & 0x80);
940 dev->error_state = pci_channel_io_normal; 933 dev->error_state = pci_channel_io_normal;
941 set_pcie_port_type(dev); 934 set_pcie_port_type(dev);
942 set_pci_aer_firmware_first(dev);
943 935
944 list_for_each_entry(slot, &dev->bus->slots, list) 936 list_for_each_entry(slot, &dev->bus->slots, list)
945 if (PCI_SLOT(dev->devfn) == slot->number) 937 if (PCI_SLOT(dev->devfn) == slot->number)
diff --git a/include/acpi/acpi_hest.h b/include/acpi/acpi_hest.h
deleted file mode 100644
index 63194d03cb2d..000000000000
--- a/include/acpi/acpi_hest.h
+++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef __ACPI_HEST_H
2#define __ACPI_HEST_H
3
4#include <linux/pci.h>
5
6#ifdef CONFIG_ACPI
7extern int acpi_hest_firmware_first_pci(struct pci_dev *pci);
8#else
9static inline int acpi_hest_firmware_first_pci(struct pci_dev *pci) { return 0; }
10#endif
11
12#endif
diff --git a/include/linux/pci.h b/include/linux/pci.h
index a788fa12ff31..63967e877f20 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -311,7 +311,8 @@ struct pci_dev {
311 unsigned int is_virtfn:1; 311 unsigned int is_virtfn:1;
312 unsigned int reset_fn:1; 312 unsigned int reset_fn:1;
313 unsigned int is_hotplug_bridge:1; 313 unsigned int is_hotplug_bridge:1;
314 unsigned int aer_firmware_first:1; 314 unsigned int __aer_firmware_first_valid:1;
315 unsigned int __aer_firmware_first:1;
315 pci_dev_flags_t dev_flags; 316 pci_dev_flags_t dev_flags;
316 atomic_t enable_cnt; /* pci_enable_device has been called */ 317 atomic_t enable_cnt; /* pci_enable_device has been called */
317 318