aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/ats.c
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2011-09-27 09:57:13 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-10-14 12:05:33 -0400
commitdb3c33c6d3fa04ee46b491e9d75d0d3b4798d074 (patch)
tree6c1031398621e1b7195b2b23b7045a2eb5e917e1 /drivers/pci/ats.c
parent78d090b0be3f072a3c95022771c35183af961aaa (diff)
PCI: Move ATS implementation into own file
ATS does not depend on IOV support, so move the code into its own file. This file will also include support for the PRI and PASID capabilities later. Also give ATS its own Kconfig variable to allow selecting it without IOV support. Reviewed-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/ats.c')
-rw-r--r--drivers/pci/ats.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
new file mode 100644
index 000000000000..ae4bf87afb09
--- /dev/null
+++ b/drivers/pci/ats.c
@@ -0,0 +1,155 @@
1/*
2 * drivers/pci/ats.c
3 *
4 * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
5 *
6 * PCI Express I/O Virtualization (IOV) support.
7 * Address Translation Service 1.0
8 */
9
10#include <linux/pci-ats.h>
11#include <linux/pci.h>
12
13#include "pci.h"
14
15static int ats_alloc_one(struct pci_dev *dev, int ps)
16{
17 int pos;
18 u16 cap;
19 struct pci_ats *ats;
20
21 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
22 if (!pos)
23 return -ENODEV;
24
25 ats = kzalloc(sizeof(*ats), GFP_KERNEL);
26 if (!ats)
27 return -ENOMEM;
28
29 ats->pos = pos;
30 ats->stu = ps;
31 pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
32 ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
33 PCI_ATS_MAX_QDEP;
34 dev->ats = ats;
35
36 return 0;
37}
38
39static void ats_free_one(struct pci_dev *dev)
40{
41 kfree(dev->ats);
42 dev->ats = NULL;
43}
44
45/**
46 * pci_enable_ats - enable the ATS capability
47 * @dev: the PCI device
48 * @ps: the IOMMU page shift
49 *
50 * Returns 0 on success, or negative on failure.
51 */
52int pci_enable_ats(struct pci_dev *dev, int ps)
53{
54 int rc;
55 u16 ctrl;
56
57 BUG_ON(dev->ats && dev->ats->is_enabled);
58
59 if (ps < PCI_ATS_MIN_STU)
60 return -EINVAL;
61
62 if (dev->is_physfn || dev->is_virtfn) {
63 struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
64
65 mutex_lock(&pdev->sriov->lock);
66 if (pdev->ats)
67 rc = pdev->ats->stu == ps ? 0 : -EINVAL;
68 else
69 rc = ats_alloc_one(pdev, ps);
70
71 if (!rc)
72 pdev->ats->ref_cnt++;
73 mutex_unlock(&pdev->sriov->lock);
74 if (rc)
75 return rc;
76 }
77
78 if (!dev->is_physfn) {
79 rc = ats_alloc_one(dev, ps);
80 if (rc)
81 return rc;
82 }
83
84 ctrl = PCI_ATS_CTRL_ENABLE;
85 if (!dev->is_virtfn)
86 ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU);
87 pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
88
89 dev->ats->is_enabled = 1;
90
91 return 0;
92}
93
94/**
95 * pci_disable_ats - disable the ATS capability
96 * @dev: the PCI device
97 */
98void pci_disable_ats(struct pci_dev *dev)
99{
100 u16 ctrl;
101
102 BUG_ON(!dev->ats || !dev->ats->is_enabled);
103
104 pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
105 ctrl &= ~PCI_ATS_CTRL_ENABLE;
106 pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
107
108 dev->ats->is_enabled = 0;
109
110 if (dev->is_physfn || dev->is_virtfn) {
111 struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
112
113 mutex_lock(&pdev->sriov->lock);
114 pdev->ats->ref_cnt--;
115 if (!pdev->ats->ref_cnt)
116 ats_free_one(pdev);
117 mutex_unlock(&pdev->sriov->lock);
118 }
119
120 if (!dev->is_physfn)
121 ats_free_one(dev);
122}
123
124/**
125 * pci_ats_queue_depth - query the ATS Invalidate Queue Depth
126 * @dev: the PCI device
127 *
128 * Returns the queue depth on success, or negative on failure.
129 *
130 * The ATS spec uses 0 in the Invalidate Queue Depth field to
131 * indicate that the function can accept 32 Invalidate Request.
132 * But here we use the `real' values (i.e. 1~32) for the Queue
133 * Depth; and 0 indicates the function shares the Queue with
134 * other functions (doesn't exclusively own a Queue).
135 */
136int pci_ats_queue_depth(struct pci_dev *dev)
137{
138 int pos;
139 u16 cap;
140
141 if (dev->is_virtfn)
142 return 0;
143
144 if (dev->ats)
145 return dev->ats->qdep;
146
147 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
148 if (!pos)
149 return -ENODEV;
150
151 pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
152
153 return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
154 PCI_ATS_MAX_QDEP;
155}