diff options
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r-- | drivers/pci/pcie/aer/aer_inject.c | 25 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.c | 22 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.h | 34 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 107 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_errprint.c | 190 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 495 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 6 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_pci.c | 1 |
8 files changed, 423 insertions, 457 deletions
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c index d92ae21a59d8..62d15f652bb6 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c | |||
@@ -22,11 +22,10 @@ | |||
22 | #include <linux/miscdevice.h> | 22 | #include <linux/miscdevice.h> |
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/fs.h> | 24 | #include <linux/fs.h> |
25 | #include <asm/uaccess.h> | 25 | #include <linux/uaccess.h> |
26 | #include "aerdrv.h" | 26 | #include "aerdrv.h" |
27 | 27 | ||
28 | struct aer_error_inj | 28 | struct aer_error_inj { |
29 | { | ||
30 | u8 bus; | 29 | u8 bus; |
31 | u8 dev; | 30 | u8 dev; |
32 | u8 fn; | 31 | u8 fn; |
@@ -38,8 +37,7 @@ struct aer_error_inj | |||
38 | u32 header_log3; | 37 | u32 header_log3; |
39 | }; | 38 | }; |
40 | 39 | ||
41 | struct aer_error | 40 | struct aer_error { |
42 | { | ||
43 | struct list_head list; | 41 | struct list_head list; |
44 | unsigned int bus; | 42 | unsigned int bus; |
45 | unsigned int devfn; | 43 | unsigned int devfn; |
@@ -55,8 +53,7 @@ struct aer_error | |||
55 | u32 source_id; | 53 | u32 source_id; |
56 | }; | 54 | }; |
57 | 55 | ||
58 | struct pci_bus_ops | 56 | struct pci_bus_ops { |
59 | { | ||
60 | struct list_head list; | 57 | struct list_head list; |
61 | struct pci_bus *bus; | 58 | struct pci_bus *bus; |
62 | struct pci_ops *ops; | 59 | struct pci_ops *ops; |
@@ -150,7 +147,7 @@ static u32 *find_pci_config_dword(struct aer_error *err, int where, | |||
150 | target = &err->header_log1; | 147 | target = &err->header_log1; |
151 | break; | 148 | break; |
152 | case PCI_ERR_HEADER_LOG+8: | 149 | case PCI_ERR_HEADER_LOG+8: |
153 | target = &err->header_log2; | 150 | target = &err->header_log2; |
154 | break; | 151 | break; |
155 | case PCI_ERR_HEADER_LOG+12: | 152 | case PCI_ERR_HEADER_LOG+12: |
156 | target = &err->header_log3; | 153 | target = &err->header_log3; |
@@ -258,8 +255,7 @@ static int pci_bus_set_aer_ops(struct pci_bus *bus) | |||
258 | bus_ops = NULL; | 255 | bus_ops = NULL; |
259 | out: | 256 | out: |
260 | spin_unlock_irqrestore(&inject_lock, flags); | 257 | spin_unlock_irqrestore(&inject_lock, flags); |
261 | if (bus_ops) | 258 | kfree(bus_ops); |
262 | kfree(bus_ops); | ||
263 | return 0; | 259 | return 0; |
264 | } | 260 | } |
265 | 261 | ||
@@ -401,10 +397,8 @@ static int aer_inject(struct aer_error_inj *einj) | |||
401 | else | 397 | else |
402 | ret = -EINVAL; | 398 | ret = -EINVAL; |
403 | out_put: | 399 | out_put: |
404 | if (err_alloc) | 400 | kfree(err_alloc); |
405 | kfree(err_alloc); | 401 | kfree(rperr_alloc); |
406 | if (rperr_alloc) | ||
407 | kfree(rperr_alloc); | ||
408 | pci_dev_put(dev); | 402 | pci_dev_put(dev); |
409 | return ret; | 403 | return ret; |
410 | } | 404 | } |
@@ -458,8 +452,7 @@ static void __exit aer_inject_exit(void) | |||
458 | } | 452 | } |
459 | 453 | ||
460 | spin_lock_irqsave(&inject_lock, flags); | 454 | spin_lock_irqsave(&inject_lock, flags); |
461 | list_for_each_entry_safe(err, err_next, | 455 | list_for_each_entry_safe(err, err_next, &pci_bus_ops_list, list) { |
462 | &pci_bus_ops_list, list) { | ||
463 | list_del(&err->list); | 456 | list_del(&err->list); |
464 | kfree(err); | 457 | kfree(err); |
465 | } | 458 | } |
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 4770f13b3ca1..10c0e62bd5a8 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c | |||
@@ -38,7 +38,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR); | |||
38 | MODULE_DESCRIPTION(DRIVER_DESC); | 38 | MODULE_DESCRIPTION(DRIVER_DESC); |
39 | MODULE_LICENSE("GPL"); | 39 | MODULE_LICENSE("GPL"); |
40 | 40 | ||
41 | static int __devinit aer_probe (struct pcie_device *dev); | 41 | static int __devinit aer_probe(struct pcie_device *dev); |
42 | static void aer_remove(struct pcie_device *dev); | 42 | static void aer_remove(struct pcie_device *dev); |
43 | static pci_ers_result_t aer_error_detected(struct pci_dev *dev, | 43 | static pci_ers_result_t aer_error_detected(struct pci_dev *dev, |
44 | enum pci_channel_state error); | 44 | enum pci_channel_state error); |
@@ -47,7 +47,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev); | |||
47 | 47 | ||
48 | static struct pci_error_handlers aer_error_handlers = { | 48 | static struct pci_error_handlers aer_error_handlers = { |
49 | .error_detected = aer_error_detected, | 49 | .error_detected = aer_error_detected, |
50 | .resume = aer_error_resume, | 50 | .resume = aer_error_resume, |
51 | }; | 51 | }; |
52 | 52 | ||
53 | static struct pcie_port_service_driver aerdriver = { | 53 | static struct pcie_port_service_driver aerdriver = { |
@@ -134,12 +134,12 @@ EXPORT_SYMBOL_GPL(aer_irq); | |||
134 | * | 134 | * |
135 | * Invoked when Root Port's AER service is loaded. | 135 | * Invoked when Root Port's AER service is loaded. |
136 | **/ | 136 | **/ |
137 | static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev) | 137 | static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) |
138 | { | 138 | { |
139 | struct aer_rpc *rpc; | 139 | struct aer_rpc *rpc; |
140 | 140 | ||
141 | if (!(rpc = kzalloc(sizeof(struct aer_rpc), | 141 | rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL); |
142 | GFP_KERNEL))) | 142 | if (!rpc) |
143 | return NULL; | 143 | return NULL; |
144 | 144 | ||
145 | /* | 145 | /* |
@@ -189,26 +189,28 @@ static void aer_remove(struct pcie_device *dev) | |||
189 | * | 189 | * |
190 | * Invoked when PCI Express bus loads AER service driver. | 190 | * Invoked when PCI Express bus loads AER service driver. |
191 | **/ | 191 | **/ |
192 | static int __devinit aer_probe (struct pcie_device *dev) | 192 | static int __devinit aer_probe(struct pcie_device *dev) |
193 | { | 193 | { |
194 | int status; | 194 | int status; |
195 | struct aer_rpc *rpc; | 195 | struct aer_rpc *rpc; |
196 | struct device *device = &dev->device; | 196 | struct device *device = &dev->device; |
197 | 197 | ||
198 | /* Init */ | 198 | /* Init */ |
199 | if ((status = aer_init(dev))) | 199 | status = aer_init(dev); |
200 | if (status) | ||
200 | return status; | 201 | return status; |
201 | 202 | ||
202 | /* Alloc rpc data structure */ | 203 | /* Alloc rpc data structure */ |
203 | if (!(rpc = aer_alloc_rpc(dev))) { | 204 | rpc = aer_alloc_rpc(dev); |
205 | if (!rpc) { | ||
204 | dev_printk(KERN_DEBUG, device, "alloc rpc failed\n"); | 206 | dev_printk(KERN_DEBUG, device, "alloc rpc failed\n"); |
205 | aer_remove(dev); | 207 | aer_remove(dev); |
206 | return -ENOMEM; | 208 | return -ENOMEM; |
207 | } | 209 | } |
208 | 210 | ||
209 | /* Request IRQ ISR */ | 211 | /* Request IRQ ISR */ |
210 | if ((status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", | 212 | status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev); |
211 | dev))) { | 213 | if (status) { |
212 | dev_printk(KERN_DEBUG, device, "request IRQ failed\n"); | 214 | dev_printk(KERN_DEBUG, device, "request IRQ failed\n"); |
213 | aer_remove(dev); | 215 | aer_remove(dev); |
214 | return status; | 216 | return status; |
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index bbd7428ca2d0..bd833ea3ba49 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h | |||
@@ -16,12 +16,9 @@ | |||
16 | #define AER_NONFATAL 0 | 16 | #define AER_NONFATAL 0 |
17 | #define AER_FATAL 1 | 17 | #define AER_FATAL 1 |
18 | #define AER_CORRECTABLE 2 | 18 | #define AER_CORRECTABLE 2 |
19 | #define AER_UNCORRECTABLE 4 | ||
20 | #define AER_ERROR_MASK 0x001fffff | ||
21 | #define AER_ERROR(d) (d & AER_ERROR_MASK) | ||
22 | 19 | ||
23 | /* Root Error Status Register Bits */ | 20 | /* Root Error Status Register Bits */ |
24 | #define ROOT_ERR_STATUS_MASKS 0x0f | 21 | #define ROOT_ERR_STATUS_MASKS 0x0f |
25 | 22 | ||
26 | #define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \ | 23 | #define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \ |
27 | PCI_EXP_RTCTL_SENFEE| \ | 24 | PCI_EXP_RTCTL_SENFEE| \ |
@@ -32,8 +29,6 @@ | |||
32 | #define ERR_COR_ID(d) (d & 0xffff) | 29 | #define ERR_COR_ID(d) (d & 0xffff) |
33 | #define ERR_UNCOR_ID(d) (d >> 16) | 30 | #define ERR_UNCOR_ID(d) (d >> 16) |
34 | 31 | ||
35 | #define AER_SUCCESS 0 | ||
36 | #define AER_UNSUCCESS 1 | ||
37 | #define AER_ERROR_SOURCES_MAX 100 | 32 | #define AER_ERROR_SOURCES_MAX 100 |
38 | 33 | ||
39 | #define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \ | 34 | #define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \ |
@@ -43,13 +38,6 @@ | |||
43 | PCI_ERR_UNC_UNX_COMP| \ | 38 | PCI_ERR_UNC_UNX_COMP| \ |
44 | PCI_ERR_UNC_MALF_TLP) | 39 | PCI_ERR_UNC_MALF_TLP) |
45 | 40 | ||
46 | /* AER Error Info Flags */ | ||
47 | #define AER_TLP_HEADER_VALID_FLAG 0x00000001 | ||
48 | #define AER_MULTI_ERROR_VALID_FLAG 0x00000002 | ||
49 | |||
50 | #define ERR_CORRECTABLE_ERROR_MASK 0x000031c1 | ||
51 | #define ERR_UNCORRECTABLE_ERROR_MASK 0x001ff010 | ||
52 | |||
53 | struct header_log_regs { | 41 | struct header_log_regs { |
54 | unsigned int dw0; | 42 | unsigned int dw0; |
55 | unsigned int dw1; | 43 | unsigned int dw1; |
@@ -61,11 +49,20 @@ struct header_log_regs { | |||
61 | struct aer_err_info { | 49 | struct aer_err_info { |
62 | struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; | 50 | struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; |
63 | int error_dev_num; | 51 | int error_dev_num; |
64 | u16 id; | 52 | |
65 | int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */ | 53 | unsigned int id:16; |
66 | int flags; | 54 | |
55 | unsigned int severity:2; /* 0:NONFATAL | 1:FATAL | 2:COR */ | ||
56 | unsigned int __pad1:5; | ||
57 | unsigned int multi_error_valid:1; | ||
58 | |||
59 | unsigned int first_error:5; | ||
60 | unsigned int __pad2:2; | ||
61 | unsigned int tlp_header_valid:1; | ||
62 | |||
67 | unsigned int status; /* COR/UNCOR Error Status */ | 63 | unsigned int status; /* COR/UNCOR Error Status */ |
68 | struct header_log_regs tlp; /* TLP Header */ | 64 | unsigned int mask; /* COR/UNCOR Error Mask */ |
65 | struct header_log_regs tlp; /* TLP Header */ | ||
69 | }; | 66 | }; |
70 | 67 | ||
71 | struct aer_err_source { | 68 | struct aer_err_source { |
@@ -125,6 +122,7 @@ extern void aer_delete_rootport(struct aer_rpc *rpc); | |||
125 | extern int aer_init(struct pcie_device *dev); | 122 | extern int aer_init(struct pcie_device *dev); |
126 | extern void aer_isr(struct work_struct *work); | 123 | extern void aer_isr(struct work_struct *work); |
127 | extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); | 124 | extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); |
125 | extern void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info); | ||
128 | extern irqreturn_t aer_irq(int irq, void *context); | 126 | extern irqreturn_t aer_irq(int irq, void *context); |
129 | 127 | ||
130 | #ifdef CONFIG_ACPI | 128 | #ifdef CONFIG_ACPI |
@@ -136,4 +134,4 @@ static inline int aer_osc_setup(struct pcie_device *pciedev) | |||
136 | } | 134 | } |
137 | #endif | 135 | #endif |
138 | 136 | ||
139 | #endif //_AERDRV_H_ | 137 | #endif /* _AERDRV_H_ */ |
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 3d8872704a58..9f5ccbeb4fa5 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c | |||
@@ -49,10 +49,11 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev) | |||
49 | PCI_EXP_DEVCTL_NFERE | | 49 | PCI_EXP_DEVCTL_NFERE | |
50 | PCI_EXP_DEVCTL_FERE | | 50 | PCI_EXP_DEVCTL_FERE | |
51 | PCI_EXP_DEVCTL_URRE; | 51 | PCI_EXP_DEVCTL_URRE; |
52 | pci_write_config_word(dev, pos+PCI_EXP_DEVCTL, | 52 | pci_write_config_word(dev, pos+PCI_EXP_DEVCTL, reg16); |
53 | reg16); | 53 | |
54 | return 0; | 54 | return 0; |
55 | } | 55 | } |
56 | EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting); | ||
56 | 57 | ||
57 | int pci_disable_pcie_error_reporting(struct pci_dev *dev) | 58 | int pci_disable_pcie_error_reporting(struct pci_dev *dev) |
58 | { | 59 | { |
@@ -68,10 +69,11 @@ int pci_disable_pcie_error_reporting(struct pci_dev *dev) | |||
68 | PCI_EXP_DEVCTL_NFERE | | 69 | PCI_EXP_DEVCTL_NFERE | |
69 | PCI_EXP_DEVCTL_FERE | | 70 | PCI_EXP_DEVCTL_FERE | |
70 | PCI_EXP_DEVCTL_URRE); | 71 | PCI_EXP_DEVCTL_URRE); |
71 | pci_write_config_word(dev, pos+PCI_EXP_DEVCTL, | 72 | pci_write_config_word(dev, pos+PCI_EXP_DEVCTL, reg16); |
72 | reg16); | 73 | |
73 | return 0; | 74 | return 0; |
74 | } | 75 | } |
76 | EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting); | ||
75 | 77 | ||
76 | int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) | 78 | int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) |
77 | { | 79 | { |
@@ -92,6 +94,7 @@ int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) | |||
92 | 94 | ||
93 | return 0; | 95 | return 0; |
94 | } | 96 | } |
97 | EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status); | ||
95 | 98 | ||
96 | #if 0 | 99 | #if 0 |
97 | int pci_cleanup_aer_correct_error_status(struct pci_dev *dev) | 100 | int pci_cleanup_aer_correct_error_status(struct pci_dev *dev) |
@@ -110,7 +113,6 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev) | |||
110 | } | 113 | } |
111 | #endif /* 0 */ | 114 | #endif /* 0 */ |
112 | 115 | ||
113 | |||
114 | static int set_device_error_reporting(struct pci_dev *dev, void *data) | 116 | static int set_device_error_reporting(struct pci_dev *dev, void *data) |
115 | { | 117 | { |
116 | bool enable = *((bool *)data); | 118 | bool enable = *((bool *)data); |
@@ -164,8 +166,9 @@ static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev) | |||
164 | e_info->dev[e_info->error_dev_num] = dev; | 166 | e_info->dev[e_info->error_dev_num] = dev; |
165 | e_info->error_dev_num++; | 167 | e_info->error_dev_num++; |
166 | return 1; | 168 | return 1; |
167 | } else | 169 | } |
168 | return 0; | 170 | |
171 | return 0; | ||
169 | } | 172 | } |
170 | 173 | ||
171 | 174 | ||
@@ -193,7 +196,7 @@ static int find_device_iter(struct pci_dev *dev, void *data) | |||
193 | * If there is no multiple error, we stop | 196 | * If there is no multiple error, we stop |
194 | * or continue based on the id comparing. | 197 | * or continue based on the id comparing. |
195 | */ | 198 | */ |
196 | if (!(e_info->flags & AER_MULTI_ERROR_VALID_FLAG)) | 199 | if (!e_info->multi_error_valid) |
197 | return result; | 200 | return result; |
198 | 201 | ||
199 | /* | 202 | /* |
@@ -233,24 +236,16 @@ static int find_device_iter(struct pci_dev *dev, void *data) | |||
233 | status = 0; | 236 | status = 0; |
234 | mask = 0; | 237 | mask = 0; |
235 | if (e_info->severity == AER_CORRECTABLE) { | 238 | if (e_info->severity == AER_CORRECTABLE) { |
236 | pci_read_config_dword(dev, | 239 | pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); |
237 | pos + PCI_ERR_COR_STATUS, | 240 | pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &mask); |
238 | &status); | 241 | if (status & ~mask) { |
239 | pci_read_config_dword(dev, | ||
240 | pos + PCI_ERR_COR_MASK, | ||
241 | &mask); | ||
242 | if (status & ERR_CORRECTABLE_ERROR_MASK & ~mask) { | ||
243 | add_error_device(e_info, dev); | 242 | add_error_device(e_info, dev); |
244 | goto added; | 243 | goto added; |
245 | } | 244 | } |
246 | } else { | 245 | } else { |
247 | pci_read_config_dword(dev, | 246 | pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); |
248 | pos + PCI_ERR_UNCOR_STATUS, | 247 | pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &mask); |
249 | &status); | 248 | if (status & ~mask) { |
250 | pci_read_config_dword(dev, | ||
251 | pos + PCI_ERR_UNCOR_MASK, | ||
252 | &mask); | ||
253 | if (status & ERR_UNCORRECTABLE_ERROR_MASK & ~mask) { | ||
254 | add_error_device(e_info, dev); | 249 | add_error_device(e_info, dev); |
255 | goto added; | 250 | goto added; |
256 | } | 251 | } |
@@ -259,7 +254,7 @@ static int find_device_iter(struct pci_dev *dev, void *data) | |||
259 | return 0; | 254 | return 0; |
260 | 255 | ||
261 | added: | 256 | added: |
262 | if (e_info->flags & AER_MULTI_ERROR_VALID_FLAG) | 257 | if (e_info->multi_error_valid) |
263 | return 0; | 258 | return 0; |
264 | else | 259 | else |
265 | return 1; | 260 | return 1; |
@@ -411,8 +406,7 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, | |||
411 | pci_cleanup_aer_uncorrect_error_status(dev); | 406 | pci_cleanup_aer_uncorrect_error_status(dev); |
412 | dev->error_state = pci_channel_io_normal; | 407 | dev->error_state = pci_channel_io_normal; |
413 | } | 408 | } |
414 | } | 409 | } else { |
415 | else { | ||
416 | /* | 410 | /* |
417 | * If the error is reported by an end point, we think this | 411 | * If the error is reported by an end point, we think this |
418 | * error is related to the upstream link of the end point. | 412 | * error is related to the upstream link of the end point. |
@@ -473,7 +467,7 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev, | |||
473 | if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) | 467 | if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) |
474 | udev = dev; | 468 | udev = dev; |
475 | else | 469 | else |
476 | udev= dev->bus->self; | 470 | udev = dev->bus->self; |
477 | 471 | ||
478 | data.is_downstream = 0; | 472 | data.is_downstream = 0; |
479 | data.aer_driver = NULL; | 473 | data.aer_driver = NULL; |
@@ -576,7 +570,7 @@ static pci_ers_result_t do_recovery(struct pcie_device *aerdev, | |||
576 | * | 570 | * |
577 | * Invoked when an error being detected by Root Port. | 571 | * Invoked when an error being detected by Root Port. |
578 | */ | 572 | */ |
579 | static void handle_error_source(struct pcie_device * aerdev, | 573 | static void handle_error_source(struct pcie_device *aerdev, |
580 | struct pci_dev *dev, | 574 | struct pci_dev *dev, |
581 | struct aer_err_info *info) | 575 | struct aer_err_info *info) |
582 | { | 576 | { |
@@ -682,7 +676,7 @@ static void disable_root_aer(struct aer_rpc *rpc) | |||
682 | * | 676 | * |
683 | * Invoked by DPC handler to consume an error. | 677 | * Invoked by DPC handler to consume an error. |
684 | */ | 678 | */ |
685 | static struct aer_err_source* get_e_source(struct aer_rpc *rpc) | 679 | static struct aer_err_source *get_e_source(struct aer_rpc *rpc) |
686 | { | 680 | { |
687 | struct aer_err_source *e_source; | 681 | struct aer_err_source *e_source; |
688 | unsigned long flags; | 682 | unsigned long flags; |
@@ -702,32 +696,50 @@ static struct aer_err_source* get_e_source(struct aer_rpc *rpc) | |||
702 | return e_source; | 696 | return e_source; |
703 | } | 697 | } |
704 | 698 | ||
699 | /** | ||
700 | * get_device_error_info - read error status from dev and store it to info | ||
701 | * @dev: pointer to the device expected to have a error record | ||
702 | * @info: pointer to structure to store the error record | ||
703 | * | ||
704 | * Return 1 on success, 0 on error. | ||
705 | */ | ||
705 | static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) | 706 | static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) |
706 | { | 707 | { |
707 | int pos; | 708 | int pos, temp; |
709 | |||
710 | info->status = 0; | ||
711 | info->tlp_header_valid = 0; | ||
708 | 712 | ||
709 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | 713 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); |
710 | 714 | ||
711 | /* The device might not support AER */ | 715 | /* The device might not support AER */ |
712 | if (!pos) | 716 | if (!pos) |
713 | return AER_SUCCESS; | 717 | return 1; |
714 | 718 | ||
715 | if (info->severity == AER_CORRECTABLE) { | 719 | if (info->severity == AER_CORRECTABLE) { |
716 | pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, | 720 | pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, |
717 | &info->status); | 721 | &info->status); |
718 | if (!(info->status & ERR_CORRECTABLE_ERROR_MASK)) | 722 | pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, |
719 | return AER_UNSUCCESS; | 723 | &info->mask); |
724 | if (!(info->status & ~info->mask)) | ||
725 | return 0; | ||
720 | } else if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE || | 726 | } else if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE || |
721 | info->severity == AER_NONFATAL) { | 727 | info->severity == AER_NONFATAL) { |
722 | 728 | ||
723 | /* Link is still healthy for IO reads */ | 729 | /* Link is still healthy for IO reads */ |
724 | pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, | 730 | pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, |
725 | &info->status); | 731 | &info->status); |
726 | if (!(info->status & ERR_UNCORRECTABLE_ERROR_MASK)) | 732 | pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, |
727 | return AER_UNSUCCESS; | 733 | &info->mask); |
734 | if (!(info->status & ~info->mask)) | ||
735 | return 0; | ||
736 | |||
737 | /* Get First Error Pointer */ | ||
738 | pci_read_config_dword(dev, pos + PCI_ERR_CAP, &temp); | ||
739 | info->first_error = PCI_ERR_CAP_FEP(temp); | ||
728 | 740 | ||
729 | if (info->status & AER_LOG_TLP_MASKS) { | 741 | if (info->status & AER_LOG_TLP_MASKS) { |
730 | info->flags |= AER_TLP_HEADER_VALID_FLAG; | 742 | info->tlp_header_valid = 1; |
731 | pci_read_config_dword(dev, | 743 | pci_read_config_dword(dev, |
732 | pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0); | 744 | pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0); |
733 | pci_read_config_dword(dev, | 745 | pci_read_config_dword(dev, |
@@ -739,7 +751,7 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) | |||
739 | } | 751 | } |
740 | } | 752 | } |
741 | 753 | ||
742 | return AER_SUCCESS; | 754 | return 1; |
743 | } | 755 | } |
744 | 756 | ||
745 | static inline void aer_process_err_devices(struct pcie_device *p_device, | 757 | static inline void aer_process_err_devices(struct pcie_device *p_device, |
@@ -753,14 +765,14 @@ static inline void aer_process_err_devices(struct pcie_device *p_device, | |||
753 | e_info->id); | 765 | e_info->id); |
754 | } | 766 | } |
755 | 767 | ||
768 | /* Report all before handle them, not to lost records by reset etc. */ | ||
756 | for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) { | 769 | for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) { |
757 | if (get_device_error_info(e_info->dev[i], e_info) == | 770 | if (get_device_error_info(e_info->dev[i], e_info)) |
758 | AER_SUCCESS) { | ||
759 | aer_print_error(e_info->dev[i], e_info); | 771 | aer_print_error(e_info->dev[i], e_info); |
760 | handle_error_source(p_device, | 772 | } |
761 | e_info->dev[i], | 773 | for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) { |
762 | e_info); | 774 | if (get_device_error_info(e_info->dev[i], e_info)) |
763 | } | 775 | handle_error_source(p_device, e_info->dev[i], e_info); |
764 | } | 776 | } |
765 | } | 777 | } |
766 | 778 | ||
@@ -806,7 +818,9 @@ static void aer_isr_one_error(struct pcie_device *p_device, | |||
806 | if (e_src->status & | 818 | if (e_src->status & |
807 | (PCI_ERR_ROOT_MULTI_COR_RCV | | 819 | (PCI_ERR_ROOT_MULTI_COR_RCV | |
808 | PCI_ERR_ROOT_MULTI_UNCOR_RCV)) | 820 | PCI_ERR_ROOT_MULTI_UNCOR_RCV)) |
809 | e_info->flags |= AER_MULTI_ERROR_VALID_FLAG; | 821 | e_info->multi_error_valid = 1; |
822 | |||
823 | aer_print_port_info(p_device->port, e_info); | ||
810 | 824 | ||
811 | find_source_device(p_device->port, e_info); | 825 | find_source_device(p_device->port, e_info); |
812 | aer_process_err_devices(p_device, e_info); | 826 | aer_process_err_devices(p_device, e_info); |
@@ -863,10 +877,5 @@ int aer_init(struct pcie_device *dev) | |||
863 | if (aer_osc_setup(dev) && !forceload) | 877 | if (aer_osc_setup(dev) && !forceload) |
864 | return -ENXIO; | 878 | return -ENXIO; |
865 | 879 | ||
866 | return AER_SUCCESS; | 880 | return 0; |
867 | } | 881 | } |
868 | |||
869 | EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting); | ||
870 | EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting); | ||
871 | EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status); | ||
872 | |||
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 0fc29ae80df8..44acde72294f 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c | |||
@@ -27,69 +27,70 @@ | |||
27 | #define AER_AGENT_COMPLETER 2 | 27 | #define AER_AGENT_COMPLETER 2 |
28 | #define AER_AGENT_TRANSMITTER 3 | 28 | #define AER_AGENT_TRANSMITTER 3 |
29 | 29 | ||
30 | #define AER_AGENT_REQUESTER_MASK (PCI_ERR_UNC_COMP_TIME| \ | 30 | #define AER_AGENT_REQUESTER_MASK(t) ((t == AER_CORRECTABLE) ? \ |
31 | PCI_ERR_UNC_UNSUP) | 31 | 0 : (PCI_ERR_UNC_COMP_TIME|PCI_ERR_UNC_UNSUP)) |
32 | 32 | #define AER_AGENT_COMPLETER_MASK(t) ((t == AER_CORRECTABLE) ? \ | |
33 | #define AER_AGENT_COMPLETER_MASK PCI_ERR_UNC_COMP_ABORT | 33 | 0 : PCI_ERR_UNC_COMP_ABORT) |
34 | 34 | #define AER_AGENT_TRANSMITTER_MASK(t) ((t == AER_CORRECTABLE) ? \ | |
35 | #define AER_AGENT_TRANSMITTER_MASK(t, e) (e & (PCI_ERR_COR_REP_ROLL| \ | 35 | (PCI_ERR_COR_REP_ROLL|PCI_ERR_COR_REP_TIMER) : 0) |
36 | ((t == AER_CORRECTABLE) ? PCI_ERR_COR_REP_TIMER: 0))) | ||
37 | 36 | ||
38 | #define AER_GET_AGENT(t, e) \ | 37 | #define AER_GET_AGENT(t, e) \ |
39 | ((e & AER_AGENT_COMPLETER_MASK) ? AER_AGENT_COMPLETER : \ | 38 | ((e & AER_AGENT_COMPLETER_MASK(t)) ? AER_AGENT_COMPLETER : \ |
40 | (e & AER_AGENT_REQUESTER_MASK) ? AER_AGENT_REQUESTER : \ | 39 | (e & AER_AGENT_REQUESTER_MASK(t)) ? AER_AGENT_REQUESTER : \ |
41 | (AER_AGENT_TRANSMITTER_MASK(t, e)) ? AER_AGENT_TRANSMITTER : \ | 40 | (e & AER_AGENT_TRANSMITTER_MASK(t)) ? AER_AGENT_TRANSMITTER : \ |
42 | AER_AGENT_RECEIVER) | 41 | AER_AGENT_RECEIVER) |
43 | 42 | ||
44 | #define AER_PHYSICAL_LAYER_ERROR_MASK PCI_ERR_COR_RCVR | ||
45 | #define AER_DATA_LINK_LAYER_ERROR_MASK(t, e) \ | ||
46 | (PCI_ERR_UNC_DLP| \ | ||
47 | PCI_ERR_COR_BAD_TLP| \ | ||
48 | PCI_ERR_COR_BAD_DLLP| \ | ||
49 | PCI_ERR_COR_REP_ROLL| \ | ||
50 | ((t == AER_CORRECTABLE) ? \ | ||
51 | PCI_ERR_COR_REP_TIMER: 0)) | ||
52 | |||
53 | #define AER_PHYSICAL_LAYER_ERROR 0 | 43 | #define AER_PHYSICAL_LAYER_ERROR 0 |
54 | #define AER_DATA_LINK_LAYER_ERROR 1 | 44 | #define AER_DATA_LINK_LAYER_ERROR 1 |
55 | #define AER_TRANSACTION_LAYER_ERROR 2 | 45 | #define AER_TRANSACTION_LAYER_ERROR 2 |
56 | 46 | ||
57 | #define AER_GET_LAYER_ERROR(t, e) \ | 47 | #define AER_PHYSICAL_LAYER_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \ |
58 | ((e & AER_PHYSICAL_LAYER_ERROR_MASK) ? \ | 48 | PCI_ERR_COR_RCVR : 0) |
59 | AER_PHYSICAL_LAYER_ERROR : \ | 49 | #define AER_DATA_LINK_LAYER_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \ |
60 | (e & AER_DATA_LINK_LAYER_ERROR_MASK(t, e)) ? \ | 50 | (PCI_ERR_COR_BAD_TLP| \ |
61 | AER_DATA_LINK_LAYER_ERROR : \ | 51 | PCI_ERR_COR_BAD_DLLP| \ |
62 | AER_TRANSACTION_LAYER_ERROR) | 52 | PCI_ERR_COR_REP_ROLL| \ |
53 | PCI_ERR_COR_REP_TIMER) : PCI_ERR_UNC_DLP) | ||
54 | |||
55 | #define AER_GET_LAYER_ERROR(t, e) \ | ||
56 | ((e & AER_PHYSICAL_LAYER_ERROR_MASK(t)) ? AER_PHYSICAL_LAYER_ERROR : \ | ||
57 | (e & AER_DATA_LINK_LAYER_ERROR_MASK(t)) ? AER_DATA_LINK_LAYER_ERROR : \ | ||
58 | AER_TRANSACTION_LAYER_ERROR) | ||
59 | |||
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) | ||
63 | 64 | ||
64 | /* | 65 | /* |
65 | * AER error strings | 66 | * AER error strings |
66 | */ | 67 | */ |
67 | static char* aer_error_severity_string[] = { | 68 | static char *aer_error_severity_string[] = { |
68 | "Uncorrected (Non-Fatal)", | 69 | "Uncorrected (Non-Fatal)", |
69 | "Uncorrected (Fatal)", | 70 | "Uncorrected (Fatal)", |
70 | "Corrected" | 71 | "Corrected" |
71 | }; | 72 | }; |
72 | 73 | ||
73 | static char* aer_error_layer[] = { | 74 | static char *aer_error_layer[] = { |
74 | "Physical Layer", | 75 | "Physical Layer", |
75 | "Data Link Layer", | 76 | "Data Link Layer", |
76 | "Transaction Layer" | 77 | "Transaction Layer" |
77 | }; | 78 | }; |
78 | static char* aer_correctable_error_string[] = { | 79 | static char *aer_correctable_error_string[] = { |
79 | "Receiver Error ", /* Bit Position 0 */ | 80 | "Receiver Error ", /* Bit Position 0 */ |
80 | NULL, | 81 | NULL, |
81 | NULL, | 82 | NULL, |
82 | NULL, | 83 | NULL, |
83 | NULL, | 84 | NULL, |
84 | NULL, | 85 | NULL, |
85 | "Bad TLP ", /* Bit Position 6 */ | 86 | "Bad TLP ", /* Bit Position 6 */ |
86 | "Bad DLLP ", /* Bit Position 7 */ | 87 | "Bad DLLP ", /* Bit Position 7 */ |
87 | "RELAY_NUM Rollover ", /* Bit Position 8 */ | 88 | "RELAY_NUM Rollover ", /* Bit Position 8 */ |
88 | NULL, | 89 | NULL, |
89 | NULL, | 90 | NULL, |
90 | NULL, | 91 | NULL, |
91 | "Replay Timer Timeout ", /* Bit Position 12 */ | 92 | "Replay Timer Timeout ", /* Bit Position 12 */ |
92 | "Advisory Non-Fatal ", /* Bit Position 13 */ | 93 | "Advisory Non-Fatal ", /* Bit Position 13 */ |
93 | NULL, | 94 | NULL, |
94 | NULL, | 95 | NULL, |
95 | NULL, | 96 | NULL, |
@@ -110,7 +111,7 @@ static char* aer_correctable_error_string[] = { | |||
110 | NULL, | 111 | NULL, |
111 | }; | 112 | }; |
112 | 113 | ||
113 | static char* aer_uncorrectable_error_string[] = { | 114 | static char *aer_uncorrectable_error_string[] = { |
114 | NULL, | 115 | NULL, |
115 | NULL, | 116 | NULL, |
116 | NULL, | 117 | NULL, |
@@ -123,10 +124,10 @@ static char* aer_uncorrectable_error_string[] = { | |||
123 | NULL, | 124 | NULL, |
124 | NULL, | 125 | NULL, |
125 | NULL, | 126 | NULL, |
126 | "Poisoned TLP ", /* Bit Position 12 */ | 127 | "Poisoned TLP ", /* Bit Position 12 */ |
127 | "Flow Control Protocol ", /* Bit Position 13 */ | 128 | "Flow Control Protocol ", /* Bit Position 13 */ |
128 | "Completion Timeout ", /* Bit Position 14 */ | 129 | "Completion Timeout ", /* Bit Position 14 */ |
129 | "Completer Abort ", /* Bit Position 15 */ | 130 | "Completer Abort ", /* Bit Position 15 */ |
130 | "Unexpected Completion ", /* Bit Position 16 */ | 131 | "Unexpected Completion ", /* Bit Position 16 */ |
131 | "Receiver Overflow ", /* Bit Position 17 */ | 132 | "Receiver Overflow ", /* Bit Position 17 */ |
132 | "Malformed TLP ", /* Bit Position 18 */ | 133 | "Malformed TLP ", /* Bit Position 18 */ |
@@ -145,98 +146,69 @@ static char* aer_uncorrectable_error_string[] = { | |||
145 | NULL, | 146 | NULL, |
146 | }; | 147 | }; |
147 | 148 | ||
148 | static char* aer_agent_string[] = { | 149 | static char *aer_agent_string[] = { |
149 | "Receiver ID", | 150 | "Receiver ID", |
150 | "Requester ID", | 151 | "Requester ID", |
151 | "Completer ID", | 152 | "Completer ID", |
152 | "Transmitter ID" | 153 | "Transmitter ID" |
153 | }; | 154 | }; |
154 | 155 | ||
155 | static char * aer_get_error_source_name(int severity, | 156 | static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev) |
156 | unsigned int status, | ||
157 | char errmsg_buff[]) | ||
158 | { | 157 | { |
159 | int i; | 158 | int i, status; |
160 | char * errmsg = NULL; | 159 | char *errmsg = NULL; |
160 | |||
161 | status = (info->status & ~info->mask); | ||
161 | 162 | ||
162 | for (i = 0; i < 32; i++) { | 163 | for (i = 0; i < 32; i++) { |
163 | if (!(status & (1 << i))) | 164 | if (!(status & (1 << i))) |
164 | continue; | 165 | continue; |
165 | 166 | ||
166 | if (severity == AER_CORRECTABLE) | 167 | if (info->severity == AER_CORRECTABLE) |
167 | errmsg = aer_correctable_error_string[i]; | 168 | errmsg = aer_correctable_error_string[i]; |
168 | else | 169 | else |
169 | errmsg = aer_uncorrectable_error_string[i]; | 170 | errmsg = aer_uncorrectable_error_string[i]; |
170 | 171 | ||
171 | if (!errmsg) { | 172 | if (errmsg) |
172 | sprintf(errmsg_buff, "Unknown Error Bit %2d ", i); | 173 | AER_PR(info, dev, " [%2d] %s%s\n", i, errmsg, |
173 | errmsg = errmsg_buff; | 174 | info->first_error == i ? " (First)" : ""); |
174 | } | 175 | else |
175 | 176 | AER_PR(info, dev, " [%2d] Unknown Error Bit%s\n", i, | |
176 | break; | 177 | info->first_error == i ? " (First)" : ""); |
177 | } | 178 | } |
178 | |||
179 | return errmsg; | ||
180 | } | 179 | } |
181 | 180 | ||
182 | static DEFINE_SPINLOCK(logbuf_lock); | ||
183 | static char errmsg_buff[100]; | ||
184 | void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) | 181 | void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) |
185 | { | 182 | { |
186 | char * errmsg; | 183 | int id = ((dev->bus->number << 8) | dev->devfn); |
187 | int err_layer, agent; | 184 | |
188 | char * loglevel; | 185 | if (info->status == 0) { |
189 | 186 | AER_PR(info, dev, | |
190 | if (info->severity == AER_CORRECTABLE) | 187 | "PCIE Bus Error: severity=%s, type=Unaccessible, " |
191 | loglevel = KERN_WARNING; | 188 | "id=%04x(Unregistered Agent ID)\n", |
192 | else | 189 | aer_error_severity_string[info->severity], id); |
193 | loglevel = KERN_ERR; | ||
194 | |||
195 | printk("%s+------ PCI-Express Device Error ------+\n", loglevel); | ||
196 | printk("%sError Severity\t\t: %s\n", loglevel, | ||
197 | aer_error_severity_string[info->severity]); | ||
198 | |||
199 | if ( info->status == 0) { | ||
200 | printk("%sPCIE Bus Error type\t: (Unaccessible)\n", loglevel); | ||
201 | printk("%sUnaccessible Received\t: %s\n", loglevel, | ||
202 | info->flags & AER_MULTI_ERROR_VALID_FLAG ? | ||
203 | "Multiple" : "First"); | ||
204 | printk("%sUnregistered Agent ID\t: %04x\n", loglevel, | ||
205 | (dev->bus->number << 8) | dev->devfn); | ||
206 | } else { | 190 | } else { |
207 | err_layer = AER_GET_LAYER_ERROR(info->severity, info->status); | 191 | int layer, agent; |
208 | printk("%sPCIE Bus Error type\t: %s\n", loglevel, | ||
209 | aer_error_layer[err_layer]); | ||
210 | |||
211 | spin_lock(&logbuf_lock); | ||
212 | errmsg = aer_get_error_source_name(info->severity, | ||
213 | info->status, | ||
214 | errmsg_buff); | ||
215 | printk("%s%s\t: %s\n", loglevel, errmsg, | ||
216 | info->flags & AER_MULTI_ERROR_VALID_FLAG ? | ||
217 | "Multiple" : "First"); | ||
218 | spin_unlock(&logbuf_lock); | ||
219 | 192 | ||
193 | layer = AER_GET_LAYER_ERROR(info->severity, info->status); | ||
220 | agent = AER_GET_AGENT(info->severity, info->status); | 194 | agent = AER_GET_AGENT(info->severity, info->status); |
221 | printk("%s%s\t\t: %04x\n", loglevel, | 195 | |
222 | aer_agent_string[agent], | 196 | AER_PR(info, dev, |
223 | (dev->bus->number << 8) | dev->devfn); | 197 | "PCIE Bus Error: severity=%s, type=%s, id=%04x(%s)\n", |
224 | 198 | aer_error_severity_string[info->severity], | |
225 | printk("%sVendorID=%04xh, DeviceID=%04xh," | 199 | aer_error_layer[layer], id, aer_agent_string[agent]); |
226 | " Bus=%02xh, Device=%02xh, Function=%02xh\n", | 200 | |
227 | loglevel, | 201 | AER_PR(info, dev, |
228 | dev->vendor, | 202 | " device [%04x:%04x] error status/mask=%08x/%08x\n", |
229 | dev->device, | 203 | dev->vendor, dev->device, info->status, info->mask); |
230 | dev->bus->number, | 204 | |
231 | PCI_SLOT(dev->devfn), | 205 | __aer_print_error(info, dev); |
232 | PCI_FUNC(dev->devfn)); | 206 | |
233 | 207 | if (info->tlp_header_valid) { | |
234 | if (info->flags & AER_TLP_HEADER_VALID_FLAG) { | ||
235 | unsigned char *tlp = (unsigned char *) &info->tlp; | 208 | unsigned char *tlp = (unsigned char *) &info->tlp; |
236 | printk("%sTLP Header:\n", loglevel); | 209 | AER_PR(info, dev, " TLP Header:" |
237 | printk("%s%02x%02x%02x%02x %02x%02x%02x%02x" | 210 | " %02x%02x%02x%02x %02x%02x%02x%02x" |
238 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", | 211 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", |
239 | loglevel, | ||
240 | *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, | 212 | *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, |
241 | *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), | 213 | *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), |
242 | *(tlp + 11), *(tlp + 10), *(tlp + 9), | 214 | *(tlp + 11), *(tlp + 10), *(tlp + 9), |
@@ -244,5 +216,15 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) | |||
244 | *(tlp + 13), *(tlp + 12)); | 216 | *(tlp + 13), *(tlp + 12)); |
245 | } | 217 | } |
246 | } | 218 | } |
219 | |||
220 | if (info->id && info->error_dev_num > 1 && info->id == id) | ||
221 | AER_PR(info, dev, | ||
222 | " Error of this Agent(%04x) is reported first\n", id); | ||
247 | } | 223 | } |
248 | 224 | ||
225 | void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) | ||
226 | { | ||
227 | dev_info(&dev->dev, "AER: %s%s error received: id=%04x\n", | ||
228 | info->multi_error_valid ? "Multiple " : "", | ||
229 | aer_error_severity_string[info->severity], info->id); | ||
230 | } | ||
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 3d27c97e0486..f289ca9bf18d 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
@@ -26,6 +26,13 @@ | |||
26 | #endif | 26 | #endif |
27 | #define MODULE_PARAM_PREFIX "pcie_aspm." | 27 | #define MODULE_PARAM_PREFIX "pcie_aspm." |
28 | 28 | ||
29 | /* Note: those are not register definitions */ | ||
30 | #define ASPM_STATE_L0S_UP (1) /* Upstream direction L0s state */ | ||
31 | #define ASPM_STATE_L0S_DW (2) /* Downstream direction L0s state */ | ||
32 | #define ASPM_STATE_L1 (4) /* L1 state */ | ||
33 | #define ASPM_STATE_L0S (ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW) | ||
34 | #define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1) | ||
35 | |||
29 | struct aspm_latency { | 36 | struct aspm_latency { |
30 | u32 l0s; /* L0s latency (nsec) */ | 37 | u32 l0s; /* L0s latency (nsec) */ |
31 | u32 l1; /* L1 latency (nsec) */ | 38 | u32 l1; /* L1 latency (nsec) */ |
@@ -40,17 +47,20 @@ struct pcie_link_state { | |||
40 | struct list_head link; /* node in parent's children list */ | 47 | struct list_head link; /* node in parent's children list */ |
41 | 48 | ||
42 | /* ASPM state */ | 49 | /* ASPM state */ |
43 | u32 aspm_support:2; /* Supported ASPM state */ | 50 | u32 aspm_support:3; /* Supported ASPM state */ |
44 | u32 aspm_enabled:2; /* Enabled ASPM state */ | 51 | u32 aspm_enabled:3; /* Enabled ASPM state */ |
45 | u32 aspm_default:2; /* Default ASPM state by BIOS */ | 52 | u32 aspm_capable:3; /* Capable ASPM state with latency */ |
53 | u32 aspm_default:3; /* Default ASPM state by BIOS */ | ||
54 | u32 aspm_disable:3; /* Disabled ASPM state */ | ||
46 | 55 | ||
47 | /* Clock PM state */ | 56 | /* Clock PM state */ |
48 | u32 clkpm_capable:1; /* Clock PM capable? */ | 57 | u32 clkpm_capable:1; /* Clock PM capable? */ |
49 | u32 clkpm_enabled:1; /* Current Clock PM state */ | 58 | u32 clkpm_enabled:1; /* Current Clock PM state */ |
50 | u32 clkpm_default:1; /* Default Clock PM state by BIOS */ | 59 | u32 clkpm_default:1; /* Default Clock PM state by BIOS */ |
51 | 60 | ||
52 | /* Latencies */ | 61 | /* Exit latencies */ |
53 | struct aspm_latency latency; /* Exit latency */ | 62 | struct aspm_latency latency_up; /* Upstream direction exit latency */ |
63 | struct aspm_latency latency_dw; /* Downstream direction exit latency */ | ||
54 | /* | 64 | /* |
55 | * Endpoint acceptable latencies. A pcie downstream port only | 65 | * Endpoint acceptable latencies. A pcie downstream port only |
56 | * has one slot under it, so at most there are 8 functions. | 66 | * has one slot under it, so at most there are 8 functions. |
@@ -82,7 +92,7 @@ static int policy_to_aspm_state(struct pcie_link_state *link) | |||
82 | return 0; | 92 | return 0; |
83 | case POLICY_POWERSAVE: | 93 | case POLICY_POWERSAVE: |
84 | /* Enable ASPM L0s/L1 */ | 94 | /* Enable ASPM L0s/L1 */ |
85 | return PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; | 95 | return ASPM_STATE_ALL; |
86 | case POLICY_DEFAULT: | 96 | case POLICY_DEFAULT: |
87 | return link->aspm_default; | 97 | return link->aspm_default; |
88 | } | 98 | } |
@@ -164,18 +174,6 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) | |||
164 | link->clkpm_capable = (blacklist) ? 0 : capable; | 174 | link->clkpm_capable = (blacklist) ? 0 : capable; |
165 | } | 175 | } |
166 | 176 | ||
167 | static bool pcie_aspm_downstream_has_switch(struct pcie_link_state *link) | ||
168 | { | ||
169 | struct pci_dev *child; | ||
170 | struct pci_bus *linkbus = link->pdev->subordinate; | ||
171 | |||
172 | list_for_each_entry(child, &linkbus->devices, bus_list) { | ||
173 | if (child->pcie_type == PCI_EXP_TYPE_UPSTREAM) | ||
174 | return true; | ||
175 | } | ||
176 | return false; | ||
177 | } | ||
178 | |||
179 | /* | 177 | /* |
180 | * pcie_aspm_configure_common_clock: check if the 2 ends of a link | 178 | * pcie_aspm_configure_common_clock: check if the 2 ends of a link |
181 | * could use common clock. If they are, configure them to use the | 179 | * could use common clock. If they are, configure them to use the |
@@ -288,71 +286,133 @@ static u32 calc_l1_acceptable(u32 encoding) | |||
288 | return (1000 << encoding); | 286 | return (1000 << encoding); |
289 | } | 287 | } |
290 | 288 | ||
291 | static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, | 289 | struct aspm_register_info { |
292 | u32 *l0s, u32 *l1, u32 *enabled) | 290 | u32 support:2; |
291 | u32 enabled:2; | ||
292 | u32 latency_encoding_l0s; | ||
293 | u32 latency_encoding_l1; | ||
294 | }; | ||
295 | |||
296 | static void pcie_get_aspm_reg(struct pci_dev *pdev, | ||
297 | struct aspm_register_info *info) | ||
293 | { | 298 | { |
294 | int pos; | 299 | int pos; |
295 | u16 reg16; | 300 | u16 reg16; |
296 | u32 reg32, encoding; | 301 | u32 reg32; |
297 | 302 | ||
298 | *l0s = *l1 = *enabled = 0; | ||
299 | pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); | 303 | pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); |
300 | pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); | 304 | pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); |
301 | *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; | 305 | info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; |
302 | if (*state != PCIE_LINK_STATE_L0S && | 306 | /* 00b and 10b are defined as "Reserved". */ |
303 | *state != (PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L0S)) | 307 | if (info->support == PCIE_LINK_STATE_L1) |
304 | *state = 0; | 308 | info->support = 0; |
305 | if (*state == 0) | 309 | info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; |
310 | info->latency_encoding_l1 = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; | ||
311 | pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); | ||
312 | info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC; | ||
313 | } | ||
314 | |||
315 | static void pcie_aspm_check_latency(struct pci_dev *endpoint) | ||
316 | { | ||
317 | u32 latency, l1_switch_latency = 0; | ||
318 | struct aspm_latency *acceptable; | ||
319 | struct pcie_link_state *link; | ||
320 | |||
321 | /* Device not in D0 doesn't need latency check */ | ||
322 | if ((endpoint->current_state != PCI_D0) && | ||
323 | (endpoint->current_state != PCI_UNKNOWN)) | ||
306 | return; | 324 | return; |
307 | 325 | ||
308 | encoding = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; | 326 | link = endpoint->bus->self->link_state; |
309 | *l0s = calc_l0s_latency(encoding); | 327 | acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)]; |
310 | if (*state & PCIE_LINK_STATE_L1) { | 328 | |
311 | encoding = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; | 329 | while (link) { |
312 | *l1 = calc_l1_latency(encoding); | 330 | /* Check upstream direction L0s latency */ |
331 | if ((link->aspm_capable & ASPM_STATE_L0S_UP) && | ||
332 | (link->latency_up.l0s > acceptable->l0s)) | ||
333 | link->aspm_capable &= ~ASPM_STATE_L0S_UP; | ||
334 | |||
335 | /* Check downstream direction L0s latency */ | ||
336 | if ((link->aspm_capable & ASPM_STATE_L0S_DW) && | ||
337 | (link->latency_dw.l0s > acceptable->l0s)) | ||
338 | link->aspm_capable &= ~ASPM_STATE_L0S_DW; | ||
339 | /* | ||
340 | * Check L1 latency. | ||
341 | * Every switch on the path to root complex need 1 | ||
342 | * more microsecond for L1. Spec doesn't mention L0s. | ||
343 | */ | ||
344 | latency = max_t(u32, link->latency_up.l1, link->latency_dw.l1); | ||
345 | if ((link->aspm_capable & ASPM_STATE_L1) && | ||
346 | (latency + l1_switch_latency > acceptable->l1)) | ||
347 | link->aspm_capable &= ~ASPM_STATE_L1; | ||
348 | l1_switch_latency += 1000; | ||
349 | |||
350 | link = link->parent; | ||
313 | } | 351 | } |
314 | pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); | ||
315 | *enabled = reg16 & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); | ||
316 | } | 352 | } |
317 | 353 | ||
318 | static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) | 354 | static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) |
319 | { | 355 | { |
320 | u32 support, l0s, l1, enabled; | ||
321 | struct pci_dev *child, *parent = link->pdev; | 356 | struct pci_dev *child, *parent = link->pdev; |
322 | struct pci_bus *linkbus = parent->subordinate; | 357 | struct pci_bus *linkbus = parent->subordinate; |
358 | struct aspm_register_info upreg, dwreg; | ||
323 | 359 | ||
324 | if (blacklist) { | 360 | if (blacklist) { |
325 | /* Set support state to 0, so we will disable ASPM later */ | 361 | /* Set enabled/disable so that we will disable ASPM later */ |
326 | link->aspm_support = 0; | 362 | link->aspm_enabled = ASPM_STATE_ALL; |
327 | link->aspm_default = 0; | 363 | link->aspm_disable = ASPM_STATE_ALL; |
328 | link->aspm_enabled = PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; | ||
329 | return; | 364 | return; |
330 | } | 365 | } |
331 | 366 | ||
332 | /* Configure common clock before checking latencies */ | 367 | /* Configure common clock before checking latencies */ |
333 | pcie_aspm_configure_common_clock(link); | 368 | pcie_aspm_configure_common_clock(link); |
334 | 369 | ||
335 | /* upstream component states */ | 370 | /* Get upstream/downstream components' register state */ |
336 | pcie_aspm_get_cap_device(parent, &support, &l0s, &l1, &enabled); | 371 | pcie_get_aspm_reg(parent, &upreg); |
337 | link->aspm_support = support; | ||
338 | link->latency.l0s = l0s; | ||
339 | link->latency.l1 = l1; | ||
340 | link->aspm_enabled = enabled; | ||
341 | |||
342 | /* downstream component states, all functions have the same setting */ | ||
343 | child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); | 372 | child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); |
344 | pcie_aspm_get_cap_device(child, &support, &l0s, &l1, &enabled); | 373 | pcie_get_aspm_reg(child, &dwreg); |
345 | link->aspm_support &= support; | ||
346 | link->latency.l0s = max_t(u32, link->latency.l0s, l0s); | ||
347 | link->latency.l1 = max_t(u32, link->latency.l1, l1); | ||
348 | 374 | ||
349 | if (!link->aspm_support) | 375 | /* |
350 | return; | 376 | * Setup L0s state |
351 | 377 | * | |
352 | link->aspm_enabled &= link->aspm_support; | 378 | * Note that we must not enable L0s in either direction on a |
379 | * given link unless components on both sides of the link each | ||
380 | * support L0s. | ||
381 | */ | ||
382 | if (dwreg.support & upreg.support & PCIE_LINK_STATE_L0S) | ||
383 | link->aspm_support |= ASPM_STATE_L0S; | ||
384 | if (dwreg.enabled & PCIE_LINK_STATE_L0S) | ||
385 | link->aspm_enabled |= ASPM_STATE_L0S_UP; | ||
386 | if (upreg.enabled & PCIE_LINK_STATE_L0S) | ||
387 | link->aspm_enabled |= ASPM_STATE_L0S_DW; | ||
388 | link->latency_up.l0s = calc_l0s_latency(upreg.latency_encoding_l0s); | ||
389 | link->latency_dw.l0s = calc_l0s_latency(dwreg.latency_encoding_l0s); | ||
390 | |||
391 | /* Setup L1 state */ | ||
392 | if (upreg.support & dwreg.support & PCIE_LINK_STATE_L1) | ||
393 | link->aspm_support |= ASPM_STATE_L1; | ||
394 | if (upreg.enabled & dwreg.enabled & PCIE_LINK_STATE_L1) | ||
395 | link->aspm_enabled |= ASPM_STATE_L1; | ||
396 | link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1); | ||
397 | link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1); | ||
398 | |||
399 | /* Save default state */ | ||
353 | link->aspm_default = link->aspm_enabled; | 400 | link->aspm_default = link->aspm_enabled; |
354 | 401 | ||
355 | /* ENDPOINT states*/ | 402 | /* Setup initial capable state. Will be updated later */ |
403 | link->aspm_capable = link->aspm_support; | ||
404 | /* | ||
405 | * If the downstream component has pci bridge function, don't | ||
406 | * do ASPM for now. | ||
407 | */ | ||
408 | list_for_each_entry(child, &linkbus->devices, bus_list) { | ||
409 | if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { | ||
410 | link->aspm_disable = ASPM_STATE_ALL; | ||
411 | break; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | /* Get and check endpoint acceptable latencies */ | ||
356 | list_for_each_entry(child, &linkbus->devices, bus_list) { | 416 | list_for_each_entry(child, &linkbus->devices, bus_list) { |
357 | int pos; | 417 | int pos; |
358 | u32 reg32, encoding; | 418 | u32 reg32, encoding; |
@@ -365,109 +425,46 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) | |||
365 | 425 | ||
366 | pos = pci_find_capability(child, PCI_CAP_ID_EXP); | 426 | pos = pci_find_capability(child, PCI_CAP_ID_EXP); |
367 | pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); | 427 | pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); |
428 | /* Calculate endpoint L0s acceptable latency */ | ||
368 | encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; | 429 | encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; |
369 | acceptable->l0s = calc_l0s_acceptable(encoding); | 430 | acceptable->l0s = calc_l0s_acceptable(encoding); |
370 | if (link->aspm_support & PCIE_LINK_STATE_L1) { | 431 | /* Calculate endpoint L1 acceptable latency */ |
371 | encoding = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; | 432 | encoding = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; |
372 | acceptable->l1 = calc_l1_acceptable(encoding); | 433 | acceptable->l1 = calc_l1_acceptable(encoding); |
373 | } | ||
374 | } | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * __pcie_aspm_check_state_one - check latency for endpoint device. | ||
379 | * @endpoint: pointer to the struct pci_dev of endpoint device | ||
380 | * | ||
381 | * TBD: The latency from the endpoint to root complex vary per switch's | ||
382 | * upstream link state above the device. Here we just do a simple check | ||
383 | * which assumes all links above the device can be in L1 state, that | ||
384 | * is we just consider the worst case. If switch's upstream link can't | ||
385 | * be put into L0S/L1, then our check is too strictly. | ||
386 | */ | ||
387 | static u32 __pcie_aspm_check_state_one(struct pci_dev *endpoint, u32 state) | ||
388 | { | ||
389 | u32 l1_switch_latency = 0; | ||
390 | struct aspm_latency *acceptable; | ||
391 | struct pcie_link_state *link; | ||
392 | |||
393 | link = endpoint->bus->self->link_state; | ||
394 | state &= link->aspm_support; | ||
395 | acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)]; | ||
396 | 434 | ||
397 | while (link && state) { | 435 | pcie_aspm_check_latency(child); |
398 | if ((state & PCIE_LINK_STATE_L0S) && | ||
399 | (link->latency.l0s > acceptable->l0s)) | ||
400 | state &= ~PCIE_LINK_STATE_L0S; | ||
401 | if ((state & PCIE_LINK_STATE_L1) && | ||
402 | (link->latency.l1 + l1_switch_latency > acceptable->l1)) | ||
403 | state &= ~PCIE_LINK_STATE_L1; | ||
404 | link = link->parent; | ||
405 | /* | ||
406 | * Every switch on the path to root complex need 1 | ||
407 | * more microsecond for L1. Spec doesn't mention L0s. | ||
408 | */ | ||
409 | l1_switch_latency += 1000; | ||
410 | } | ||
411 | return state; | ||
412 | } | ||
413 | |||
414 | static u32 pcie_aspm_check_state(struct pcie_link_state *link, u32 state) | ||
415 | { | ||
416 | pci_power_t power_state; | ||
417 | struct pci_dev *child; | ||
418 | struct pci_bus *linkbus = link->pdev->subordinate; | ||
419 | |||
420 | /* If no child, ignore the link */ | ||
421 | if (list_empty(&linkbus->devices)) | ||
422 | return state; | ||
423 | |||
424 | list_for_each_entry(child, &linkbus->devices, bus_list) { | ||
425 | /* | ||
426 | * If downstream component of a link is pci bridge, we | ||
427 | * disable ASPM for now for the link | ||
428 | */ | ||
429 | if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) | ||
430 | return 0; | ||
431 | |||
432 | if ((child->pcie_type != PCI_EXP_TYPE_ENDPOINT && | ||
433 | child->pcie_type != PCI_EXP_TYPE_LEG_END)) | ||
434 | continue; | ||
435 | /* Device not in D0 doesn't need check latency */ | ||
436 | power_state = child->current_state; | ||
437 | if (power_state == PCI_D1 || power_state == PCI_D2 || | ||
438 | power_state == PCI_D3hot || power_state == PCI_D3cold) | ||
439 | continue; | ||
440 | state = __pcie_aspm_check_state_one(child, state); | ||
441 | } | 436 | } |
442 | return state; | ||
443 | } | 437 | } |
444 | 438 | ||
445 | static void __pcie_aspm_config_one_dev(struct pci_dev *pdev, unsigned int state) | 439 | static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val) |
446 | { | 440 | { |
447 | u16 reg16; | 441 | u16 reg16; |
448 | int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); | 442 | int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); |
449 | 443 | ||
450 | pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); | 444 | pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); |
451 | reg16 &= ~0x3; | 445 | reg16 &= ~0x3; |
452 | reg16 |= state; | 446 | reg16 |= val; |
453 | pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); | 447 | pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); |
454 | } | 448 | } |
455 | 449 | ||
456 | static void __pcie_aspm_config_link(struct pcie_link_state *link, u32 state) | 450 | static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state) |
457 | { | 451 | { |
452 | u32 upstream = 0, dwstream = 0; | ||
458 | struct pci_dev *child, *parent = link->pdev; | 453 | struct pci_dev *child, *parent = link->pdev; |
459 | struct pci_bus *linkbus = parent->subordinate; | 454 | struct pci_bus *linkbus = parent->subordinate; |
460 | 455 | ||
461 | /* If no child, disable the link */ | 456 | /* Nothing to do if the link is already in the requested state */ |
462 | if (list_empty(&linkbus->devices)) | 457 | state &= (link->aspm_capable & ~link->aspm_disable); |
463 | state = 0; | 458 | if (link->aspm_enabled == state) |
464 | /* | 459 | return; |
465 | * If the downstream component has pci bridge function, don't | 460 | /* Convert ASPM state to upstream/downstream ASPM register state */ |
466 | * do ASPM now. | 461 | if (state & ASPM_STATE_L0S_UP) |
467 | */ | 462 | dwstream |= PCIE_LINK_STATE_L0S; |
468 | list_for_each_entry(child, &linkbus->devices, bus_list) { | 463 | if (state & ASPM_STATE_L0S_DW) |
469 | if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) | 464 | upstream |= PCIE_LINK_STATE_L0S; |
470 | return; | 465 | if (state & ASPM_STATE_L1) { |
466 | upstream |= PCIE_LINK_STATE_L1; | ||
467 | dwstream |= PCIE_LINK_STATE_L1; | ||
471 | } | 468 | } |
472 | /* | 469 | /* |
473 | * Spec 2.0 suggests all functions should be configured the | 470 | * Spec 2.0 suggests all functions should be configured the |
@@ -475,67 +472,24 @@ static void __pcie_aspm_config_link(struct pcie_link_state *link, u32 state) | |||
475 | * upstream component first and then downstream, and vice | 472 | * upstream component first and then downstream, and vice |
476 | * versa for disabling ASPM L1. Spec doesn't mention L0S. | 473 | * versa for disabling ASPM L1. Spec doesn't mention L0S. |
477 | */ | 474 | */ |
478 | if (state & PCIE_LINK_STATE_L1) | 475 | if (state & ASPM_STATE_L1) |
479 | __pcie_aspm_config_one_dev(parent, state); | 476 | pcie_config_aspm_dev(parent, upstream); |
480 | |||
481 | list_for_each_entry(child, &linkbus->devices, bus_list) | 477 | list_for_each_entry(child, &linkbus->devices, bus_list) |
482 | __pcie_aspm_config_one_dev(child, state); | 478 | pcie_config_aspm_dev(child, dwstream); |
483 | 479 | if (!(state & ASPM_STATE_L1)) | |
484 | if (!(state & PCIE_LINK_STATE_L1)) | 480 | pcie_config_aspm_dev(parent, upstream); |
485 | __pcie_aspm_config_one_dev(parent, state); | ||
486 | 481 | ||
487 | link->aspm_enabled = state; | 482 | link->aspm_enabled = state; |
488 | } | 483 | } |
489 | 484 | ||
490 | /* Check the whole hierarchy, and configure each link in the hierarchy */ | 485 | static void pcie_config_aspm_path(struct pcie_link_state *link) |
491 | static void __pcie_aspm_configure_link_state(struct pcie_link_state *link, | ||
492 | u32 state) | ||
493 | { | 486 | { |
494 | struct pcie_link_state *leaf, *root = link->root; | 487 | while (link) { |
495 | 488 | pcie_config_aspm_link(link, policy_to_aspm_state(link)); | |
496 | state &= (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); | 489 | link = link->parent; |
497 | |||
498 | /* Check all links who have specific root port link */ | ||
499 | list_for_each_entry(leaf, &link_list, sibling) { | ||
500 | if (!list_empty(&leaf->children) || (leaf->root != root)) | ||
501 | continue; | ||
502 | state = pcie_aspm_check_state(leaf, state); | ||
503 | } | ||
504 | /* Check root port link too in case it hasn't children */ | ||
505 | state = pcie_aspm_check_state(root, state); | ||
506 | if (link->aspm_enabled == state) | ||
507 | return; | ||
508 | /* | ||
509 | * We must change the hierarchy. See comments in | ||
510 | * __pcie_aspm_config_link for the order | ||
511 | **/ | ||
512 | if (state & PCIE_LINK_STATE_L1) { | ||
513 | list_for_each_entry(leaf, &link_list, sibling) { | ||
514 | if (leaf->root == root) | ||
515 | __pcie_aspm_config_link(leaf, state); | ||
516 | } | ||
517 | } else { | ||
518 | list_for_each_entry_reverse(leaf, &link_list, sibling) { | ||
519 | if (leaf->root == root) | ||
520 | __pcie_aspm_config_link(leaf, state); | ||
521 | } | ||
522 | } | 490 | } |
523 | } | 491 | } |
524 | 492 | ||
525 | /* | ||
526 | * pcie_aspm_configure_link_state: enable/disable PCI express link state | ||
527 | * @pdev: the root port or switch downstream port | ||
528 | */ | ||
529 | static void pcie_aspm_configure_link_state(struct pcie_link_state *link, | ||
530 | u32 state) | ||
531 | { | ||
532 | down_read(&pci_bus_sem); | ||
533 | mutex_lock(&aspm_lock); | ||
534 | __pcie_aspm_configure_link_state(link, state); | ||
535 | mutex_unlock(&aspm_lock); | ||
536 | up_read(&pci_bus_sem); | ||
537 | } | ||
538 | |||
539 | static void free_link_state(struct pcie_link_state *link) | 493 | static void free_link_state(struct pcie_link_state *link) |
540 | { | 494 | { |
541 | link->pdev->link_state = NULL; | 495 | link->pdev->link_state = NULL; |
@@ -570,10 +524,9 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) | |||
570 | return 0; | 524 | return 0; |
571 | } | 525 | } |
572 | 526 | ||
573 | static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) | 527 | static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev) |
574 | { | 528 | { |
575 | struct pcie_link_state *link; | 529 | struct pcie_link_state *link; |
576 | int blacklist = !!pcie_aspm_sanity_check(pdev); | ||
577 | 530 | ||
578 | link = kzalloc(sizeof(*link), GFP_KERNEL); | 531 | link = kzalloc(sizeof(*link), GFP_KERNEL); |
579 | if (!link) | 532 | if (!link) |
@@ -599,15 +552,7 @@ static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) | |||
599 | link->root = link->parent->root; | 552 | link->root = link->parent->root; |
600 | 553 | ||
601 | list_add(&link->sibling, &link_list); | 554 | list_add(&link->sibling, &link_list); |
602 | |||
603 | pdev->link_state = link; | 555 | pdev->link_state = link; |
604 | |||
605 | /* Check ASPM capability */ | ||
606 | pcie_aspm_cap_init(link, blacklist); | ||
607 | |||
608 | /* Check Clock PM capability */ | ||
609 | pcie_clkpm_cap_init(link, blacklist); | ||
610 | |||
611 | return link; | 556 | return link; |
612 | } | 557 | } |
613 | 558 | ||
@@ -618,8 +563,8 @@ static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) | |||
618 | */ | 563 | */ |
619 | void pcie_aspm_init_link_state(struct pci_dev *pdev) | 564 | void pcie_aspm_init_link_state(struct pci_dev *pdev) |
620 | { | 565 | { |
621 | u32 state; | ||
622 | struct pcie_link_state *link; | 566 | struct pcie_link_state *link; |
567 | int blacklist = !!pcie_aspm_sanity_check(pdev); | ||
623 | 568 | ||
624 | if (aspm_disabled || !pdev->is_pcie || pdev->link_state) | 569 | if (aspm_disabled || !pdev->is_pcie || pdev->link_state) |
625 | return; | 570 | return; |
@@ -637,47 +582,64 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) | |||
637 | goto out; | 582 | goto out; |
638 | 583 | ||
639 | mutex_lock(&aspm_lock); | 584 | mutex_lock(&aspm_lock); |
640 | link = pcie_aspm_setup_link_state(pdev); | 585 | link = alloc_pcie_link_state(pdev); |
641 | if (!link) | 586 | if (!link) |
642 | goto unlock; | 587 | goto unlock; |
643 | /* | 588 | /* |
644 | * Setup initial ASPM state | 589 | * Setup initial ASPM state. Note that we need to configure |
645 | * | 590 | * upstream links also because capable state of them can be |
646 | * If link has switch, delay the link config. The leaf link | 591 | * update through pcie_aspm_cap_init(). |
647 | * initialization will config the whole hierarchy. But we must | ||
648 | * make sure BIOS doesn't set unsupported link state. | ||
649 | */ | 592 | */ |
650 | if (pcie_aspm_downstream_has_switch(link)) { | 593 | pcie_aspm_cap_init(link, blacklist); |
651 | state = pcie_aspm_check_state(link, link->aspm_default); | 594 | pcie_config_aspm_path(link); |
652 | __pcie_aspm_config_link(link, state); | ||
653 | } else { | ||
654 | state = policy_to_aspm_state(link); | ||
655 | __pcie_aspm_configure_link_state(link, state); | ||
656 | } | ||
657 | 595 | ||
658 | /* Setup initial Clock PM state */ | 596 | /* Setup initial Clock PM state */ |
659 | state = (link->clkpm_capable) ? policy_to_clkpm_state(link) : 0; | 597 | pcie_clkpm_cap_init(link, blacklist); |
660 | pcie_set_clkpm(link, state); | 598 | pcie_set_clkpm(link, policy_to_clkpm_state(link)); |
661 | unlock: | 599 | unlock: |
662 | mutex_unlock(&aspm_lock); | 600 | mutex_unlock(&aspm_lock); |
663 | out: | 601 | out: |
664 | up_read(&pci_bus_sem); | 602 | up_read(&pci_bus_sem); |
665 | } | 603 | } |
666 | 604 | ||
605 | /* Recheck latencies and update aspm_capable for links under the root */ | ||
606 | static void pcie_update_aspm_capable(struct pcie_link_state *root) | ||
607 | { | ||
608 | struct pcie_link_state *link; | ||
609 | BUG_ON(root->parent); | ||
610 | list_for_each_entry(link, &link_list, sibling) { | ||
611 | if (link->root != root) | ||
612 | continue; | ||
613 | link->aspm_capable = link->aspm_support; | ||
614 | } | ||
615 | list_for_each_entry(link, &link_list, sibling) { | ||
616 | struct pci_dev *child; | ||
617 | struct pci_bus *linkbus = link->pdev->subordinate; | ||
618 | if (link->root != root) | ||
619 | continue; | ||
620 | list_for_each_entry(child, &linkbus->devices, bus_list) { | ||
621 | if ((child->pcie_type != PCI_EXP_TYPE_ENDPOINT) && | ||
622 | (child->pcie_type != PCI_EXP_TYPE_LEG_END)) | ||
623 | continue; | ||
624 | pcie_aspm_check_latency(child); | ||
625 | } | ||
626 | } | ||
627 | } | ||
628 | |||
667 | /* @pdev: the endpoint device */ | 629 | /* @pdev: the endpoint device */ |
668 | void pcie_aspm_exit_link_state(struct pci_dev *pdev) | 630 | void pcie_aspm_exit_link_state(struct pci_dev *pdev) |
669 | { | 631 | { |
670 | struct pci_dev *parent = pdev->bus->self; | 632 | struct pci_dev *parent = pdev->bus->self; |
671 | struct pcie_link_state *link_state = parent->link_state; | 633 | struct pcie_link_state *link, *root, *parent_link; |
672 | 634 | ||
673 | if (aspm_disabled || !pdev->is_pcie || !parent || !link_state) | 635 | if (aspm_disabled || !pdev->is_pcie || !parent || !parent->link_state) |
674 | return; | 636 | return; |
675 | if (parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT && | 637 | if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && |
676 | parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) | 638 | (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) |
677 | return; | 639 | return; |
640 | |||
678 | down_read(&pci_bus_sem); | 641 | down_read(&pci_bus_sem); |
679 | mutex_lock(&aspm_lock); | 642 | mutex_lock(&aspm_lock); |
680 | |||
681 | /* | 643 | /* |
682 | * All PCIe functions are in one slot, remove one function will remove | 644 | * All PCIe functions are in one slot, remove one function will remove |
683 | * the whole slot, so just wait until we are the last function left. | 645 | * the whole slot, so just wait until we are the last function left. |
@@ -685,13 +647,20 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) | |||
685 | if (!list_is_last(&pdev->bus_list, &parent->subordinate->devices)) | 647 | if (!list_is_last(&pdev->bus_list, &parent->subordinate->devices)) |
686 | goto out; | 648 | goto out; |
687 | 649 | ||
650 | link = parent->link_state; | ||
651 | root = link->root; | ||
652 | parent_link = link->parent; | ||
653 | |||
688 | /* All functions are removed, so just disable ASPM for the link */ | 654 | /* All functions are removed, so just disable ASPM for the link */ |
689 | __pcie_aspm_config_one_dev(parent, 0); | 655 | pcie_config_aspm_link(link, 0); |
690 | list_del(&link_state->sibling); | 656 | list_del(&link->sibling); |
691 | list_del(&link_state->link); | 657 | list_del(&link->link); |
692 | /* Clock PM is for endpoint device */ | 658 | /* Clock PM is for endpoint device */ |
659 | free_link_state(link); | ||
693 | 660 | ||
694 | free_link_state(link_state); | 661 | /* Recheck latencies and configure upstream links */ |
662 | pcie_update_aspm_capable(root); | ||
663 | pcie_config_aspm_path(parent_link); | ||
695 | out: | 664 | out: |
696 | mutex_unlock(&aspm_lock); | 665 | mutex_unlock(&aspm_lock); |
697 | up_read(&pci_bus_sem); | 666 | up_read(&pci_bus_sem); |
@@ -700,18 +669,23 @@ out: | |||
700 | /* @pdev: the root port or switch downstream port */ | 669 | /* @pdev: the root port or switch downstream port */ |
701 | void pcie_aspm_pm_state_change(struct pci_dev *pdev) | 670 | void pcie_aspm_pm_state_change(struct pci_dev *pdev) |
702 | { | 671 | { |
703 | struct pcie_link_state *link_state = pdev->link_state; | 672 | struct pcie_link_state *link = pdev->link_state; |
704 | 673 | ||
705 | if (aspm_disabled || !pdev->is_pcie || !pdev->link_state) | 674 | if (aspm_disabled || !pdev->is_pcie || !link) |
706 | return; | 675 | return; |
707 | if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && | 676 | if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && |
708 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) | 677 | (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) |
709 | return; | 678 | return; |
710 | /* | 679 | /* |
711 | * devices changed PM state, we should recheck if latency meets all | 680 | * Devices changed PM state, we should recheck if latency |
712 | * functions' requirement | 681 | * meets all functions' requirement |
713 | */ | 682 | */ |
714 | pcie_aspm_configure_link_state(link_state, link_state->aspm_enabled); | 683 | down_read(&pci_bus_sem); |
684 | mutex_lock(&aspm_lock); | ||
685 | pcie_update_aspm_capable(link->root); | ||
686 | pcie_config_aspm_path(link); | ||
687 | mutex_unlock(&aspm_lock); | ||
688 | up_read(&pci_bus_sem); | ||
715 | } | 689 | } |
716 | 690 | ||
717 | /* | 691 | /* |
@@ -721,7 +695,7 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) | |||
721 | void pci_disable_link_state(struct pci_dev *pdev, int state) | 695 | void pci_disable_link_state(struct pci_dev *pdev, int state) |
722 | { | 696 | { |
723 | struct pci_dev *parent = pdev->bus->self; | 697 | struct pci_dev *parent = pdev->bus->self; |
724 | struct pcie_link_state *link_state; | 698 | struct pcie_link_state *link; |
725 | 699 | ||
726 | if (aspm_disabled || !pdev->is_pcie) | 700 | if (aspm_disabled || !pdev->is_pcie) |
727 | return; | 701 | return; |
@@ -733,12 +707,16 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) | |||
733 | 707 | ||
734 | down_read(&pci_bus_sem); | 708 | down_read(&pci_bus_sem); |
735 | mutex_lock(&aspm_lock); | 709 | mutex_lock(&aspm_lock); |
736 | link_state = parent->link_state; | 710 | link = parent->link_state; |
737 | link_state->aspm_support &= ~state; | 711 | if (state & PCIE_LINK_STATE_L0S) |
738 | __pcie_aspm_configure_link_state(link_state, link_state->aspm_enabled); | 712 | link->aspm_disable |= ASPM_STATE_L0S; |
713 | if (state & PCIE_LINK_STATE_L1) | ||
714 | link->aspm_disable |= ASPM_STATE_L1; | ||
715 | pcie_config_aspm_link(link, policy_to_aspm_state(link)); | ||
716 | |||
739 | if (state & PCIE_LINK_STATE_CLKPM) { | 717 | if (state & PCIE_LINK_STATE_CLKPM) { |
740 | link_state->clkpm_capable = 0; | 718 | link->clkpm_capable = 0; |
741 | pcie_set_clkpm(link_state, 0); | 719 | pcie_set_clkpm(link, 0); |
742 | } | 720 | } |
743 | mutex_unlock(&aspm_lock); | 721 | mutex_unlock(&aspm_lock); |
744 | up_read(&pci_bus_sem); | 722 | up_read(&pci_bus_sem); |
@@ -748,7 +726,7 @@ EXPORT_SYMBOL(pci_disable_link_state); | |||
748 | static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) | 726 | static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) |
749 | { | 727 | { |
750 | int i; | 728 | int i; |
751 | struct pcie_link_state *link_state; | 729 | struct pcie_link_state *link; |
752 | 730 | ||
753 | for (i = 0; i < ARRAY_SIZE(policy_str); i++) | 731 | for (i = 0; i < ARRAY_SIZE(policy_str); i++) |
754 | if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) | 732 | if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) |
@@ -761,10 +739,9 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) | |||
761 | down_read(&pci_bus_sem); | 739 | down_read(&pci_bus_sem); |
762 | mutex_lock(&aspm_lock); | 740 | mutex_lock(&aspm_lock); |
763 | aspm_policy = i; | 741 | aspm_policy = i; |
764 | list_for_each_entry(link_state, &link_list, sibling) { | 742 | list_for_each_entry(link, &link_list, sibling) { |
765 | __pcie_aspm_configure_link_state(link_state, | 743 | pcie_config_aspm_link(link, policy_to_aspm_state(link)); |
766 | policy_to_aspm_state(link_state)); | 744 | pcie_set_clkpm(link, policy_to_clkpm_state(link)); |
767 | pcie_set_clkpm(link_state, policy_to_clkpm_state(link_state)); | ||
768 | } | 745 | } |
769 | mutex_unlock(&aspm_lock); | 746 | mutex_unlock(&aspm_lock); |
770 | up_read(&pci_bus_sem); | 747 | up_read(&pci_bus_sem); |
@@ -802,18 +779,28 @@ static ssize_t link_state_store(struct device *dev, | |||
802 | size_t n) | 779 | size_t n) |
803 | { | 780 | { |
804 | struct pci_dev *pdev = to_pci_dev(dev); | 781 | struct pci_dev *pdev = to_pci_dev(dev); |
805 | int state; | 782 | struct pcie_link_state *link, *root = pdev->link_state->root; |
783 | u32 val = buf[0] - '0', state = 0; | ||
806 | 784 | ||
807 | if (n < 1) | 785 | if (n < 1 || val > 3) |
808 | return -EINVAL; | 786 | return -EINVAL; |
809 | state = buf[0]-'0'; | ||
810 | if (state >= 0 && state <= 3) { | ||
811 | /* setup link aspm state */ | ||
812 | pcie_aspm_configure_link_state(pdev->link_state, state); | ||
813 | return n; | ||
814 | } | ||
815 | 787 | ||
816 | return -EINVAL; | 788 | /* Convert requested state to ASPM state */ |
789 | if (val & PCIE_LINK_STATE_L0S) | ||
790 | state |= ASPM_STATE_L0S; | ||
791 | if (val & PCIE_LINK_STATE_L1) | ||
792 | state |= ASPM_STATE_L1; | ||
793 | |||
794 | down_read(&pci_bus_sem); | ||
795 | mutex_lock(&aspm_lock); | ||
796 | list_for_each_entry(link, &link_list, sibling) { | ||
797 | if (link->root != root) | ||
798 | continue; | ||
799 | pcie_config_aspm_link(link, state); | ||
800 | } | ||
801 | mutex_unlock(&aspm_lock); | ||
802 | up_read(&pci_bus_sem); | ||
803 | return n; | ||
817 | } | 804 | } |
818 | 805 | ||
819 | static ssize_t clk_ctl_show(struct device *dev, | 806 | static ssize_t clk_ctl_show(struct device *dev, |
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 13ffdc35ea0e..52f84fca9f7d 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -187,14 +187,9 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) | |||
187 | */ | 187 | */ |
188 | static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) | 188 | static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) |
189 | { | 189 | { |
190 | struct pcie_port_data *port_data = pci_get_drvdata(dev); | ||
191 | int irq, interrupt_mode = PCIE_PORT_NO_IRQ; | 190 | int irq, interrupt_mode = PCIE_PORT_NO_IRQ; |
192 | int i; | 191 | int i; |
193 | 192 | ||
194 | /* Check MSI quirk */ | ||
195 | if (port_data->port_type == PCIE_RC_PORT && pcie_mch_quirk) | ||
196 | goto Fallback; | ||
197 | |||
198 | /* Try to use MSI-X if supported */ | 193 | /* Try to use MSI-X if supported */ |
199 | if (!pcie_port_enable_msix(dev, vectors, mask)) | 194 | if (!pcie_port_enable_msix(dev, vectors, mask)) |
200 | return PCIE_PORT_MSIX_MODE; | 195 | return PCIE_PORT_MSIX_MODE; |
@@ -203,7 +198,6 @@ static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) | |||
203 | if (!pci_enable_msi(dev)) | 198 | if (!pci_enable_msi(dev)) |
204 | interrupt_mode = PCIE_PORT_MSI_MODE; | 199 | interrupt_mode = PCIE_PORT_MSI_MODE; |
205 | 200 | ||
206 | Fallback: | ||
207 | if (interrupt_mode == PCIE_PORT_NO_IRQ && dev->pin) | 201 | if (interrupt_mode == PCIE_PORT_NO_IRQ && dev->pin) |
208 | interrupt_mode = PCIE_PORT_INTx_MODE; | 202 | interrupt_mode = PCIE_PORT_INTx_MODE; |
209 | 203 | ||
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 091ce70051e0..6df5c984a791 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c | |||
@@ -205,6 +205,7 @@ static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) | |||
205 | 205 | ||
206 | /* If fatal, restore cfg space for possible link reset at upstream */ | 206 | /* If fatal, restore cfg space for possible link reset at upstream */ |
207 | if (dev->error_state == pci_channel_io_frozen) { | 207 | if (dev->error_state == pci_channel_io_frozen) { |
208 | dev->state_saved = true; | ||
208 | pci_restore_state(dev); | 209 | pci_restore_state(dev); |
209 | pcie_portdrv_restore_config(dev); | 210 | pcie_portdrv_restore_config(dev); |
210 | pci_enable_pcie_error_reporting(dev); | 211 | pci_enable_pcie_error_reporting(dev); |