diff options
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 74 |
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 | ||
129 | static 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 | */ | ||
134 | static 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, ®16); | 170 | pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, ®16); |
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 | ||
208 | added: | 195 | static 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 | /** |