diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/pci/pcie | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r-- | drivers/pci/pcie/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aer_inject.c | 32 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.c | 3 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.h | 18 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_acpi.c | 34 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_errprint.c | 182 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 75 | ||||
-rw-r--r-- | drivers/pci/pcie/pme.c | 31 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv.h | 5 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_acpi.c | 23 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 24 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_pci.c | 37 |
13 files changed, 299 insertions, 169 deletions
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index dda70981b7a6..dc29348264c6 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig | |||
@@ -31,7 +31,7 @@ source "drivers/pci/pcie/aer/Kconfig" | |||
31 | # PCI Express ASPM | 31 | # PCI Express ASPM |
32 | # | 32 | # |
33 | config PCIEASPM | 33 | config PCIEASPM |
34 | bool "PCI Express ASPM control" if EMBEDDED | 34 | bool "PCI Express ASPM control" if EXPERT |
35 | depends on PCI && PCIEPORTBUS | 35 | depends on PCI && PCIEPORTBUS |
36 | default y | 36 | default y |
37 | help | 37 | help |
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c index 909924692b8a..95489cd9a555 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c | |||
@@ -27,6 +27,10 @@ | |||
27 | #include <linux/stddef.h> | 27 | #include <linux/stddef.h> |
28 | #include "aerdrv.h" | 28 | #include "aerdrv.h" |
29 | 29 | ||
30 | /* Override the existing corrected and uncorrected error masks */ | ||
31 | static int aer_mask_override; | ||
32 | module_param(aer_mask_override, bool, 0); | ||
33 | |||
30 | struct aer_error_inj { | 34 | struct aer_error_inj { |
31 | u8 bus; | 35 | u8 bus; |
32 | u8 dev; | 36 | u8 dev; |
@@ -322,7 +326,7 @@ static int aer_inject(struct aer_error_inj *einj) | |||
322 | unsigned long flags; | 326 | unsigned long flags; |
323 | unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); | 327 | unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); |
324 | int pos_cap_err, rp_pos_cap_err; | 328 | int pos_cap_err, rp_pos_cap_err; |
325 | u32 sever, cor_mask, uncor_mask; | 329 | u32 sever, cor_mask, uncor_mask, cor_mask_orig = 0, uncor_mask_orig = 0; |
326 | int ret = 0; | 330 | int ret = 0; |
327 | 331 | ||
328 | dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn); | 332 | dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn); |
@@ -361,6 +365,18 @@ static int aer_inject(struct aer_error_inj *einj) | |||
361 | goto out_put; | 365 | goto out_put; |
362 | } | 366 | } |
363 | 367 | ||
368 | if (aer_mask_override) { | ||
369 | cor_mask_orig = cor_mask; | ||
370 | cor_mask &= !(einj->cor_status); | ||
371 | pci_write_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, | ||
372 | cor_mask); | ||
373 | |||
374 | uncor_mask_orig = uncor_mask; | ||
375 | uncor_mask &= !(einj->uncor_status); | ||
376 | pci_write_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, | ||
377 | uncor_mask); | ||
378 | } | ||
379 | |||
364 | spin_lock_irqsave(&inject_lock, flags); | 380 | spin_lock_irqsave(&inject_lock, flags); |
365 | 381 | ||
366 | err = __find_aer_error_by_dev(dev); | 382 | err = __find_aer_error_by_dev(dev); |
@@ -378,14 +394,16 @@ static int aer_inject(struct aer_error_inj *einj) | |||
378 | err->header_log2 = einj->header_log2; | 394 | err->header_log2 = einj->header_log2; |
379 | err->header_log3 = einj->header_log3; | 395 | err->header_log3 = einj->header_log3; |
380 | 396 | ||
381 | if (einj->cor_status && !(einj->cor_status & ~cor_mask)) { | 397 | if (!aer_mask_override && einj->cor_status && |
398 | !(einj->cor_status & ~cor_mask)) { | ||
382 | ret = -EINVAL; | 399 | ret = -EINVAL; |
383 | printk(KERN_WARNING "The correctable error(s) is masked " | 400 | printk(KERN_WARNING "The correctable error(s) is masked " |
384 | "by device\n"); | 401 | "by device\n"); |
385 | spin_unlock_irqrestore(&inject_lock, flags); | 402 | spin_unlock_irqrestore(&inject_lock, flags); |
386 | goto out_put; | 403 | goto out_put; |
387 | } | 404 | } |
388 | if (einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) { | 405 | if (!aer_mask_override && einj->uncor_status && |
406 | !(einj->uncor_status & ~uncor_mask)) { | ||
389 | ret = -EINVAL; | 407 | ret = -EINVAL; |
390 | printk(KERN_WARNING "The uncorrectable error(s) is masked " | 408 | printk(KERN_WARNING "The uncorrectable error(s) is masked " |
391 | "by device\n"); | 409 | "by device\n"); |
@@ -425,6 +443,13 @@ static int aer_inject(struct aer_error_inj *einj) | |||
425 | } | 443 | } |
426 | spin_unlock_irqrestore(&inject_lock, flags); | 444 | spin_unlock_irqrestore(&inject_lock, flags); |
427 | 445 | ||
446 | if (aer_mask_override) { | ||
447 | pci_write_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, | ||
448 | cor_mask_orig); | ||
449 | pci_write_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, | ||
450 | uncor_mask_orig); | ||
451 | } | ||
452 | |||
428 | ret = pci_bus_set_aer_ops(dev->bus); | 453 | ret = pci_bus_set_aer_ops(dev->bus); |
429 | if (ret) | 454 | if (ret) |
430 | goto out_put; | 455 | goto out_put; |
@@ -472,6 +497,7 @@ static ssize_t aer_inject_write(struct file *filp, const char __user *ubuf, | |||
472 | static const struct file_operations aer_inject_fops = { | 497 | static const struct file_operations aer_inject_fops = { |
473 | .write = aer_inject_write, | 498 | .write = aer_inject_write, |
474 | .owner = THIS_MODULE, | 499 | .owner = THIS_MODULE, |
500 | .llseek = noop_llseek, | ||
475 | }; | 501 | }; |
476 | 502 | ||
477 | static struct miscdevice aer_inject_device = { | 503 | static struct miscdevice aer_inject_device = { |
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index f409948e1a9b..58ad7917553c 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/pci.h> | 19 | #include <linux/pci.h> |
20 | #include <linux/pci-acpi.h> | ||
20 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
21 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
22 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
@@ -416,7 +417,7 @@ static void aer_error_resume(struct pci_dev *dev) | |||
416 | */ | 417 | */ |
417 | static int __init aer_service_init(void) | 418 | static int __init aer_service_init(void) |
418 | { | 419 | { |
419 | if (!pci_aer_available()) | 420 | if (!pci_aer_available() || aer_acpi_firmware_first()) |
420 | return -ENXIO; | 421 | return -ENXIO; |
421 | return pcie_port_service_register(&aerdriver); | 422 | return pcie_port_service_register(&aerdriver); |
422 | } | 423 | } |
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index 80c11d131499..94a7598eb262 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h | |||
@@ -35,13 +35,6 @@ | |||
35 | PCI_ERR_UNC_UNX_COMP| \ | 35 | PCI_ERR_UNC_UNX_COMP| \ |
36 | PCI_ERR_UNC_MALF_TLP) | 36 | PCI_ERR_UNC_MALF_TLP) |
37 | 37 | ||
38 | struct header_log_regs { | ||
39 | unsigned int dw0; | ||
40 | unsigned int dw1; | ||
41 | unsigned int dw2; | ||
42 | unsigned int dw3; | ||
43 | }; | ||
44 | |||
45 | #define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */ | 38 | #define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */ |
46 | struct aer_err_info { | 39 | struct aer_err_info { |
47 | struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; | 40 | struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; |
@@ -59,7 +52,7 @@ struct aer_err_info { | |||
59 | 52 | ||
60 | unsigned int status; /* COR/UNCOR Error Status */ | 53 | unsigned int status; /* COR/UNCOR Error Status */ |
61 | unsigned int mask; /* COR/UNCOR Error Mask */ | 54 | unsigned int mask; /* COR/UNCOR Error Mask */ |
62 | struct header_log_regs tlp; /* TLP Header */ | 55 | struct aer_header_log_regs tlp; /* TLP Header */ |
63 | }; | 56 | }; |
64 | 57 | ||
65 | struct aer_err_source { | 58 | struct aer_err_source { |
@@ -121,15 +114,6 @@ extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); | |||
121 | extern void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info); | 114 | extern void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info); |
122 | extern irqreturn_t aer_irq(int irq, void *context); | 115 | extern irqreturn_t aer_irq(int irq, void *context); |
123 | 116 | ||
124 | #ifdef CONFIG_ACPI | ||
125 | extern int aer_osc_setup(struct pcie_device *pciedev); | ||
126 | #else | ||
127 | static inline int aer_osc_setup(struct pcie_device *pciedev) | ||
128 | { | ||
129 | return 0; | ||
130 | } | ||
131 | #endif | ||
132 | |||
133 | #ifdef CONFIG_ACPI_APEI | 117 | #ifdef CONFIG_ACPI_APEI |
134 | extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev); | 118 | extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev); |
135 | #else | 119 | #else |
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 2bb9b8972211..275bf158ffa7 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c | |||
@@ -93,4 +93,38 @@ int pcie_aer_get_firmware_first(struct pci_dev *dev) | |||
93 | aer_set_firmware_first(dev); | 93 | aer_set_firmware_first(dev); |
94 | return dev->__aer_firmware_first; | 94 | return dev->__aer_firmware_first; |
95 | } | 95 | } |
96 | |||
97 | static bool aer_firmware_first; | ||
98 | |||
99 | static int aer_hest_parse_aff(struct acpi_hest_header *hest_hdr, void *data) | ||
100 | { | ||
101 | struct acpi_hest_aer_common *p; | ||
102 | |||
103 | if (aer_firmware_first) | ||
104 | return 0; | ||
105 | |||
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; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * aer_acpi_firmware_first - Check if APEI should control AER. | ||
119 | */ | ||
120 | bool aer_acpi_firmware_first(void) | ||
121 | { | ||
122 | static bool parsed = false; | ||
123 | |||
124 | if (!parsed) { | ||
125 | apei_hest_parse(aer_hest_parse_aff, NULL); | ||
126 | parsed = true; | ||
127 | } | ||
128 | return aer_firmware_first; | ||
129 | } | ||
96 | #endif | 130 | #endif |
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 29e268fadf14..43421fbe080a 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c | |||
@@ -754,7 +754,7 @@ void aer_isr(struct work_struct *work) | |||
754 | { | 754 | { |
755 | struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler); | 755 | struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler); |
756 | struct pcie_device *p_device = rpc->rpd; | 756 | struct pcie_device *p_device = rpc->rpd; |
757 | struct aer_err_source e_src; | 757 | struct aer_err_source uninitialized_var(e_src); |
758 | 758 | ||
759 | mutex_lock(&rpc->rpc_mutex); | 759 | mutex_lock(&rpc->rpc_mutex); |
760 | while (get_e_source(rpc, &e_src)) | 760 | while (get_e_source(rpc, &e_src)) |
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 9d3e4c8d0184..b07a42e0b350 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/pm.h> | 20 | #include <linux/pm.h> |
21 | #include <linux/suspend.h> | 21 | #include <linux/suspend.h> |
22 | #include <linux/cper.h> | ||
22 | 23 | ||
23 | #include "aerdrv.h" | 24 | #include "aerdrv.h" |
24 | 25 | ||
@@ -57,86 +58,44 @@ | |||
57 | (e & AER_DATA_LINK_LAYER_ERROR_MASK(t)) ? AER_DATA_LINK_LAYER_ERROR : \ | 58 | (e & AER_DATA_LINK_LAYER_ERROR_MASK(t)) ? AER_DATA_LINK_LAYER_ERROR : \ |
58 | AER_TRANSACTION_LAYER_ERROR) | 59 | AER_TRANSACTION_LAYER_ERROR) |
59 | 60 | ||
60 | #define AER_PR(info, pdev, fmt, args...) \ | ||
61 | printk("%s%s %s: " fmt, (info->severity == AER_CORRECTABLE) ? \ | ||
62 | KERN_WARNING : KERN_ERR, dev_driver_string(&pdev->dev), \ | ||
63 | dev_name(&pdev->dev), ## args) | ||
64 | |||
65 | /* | 61 | /* |
66 | * AER error strings | 62 | * AER error strings |
67 | */ | 63 | */ |
68 | static char *aer_error_severity_string[] = { | 64 | static const char *aer_error_severity_string[] = { |
69 | "Uncorrected (Non-Fatal)", | 65 | "Uncorrected (Non-Fatal)", |
70 | "Uncorrected (Fatal)", | 66 | "Uncorrected (Fatal)", |
71 | "Corrected" | 67 | "Corrected" |
72 | }; | 68 | }; |
73 | 69 | ||
74 | static char *aer_error_layer[] = { | 70 | static const char *aer_error_layer[] = { |
75 | "Physical Layer", | 71 | "Physical Layer", |
76 | "Data Link Layer", | 72 | "Data Link Layer", |
77 | "Transaction Layer" | 73 | "Transaction Layer" |
78 | }; | 74 | }; |
79 | static char *aer_correctable_error_string[] = { | 75 | |
80 | "Receiver Error ", /* Bit Position 0 */ | 76 | static const char *aer_correctable_error_string[] = { |
81 | NULL, | 77 | "Receiver Error", /* Bit Position 0 */ |
82 | NULL, | ||
83 | NULL, | ||
84 | NULL, | ||
85 | NULL, | ||
86 | "Bad TLP ", /* Bit Position 6 */ | ||
87 | "Bad DLLP ", /* Bit Position 7 */ | ||
88 | "RELAY_NUM Rollover ", /* Bit Position 8 */ | ||
89 | NULL, | ||
90 | NULL, | ||
91 | NULL, | ||
92 | "Replay Timer Timeout ", /* Bit Position 12 */ | ||
93 | "Advisory Non-Fatal ", /* Bit Position 13 */ | ||
94 | NULL, | ||
95 | NULL, | ||
96 | NULL, | ||
97 | NULL, | ||
98 | NULL, | ||
99 | NULL, | ||
100 | NULL, | ||
101 | NULL, | ||
102 | NULL, | ||
103 | NULL, | ||
104 | NULL, | 78 | NULL, |
105 | NULL, | 79 | NULL, |
106 | NULL, | 80 | NULL, |
107 | NULL, | 81 | NULL, |
108 | NULL, | 82 | NULL, |
83 | "Bad TLP", /* Bit Position 6 */ | ||
84 | "Bad DLLP", /* Bit Position 7 */ | ||
85 | "RELAY_NUM Rollover", /* Bit Position 8 */ | ||
109 | NULL, | 86 | NULL, |
110 | NULL, | 87 | NULL, |
111 | NULL, | 88 | NULL, |
89 | "Replay Timer Timeout", /* Bit Position 12 */ | ||
90 | "Advisory Non-Fatal", /* Bit Position 13 */ | ||
112 | }; | 91 | }; |
113 | 92 | ||
114 | static char *aer_uncorrectable_error_string[] = { | 93 | static const char *aer_uncorrectable_error_string[] = { |
115 | NULL, | ||
116 | NULL, | ||
117 | NULL, | ||
118 | NULL, | ||
119 | "Data Link Protocol ", /* Bit Position 4 */ | ||
120 | NULL, | ||
121 | NULL, | ||
122 | NULL, | ||
123 | NULL, | ||
124 | NULL, | ||
125 | NULL, | ||
126 | NULL, | ||
127 | "Poisoned TLP ", /* Bit Position 12 */ | ||
128 | "Flow Control Protocol ", /* Bit Position 13 */ | ||
129 | "Completion Timeout ", /* Bit Position 14 */ | ||
130 | "Completer Abort ", /* Bit Position 15 */ | ||
131 | "Unexpected Completion ", /* Bit Position 16 */ | ||
132 | "Receiver Overflow ", /* Bit Position 17 */ | ||
133 | "Malformed TLP ", /* Bit Position 18 */ | ||
134 | "ECRC ", /* Bit Position 19 */ | ||
135 | "Unsupported Request ", /* Bit Position 20 */ | ||
136 | NULL, | 94 | NULL, |
137 | NULL, | 95 | NULL, |
138 | NULL, | 96 | NULL, |
139 | NULL, | 97 | NULL, |
98 | "Data Link Protocol", /* Bit Position 4 */ | ||
140 | NULL, | 99 | NULL, |
141 | NULL, | 100 | NULL, |
142 | NULL, | 101 | NULL, |
@@ -144,19 +103,29 @@ static char *aer_uncorrectable_error_string[] = { | |||
144 | NULL, | 103 | NULL, |
145 | NULL, | 104 | NULL, |
146 | NULL, | 105 | NULL, |
106 | "Poisoned TLP", /* Bit Position 12 */ | ||
107 | "Flow Control Protocol", /* Bit Position 13 */ | ||
108 | "Completion Timeout", /* Bit Position 14 */ | ||
109 | "Completer Abort", /* Bit Position 15 */ | ||
110 | "Unexpected Completion", /* Bit Position 16 */ | ||
111 | "Receiver Overflow", /* Bit Position 17 */ | ||
112 | "Malformed TLP", /* Bit Position 18 */ | ||
113 | "ECRC", /* Bit Position 19 */ | ||
114 | "Unsupported Request", /* Bit Position 20 */ | ||
147 | }; | 115 | }; |
148 | 116 | ||
149 | static char *aer_agent_string[] = { | 117 | static const char *aer_agent_string[] = { |
150 | "Receiver ID", | 118 | "Receiver ID", |
151 | "Requester ID", | 119 | "Requester ID", |
152 | "Completer ID", | 120 | "Completer ID", |
153 | "Transmitter ID" | 121 | "Transmitter ID" |
154 | }; | 122 | }; |
155 | 123 | ||
156 | static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev) | 124 | static void __aer_print_error(const char *prefix, |
125 | struct aer_err_info *info) | ||
157 | { | 126 | { |
158 | int i, status; | 127 | int i, status; |
159 | char *errmsg = NULL; | 128 | const char *errmsg = NULL; |
160 | 129 | ||
161 | status = (info->status & ~info->mask); | 130 | status = (info->status & ~info->mask); |
162 | 131 | ||
@@ -165,15 +134,17 @@ static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev) | |||
165 | continue; | 134 | continue; |
166 | 135 | ||
167 | if (info->severity == AER_CORRECTABLE) | 136 | if (info->severity == AER_CORRECTABLE) |
168 | errmsg = aer_correctable_error_string[i]; | 137 | errmsg = i < ARRAY_SIZE(aer_correctable_error_string) ? |
138 | aer_correctable_error_string[i] : NULL; | ||
169 | else | 139 | else |
170 | errmsg = aer_uncorrectable_error_string[i]; | 140 | errmsg = i < ARRAY_SIZE(aer_uncorrectable_error_string) ? |
141 | aer_uncorrectable_error_string[i] : NULL; | ||
171 | 142 | ||
172 | if (errmsg) | 143 | if (errmsg) |
173 | AER_PR(info, dev, " [%2d] %s%s\n", i, errmsg, | 144 | printk("%s"" [%2d] %-22s%s\n", prefix, i, errmsg, |
174 | info->first_error == i ? " (First)" : ""); | 145 | info->first_error == i ? " (First)" : ""); |
175 | else | 146 | else |
176 | AER_PR(info, dev, " [%2d] Unknown Error Bit%s\n", i, | 147 | printk("%s"" [%2d] Unknown Error Bit%s\n", prefix, i, |
177 | info->first_error == i ? " (First)" : ""); | 148 | info->first_error == i ? " (First)" : ""); |
178 | } | 149 | } |
179 | } | 150 | } |
@@ -181,11 +152,15 @@ static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev) | |||
181 | void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) | 152 | void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) |
182 | { | 153 | { |
183 | int id = ((dev->bus->number << 8) | dev->devfn); | 154 | int id = ((dev->bus->number << 8) | dev->devfn); |
155 | char prefix[44]; | ||
156 | |||
157 | snprintf(prefix, sizeof(prefix), "%s%s %s: ", | ||
158 | (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR, | ||
159 | dev_driver_string(&dev->dev), dev_name(&dev->dev)); | ||
184 | 160 | ||
185 | if (info->status == 0) { | 161 | if (info->status == 0) { |
186 | AER_PR(info, dev, | 162 | printk("%s""PCIe Bus Error: severity=%s, type=Unaccessible, " |
187 | "PCIe Bus Error: severity=%s, type=Unaccessible, " | 163 | "id=%04x(Unregistered Agent ID)\n", prefix, |
188 | "id=%04x(Unregistered Agent ID)\n", | ||
189 | aer_error_severity_string[info->severity], id); | 164 | aer_error_severity_string[info->severity], id); |
190 | } else { | 165 | } else { |
191 | int layer, agent; | 166 | int layer, agent; |
@@ -193,23 +168,22 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) | |||
193 | layer = AER_GET_LAYER_ERROR(info->severity, info->status); | 168 | layer = AER_GET_LAYER_ERROR(info->severity, info->status); |
194 | agent = AER_GET_AGENT(info->severity, info->status); | 169 | agent = AER_GET_AGENT(info->severity, info->status); |
195 | 170 | ||
196 | AER_PR(info, dev, | 171 | printk("%s""PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", |
197 | "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", | 172 | prefix, aer_error_severity_string[info->severity], |
198 | aer_error_severity_string[info->severity], | ||
199 | aer_error_layer[layer], id, aer_agent_string[agent]); | 173 | aer_error_layer[layer], id, aer_agent_string[agent]); |
200 | 174 | ||
201 | AER_PR(info, dev, | 175 | printk("%s"" device [%04x:%04x] error status/mask=%08x/%08x\n", |
202 | " device [%04x:%04x] error status/mask=%08x/%08x\n", | 176 | prefix, dev->vendor, dev->device, |
203 | dev->vendor, dev->device, info->status, info->mask); | 177 | info->status, info->mask); |
204 | 178 | ||
205 | __aer_print_error(info, dev); | 179 | __aer_print_error(prefix, info); |
206 | 180 | ||
207 | if (info->tlp_header_valid) { | 181 | if (info->tlp_header_valid) { |
208 | unsigned char *tlp = (unsigned char *) &info->tlp; | 182 | unsigned char *tlp = (unsigned char *) &info->tlp; |
209 | AER_PR(info, dev, " TLP Header:" | 183 | printk("%s"" TLP Header:" |
210 | " %02x%02x%02x%02x %02x%02x%02x%02x" | 184 | " %02x%02x%02x%02x %02x%02x%02x%02x" |
211 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", | 185 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", |
212 | *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, | 186 | prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, |
213 | *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), | 187 | *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), |
214 | *(tlp + 11), *(tlp + 10), *(tlp + 9), | 188 | *(tlp + 11), *(tlp + 10), *(tlp + 9), |
215 | *(tlp + 8), *(tlp + 15), *(tlp + 14), | 189 | *(tlp + 8), *(tlp + 15), *(tlp + 14), |
@@ -218,8 +192,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) | |||
218 | } | 192 | } |
219 | 193 | ||
220 | if (info->id && info->error_dev_num > 1 && info->id == id) | 194 | if (info->id && info->error_dev_num > 1 && info->id == id) |
221 | AER_PR(info, dev, | 195 | printk("%s"" Error of this Agent(%04x) is reported first\n", |
222 | " Error of this Agent(%04x) is reported first\n", id); | 196 | prefix, id); |
223 | } | 197 | } |
224 | 198 | ||
225 | void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) | 199 | void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) |
@@ -228,3 +202,61 @@ void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) | |||
228 | info->multi_error_valid ? "Multiple " : "", | 202 | info->multi_error_valid ? "Multiple " : "", |
229 | aer_error_severity_string[info->severity], info->id); | 203 | aer_error_severity_string[info->severity], info->id); |
230 | } | 204 | } |
205 | |||
206 | #ifdef CONFIG_ACPI_APEI_PCIEAER | ||
207 | static int cper_severity_to_aer(int cper_severity) | ||
208 | { | ||
209 | switch (cper_severity) { | ||
210 | case CPER_SEV_RECOVERABLE: | ||
211 | return AER_NONFATAL; | ||
212 | case CPER_SEV_FATAL: | ||
213 | return AER_FATAL; | ||
214 | default: | ||
215 | return AER_CORRECTABLE; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | void cper_print_aer(const char *prefix, int cper_severity, | ||
220 | struct aer_capability_regs *aer) | ||
221 | { | ||
222 | int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0; | ||
223 | u32 status, mask; | ||
224 | const char **status_strs; | ||
225 | |||
226 | aer_severity = cper_severity_to_aer(cper_severity); | ||
227 | if (aer_severity == AER_CORRECTABLE) { | ||
228 | status = aer->cor_status; | ||
229 | mask = aer->cor_mask; | ||
230 | status_strs = aer_correctable_error_string; | ||
231 | status_strs_size = ARRAY_SIZE(aer_correctable_error_string); | ||
232 | } else { | ||
233 | status = aer->uncor_status; | ||
234 | mask = aer->uncor_mask; | ||
235 | status_strs = aer_uncorrectable_error_string; | ||
236 | status_strs_size = ARRAY_SIZE(aer_uncorrectable_error_string); | ||
237 | tlp_header_valid = status & AER_LOG_TLP_MASKS; | ||
238 | } | ||
239 | layer = AER_GET_LAYER_ERROR(aer_severity, status); | ||
240 | agent = AER_GET_AGENT(aer_severity, status); | ||
241 | printk("%s""aer_status: 0x%08x, aer_mask: 0x%08x\n", | ||
242 | prefix, status, mask); | ||
243 | cper_print_bits(prefix, status, status_strs, status_strs_size); | ||
244 | printk("%s""aer_layer=%s, aer_agent=%s\n", prefix, | ||
245 | aer_error_layer[layer], aer_agent_string[agent]); | ||
246 | if (aer_severity != AER_CORRECTABLE) | ||
247 | printk("%s""aer_uncor_severity: 0x%08x\n", | ||
248 | prefix, aer->uncor_severity); | ||
249 | if (tlp_header_valid) { | ||
250 | const unsigned char *tlp; | ||
251 | tlp = (const unsigned char *)&aer->header_log; | ||
252 | printk("%s""aer_tlp_header:" | ||
253 | " %02x%02x%02x%02x %02x%02x%02x%02x" | ||
254 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", | ||
255 | prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, | ||
256 | *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), | ||
257 | *(tlp + 11), *(tlp + 10), *(tlp + 9), | ||
258 | *(tlp + 8), *(tlp + 15), *(tlp + 14), | ||
259 | *(tlp + 13), *(tlp + 12)); | ||
260 | } | ||
261 | } | ||
262 | #endif | ||
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 71222814c1ec..6892601fc76f 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
@@ -68,7 +68,8 @@ struct pcie_link_state { | |||
68 | struct aspm_latency acceptable[8]; | 68 | struct aspm_latency acceptable[8]; |
69 | }; | 69 | }; |
70 | 70 | ||
71 | static int aspm_disabled, aspm_force; | 71 | static int aspm_disabled, aspm_force, aspm_clear_state; |
72 | static bool aspm_support_enabled = true; | ||
72 | static DEFINE_MUTEX(aspm_lock); | 73 | static DEFINE_MUTEX(aspm_lock); |
73 | static LIST_HEAD(link_list); | 74 | static LIST_HEAD(link_list); |
74 | 75 | ||
@@ -139,7 +140,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable) | |||
139 | { | 140 | { |
140 | /* Don't enable Clock PM if the link is not Clock PM capable */ | 141 | /* Don't enable Clock PM if the link is not Clock PM capable */ |
141 | if (!link->clkpm_capable && enable) | 142 | if (!link->clkpm_capable && enable) |
142 | return; | 143 | enable = 0; |
143 | /* Need nothing if the specified equals to current state */ | 144 | /* Need nothing if the specified equals to current state */ |
144 | if (link->clkpm_enabled == enable) | 145 | if (link->clkpm_enabled == enable) |
145 | return; | 146 | return; |
@@ -498,6 +499,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) | |||
498 | struct pci_dev *child; | 499 | struct pci_dev *child; |
499 | int pos; | 500 | int pos; |
500 | u32 reg32; | 501 | u32 reg32; |
502 | |||
503 | if (aspm_clear_state) | ||
504 | return -EINVAL; | ||
505 | |||
501 | /* | 506 | /* |
502 | * Some functions in a slot might not all be PCIe functions, | 507 | * Some functions in a slot might not all be PCIe functions, |
503 | * very strange. Disable ASPM for the whole slot | 508 | * very strange. Disable ASPM for the whole slot |
@@ -563,12 +568,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) | |||
563 | struct pcie_link_state *link; | 568 | struct pcie_link_state *link; |
564 | int blacklist = !!pcie_aspm_sanity_check(pdev); | 569 | int blacklist = !!pcie_aspm_sanity_check(pdev); |
565 | 570 | ||
566 | if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state) | 571 | if (!pci_is_pcie(pdev) || pdev->link_state) |
567 | return; | 572 | return; |
568 | if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && | 573 | if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && |
569 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) | 574 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) |
570 | return; | 575 | return; |
571 | 576 | ||
577 | if (aspm_disabled && !aspm_clear_state) | ||
578 | return; | ||
579 | |||
572 | /* VIA has a strange chipset, root port is under a bridge */ | 580 | /* VIA has a strange chipset, root port is under a bridge */ |
573 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && | 581 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && |
574 | pdev->bus->self) | 582 | pdev->bus->self) |
@@ -600,7 +608,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) | |||
600 | * the BIOS's expectation, we'll do so once pci_enable_device() is | 608 | * the BIOS's expectation, we'll do so once pci_enable_device() is |
601 | * called. | 609 | * called. |
602 | */ | 610 | */ |
603 | if (aspm_policy != POLICY_POWERSAVE) { | 611 | if (aspm_policy != POLICY_POWERSAVE || aspm_clear_state) { |
604 | pcie_config_aspm_path(link); | 612 | pcie_config_aspm_path(link); |
605 | pcie_set_clkpm(link, policy_to_clkpm_state(link)); | 613 | pcie_set_clkpm(link, policy_to_clkpm_state(link)); |
606 | } | 614 | } |
@@ -641,7 +649,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) | |||
641 | struct pci_dev *parent = pdev->bus->self; | 649 | struct pci_dev *parent = pdev->bus->self; |
642 | struct pcie_link_state *link, *root, *parent_link; | 650 | struct pcie_link_state *link, *root, *parent_link; |
643 | 651 | ||
644 | if (aspm_disabled || !pci_is_pcie(pdev) || | 652 | if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) || |
645 | !parent || !parent->link_state) | 653 | !parent || !parent->link_state) |
646 | return; | 654 | return; |
647 | if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && | 655 | if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && |
@@ -700,11 +708,33 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) | |||
700 | up_read(&pci_bus_sem); | 708 | up_read(&pci_bus_sem); |
701 | } | 709 | } |
702 | 710 | ||
711 | void pcie_aspm_powersave_config_link(struct pci_dev *pdev) | ||
712 | { | ||
713 | struct pcie_link_state *link = pdev->link_state; | ||
714 | |||
715 | if (aspm_disabled || !pci_is_pcie(pdev) || !link) | ||
716 | return; | ||
717 | |||
718 | if (aspm_policy != POLICY_POWERSAVE) | ||
719 | return; | ||
720 | |||
721 | if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && | ||
722 | (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) | ||
723 | return; | ||
724 | |||
725 | down_read(&pci_bus_sem); | ||
726 | mutex_lock(&aspm_lock); | ||
727 | pcie_config_aspm_path(link); | ||
728 | pcie_set_clkpm(link, policy_to_clkpm_state(link)); | ||
729 | mutex_unlock(&aspm_lock); | ||
730 | up_read(&pci_bus_sem); | ||
731 | } | ||
732 | |||
703 | /* | 733 | /* |
704 | * pci_disable_link_state - disable pci device's link state, so the link will | 734 | * pci_disable_link_state - disable pci device's link state, so the link will |
705 | * never enter specific states | 735 | * never enter specific states |
706 | */ | 736 | */ |
707 | void pci_disable_link_state(struct pci_dev *pdev, int state) | 737 | static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) |
708 | { | 738 | { |
709 | struct pci_dev *parent = pdev->bus->self; | 739 | struct pci_dev *parent = pdev->bus->self; |
710 | struct pcie_link_state *link; | 740 | struct pcie_link_state *link; |
@@ -717,7 +747,8 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) | |||
717 | if (!parent || !parent->link_state) | 747 | if (!parent || !parent->link_state) |
718 | return; | 748 | return; |
719 | 749 | ||
720 | down_read(&pci_bus_sem); | 750 | if (sem) |
751 | down_read(&pci_bus_sem); | ||
721 | mutex_lock(&aspm_lock); | 752 | mutex_lock(&aspm_lock); |
722 | link = parent->link_state; | 753 | link = parent->link_state; |
723 | if (state & PCIE_LINK_STATE_L0S) | 754 | if (state & PCIE_LINK_STATE_L0S) |
@@ -731,7 +762,19 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) | |||
731 | pcie_set_clkpm(link, 0); | 762 | pcie_set_clkpm(link, 0); |
732 | } | 763 | } |
733 | mutex_unlock(&aspm_lock); | 764 | mutex_unlock(&aspm_lock); |
734 | up_read(&pci_bus_sem); | 765 | if (sem) |
766 | up_read(&pci_bus_sem); | ||
767 | } | ||
768 | |||
769 | void pci_disable_link_state_locked(struct pci_dev *pdev, int state) | ||
770 | { | ||
771 | __pci_disable_link_state(pdev, state, false); | ||
772 | } | ||
773 | EXPORT_SYMBOL(pci_disable_link_state_locked); | ||
774 | |||
775 | void pci_disable_link_state(struct pci_dev *pdev, int state) | ||
776 | { | ||
777 | __pci_disable_link_state(pdev, state, true); | ||
735 | } | 778 | } |
736 | EXPORT_SYMBOL(pci_disable_link_state); | 779 | EXPORT_SYMBOL(pci_disable_link_state); |
737 | 780 | ||
@@ -740,6 +783,8 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) | |||
740 | int i; | 783 | int i; |
741 | struct pcie_link_state *link; | 784 | struct pcie_link_state *link; |
742 | 785 | ||
786 | if (aspm_disabled) | ||
787 | return -EPERM; | ||
743 | for (i = 0; i < ARRAY_SIZE(policy_str); i++) | 788 | for (i = 0; i < ARRAY_SIZE(policy_str); i++) |
744 | if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) | 789 | if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) |
745 | break; | 790 | break; |
@@ -794,6 +839,8 @@ static ssize_t link_state_store(struct device *dev, | |||
794 | struct pcie_link_state *link, *root = pdev->link_state->root; | 839 | struct pcie_link_state *link, *root = pdev->link_state->root; |
795 | u32 val = buf[0] - '0', state = 0; | 840 | u32 val = buf[0] - '0', state = 0; |
796 | 841 | ||
842 | if (aspm_disabled) | ||
843 | return -EPERM; | ||
797 | if (n < 1 || val > 3) | 844 | if (n < 1 || val > 3) |
798 | return -EINVAL; | 845 | return -EINVAL; |
799 | 846 | ||
@@ -889,6 +936,7 @@ static int __init pcie_aspm_disable(char *str) | |||
889 | { | 936 | { |
890 | if (!strcmp(str, "off")) { | 937 | if (!strcmp(str, "off")) { |
891 | aspm_disabled = 1; | 938 | aspm_disabled = 1; |
939 | aspm_support_enabled = false; | ||
892 | printk(KERN_INFO "PCIe ASPM is disabled\n"); | 940 | printk(KERN_INFO "PCIe ASPM is disabled\n"); |
893 | } else if (!strcmp(str, "force")) { | 941 | } else if (!strcmp(str, "force")) { |
894 | aspm_force = 1; | 942 | aspm_force = 1; |
@@ -899,6 +947,12 @@ static int __init pcie_aspm_disable(char *str) | |||
899 | 947 | ||
900 | __setup("pcie_aspm=", pcie_aspm_disable); | 948 | __setup("pcie_aspm=", pcie_aspm_disable); |
901 | 949 | ||
950 | void pcie_clear_aspm(void) | ||
951 | { | ||
952 | if (!aspm_force) | ||
953 | aspm_clear_state = 1; | ||
954 | } | ||
955 | |||
902 | void pcie_no_aspm(void) | 956 | void pcie_no_aspm(void) |
903 | { | 957 | { |
904 | if (!aspm_force) | 958 | if (!aspm_force) |
@@ -917,3 +971,8 @@ int pcie_aspm_enabled(void) | |||
917 | } | 971 | } |
918 | EXPORT_SYMBOL(pcie_aspm_enabled); | 972 | EXPORT_SYMBOL(pcie_aspm_enabled); |
919 | 973 | ||
974 | bool pcie_aspm_support_enabled(void) | ||
975 | { | ||
976 | return aspm_support_enabled; | ||
977 | } | ||
978 | EXPORT_SYMBOL(pcie_aspm_support_enabled); | ||
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 2f3c90407227..0057344a3fcb 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c | |||
@@ -26,9 +26,6 @@ | |||
26 | #include "../pci.h" | 26 | #include "../pci.h" |
27 | #include "portdrv.h" | 27 | #include "portdrv.h" |
28 | 28 | ||
29 | #define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ | ||
30 | #define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ | ||
31 | |||
32 | /* | 29 | /* |
33 | * If this switch is set, MSI will not be used for PCIe PME signaling. This | 30 | * If this switch is set, MSI will not be used for PCIe PME signaling. This |
34 | * causes the PCIe port driver to use INTx interrupts only, but it turns out | 31 | * causes the PCIe port driver to use INTx interrupts only, but it turns out |
@@ -74,22 +71,6 @@ void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) | |||
74 | } | 71 | } |
75 | 72 | ||
76 | /** | 73 | /** |
77 | * pcie_pme_clear_status - Clear root port PME interrupt status. | ||
78 | * @dev: PCIe root port or event collector. | ||
79 | */ | ||
80 | static void pcie_pme_clear_status(struct pci_dev *dev) | ||
81 | { | ||
82 | int rtsta_pos; | ||
83 | u32 rtsta; | ||
84 | |||
85 | rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA; | ||
86 | |||
87 | pci_read_config_dword(dev, rtsta_pos, &rtsta); | ||
88 | rtsta |= PCI_EXP_RTSTA_PME; | ||
89 | pci_write_config_dword(dev, rtsta_pos, rtsta); | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#. | 74 | * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#. |
94 | * @bus: PCI bus to scan. | 75 | * @bus: PCI bus to scan. |
95 | * | 76 | * |
@@ -103,8 +84,8 @@ static bool pcie_pme_walk_bus(struct pci_bus *bus) | |||
103 | list_for_each_entry(dev, &bus->devices, bus_list) { | 84 | list_for_each_entry(dev, &bus->devices, bus_list) { |
104 | /* Skip PCIe devices in case we started from a root port. */ | 85 | /* Skip PCIe devices in case we started from a root port. */ |
105 | if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) { | 86 | if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) { |
106 | pm_request_resume(&dev->dev); | ||
107 | pci_wakeup_event(dev); | 87 | pci_wakeup_event(dev); |
88 | pm_request_resume(&dev->dev); | ||
108 | ret = true; | 89 | ret = true; |
109 | } | 90 | } |
110 | 91 | ||
@@ -206,8 +187,8 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) | |||
206 | /* The device is there, but we have to check its PME status. */ | 187 | /* The device is there, but we have to check its PME status. */ |
207 | found = pci_check_pme_status(dev); | 188 | found = pci_check_pme_status(dev); |
208 | if (found) { | 189 | if (found) { |
209 | pm_request_resume(&dev->dev); | ||
210 | pci_wakeup_event(dev); | 190 | pci_wakeup_event(dev); |
191 | pm_request_resume(&dev->dev); | ||
211 | } | 192 | } |
212 | pci_dev_put(dev); | 193 | pci_dev_put(dev); |
213 | } else if (devfn) { | 194 | } else if (devfn) { |
@@ -253,7 +234,7 @@ static void pcie_pme_work_fn(struct work_struct *work) | |||
253 | * Clear PME status of the port. If there are other | 234 | * Clear PME status of the port. If there are other |
254 | * pending PMEs, the status will be set again. | 235 | * pending PMEs, the status will be set again. |
255 | */ | 236 | */ |
256 | pcie_pme_clear_status(port); | 237 | pcie_clear_root_pme_status(port); |
257 | 238 | ||
258 | spin_unlock_irq(&data->lock); | 239 | spin_unlock_irq(&data->lock); |
259 | pcie_pme_handle_request(port, rtsta & 0xffff); | 240 | pcie_pme_handle_request(port, rtsta & 0xffff); |
@@ -378,7 +359,7 @@ static int pcie_pme_probe(struct pcie_device *srv) | |||
378 | 359 | ||
379 | port = srv->port; | 360 | port = srv->port; |
380 | pcie_pme_interrupt_enable(port, false); | 361 | pcie_pme_interrupt_enable(port, false); |
381 | pcie_pme_clear_status(port); | 362 | pcie_clear_root_pme_status(port); |
382 | 363 | ||
383 | ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv); | 364 | ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv); |
384 | if (ret) { | 365 | if (ret) { |
@@ -402,7 +383,7 @@ static int pcie_pme_suspend(struct pcie_device *srv) | |||
402 | 383 | ||
403 | spin_lock_irq(&data->lock); | 384 | spin_lock_irq(&data->lock); |
404 | pcie_pme_interrupt_enable(port, false); | 385 | pcie_pme_interrupt_enable(port, false); |
405 | pcie_pme_clear_status(port); | 386 | pcie_clear_root_pme_status(port); |
406 | data->noirq = true; | 387 | data->noirq = true; |
407 | spin_unlock_irq(&data->lock); | 388 | spin_unlock_irq(&data->lock); |
408 | 389 | ||
@@ -422,7 +403,7 @@ static int pcie_pme_resume(struct pcie_device *srv) | |||
422 | 403 | ||
423 | spin_lock_irq(&data->lock); | 404 | spin_lock_irq(&data->lock); |
424 | data->noirq = false; | 405 | data->noirq = false; |
425 | pcie_pme_clear_status(port); | 406 | pcie_clear_root_pme_status(port); |
426 | pcie_pme_interrupt_enable(port, true); | 407 | pcie_pme_interrupt_enable(port, true); |
427 | spin_unlock_irq(&data->lock); | 408 | spin_unlock_irq(&data->lock); |
428 | 409 | ||
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 7b5aba0a3291..bd00a01aef14 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h | |||
@@ -20,9 +20,6 @@ | |||
20 | 20 | ||
21 | #define get_descriptor_id(type, service) (((type - 4) << 4) | service) | 21 | #define get_descriptor_id(type, service) (((type - 4) << 4) | service) |
22 | 22 | ||
23 | extern bool pcie_ports_disabled; | ||
24 | extern bool pcie_ports_auto; | ||
25 | |||
26 | extern struct bus_type pcie_port_bus_type; | 23 | extern struct bus_type pcie_port_bus_type; |
27 | extern int pcie_port_device_register(struct pci_dev *dev); | 24 | extern int pcie_port_device_register(struct pci_dev *dev); |
28 | #ifdef CONFIG_PM | 25 | #ifdef CONFIG_PM |
@@ -35,6 +32,8 @@ extern void pcie_port_bus_unregister(void); | |||
35 | 32 | ||
36 | struct pci_dev; | 33 | struct pci_dev; |
37 | 34 | ||
35 | extern void pcie_clear_root_pme_status(struct pci_dev *dev); | ||
36 | |||
38 | #ifdef CONFIG_PCIE_PME | 37 | #ifdef CONFIG_PCIE_PME |
39 | extern bool pcie_pme_msi_disabled; | 38 | extern bool pcie_pme_msi_disabled; |
40 | 39 | ||
diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c index b7c4cb1ccb23..a86b56e5f2f2 100644 --- a/drivers/pci/pcie/portdrv_acpi.c +++ b/drivers/pci/pcie/portdrv_acpi.c | |||
@@ -33,7 +33,7 @@ | |||
33 | */ | 33 | */ |
34 | int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) | 34 | int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) |
35 | { | 35 | { |
36 | acpi_status status; | 36 | struct acpi_pci_root *root; |
37 | acpi_handle handle; | 37 | acpi_handle handle; |
38 | u32 flags; | 38 | u32 flags; |
39 | 39 | ||
@@ -44,26 +44,11 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) | |||
44 | if (!handle) | 44 | if (!handle) |
45 | return -EINVAL; | 45 | return -EINVAL; |
46 | 46 | ||
47 | flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL | 47 | root = acpi_pci_find_root(handle); |
48 | | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | 48 | if (!root) |
49 | | OSC_PCI_EXPRESS_PME_CONTROL; | ||
50 | |||
51 | if (pci_aer_available()) { | ||
52 | if (pcie_aer_get_firmware_first(port)) | ||
53 | dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n"); | ||
54 | else | ||
55 | flags |= OSC_PCI_EXPRESS_AER_CONTROL; | ||
56 | } | ||
57 | |||
58 | status = acpi_pci_osc_control_set(handle, &flags, | ||
59 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | ||
60 | if (ACPI_FAILURE(status)) { | ||
61 | dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n", | ||
62 | status); | ||
63 | return -ENODEV; | 49 | return -ENODEV; |
64 | } | ||
65 | 50 | ||
66 | dev_info(&port->dev, "ACPI _OSC control granted for 0x%02x\n", flags); | 51 | flags = root->osc_control_set; |
67 | 52 | ||
68 | *srv_mask = PCIE_PORT_SERVICE_VC; | 53 | *srv_mask = PCIE_PORT_SERVICE_VC; |
69 | if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL) | 54 | if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL) |
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index a9c222d79ebc..595654a1a6a6 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/pcieport_if.h> | 16 | #include <linux/pcieport_if.h> |
17 | #include <linux/aer.h> | 17 | #include <linux/aer.h> |
18 | #include <linux/pci-aspm.h> | ||
19 | 18 | ||
20 | #include "../pci.h" | 19 | #include "../pci.h" |
21 | #include "portdrv.h" | 20 | #include "portdrv.h" |
@@ -241,17 +240,17 @@ static int get_port_device_capability(struct pci_dev *dev) | |||
241 | int cap_mask; | 240 | int cap_mask; |
242 | int err; | 241 | int err; |
243 | 242 | ||
243 | if (pcie_ports_disabled) | ||
244 | return 0; | ||
245 | |||
244 | err = pcie_port_platform_notify(dev, &cap_mask); | 246 | err = pcie_port_platform_notify(dev, &cap_mask); |
245 | if (pcie_ports_auto) { | 247 | if (!pcie_ports_auto) { |
246 | if (err) { | ||
247 | pcie_no_aspm(); | ||
248 | return 0; | ||
249 | } | ||
250 | } else { | ||
251 | cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP | 248 | cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP |
252 | | PCIE_PORT_SERVICE_VC; | 249 | | PCIE_PORT_SERVICE_VC; |
253 | if (pci_aer_available()) | 250 | if (pci_aer_available()) |
254 | cap_mask |= PCIE_PORT_SERVICE_AER; | 251 | cap_mask |= PCIE_PORT_SERVICE_AER; |
252 | } else if (err) { | ||
253 | return 0; | ||
255 | } | 254 | } |
256 | 255 | ||
257 | pos = pci_pcie_cap(dev); | 256 | pos = pci_pcie_cap(dev); |
@@ -349,15 +348,16 @@ int pcie_port_device_register(struct pci_dev *dev) | |||
349 | int status, capabilities, i, nr_service; | 348 | int status, capabilities, i, nr_service; |
350 | int irqs[PCIE_PORT_DEVICE_MAXSERVICES]; | 349 | int irqs[PCIE_PORT_DEVICE_MAXSERVICES]; |
351 | 350 | ||
352 | /* Get and check PCI Express port services */ | ||
353 | capabilities = get_port_device_capability(dev); | ||
354 | if (!capabilities) | ||
355 | return -ENODEV; | ||
356 | |||
357 | /* Enable PCI Express port device */ | 351 | /* Enable PCI Express port device */ |
358 | status = pci_enable_device(dev); | 352 | status = pci_enable_device(dev); |
359 | if (status) | 353 | if (status) |
360 | return status; | 354 | return status; |
355 | |||
356 | /* Get and check PCI Express port services */ | ||
357 | capabilities = get_port_device_capability(dev); | ||
358 | if (!capabilities) | ||
359 | return 0; | ||
360 | |||
361 | pci_set_master(dev); | 361 | pci_set_master(dev); |
362 | /* | 362 | /* |
363 | * Initialize service irqs. Don't use service devices that | 363 | * Initialize service irqs. Don't use service devices that |
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index f9033e190fb6..e0610bda1dea 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c | |||
@@ -57,6 +57,22 @@ __setup("pcie_ports=", pcie_port_setup); | |||
57 | 57 | ||
58 | /* global data */ | 58 | /* global data */ |
59 | 59 | ||
60 | /** | ||
61 | * pcie_clear_root_pme_status - Clear root port PME interrupt status. | ||
62 | * @dev: PCIe root port or event collector. | ||
63 | */ | ||
64 | void pcie_clear_root_pme_status(struct pci_dev *dev) | ||
65 | { | ||
66 | int rtsta_pos; | ||
67 | u32 rtsta; | ||
68 | |||
69 | rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA; | ||
70 | |||
71 | pci_read_config_dword(dev, rtsta_pos, &rtsta); | ||
72 | rtsta |= PCI_EXP_RTSTA_PME; | ||
73 | pci_write_config_dword(dev, rtsta_pos, rtsta); | ||
74 | } | ||
75 | |||
60 | static int pcie_portdrv_restore_config(struct pci_dev *dev) | 76 | static int pcie_portdrv_restore_config(struct pci_dev *dev) |
61 | { | 77 | { |
62 | int retval; | 78 | int retval; |
@@ -69,6 +85,20 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) | |||
69 | } | 85 | } |
70 | 86 | ||
71 | #ifdef CONFIG_PM | 87 | #ifdef CONFIG_PM |
88 | static int pcie_port_resume_noirq(struct device *dev) | ||
89 | { | ||
90 | struct pci_dev *pdev = to_pci_dev(dev); | ||
91 | |||
92 | /* | ||
93 | * Some BIOSes forget to clear Root PME Status bits after system wakeup | ||
94 | * which breaks ACPI-based runtime wakeup on PCI Express, so clear those | ||
95 | * bits now just in case (shouldn't hurt). | ||
96 | */ | ||
97 | if(pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) | ||
98 | pcie_clear_root_pme_status(pdev); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
72 | static const struct dev_pm_ops pcie_portdrv_pm_ops = { | 102 | static const struct dev_pm_ops pcie_portdrv_pm_ops = { |
73 | .suspend = pcie_port_device_suspend, | 103 | .suspend = pcie_port_device_suspend, |
74 | .resume = pcie_port_device_resume, | 104 | .resume = pcie_port_device_resume, |
@@ -76,6 +106,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = { | |||
76 | .thaw = pcie_port_device_resume, | 106 | .thaw = pcie_port_device_resume, |
77 | .poweroff = pcie_port_device_suspend, | 107 | .poweroff = pcie_port_device_suspend, |
78 | .restore = pcie_port_device_resume, | 108 | .restore = pcie_port_device_resume, |
109 | .resume_noirq = pcie_port_resume_noirq, | ||
79 | }; | 110 | }; |
80 | 111 | ||
81 | #define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) | 112 | #define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) |
@@ -327,10 +358,8 @@ static int __init pcie_portdrv_init(void) | |||
327 | { | 358 | { |
328 | int retval; | 359 | int retval; |
329 | 360 | ||
330 | if (pcie_ports_disabled) { | 361 | if (pcie_ports_disabled) |
331 | pcie_no_aspm(); | 362 | return pci_register_driver(&pcie_portdriver); |
332 | return -EACCES; | ||
333 | } | ||
334 | 363 | ||
335 | dmi_check_system(pcie_portdrv_dmi_table); | 364 | dmi_check_system(pcie_portdrv_dmi_table); |
336 | 365 | ||