diff options
Diffstat (limited to 'drivers/pci/ats.c')
-rw-r--r-- | drivers/pci/ats.c | 87 |
1 files changed, 71 insertions, 16 deletions
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index eeb9fb2b47aa..ad8ddbbbf245 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c | |||
@@ -153,23 +153,27 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs) | |||
153 | u32 max_requests; | 153 | u32 max_requests; |
154 | int pos; | 154 | int pos; |
155 | 155 | ||
156 | if (WARN_ON(pdev->pri_enabled)) | ||
157 | return -EBUSY; | ||
158 | |||
156 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); | 159 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); |
157 | if (!pos) | 160 | if (!pos) |
158 | return -EINVAL; | 161 | return -EINVAL; |
159 | 162 | ||
160 | pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); | ||
161 | pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status); | 163 | pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status); |
162 | if ((control & PCI_PRI_CTRL_ENABLE) || | 164 | if (!(status & PCI_PRI_STATUS_STOPPED)) |
163 | !(status & PCI_PRI_STATUS_STOPPED)) | ||
164 | return -EBUSY; | 165 | return -EBUSY; |
165 | 166 | ||
166 | pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests); | 167 | pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests); |
167 | reqs = min(max_requests, reqs); | 168 | reqs = min(max_requests, reqs); |
169 | pdev->pri_reqs_alloc = reqs; | ||
168 | pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs); | 170 | pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs); |
169 | 171 | ||
170 | control |= PCI_PRI_CTRL_ENABLE; | 172 | control = PCI_PRI_CTRL_ENABLE; |
171 | pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); | 173 | pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); |
172 | 174 | ||
175 | pdev->pri_enabled = 1; | ||
176 | |||
173 | return 0; | 177 | return 0; |
174 | } | 178 | } |
175 | EXPORT_SYMBOL_GPL(pci_enable_pri); | 179 | EXPORT_SYMBOL_GPL(pci_enable_pri); |
@@ -185,6 +189,9 @@ void pci_disable_pri(struct pci_dev *pdev) | |||
185 | u16 control; | 189 | u16 control; |
186 | int pos; | 190 | int pos; |
187 | 191 | ||
192 | if (WARN_ON(!pdev->pri_enabled)) | ||
193 | return; | ||
194 | |||
188 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); | 195 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); |
189 | if (!pos) | 196 | if (!pos) |
190 | return; | 197 | return; |
@@ -192,10 +199,34 @@ void pci_disable_pri(struct pci_dev *pdev) | |||
192 | pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); | 199 | pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); |
193 | control &= ~PCI_PRI_CTRL_ENABLE; | 200 | control &= ~PCI_PRI_CTRL_ENABLE; |
194 | pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); | 201 | pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); |
202 | |||
203 | pdev->pri_enabled = 0; | ||
195 | } | 204 | } |
196 | EXPORT_SYMBOL_GPL(pci_disable_pri); | 205 | EXPORT_SYMBOL_GPL(pci_disable_pri); |
197 | 206 | ||
198 | /** | 207 | /** |
208 | * pci_restore_pri_state - Restore PRI | ||
209 | * @pdev: PCI device structure | ||
210 | */ | ||
211 | void pci_restore_pri_state(struct pci_dev *pdev) | ||
212 | { | ||
213 | u16 control = PCI_PRI_CTRL_ENABLE; | ||
214 | u32 reqs = pdev->pri_reqs_alloc; | ||
215 | int pos; | ||
216 | |||
217 | if (!pdev->pri_enabled) | ||
218 | return; | ||
219 | |||
220 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); | ||
221 | if (!pos) | ||
222 | return; | ||
223 | |||
224 | pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs); | ||
225 | pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); | ||
226 | } | ||
227 | EXPORT_SYMBOL_GPL(pci_restore_pri_state); | ||
228 | |||
229 | /** | ||
199 | * pci_reset_pri - Resets device's PRI state | 230 | * pci_reset_pri - Resets device's PRI state |
200 | * @pdev: PCI device structure | 231 | * @pdev: PCI device structure |
201 | * | 232 | * |
@@ -207,16 +238,14 @@ int pci_reset_pri(struct pci_dev *pdev) | |||
207 | u16 control; | 238 | u16 control; |
208 | int pos; | 239 | int pos; |
209 | 240 | ||
241 | if (WARN_ON(pdev->pri_enabled)) | ||
242 | return -EBUSY; | ||
243 | |||
210 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); | 244 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); |
211 | if (!pos) | 245 | if (!pos) |
212 | return -EINVAL; | 246 | return -EINVAL; |
213 | 247 | ||
214 | pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); | 248 | control = PCI_PRI_CTRL_RESET; |
215 | if (control & PCI_PRI_CTRL_ENABLE) | ||
216 | return -EBUSY; | ||
217 | |||
218 | control |= PCI_PRI_CTRL_RESET; | ||
219 | |||
220 | pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); | 249 | pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); |
221 | 250 | ||
222 | return 0; | 251 | return 0; |
@@ -239,16 +268,14 @@ int pci_enable_pasid(struct pci_dev *pdev, int features) | |||
239 | u16 control, supported; | 268 | u16 control, supported; |
240 | int pos; | 269 | int pos; |
241 | 270 | ||
271 | if (WARN_ON(pdev->pasid_enabled)) | ||
272 | return -EBUSY; | ||
273 | |||
242 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); | 274 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); |
243 | if (!pos) | 275 | if (!pos) |
244 | return -EINVAL; | 276 | return -EINVAL; |
245 | 277 | ||
246 | pci_read_config_word(pdev, pos + PCI_PASID_CTRL, &control); | ||
247 | pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported); | 278 | pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported); |
248 | |||
249 | if (control & PCI_PASID_CTRL_ENABLE) | ||
250 | return -EINVAL; | ||
251 | |||
252 | supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV; | 279 | supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV; |
253 | 280 | ||
254 | /* User wants to enable anything unsupported? */ | 281 | /* User wants to enable anything unsupported? */ |
@@ -256,9 +283,12 @@ int pci_enable_pasid(struct pci_dev *pdev, int features) | |||
256 | return -EINVAL; | 283 | return -EINVAL; |
257 | 284 | ||
258 | control = PCI_PASID_CTRL_ENABLE | features; | 285 | control = PCI_PASID_CTRL_ENABLE | features; |
286 | pdev->pasid_features = features; | ||
259 | 287 | ||
260 | pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control); | 288 | pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control); |
261 | 289 | ||
290 | pdev->pasid_enabled = 1; | ||
291 | |||
262 | return 0; | 292 | return 0; |
263 | } | 293 | } |
264 | EXPORT_SYMBOL_GPL(pci_enable_pasid); | 294 | EXPORT_SYMBOL_GPL(pci_enable_pasid); |
@@ -266,22 +296,47 @@ EXPORT_SYMBOL_GPL(pci_enable_pasid); | |||
266 | /** | 296 | /** |
267 | * pci_disable_pasid - Disable the PASID capability | 297 | * pci_disable_pasid - Disable the PASID capability |
268 | * @pdev: PCI device structure | 298 | * @pdev: PCI device structure |
269 | * | ||
270 | */ | 299 | */ |
271 | void pci_disable_pasid(struct pci_dev *pdev) | 300 | void pci_disable_pasid(struct pci_dev *pdev) |
272 | { | 301 | { |
273 | u16 control = 0; | 302 | u16 control = 0; |
274 | int pos; | 303 | int pos; |
275 | 304 | ||
305 | if (WARN_ON(!pdev->pasid_enabled)) | ||
306 | return; | ||
307 | |||
276 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); | 308 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); |
277 | if (!pos) | 309 | if (!pos) |
278 | return; | 310 | return; |
279 | 311 | ||
280 | pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control); | 312 | pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control); |
313 | |||
314 | pdev->pasid_enabled = 0; | ||
281 | } | 315 | } |
282 | EXPORT_SYMBOL_GPL(pci_disable_pasid); | 316 | EXPORT_SYMBOL_GPL(pci_disable_pasid); |
283 | 317 | ||
284 | /** | 318 | /** |
319 | * pci_restore_pasid_state - Restore PASID capabilities | ||
320 | * @pdev: PCI device structure | ||
321 | */ | ||
322 | void pci_restore_pasid_state(struct pci_dev *pdev) | ||
323 | { | ||
324 | u16 control; | ||
325 | int pos; | ||
326 | |||
327 | if (!pdev->pasid_enabled) | ||
328 | return; | ||
329 | |||
330 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); | ||
331 | if (!pos) | ||
332 | return; | ||
333 | |||
334 | control = PCI_PASID_CTRL_ENABLE | pdev->pasid_features; | ||
335 | pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control); | ||
336 | } | ||
337 | EXPORT_SYMBOL_GPL(pci_restore_pasid_state); | ||
338 | |||
339 | /** | ||
285 | * pci_pasid_features - Check which PASID features are supported | 340 | * pci_pasid_features - Check which PASID features are supported |
286 | * @pdev: PCI device structure | 341 | * @pdev: PCI device structure |
287 | * | 342 | * |