Root/
1 | /* |
2 | * drivers/pci/ats.c |
3 | * |
4 | * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com> |
5 | * Copyright (C) 2011 Advanced Micro Devices, |
6 | * |
7 | * PCI Express I/O Virtualization (IOV) support. |
8 | * Address Translation Service 1.0 |
9 | * Page Request Interface added by Joerg Roedel <joerg.roedel@amd.com> |
10 | * PASID support added by Joerg Roedel <joerg.roedel@amd.com> |
11 | */ |
12 | |
13 | #include <linux/export.h> |
14 | #include <linux/pci-ats.h> |
15 | #include <linux/pci.h> |
16 | #include <linux/slab.h> |
17 | |
18 | #include "pci.h" |
19 | |
20 | static int ats_alloc_one(struct pci_dev *dev, int ps) |
21 | { |
22 | int pos; |
23 | u16 cap; |
24 | struct pci_ats *ats; |
25 | |
26 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); |
27 | if (!pos) |
28 | return -ENODEV; |
29 | |
30 | ats = kzalloc(sizeof(*ats), GFP_KERNEL); |
31 | if (!ats) |
32 | return -ENOMEM; |
33 | |
34 | ats->pos = pos; |
35 | ats->stu = ps; |
36 | pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap); |
37 | ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : |
38 | PCI_ATS_MAX_QDEP; |
39 | dev->ats = ats; |
40 | |
41 | return 0; |
42 | } |
43 | |
44 | static void ats_free_one(struct pci_dev *dev) |
45 | { |
46 | kfree(dev->ats); |
47 | dev->ats = NULL; |
48 | } |
49 | |
50 | /** |
51 | * pci_enable_ats - enable the ATS capability |
52 | * @dev: the PCI device |
53 | * @ps: the IOMMU page shift |
54 | * |
55 | * Returns 0 on success, or negative on failure. |
56 | */ |
57 | int pci_enable_ats(struct pci_dev *dev, int ps) |
58 | { |
59 | int rc; |
60 | u16 ctrl; |
61 | |
62 | BUG_ON(dev->ats && dev->ats->is_enabled); |
63 | |
64 | if (ps < PCI_ATS_MIN_STU) |
65 | return -EINVAL; |
66 | |
67 | if (dev->is_physfn || dev->is_virtfn) { |
68 | struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; |
69 | |
70 | mutex_lock(&pdev->sriov->lock); |
71 | if (pdev->ats) |
72 | rc = pdev->ats->stu == ps ? 0 : -EINVAL; |
73 | else |
74 | rc = ats_alloc_one(pdev, ps); |
75 | |
76 | if (!rc) |
77 | pdev->ats->ref_cnt++; |
78 | mutex_unlock(&pdev->sriov->lock); |
79 | if (rc) |
80 | return rc; |
81 | } |
82 | |
83 | if (!dev->is_physfn) { |
84 | rc = ats_alloc_one(dev, ps); |
85 | if (rc) |
86 | return rc; |
87 | } |
88 | |
89 | ctrl = PCI_ATS_CTRL_ENABLE; |
90 | if (!dev->is_virtfn) |
91 | ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU); |
92 | pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); |
93 | |
94 | dev->ats->is_enabled = 1; |
95 | |
96 | return 0; |
97 | } |
98 | EXPORT_SYMBOL_GPL(pci_enable_ats); |
99 | |
100 | /** |
101 | * pci_disable_ats - disable the ATS capability |
102 | * @dev: the PCI device |
103 | */ |
104 | void pci_disable_ats(struct pci_dev *dev) |
105 | { |
106 | u16 ctrl; |
107 | |
108 | BUG_ON(!dev->ats || !dev->ats->is_enabled); |
109 | |
110 | pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl); |
111 | ctrl &= ~PCI_ATS_CTRL_ENABLE; |
112 | pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); |
113 | |
114 | dev->ats->is_enabled = 0; |
115 | |
116 | if (dev->is_physfn || dev->is_virtfn) { |
117 | struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; |
118 | |
119 | mutex_lock(&pdev->sriov->lock); |
120 | pdev->ats->ref_cnt--; |
121 | if (!pdev->ats->ref_cnt) |
122 | ats_free_one(pdev); |
123 | mutex_unlock(&pdev->sriov->lock); |
124 | } |
125 | |
126 | if (!dev->is_physfn) |
127 | ats_free_one(dev); |
128 | } |
129 | EXPORT_SYMBOL_GPL(pci_disable_ats); |
130 | |
131 | void pci_restore_ats_state(struct pci_dev *dev) |
132 | { |
133 | u16 ctrl; |
134 | |
135 | if (!pci_ats_enabled(dev)) |
136 | return; |
137 | if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS)) |
138 | BUG(); |
139 | |
140 | ctrl = PCI_ATS_CTRL_ENABLE; |
141 | if (!dev->is_virtfn) |
142 | ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU); |
143 | |
144 | pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); |
145 | } |
146 | EXPORT_SYMBOL_GPL(pci_restore_ats_state); |
147 | |
148 | /** |
149 | * pci_ats_queue_depth - query the ATS Invalidate Queue Depth |
150 | * @dev: the PCI device |
151 | * |
152 | * Returns the queue depth on success, or negative on failure. |
153 | * |
154 | * The ATS spec uses 0 in the Invalidate Queue Depth field to |
155 | * indicate that the function can accept 32 Invalidate Request. |
156 | * But here we use the `real' values (i.e. 1~32) for the Queue |
157 | * Depth; and 0 indicates the function shares the Queue with |
158 | * other functions (doesn't exclusively own a Queue). |
159 | */ |
160 | int pci_ats_queue_depth(struct pci_dev *dev) |
161 | { |
162 | int pos; |
163 | u16 cap; |
164 | |
165 | if (dev->is_virtfn) |
166 | return 0; |
167 | |
168 | if (dev->ats) |
169 | return dev->ats->qdep; |
170 | |
171 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); |
172 | if (!pos) |
173 | return -ENODEV; |
174 | |
175 | pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap); |
176 | |
177 | return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : |
178 | PCI_ATS_MAX_QDEP; |
179 | } |
180 | EXPORT_SYMBOL_GPL(pci_ats_queue_depth); |
181 | |
182 | #ifdef CONFIG_PCI_PRI |
183 | /** |
184 | * pci_enable_pri - Enable PRI capability |
185 | * @ pdev: PCI device structure |
186 | * |
187 | * Returns 0 on success, negative value on error |
188 | */ |
189 | int pci_enable_pri(struct pci_dev *pdev, u32 reqs) |
190 | { |
191 | u16 control, status; |
192 | u32 max_requests; |
193 | int pos; |
194 | |
195 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); |
196 | if (!pos) |
197 | return -EINVAL; |
198 | |
199 | pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); |
200 | pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status); |
201 | if ((control & PCI_PRI_CTRL_ENABLE) || |
202 | !(status & PCI_PRI_STATUS_STOPPED)) |
203 | return -EBUSY; |
204 | |
205 | pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests); |
206 | reqs = min(max_requests, reqs); |
207 | pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs); |
208 | |
209 | control |= PCI_PRI_CTRL_ENABLE; |
210 | pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); |
211 | |
212 | return 0; |
213 | } |
214 | EXPORT_SYMBOL_GPL(pci_enable_pri); |
215 | |
216 | /** |
217 | * pci_disable_pri - Disable PRI capability |
218 | * @pdev: PCI device structure |
219 | * |
220 | * Only clears the enabled-bit, regardless of its former value |
221 | */ |
222 | void pci_disable_pri(struct pci_dev *pdev) |
223 | { |
224 | u16 control; |
225 | int pos; |
226 | |
227 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); |
228 | if (!pos) |
229 | return; |
230 | |
231 | pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); |
232 | control &= ~PCI_PRI_CTRL_ENABLE; |
233 | pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); |
234 | } |
235 | EXPORT_SYMBOL_GPL(pci_disable_pri); |
236 | |
237 | /** |
238 | * pci_pri_enabled - Checks if PRI capability is enabled |
239 | * @pdev: PCI device structure |
240 | * |
241 | * Returns true if PRI is enabled on the device, false otherwise |
242 | */ |
243 | bool pci_pri_enabled(struct pci_dev *pdev) |
244 | { |
245 | u16 control; |
246 | int pos; |
247 | |
248 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); |
249 | if (!pos) |
250 | return false; |
251 | |
252 | pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); |
253 | |
254 | return (control & PCI_PRI_CTRL_ENABLE) ? true : false; |
255 | } |
256 | EXPORT_SYMBOL_GPL(pci_pri_enabled); |
257 | |
258 | /** |
259 | * pci_reset_pri - Resets device's PRI state |
260 | * @pdev: PCI device structure |
261 | * |
262 | * The PRI capability must be disabled before this function is called. |
263 | * Returns 0 on success, negative value on error. |
264 | */ |
265 | int pci_reset_pri(struct pci_dev *pdev) |
266 | { |
267 | u16 control; |
268 | int pos; |
269 | |
270 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); |
271 | if (!pos) |
272 | return -EINVAL; |
273 | |
274 | pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); |
275 | if (control & PCI_PRI_CTRL_ENABLE) |
276 | return -EBUSY; |
277 | |
278 | control |= PCI_PRI_CTRL_RESET; |
279 | |
280 | pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control); |
281 | |
282 | return 0; |
283 | } |
284 | EXPORT_SYMBOL_GPL(pci_reset_pri); |
285 | |
286 | /** |
287 | * pci_pri_stopped - Checks whether the PRI capability is stopped |
288 | * @pdev: PCI device structure |
289 | * |
290 | * Returns true if the PRI capability on the device is disabled and the |
291 | * device has no outstanding PRI requests, false otherwise. The device |
292 | * indicates this via the STOPPED bit in the status register of the |
293 | * capability. |
294 | * The device internal state can be cleared by resetting the PRI state |
295 | * with pci_reset_pri(). This can force the capability into the STOPPED |
296 | * state. |
297 | */ |
298 | bool pci_pri_stopped(struct pci_dev *pdev) |
299 | { |
300 | u16 control, status; |
301 | int pos; |
302 | |
303 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); |
304 | if (!pos) |
305 | return true; |
306 | |
307 | pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); |
308 | pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status); |
309 | |
310 | if (control & PCI_PRI_CTRL_ENABLE) |
311 | return false; |
312 | |
313 | return (status & PCI_PRI_STATUS_STOPPED) ? true : false; |
314 | } |
315 | EXPORT_SYMBOL_GPL(pci_pri_stopped); |
316 | |
317 | /** |
318 | * pci_pri_status - Request PRI status of a device |
319 | * @pdev: PCI device structure |
320 | * |
321 | * Returns negative value on failure, status on success. The status can |
322 | * be checked against status-bits. Supported bits are currently: |
323 | * PCI_PRI_STATUS_RF: Response failure |
324 | * PCI_PRI_STATUS_UPRGI: Unexpected Page Request Group Index |
325 | * PCI_PRI_STATUS_STOPPED: PRI has stopped |
326 | */ |
327 | int pci_pri_status(struct pci_dev *pdev) |
328 | { |
329 | u16 status, control; |
330 | int pos; |
331 | |
332 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); |
333 | if (!pos) |
334 | return -EINVAL; |
335 | |
336 | pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); |
337 | pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status); |
338 | |
339 | /* Stopped bit is undefined when enable == 1, so clear it */ |
340 | if (control & PCI_PRI_CTRL_ENABLE) |
341 | status &= ~PCI_PRI_STATUS_STOPPED; |
342 | |
343 | return status; |
344 | } |
345 | EXPORT_SYMBOL_GPL(pci_pri_status); |
346 | #endif /* CONFIG_PCI_PRI */ |
347 | |
348 | #ifdef CONFIG_PCI_PASID |
349 | /** |
350 | * pci_enable_pasid - Enable the PASID capability |
351 | * @pdev: PCI device structure |
352 | * @features: Features to enable |
353 | * |
354 | * Returns 0 on success, negative value on error. This function checks |
355 | * whether the features are actually supported by the device and returns |
356 | * an error if not. |
357 | */ |
358 | int pci_enable_pasid(struct pci_dev *pdev, int features) |
359 | { |
360 | u16 control, supported; |
361 | int pos; |
362 | |
363 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); |
364 | if (!pos) |
365 | return -EINVAL; |
366 | |
367 | pci_read_config_word(pdev, pos + PCI_PASID_CTRL, &control); |
368 | pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported); |
369 | |
370 | if (control & PCI_PASID_CTRL_ENABLE) |
371 | return -EINVAL; |
372 | |
373 | supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV; |
374 | |
375 | /* User wants to enable anything unsupported? */ |
376 | if ((supported & features) != features) |
377 | return -EINVAL; |
378 | |
379 | control = PCI_PASID_CTRL_ENABLE | features; |
380 | |
381 | pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control); |
382 | |
383 | return 0; |
384 | } |
385 | EXPORT_SYMBOL_GPL(pci_enable_pasid); |
386 | |
387 | /** |
388 | * pci_disable_pasid - Disable the PASID capability |
389 | * @pdev: PCI device structure |
390 | * |
391 | */ |
392 | void pci_disable_pasid(struct pci_dev *pdev) |
393 | { |
394 | u16 control = 0; |
395 | int pos; |
396 | |
397 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); |
398 | if (!pos) |
399 | return; |
400 | |
401 | pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control); |
402 | } |
403 | EXPORT_SYMBOL_GPL(pci_disable_pasid); |
404 | |
405 | /** |
406 | * pci_pasid_features - Check which PASID features are supported |
407 | * @pdev: PCI device structure |
408 | * |
409 | * Returns a negative value when no PASI capability is present. |
410 | * Otherwise is returns a bitmask with supported features. Current |
411 | * features reported are: |
412 | * PCI_PASID_CAP_EXEC - Execute permission supported |
413 | * PCI_PASID_CAP_PRIV - Priviledged mode supported |
414 | */ |
415 | int pci_pasid_features(struct pci_dev *pdev) |
416 | { |
417 | u16 supported; |
418 | int pos; |
419 | |
420 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); |
421 | if (!pos) |
422 | return -EINVAL; |
423 | |
424 | pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported); |
425 | |
426 | supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV; |
427 | |
428 | return supported; |
429 | } |
430 | EXPORT_SYMBOL_GPL(pci_pasid_features); |
431 | |
432 | #define PASID_NUMBER_SHIFT 8 |
433 | #define PASID_NUMBER_MASK (0x1f << PASID_NUMBER_SHIFT) |
434 | /** |
435 | * pci_max_pasid - Get maximum number of PASIDs supported by device |
436 | * @pdev: PCI device structure |
437 | * |
438 | * Returns negative value when PASID capability is not present. |
439 | * Otherwise it returns the numer of supported PASIDs. |
440 | */ |
441 | int pci_max_pasids(struct pci_dev *pdev) |
442 | { |
443 | u16 supported; |
444 | int pos; |
445 | |
446 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); |
447 | if (!pos) |
448 | return -EINVAL; |
449 | |
450 | pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported); |
451 | |
452 | supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT; |
453 | |
454 | return (1 << supported); |
455 | } |
456 | EXPORT_SYMBOL_GPL(pci_max_pasids); |
457 | #endif /* CONFIG_PCI_PASID */ |
458 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9