blob: 2026f5388796cc73ba985c1d906db98e901f7b9c [file] [log] [blame]
Joerg Roedeldb3c33c2011-09-27 15:57:13 +02001/*
2 * drivers/pci/ats.c
3 *
4 * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
Joerg Roedelc320b972011-09-27 15:57:15 +02005 * Copyright (C) 2011 Advanced Micro Devices,
Joerg Roedeldb3c33c2011-09-27 15:57:13 +02006 *
7 * PCI Express I/O Virtualization (IOV) support.
8 * Address Translation Service 1.0
Joerg Roedelc320b972011-09-27 15:57:15 +02009 * Page Request Interface added by Joerg Roedel <joerg.roedel@amd.com>
Joerg Roedel086ac112011-09-27 15:57:16 +020010 * PASID support added by Joerg Roedel <joerg.roedel@amd.com>
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020011 */
12
Paul Gortmaker363c75d2011-05-27 09:37:25 -040013#include <linux/export.h>
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020014#include <linux/pci-ats.h>
15#include <linux/pci.h>
James Bottomley8c451942011-11-29 19:20:23 +000016#include <linux/slab.h>
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020017
18#include "pci.h"
19
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050020static void ats_alloc_one(struct pci_dev *dev)
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020021{
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)
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050028 return;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020029
30 ats = kzalloc(sizeof(*ats), GFP_KERNEL);
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050031 if (!ats) {
32 dev_warn(&dev->dev, "can't allocate space for ATS state\n");
33 return;
34 }
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020035
36 ats->pos = pos;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020037 pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
38 ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
39 PCI_ATS_MAX_QDEP;
40 dev->ats = ats;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020041}
42
43static void ats_free_one(struct pci_dev *dev)
44{
45 kfree(dev->ats);
46 dev->ats = NULL;
47}
48
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050049void pci_ats_init(struct pci_dev *dev)
50{
51 ats_alloc_one(dev);
52}
53
54void pci_ats_free(struct pci_dev *dev)
55{
56 ats_free_one(dev);
57}
58
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020059/**
60 * pci_enable_ats - enable the ATS capability
61 * @dev: the PCI device
62 * @ps: the IOMMU page shift
63 *
64 * Returns 0 on success, or negative on failure.
65 */
66int pci_enable_ats(struct pci_dev *dev, int ps)
67{
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020068 u16 ctrl;
69
70 BUG_ON(dev->ats && dev->ats->is_enabled);
71
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050072 if (!dev->ats)
73 return -EINVAL;
74
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020075 if (ps < PCI_ATS_MIN_STU)
76 return -EINVAL;
77
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050078 /*
79 * Note that enabling ATS on a VF fails unless it's already enabled
80 * with the same STU on the PF.
81 */
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020082 ctrl = PCI_ATS_CTRL_ENABLE;
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050083 if (dev->is_virtfn) {
84 struct pci_dev *pdev = dev->physfn;
85
86 if (pdev->ats->stu != ps)
87 return -EINVAL;
88
89 atomic_inc(&pdev->ats->ref_cnt); /* count enabled VFs */
90 } else {
91 dev->ats->stu = ps;
92 ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU);
93 }
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020094 pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
95
96 dev->ats->is_enabled = 1;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020097 return 0;
98}
Joerg Roedeld4c06362011-09-27 15:57:14 +020099EXPORT_SYMBOL_GPL(pci_enable_ats);
Joerg Roedeldb3c33c2011-09-27 15:57:13 +0200100
101/**
102 * pci_disable_ats - disable the ATS capability
103 * @dev: the PCI device
104 */
105void pci_disable_ats(struct pci_dev *dev)
106{
107 u16 ctrl;
108
109 BUG_ON(!dev->ats || !dev->ats->is_enabled);
110
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -0500111 if (atomic_read(&dev->ats->ref_cnt))
112 return; /* VFs still enabled */
113
114 if (dev->is_virtfn) {
115 struct pci_dev *pdev = dev->physfn;
116
117 atomic_dec(&pdev->ats->ref_cnt);
118 }
119
Joerg Roedeldb3c33c2011-09-27 15:57:13 +0200120 pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
121 ctrl &= ~PCI_ATS_CTRL_ENABLE;
122 pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
123
124 dev->ats->is_enabled = 0;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +0200125}
Joerg Roedeld4c06362011-09-27 15:57:14 +0200126EXPORT_SYMBOL_GPL(pci_disable_ats);
Joerg Roedeldb3c33c2011-09-27 15:57:13 +0200127
Hao, Xudong1900ca12011-12-17 21:24:40 +0800128void pci_restore_ats_state(struct pci_dev *dev)
129{
130 u16 ctrl;
131
132 if (!pci_ats_enabled(dev))
133 return;
134 if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS))
135 BUG();
136
137 ctrl = PCI_ATS_CTRL_ENABLE;
138 if (!dev->is_virtfn)
139 ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU);
Hao, Xudong1900ca12011-12-17 21:24:40 +0800140 pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
141}
142EXPORT_SYMBOL_GPL(pci_restore_ats_state);
143
Joerg Roedeldb3c33c2011-09-27 15:57:13 +0200144/**
145 * pci_ats_queue_depth - query the ATS Invalidate Queue Depth
146 * @dev: the PCI device
147 *
148 * Returns the queue depth on success, or negative on failure.
149 *
150 * The ATS spec uses 0 in the Invalidate Queue Depth field to
151 * indicate that the function can accept 32 Invalidate Request.
152 * But here we use the `real' values (i.e. 1~32) for the Queue
153 * Depth; and 0 indicates the function shares the Queue with
154 * other functions (doesn't exclusively own a Queue).
155 */
156int pci_ats_queue_depth(struct pci_dev *dev)
157{
Joerg Roedeldb3c33c2011-09-27 15:57:13 +0200158 if (dev->is_virtfn)
159 return 0;
160
161 if (dev->ats)
162 return dev->ats->qdep;
163
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -0500164 return -ENODEV;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +0200165}
Joerg Roedeld4c06362011-09-27 15:57:14 +0200166EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
Joerg Roedelc320b972011-09-27 15:57:15 +0200167
168#ifdef CONFIG_PCI_PRI
169/**
170 * pci_enable_pri - Enable PRI capability
171 * @ pdev: PCI device structure
172 *
173 * Returns 0 on success, negative value on error
174 */
175int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
176{
177 u16 control, status;
178 u32 max_requests;
179 int pos;
180
Alex Williamson69166fb2011-11-02 14:07:15 -0600181 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
Joerg Roedelc320b972011-09-27 15:57:15 +0200182 if (!pos)
183 return -EINVAL;
184
Alex Williamson91f57d52011-11-11 10:07:36 -0700185 pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
186 pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
187 if ((control & PCI_PRI_CTRL_ENABLE) ||
188 !(status & PCI_PRI_STATUS_STOPPED))
Joerg Roedelc320b972011-09-27 15:57:15 +0200189 return -EBUSY;
190
Alex Williamson91f57d52011-11-11 10:07:36 -0700191 pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests);
Joerg Roedelc320b972011-09-27 15:57:15 +0200192 reqs = min(max_requests, reqs);
Alex Williamson91f57d52011-11-11 10:07:36 -0700193 pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
Joerg Roedelc320b972011-09-27 15:57:15 +0200194
Alex Williamson91f57d52011-11-11 10:07:36 -0700195 control |= PCI_PRI_CTRL_ENABLE;
196 pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
Joerg Roedelc320b972011-09-27 15:57:15 +0200197
198 return 0;
199}
200EXPORT_SYMBOL_GPL(pci_enable_pri);
201
202/**
203 * pci_disable_pri - Disable PRI capability
204 * @pdev: PCI device structure
205 *
206 * Only clears the enabled-bit, regardless of its former value
207 */
208void pci_disable_pri(struct pci_dev *pdev)
209{
210 u16 control;
211 int pos;
212
Alex Williamson69166fb2011-11-02 14:07:15 -0600213 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
Joerg Roedelc320b972011-09-27 15:57:15 +0200214 if (!pos)
215 return;
216
Alex Williamson91f57d52011-11-11 10:07:36 -0700217 pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
218 control &= ~PCI_PRI_CTRL_ENABLE;
219 pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
Joerg Roedelc320b972011-09-27 15:57:15 +0200220}
221EXPORT_SYMBOL_GPL(pci_disable_pri);
222
223/**
Joerg Roedelc320b972011-09-27 15:57:15 +0200224 * pci_reset_pri - Resets device's PRI state
225 * @pdev: PCI device structure
226 *
227 * The PRI capability must be disabled before this function is called.
228 * Returns 0 on success, negative value on error.
229 */
230int pci_reset_pri(struct pci_dev *pdev)
231{
232 u16 control;
233 int pos;
234
Alex Williamson69166fb2011-11-02 14:07:15 -0600235 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
Joerg Roedelc320b972011-09-27 15:57:15 +0200236 if (!pos)
237 return -EINVAL;
238
Alex Williamson91f57d52011-11-11 10:07:36 -0700239 pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
240 if (control & PCI_PRI_CTRL_ENABLE)
Joerg Roedelc320b972011-09-27 15:57:15 +0200241 return -EBUSY;
242
Alex Williamson91f57d52011-11-11 10:07:36 -0700243 control |= PCI_PRI_CTRL_RESET;
Joerg Roedelc320b972011-09-27 15:57:15 +0200244
Alex Williamson91f57d52011-11-11 10:07:36 -0700245 pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
Joerg Roedelc320b972011-09-27 15:57:15 +0200246
247 return 0;
248}
249EXPORT_SYMBOL_GPL(pci_reset_pri);
Joerg Roedelc320b972011-09-27 15:57:15 +0200250#endif /* CONFIG_PCI_PRI */
Joerg Roedel086ac112011-09-27 15:57:16 +0200251
252#ifdef CONFIG_PCI_PASID
253/**
254 * pci_enable_pasid - Enable the PASID capability
255 * @pdev: PCI device structure
256 * @features: Features to enable
257 *
258 * Returns 0 on success, negative value on error. This function checks
259 * whether the features are actually supported by the device and returns
260 * an error if not.
261 */
262int pci_enable_pasid(struct pci_dev *pdev, int features)
263{
264 u16 control, supported;
265 int pos;
266
Alex Williamson69166fb2011-11-02 14:07:15 -0600267 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
Joerg Roedel086ac112011-09-27 15:57:16 +0200268 if (!pos)
269 return -EINVAL;
270
Alex Williamson91f57d52011-11-11 10:07:36 -0700271 pci_read_config_word(pdev, pos + PCI_PASID_CTRL, &control);
272 pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
Joerg Roedel086ac112011-09-27 15:57:16 +0200273
Alex Williamson91f57d52011-11-11 10:07:36 -0700274 if (control & PCI_PASID_CTRL_ENABLE)
Joerg Roedel086ac112011-09-27 15:57:16 +0200275 return -EINVAL;
276
Alex Williamson91f57d52011-11-11 10:07:36 -0700277 supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
Joerg Roedel086ac112011-09-27 15:57:16 +0200278
279 /* User wants to enable anything unsupported? */
280 if ((supported & features) != features)
281 return -EINVAL;
282
Alex Williamson91f57d52011-11-11 10:07:36 -0700283 control = PCI_PASID_CTRL_ENABLE | features;
Joerg Roedel086ac112011-09-27 15:57:16 +0200284
Alex Williamson91f57d52011-11-11 10:07:36 -0700285 pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
Joerg Roedel086ac112011-09-27 15:57:16 +0200286
287 return 0;
288}
289EXPORT_SYMBOL_GPL(pci_enable_pasid);
290
291/**
292 * pci_disable_pasid - Disable the PASID capability
293 * @pdev: PCI device structure
294 *
295 */
296void pci_disable_pasid(struct pci_dev *pdev)
297{
298 u16 control = 0;
299 int pos;
300
Alex Williamson69166fb2011-11-02 14:07:15 -0600301 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
Joerg Roedel086ac112011-09-27 15:57:16 +0200302 if (!pos)
303 return;
304
Alex Williamson91f57d52011-11-11 10:07:36 -0700305 pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
Joerg Roedel086ac112011-09-27 15:57:16 +0200306}
307EXPORT_SYMBOL_GPL(pci_disable_pasid);
308
309/**
310 * pci_pasid_features - Check which PASID features are supported
311 * @pdev: PCI device structure
312 *
313 * Returns a negative value when no PASI capability is present.
314 * Otherwise is returns a bitmask with supported features. Current
315 * features reported are:
Alex Williamson91f57d52011-11-11 10:07:36 -0700316 * PCI_PASID_CAP_EXEC - Execute permission supported
Bjorn Helgaasf7625982013-11-14 11:28:18 -0700317 * PCI_PASID_CAP_PRIV - Privileged mode supported
Joerg Roedel086ac112011-09-27 15:57:16 +0200318 */
319int pci_pasid_features(struct pci_dev *pdev)
320{
321 u16 supported;
322 int pos;
323
Alex Williamson69166fb2011-11-02 14:07:15 -0600324 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
Joerg Roedel086ac112011-09-27 15:57:16 +0200325 if (!pos)
326 return -EINVAL;
327
Alex Williamson91f57d52011-11-11 10:07:36 -0700328 pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
Joerg Roedel086ac112011-09-27 15:57:16 +0200329
Alex Williamson91f57d52011-11-11 10:07:36 -0700330 supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
Joerg Roedel086ac112011-09-27 15:57:16 +0200331
332 return supported;
333}
334EXPORT_SYMBOL_GPL(pci_pasid_features);
335
336#define PASID_NUMBER_SHIFT 8
337#define PASID_NUMBER_MASK (0x1f << PASID_NUMBER_SHIFT)
338/**
339 * pci_max_pasid - Get maximum number of PASIDs supported by device
340 * @pdev: PCI device structure
341 *
342 * Returns negative value when PASID capability is not present.
343 * Otherwise it returns the numer of supported PASIDs.
344 */
345int pci_max_pasids(struct pci_dev *pdev)
346{
347 u16 supported;
348 int pos;
349
Alex Williamson69166fb2011-11-02 14:07:15 -0600350 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
Joerg Roedel086ac112011-09-27 15:57:16 +0200351 if (!pos)
352 return -EINVAL;
353
Alex Williamson91f57d52011-11-11 10:07:36 -0700354 pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
Joerg Roedel086ac112011-09-27 15:57:16 +0200355
356 supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
357
358 return (1 << supported);
359}
360EXPORT_SYMBOL_GPL(pci_max_pasids);
361#endif /* CONFIG_PCI_PASID */