diff options
| -rw-r--r-- | drivers/acpi/Makefile | 1 | ||||
| -rw-r--r-- | drivers/acpi/hest.c | 139 | ||||
| -rw-r--r-- | drivers/pci/pcie/aer/aerdrv.h | 17 | ||||
| -rw-r--r-- | drivers/pci/pcie/aer/aerdrv_acpi.c | 77 | ||||
| -rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 8 | ||||
| -rw-r--r-- | drivers/pci/probe.c | 8 | ||||
| -rw-r--r-- | include/acpi/acpi_hest.h | 12 | ||||
| -rw-r--r-- | include/linux/pci.h | 3 |
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. |
| 21 | acpi-y += osl.o utils.o reboot.o | 21 | acpi-y += osl.o utils.o reboot.o |
| 22 | acpi-y += atomicio.o | 22 | acpi-y += atomicio.o |
| 23 | acpi-y += hest.o | ||
| 24 | 23 | ||
| 25 | # sleep related files | 24 | # sleep related files |
| 26 | acpi-y += wakeup.o | 25 | acpi-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 | |||
| 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; | ||
| 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 | } | ||
| 139 | EXPORT_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 | ||
| 138 | extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev); | ||
| 139 | #else | ||
| 140 | static 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 | |||
| 148 | static 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 | ||
| 59 | static 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 | |||
| 68 | struct aer_hest_parse_info { | ||
| 69 | struct pci_dev *pci_dev; | ||
| 70 | int firmware_first; | ||
| 71 | }; | ||
| 72 | |||
| 73 | static 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 | |||
| 109 | static 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 | |||
| 126 | int 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 | */ |
| 860 | int aer_init(struct pcie_device *dev) | 860 | int 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 | ||
| 907 | static 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 | ||
| 7 | extern int acpi_hest_firmware_first_pci(struct pci_dev *pci); | ||
| 8 | #else | ||
| 9 | static 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 | ||
