aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pcie
diff options
context:
space:
mode:
authorZhang, Yanmin <yanmin_zhang@linux.intel.com>2009-06-16 01:35:16 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-06-16 17:30:14 -0400
commit3d5505c56db5c8d1eeca45c325b19e95115afdea (patch)
treefe3f99f5f38c2b93f7c4421aaeaf3df604dda374 /drivers/pci/pcie
parent28eb27cf0839a30948335f9b2edda739f48b7a2e (diff)
PCI AER: multiple error support
When a root port receives the same errors more than once before the kernel process them, the Multiple Error Messages Received flags are set by hardware. Because the root port could only save one kind of correctable error source id and another uncorrectable error source id at the same time, the second message sender id is lost if the 2 messages are sent from 2 different devices. This patch makes the kernel search all devices under the root port when multiple messages are received. Reviewed-by: Andrew Patterson <andrew.patterson@hp.com> Signed-off-by: Zhang Yanmin <yanmin_zhang@linux.intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pcie')
-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);