diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.h | 4 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 88 |
2 files changed, 69 insertions, 23 deletions
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index dadf492e9ce9..bbd7428ca2d0 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h | |||
@@ -57,8 +57,10 @@ struct header_log_regs { | |||
57 | unsigned int dw3; | 57 | unsigned int dw3; |
58 | }; | 58 | }; |
59 | 59 | ||
60 | #define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */ | ||
60 | struct aer_err_info { | 61 | struct aer_err_info { |
61 | struct pci_dev *dev; | 62 | struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; |
63 | int error_dev_num; | ||
62 | u16 id; | 64 | u16 id; |
63 | int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */ | 65 | int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */ |
64 | int flags; | 66 | int flags; |
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 2750e7b266b4..3d8872704a58 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c | |||
@@ -158,6 +158,17 @@ static inline int compare_device_id(struct pci_dev *dev, | |||
158 | return 0; | 158 | return 0; |
159 | } | 159 | } |
160 | 160 | ||
161 | static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev) | ||
162 | { | ||
163 | if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) { | ||
164 | e_info->dev[e_info->error_dev_num] = dev; | ||
165 | e_info->error_dev_num++; | ||
166 | return 1; | ||
167 | } else | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | |||
161 | #define PCI_BUS(x) (((x) >> 8) & 0xff) | 172 | #define PCI_BUS(x) (((x) >> 8) & 0xff) |
162 | 173 | ||
163 | static int find_device_iter(struct pci_dev *dev, void *data) | 174 | static int find_device_iter(struct pci_dev *dev, void *data) |
@@ -176,15 +187,31 @@ static int find_device_iter(struct pci_dev *dev, void *data) | |||
176 | if (!nosourceid && (PCI_BUS(e_info->id) != 0)) { | 187 | if (!nosourceid && (PCI_BUS(e_info->id) != 0)) { |
177 | result = compare_device_id(dev, e_info); | 188 | result = compare_device_id(dev, e_info); |
178 | if (result) | 189 | if (result) |
179 | e_info->dev = dev; | 190 | add_error_device(e_info, dev); |
180 | return result; | 191 | |
192 | /* | ||
193 | * If there is no multiple error, we stop | ||
194 | * or continue based on the id comparing. | ||
195 | */ | ||
196 | if (!(e_info->flags & AER_MULTI_ERROR_VALID_FLAG)) | ||
197 | return result; | ||
198 | |||
199 | /* | ||
200 | * If there are multiple errors and id does match, | ||
201 | * We need continue to search other devices under | ||
202 | * the root port. Return 0 means that. | ||
203 | */ | ||
204 | if (result) | ||
205 | return 0; | ||
181 | } | 206 | } |
182 | 207 | ||
183 | /* | 208 | /* |
184 | * Next is to check when bus id is equal to 0 or | 209 | * When either |
185 | * nosourceid==y. Some ports might lose the bus | 210 | * 1) nosourceid==y; |
186 | * id of error source id. We check AER status | 211 | * 2) bus id is equal to 0. Some ports might lose the bus |
187 | * registers to find the initial reporter. | 212 | * id of error source id; |
213 | * 3) There are multiple errors and prior id comparing fails; | ||
214 | * We check AER status registers to find the initial reporter. | ||
188 | */ | 215 | */ |
189 | if (atomic_read(&dev->enable_cnt) == 0) | 216 | if (atomic_read(&dev->enable_cnt) == 0) |
190 | return 0; | 217 | return 0; |
@@ -213,8 +240,8 @@ static int find_device_iter(struct pci_dev *dev, void *data) | |||
213 | pos + PCI_ERR_COR_MASK, | 240 | pos + PCI_ERR_COR_MASK, |
214 | &mask); | 241 | &mask); |
215 | if (status & ERR_CORRECTABLE_ERROR_MASK & ~mask) { | 242 | if (status & ERR_CORRECTABLE_ERROR_MASK & ~mask) { |
216 | e_info->dev = dev; | 243 | add_error_device(e_info, dev); |
217 | return 1; | 244 | goto added; |
218 | } | 245 | } |
219 | } else { | 246 | } else { |
220 | pci_read_config_dword(dev, | 247 | pci_read_config_dword(dev, |
@@ -224,12 +251,18 @@ static int find_device_iter(struct pci_dev *dev, void *data) | |||
224 | pos + PCI_ERR_UNCOR_MASK, | 251 | pos + PCI_ERR_UNCOR_MASK, |
225 | &mask); | 252 | &mask); |
226 | if (status & ERR_UNCORRECTABLE_ERROR_MASK & ~mask) { | 253 | if (status & ERR_UNCORRECTABLE_ERROR_MASK & ~mask) { |
227 | e_info->dev = dev; | 254 | add_error_device(e_info, dev); |
228 | return 1; | 255 | goto added; |
229 | } | 256 | } |
230 | } | 257 | } |
231 | 258 | ||
232 | return 0; | 259 | return 0; |
260 | |||
261 | added: | ||
262 | if (e_info->flags & AER_MULTI_ERROR_VALID_FLAG) | ||
263 | return 0; | ||
264 | else | ||
265 | return 1; | ||
233 | } | 266 | } |
234 | 267 | ||
235 | /** | 268 | /** |
@@ -709,6 +742,28 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) | |||
709 | return AER_SUCCESS; | 742 | return AER_SUCCESS; |
710 | } | 743 | } |
711 | 744 | ||
745 | static inline void aer_process_err_devices(struct pcie_device *p_device, | ||
746 | struct aer_err_info *e_info) | ||
747 | { | ||
748 | int i; | ||
749 | |||
750 | if (!e_info->dev[0]) { | ||
751 | dev_printk(KERN_DEBUG, &p_device->port->dev, | ||
752 | "can't find device of ID%04x\n", | ||
753 | e_info->id); | ||
754 | } | ||
755 | |||
756 | 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) == | ||
758 | AER_SUCCESS) { | ||
759 | aer_print_error(e_info->dev[i], e_info); | ||
760 | handle_error_source(p_device, | ||
761 | e_info->dev[i], | ||
762 | e_info); | ||
763 | } | ||
764 | } | ||
765 | } | ||
766 | |||
712 | /** | 767 | /** |
713 | * aer_isr_one_error - consume an error detected by root port | 768 | * aer_isr_one_error - consume an error detected by root port |
714 | * @p_device: pointer to error root port service device | 769 | * @p_device: pointer to error root port service device |
@@ -754,18 +809,7 @@ static void aer_isr_one_error(struct pcie_device *p_device, | |||
754 | e_info->flags |= AER_MULTI_ERROR_VALID_FLAG; | 809 | e_info->flags |= AER_MULTI_ERROR_VALID_FLAG; |
755 | 810 | ||
756 | find_source_device(p_device->port, e_info); | 811 | find_source_device(p_device->port, e_info); |
757 | if (e_info->dev == NULL) { | 812 | aer_process_err_devices(p_device, e_info); |
758 | printk(KERN_DEBUG "%s->can't find device of ID%04x\n", | ||
759 | __func__, e_info->id); | ||
760 | continue; | ||
761 | } | ||
762 | if (get_device_error_info(e_info->dev, e_info) == | ||
763 | AER_SUCCESS) { | ||
764 | aer_print_error(e_info->dev, e_info); | ||
765 | handle_error_source(p_device, | ||
766 | e_info->dev, | ||
767 | e_info); | ||
768 | } | ||
769 | } | 813 | } |
770 | 814 | ||
771 | kfree(e_info); | 815 | kfree(e_info); |