aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c74
1 files changed, 34 insertions, 40 deletions
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 5fa5c76719b0..5b02f62cdc47 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -126,14 +126,17 @@ static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev)
126 126
127#define PCI_BUS(x) (((x) >> 8) & 0xff) 127#define PCI_BUS(x) (((x) >> 8) & 0xff)
128 128
129static int find_device_iter(struct pci_dev *dev, void *data) 129/**
130 * is_error_source - check whether the device is source of reported error
131 * @dev: pointer to pci_dev to be checked
132 * @e_info: pointer to reported error info
133 */
134static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
130{ 135{
131 int pos; 136 int pos;
132 u32 status; 137 u32 status, mask;
133 u32 mask;
134 u16 reg16; 138 u16 reg16;
135 int result; 139 int result;
136 struct aer_err_info *e_info = (struct aer_err_info *)data;
137 140
138 /* 141 /*
139 * When bus id is equal to 0, it might be a bad id 142 * When bus id is equal to 0, it might be a bad id
@@ -142,22 +145,11 @@ static int find_device_iter(struct pci_dev *dev, void *data)
142 if (!nosourceid && (PCI_BUS(e_info->id) != 0)) { 145 if (!nosourceid && (PCI_BUS(e_info->id) != 0)) {
143 result = compare_device_id(dev, e_info); 146 result = compare_device_id(dev, e_info);
144 if (result) 147 if (result)
145 add_error_device(e_info, dev); 148 return true;
146 149
147 /* 150 /* Continue id comparing if there is no multiple error */
148 * If there is no multiple error, we stop
149 * or continue based on the id comparing.
150 */
151 if (!e_info->multi_error_valid) 151 if (!e_info->multi_error_valid)
152 return result; 152 return false;
153
154 /*
155 * If there are multiple errors and id does match,
156 * We need continue to search other devices under
157 * the root port. Return 0 means that.
158 */
159 if (result)
160 return 0;
161 } 153 }
162 154
163 /* 155 /*
@@ -166,50 +158,52 @@ static int find_device_iter(struct pci_dev *dev, void *data)
166 * 2) bus id is equal to 0. Some ports might lose the bus 158 * 2) bus id is equal to 0. Some ports might lose the bus
167 * id of error source id; 159 * id of error source id;
168 * 3) There are multiple errors and prior id comparing fails; 160 * 3) There are multiple errors and prior id comparing fails;
169 * We check AER status registers to find the initial reporter. 161 * We check AER status registers to find possible reporter.
170 */ 162 */
171 if (atomic_read(&dev->enable_cnt) == 0) 163 if (atomic_read(&dev->enable_cnt) == 0)
172 return 0; 164 return false;
173 pos = pci_pcie_cap(dev); 165 pos = pci_pcie_cap(dev);
174 if (!pos) 166 if (!pos)
175 return 0; 167 return false;
168
176 /* Check if AER is enabled */ 169 /* Check if AER is enabled */
177 pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16); 170 pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
178 if (!(reg16 & ( 171 if (!(reg16 & (
179 PCI_EXP_DEVCTL_CERE | 172 PCI_EXP_DEVCTL_CERE |
180 PCI_EXP_DEVCTL_NFERE | 173 PCI_EXP_DEVCTL_NFERE |
181 PCI_EXP_DEVCTL_FERE | 174 PCI_EXP_DEVCTL_FERE |
182 PCI_EXP_DEVCTL_URRE))) 175 PCI_EXP_DEVCTL_URRE)))
183 return 0; 176 return false;
184 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 177 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
185 if (!pos) 178 if (!pos)
186 return 0; 179 return false;
187 180
188 status = 0; 181 /* Check if error is recorded */
189 mask = 0;
190 if (e_info->severity == AER_CORRECTABLE) { 182 if (e_info->severity == AER_CORRECTABLE) {
191 pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); 183 pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status);
192 pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &mask); 184 pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &mask);
193 if (status & ~mask) {
194 add_error_device(e_info, dev);
195 goto added;
196 }
197 } else { 185 } else {
198 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); 186 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
199 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &mask); 187 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &mask);
200 if (status & ~mask) {
201 add_error_device(e_info, dev);
202 goto added;
203 }
204 } 188 }
189 if (status & ~mask)
190 return true;
205 191
206 return 0; 192 return false;
193}
207 194
208added: 195static int find_device_iter(struct pci_dev *dev, void *data)
209 if (e_info->multi_error_valid) 196{
210 return 0; 197 struct aer_err_info *e_info = (struct aer_err_info *)data;
211 else 198
212 return 1; 199 if (is_error_source(dev, e_info)) {
200 add_error_device(e_info, dev);
201
202 /* If there is only a single error, stop iteration */
203 if (!e_info->multi_error_valid)
204 return 1;
205 }
206 return 0;
213} 207}
214 208
215/** 209/**