aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h4
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c88
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 */
60struct aer_err_info { 61struct 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
161static 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
163static int find_device_iter(struct pci_dev *dev, void *data) 174static 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
261added:
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
745static 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);