blob: 982b46f0a54da967dad65ac94ae87c81787789cd [file] [log] [blame]
Bjorn Helgaas7328c8f2018-01-26 11:45:16 -06001// SPDX-License-Identifier: GPL-2.0
Joerg Roedeldb3c33c2011-09-27 15:57:13 +02002/*
Bjorn Helgaasdf62ab52018-03-09 16:36:33 -06003 * PCI Express I/O Virtualization (IOV) support
Joerg Roedeldb3c33c2011-09-27 15:57:13 +02004 * Address Translation Service 1.0
Joerg Roedelc320b972011-09-27 15:57:15 +02005 * Page Request Interface added by Joerg Roedel <joerg.roedel@amd.com>
Joerg Roedel086ac112011-09-27 15:57:16 +02006 * PASID support added by Joerg Roedel <joerg.roedel@amd.com>
Bjorn Helgaasdf62ab52018-03-09 16:36:33 -06007 *
8 * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
9 * Copyright (C) 2011 Advanced Micro Devices,
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020010 */
11
Paul Gortmaker363c75d2011-05-27 09:37:25 -040012#include <linux/export.h>
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020013#include <linux/pci-ats.h>
14#include <linux/pci.h>
James Bottomley8c451942011-11-29 19:20:23 +000015#include <linux/slab.h>
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020016
17#include "pci.h"
18
Bjorn Helgaasafdd5962015-07-17 15:35:18 -050019void pci_ats_init(struct pci_dev *dev)
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020020{
21 int pos;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020022
Gil Kupfercef74402018-05-10 17:56:02 -050023 if (pci_ats_disabled())
24 return;
25
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020026 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
Bjorn Helgaasd544d752015-07-17 15:15:19 -050030 dev->ats_cap = pos;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020031}
32
33/**
34 * pci_enable_ats - enable the ATS capability
35 * @dev: the PCI device
36 * @ps: the IOMMU page shift
37 *
38 * Returns 0 on success, or negative on failure.
39 */
40int pci_enable_ats(struct pci_dev *dev, int ps)
41{
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020042 u16 ctrl;
Bjorn Helgaasc39127d2015-07-17 15:38:13 -050043 struct pci_dev *pdev;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020044
Bjorn Helgaasd544d752015-07-17 15:15:19 -050045 if (!dev->ats_cap)
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050046 return -EINVAL;
47
Bjorn Helgaasf7ef1342015-07-20 09:23:37 -050048 if (WARN_ON(dev->ats_enabled))
Bjorn Helgaasa021f302015-07-17 15:43:27 -050049 return -EBUSY;
50
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020051 if (ps < PCI_ATS_MIN_STU)
52 return -EINVAL;
53
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050054 /*
55 * Note that enabling ATS on a VF fails unless it's already enabled
56 * with the same STU on the PF.
57 */
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020058 ctrl = PCI_ATS_CTRL_ENABLE;
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050059 if (dev->is_virtfn) {
Bjorn Helgaasc39127d2015-07-17 15:38:13 -050060 pdev = pci_physfn(dev);
Bjorn Helgaasd544d752015-07-17 15:15:19 -050061 if (pdev->ats_stu != ps)
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050062 return -EINVAL;
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050063 } else {
Bjorn Helgaasd544d752015-07-17 15:15:19 -050064 dev->ats_stu = ps;
65 ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
Bjorn Helgaasedc90fe2015-07-17 15:05:46 -050066 }
Bjorn Helgaasd544d752015-07-17 15:15:19 -050067 pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020068
Bjorn Helgaasd544d752015-07-17 15:15:19 -050069 dev->ats_enabled = 1;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020070 return 0;
71}
72
73/**
74 * pci_disable_ats - disable the ATS capability
75 * @dev: the PCI device
76 */
77void pci_disable_ats(struct pci_dev *dev)
78{
79 u16 ctrl;
80
Bjorn Helgaasf7ef1342015-07-20 09:23:37 -050081 if (WARN_ON(!dev->ats_enabled))
Bjorn Helgaasa021f302015-07-17 15:43:27 -050082 return;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020083
Bjorn Helgaasd544d752015-07-17 15:15:19 -050084 pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, &ctrl);
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020085 ctrl &= ~PCI_ATS_CTRL_ENABLE;
Bjorn Helgaasd544d752015-07-17 15:15:19 -050086 pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020087
Bjorn Helgaasd544d752015-07-17 15:15:19 -050088 dev->ats_enabled = 0;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +020089}
90
Hao, Xudong1900ca12011-12-17 21:24:40 +080091void pci_restore_ats_state(struct pci_dev *dev)
92{
93 u16 ctrl;
94
Bjorn Helgaasf7ef1342015-07-20 09:23:37 -050095 if (!dev->ats_enabled)
Hao, Xudong1900ca12011-12-17 21:24:40 +080096 return;
Hao, Xudong1900ca12011-12-17 21:24:40 +080097
98 ctrl = PCI_ATS_CTRL_ENABLE;
99 if (!dev->is_virtfn)
Bjorn Helgaasd544d752015-07-17 15:15:19 -0500100 ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
101 pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
Hao, Xudong1900ca12011-12-17 21:24:40 +0800102}
Hao, Xudong1900ca12011-12-17 21:24:40 +0800103
Joerg Roedeldb3c33c2011-09-27 15:57:13 +0200104/**
105 * pci_ats_queue_depth - query the ATS Invalidate Queue Depth
106 * @dev: the PCI device
107 *
108 * Returns the queue depth on success, or negative on failure.
109 *
110 * The ATS spec uses 0 in the Invalidate Queue Depth field to
111 * indicate that the function can accept 32 Invalidate Request.
112 * But here we use the `real' values (i.e. 1~32) for the Queue
113 * Depth; and 0 indicates the function shares the Queue with
114 * other functions (doesn't exclusively own a Queue).
115 */
116int pci_ats_queue_depth(struct pci_dev *dev)
117{
Bjorn Helgaasa71f9382015-07-20 09:24:32 -0500118 u16 cap;
119
Bjorn Helgaas3c765392015-07-17 15:30:26 -0500120 if (!dev->ats_cap)
121 return -EINVAL;
122
Joerg Roedeldb3c33c2011-09-27 15:57:13 +0200123 if (dev->is_virtfn)
124 return 0;
125
Bjorn Helgaasa71f9382015-07-20 09:24:32 -0500126 pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CAP, &cap);
127 return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : PCI_ATS_MAX_QDEP;
Joerg Roedeldb3c33c2011-09-27 15:57:13 +0200128}
Joerg Roedelc320b972011-09-27 15:57:15 +0200129
Kuppuswamy Sathyanarayanan8c938dd2019-02-19 11:06:09 -0800130/**
131 * pci_ats_page_aligned - Return Page Aligned Request bit status.
132 * @pdev: the PCI device
133 *
134 * Returns 1, if the Untranslated Addresses generated by the device
135 * are always aligned or 0 otherwise.
136 *
137 * Per PCIe spec r4.0, sec 10.5.1.2, if the Page Aligned Request bit
138 * is set, it indicates the Untranslated Addresses generated by the
139 * device are always aligned to a 4096 byte boundary.
140 */
141int pci_ats_page_aligned(struct pci_dev *pdev)
142{
143 u16 cap;
144
145 if (!pdev->ats_cap)
146 return 0;
147
148 pci_read_config_word(pdev, pdev->ats_cap + PCI_ATS_CAP, &cap);
149
150 if (cap & PCI_ATS_CAP_PAGE_ALIGNED)
151 return 1;
152
153 return 0;
154}
Kuppuswamy Sathyanarayanan8c938dd2019-02-19 11:06:09 -0800155
Joerg Roedelc320b972011-09-27 15:57:15 +0200156#ifdef CONFIG_PCI_PRI
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500157void pci_pri_init(struct pci_dev *pdev)
158{
Bjorn Helgaase5adf792019-10-09 16:07:51 -0500159 u16 status;
160
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500161 pdev->pri_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
Bjorn Helgaase5adf792019-10-09 16:07:51 -0500162
163 if (!pdev->pri_cap)
164 return;
165
166 pci_read_config_word(pdev, pdev->pri_cap + PCI_PRI_STATUS, &status);
167 if (status & PCI_PRI_STATUS_PASID)
168 pdev->pasid_required = 1;
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500169}
170
Joerg Roedelc320b972011-09-27 15:57:15 +0200171/**
172 * pci_enable_pri - Enable PRI capability
173 * @ pdev: PCI device structure
174 *
175 * Returns 0 on success, negative value on error
176 */
177int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
178{
179 u16 control, status;
180 u32 max_requests;
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500181 int pri = pdev->pri_cap;
Joerg Roedelc320b972011-09-27 15:57:15 +0200182
Kuppuswamy Sathyanarayanan9bf49e32019-09-05 14:31:42 -0500183 /*
184 * VFs must not implement the PRI Capability. If their PF
185 * implements PRI, it is shared by the VFs, so if the PF PRI is
186 * enabled, it is also enabled for the VF.
187 */
188 if (pdev->is_virtfn) {
189 if (pci_physfn(pdev)->pri_enabled)
190 return 0;
191 return -EINVAL;
192 }
193
Jean-Philippe Bruckera4f4fa62017-05-30 09:25:48 -0700194 if (WARN_ON(pdev->pri_enabled))
195 return -EBUSY;
196
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500197 if (!pri)
Joerg Roedelc320b972011-09-27 15:57:15 +0200198 return -EINVAL;
199
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500200 pci_read_config_word(pdev, pri + PCI_PRI_STATUS, &status);
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700201 if (!(status & PCI_PRI_STATUS_STOPPED))
Joerg Roedelc320b972011-09-27 15:57:15 +0200202 return -EBUSY;
203
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500204 pci_read_config_dword(pdev, pri + PCI_PRI_MAX_REQ, &max_requests);
Joerg Roedelc320b972011-09-27 15:57:15 +0200205 reqs = min(max_requests, reqs);
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700206 pdev->pri_reqs_alloc = reqs;
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500207 pci_write_config_dword(pdev, pri + PCI_PRI_ALLOC_REQ, reqs);
Joerg Roedelc320b972011-09-27 15:57:15 +0200208
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700209 control = PCI_PRI_CTRL_ENABLE;
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500210 pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
Joerg Roedelc320b972011-09-27 15:57:15 +0200211
Jean-Philippe Bruckera4f4fa62017-05-30 09:25:48 -0700212 pdev->pri_enabled = 1;
213
Joerg Roedelc320b972011-09-27 15:57:15 +0200214 return 0;
215}
Joerg Roedelc320b972011-09-27 15:57:15 +0200216
217/**
218 * pci_disable_pri - Disable PRI capability
219 * @pdev: PCI device structure
220 *
221 * Only clears the enabled-bit, regardless of its former value
222 */
223void pci_disable_pri(struct pci_dev *pdev)
224{
225 u16 control;
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500226 int pri = pdev->pri_cap;
Joerg Roedelc320b972011-09-27 15:57:15 +0200227
Kuppuswamy Sathyanarayanan9bf49e32019-09-05 14:31:42 -0500228 /* VFs share the PF PRI */
229 if (pdev->is_virtfn)
230 return;
231
Jean-Philippe Bruckera4f4fa62017-05-30 09:25:48 -0700232 if (WARN_ON(!pdev->pri_enabled))
233 return;
234
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500235 if (!pri)
Joerg Roedelc320b972011-09-27 15:57:15 +0200236 return;
237
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500238 pci_read_config_word(pdev, pri + PCI_PRI_CTRL, &control);
Alex Williamson91f57d52011-11-11 10:07:36 -0700239 control &= ~PCI_PRI_CTRL_ENABLE;
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500240 pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
Jean-Philippe Bruckera4f4fa62017-05-30 09:25:48 -0700241
242 pdev->pri_enabled = 0;
Joerg Roedelc320b972011-09-27 15:57:15 +0200243}
244EXPORT_SYMBOL_GPL(pci_disable_pri);
245
246/**
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700247 * pci_restore_pri_state - Restore PRI
248 * @pdev: PCI device structure
249 */
250void pci_restore_pri_state(struct pci_dev *pdev)
251{
252 u16 control = PCI_PRI_CTRL_ENABLE;
253 u32 reqs = pdev->pri_reqs_alloc;
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500254 int pri = pdev->pri_cap;
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700255
Kuppuswamy Sathyanarayanan9bf49e32019-09-05 14:31:42 -0500256 if (pdev->is_virtfn)
257 return;
258
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700259 if (!pdev->pri_enabled)
260 return;
261
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500262 if (!pri)
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700263 return;
264
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500265 pci_write_config_dword(pdev, pri + PCI_PRI_ALLOC_REQ, reqs);
266 pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700267}
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700268
269/**
Joerg Roedelc320b972011-09-27 15:57:15 +0200270 * pci_reset_pri - Resets device's PRI state
271 * @pdev: PCI device structure
272 *
273 * The PRI capability must be disabled before this function is called.
274 * Returns 0 on success, negative value on error.
275 */
276int pci_reset_pri(struct pci_dev *pdev)
277{
278 u16 control;
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500279 int pri = pdev->pri_cap;
Joerg Roedelc320b972011-09-27 15:57:15 +0200280
Kuppuswamy Sathyanarayanan9bf49e32019-09-05 14:31:42 -0500281 if (pdev->is_virtfn)
282 return 0;
283
Jean-Philippe Bruckera4f4fa62017-05-30 09:25:48 -0700284 if (WARN_ON(pdev->pri_enabled))
285 return -EBUSY;
286
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500287 if (!pri)
Joerg Roedelc320b972011-09-27 15:57:15 +0200288 return -EINVAL;
289
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700290 control = PCI_PRI_CTRL_RESET;
Kuppuswamy Sathyanarayananc0651902019-09-05 14:31:45 -0500291 pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
Joerg Roedelc320b972011-09-27 15:57:15 +0200292
293 return 0;
294}
Bjorn Helgaas8cbb8a92019-10-09 14:54:01 -0500295
296/**
297 * pci_prg_resp_pasid_required - Return PRG Response PASID Required bit
298 * status.
299 * @pdev: PCI device structure
300 *
301 * Returns 1 if PASID is required in PRG Response Message, 0 otherwise.
302 */
303int pci_prg_resp_pasid_required(struct pci_dev *pdev)
304{
Kuppuswamy Sathyanarayanan9bf49e32019-09-05 14:31:42 -0500305 if (pdev->is_virtfn)
306 pdev = pci_physfn(pdev);
307
Bjorn Helgaase5adf792019-10-09 16:07:51 -0500308 return pdev->pasid_required;
Bjorn Helgaas8cbb8a92019-10-09 14:54:01 -0500309}
Joerg Roedelc320b972011-09-27 15:57:15 +0200310#endif /* CONFIG_PCI_PRI */
Joerg Roedel086ac112011-09-27 15:57:16 +0200311
312#ifdef CONFIG_PCI_PASID
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500313void pci_pasid_init(struct pci_dev *pdev)
314{
315 pdev->pasid_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
316}
317
Joerg Roedel086ac112011-09-27 15:57:16 +0200318/**
319 * pci_enable_pasid - Enable the PASID capability
320 * @pdev: PCI device structure
321 * @features: Features to enable
322 *
323 * Returns 0 on success, negative value on error. This function checks
324 * whether the features are actually supported by the device and returns
325 * an error if not.
326 */
327int pci_enable_pasid(struct pci_dev *pdev, int features)
328{
329 u16 control, supported;
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500330 int pasid = pdev->pasid_cap;
Joerg Roedel086ac112011-09-27 15:57:16 +0200331
Kuppuswamy Sathyanarayanan2b0ae7c2019-09-05 14:31:43 -0500332 /*
333 * VFs must not implement the PASID Capability, but if a PF
334 * supports PASID, its VFs share the PF PASID configuration.
335 */
336 if (pdev->is_virtfn) {
337 if (pci_physfn(pdev)->pasid_enabled)
338 return 0;
339 return -EINVAL;
340 }
341
Jean-Philippe Bruckera4f4fa62017-05-30 09:25:48 -0700342 if (WARN_ON(pdev->pasid_enabled))
343 return -EBUSY;
344
Sinan Kaya7ce3f912018-06-30 11:24:24 -0400345 if (!pdev->eetlp_prefix_path)
346 return -EINVAL;
347
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500348 if (!pasid)
Joerg Roedel086ac112011-09-27 15:57:16 +0200349 return -EINVAL;
350
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500351 pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
Alex Williamson91f57d52011-11-11 10:07:36 -0700352 supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
Joerg Roedel086ac112011-09-27 15:57:16 +0200353
354 /* User wants to enable anything unsupported? */
355 if ((supported & features) != features)
356 return -EINVAL;
357
Alex Williamson91f57d52011-11-11 10:07:36 -0700358 control = PCI_PASID_CTRL_ENABLE | features;
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700359 pdev->pasid_features = features;
Joerg Roedel086ac112011-09-27 15:57:16 +0200360
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500361 pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
Joerg Roedel086ac112011-09-27 15:57:16 +0200362
Jean-Philippe Bruckera4f4fa62017-05-30 09:25:48 -0700363 pdev->pasid_enabled = 1;
364
Joerg Roedel086ac112011-09-27 15:57:16 +0200365 return 0;
366}
Joerg Roedel086ac112011-09-27 15:57:16 +0200367
368/**
369 * pci_disable_pasid - Disable the PASID capability
370 * @pdev: PCI device structure
Joerg Roedel086ac112011-09-27 15:57:16 +0200371 */
372void pci_disable_pasid(struct pci_dev *pdev)
373{
374 u16 control = 0;
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500375 int pasid = pdev->pasid_cap;
Joerg Roedel086ac112011-09-27 15:57:16 +0200376
Kuppuswamy Sathyanarayanan2b0ae7c2019-09-05 14:31:43 -0500377 /* VFs share the PF PASID configuration */
378 if (pdev->is_virtfn)
379 return;
380
Jean-Philippe Bruckera4f4fa62017-05-30 09:25:48 -0700381 if (WARN_ON(!pdev->pasid_enabled))
382 return;
383
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500384 if (!pasid)
Joerg Roedel086ac112011-09-27 15:57:16 +0200385 return;
386
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500387 pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
Jean-Philippe Bruckera4f4fa62017-05-30 09:25:48 -0700388
389 pdev->pasid_enabled = 0;
Joerg Roedel086ac112011-09-27 15:57:16 +0200390}
Joerg Roedel086ac112011-09-27 15:57:16 +0200391
392/**
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700393 * pci_restore_pasid_state - Restore PASID capabilities
394 * @pdev: PCI device structure
395 */
396void pci_restore_pasid_state(struct pci_dev *pdev)
397{
398 u16 control;
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500399 int pasid = pdev->pasid_cap;
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700400
Kuppuswamy Sathyanarayanan2b0ae7c2019-09-05 14:31:43 -0500401 if (pdev->is_virtfn)
402 return;
403
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700404 if (!pdev->pasid_enabled)
405 return;
406
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500407 if (!pasid)
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700408 return;
409
410 control = PCI_PASID_CTRL_ENABLE | pdev->pasid_features;
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500411 pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700412}
CQ Tang4ebeb1e2017-05-30 09:25:49 -0700413
414/**
Joerg Roedel086ac112011-09-27 15:57:16 +0200415 * pci_pasid_features - Check which PASID features are supported
416 * @pdev: PCI device structure
417 *
418 * Returns a negative value when no PASI capability is present.
419 * Otherwise is returns a bitmask with supported features. Current
420 * features reported are:
Alex Williamson91f57d52011-11-11 10:07:36 -0700421 * PCI_PASID_CAP_EXEC - Execute permission supported
Bjorn Helgaasf7625982013-11-14 11:28:18 -0700422 * PCI_PASID_CAP_PRIV - Privileged mode supported
Joerg Roedel086ac112011-09-27 15:57:16 +0200423 */
424int pci_pasid_features(struct pci_dev *pdev)
425{
426 u16 supported;
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500427 int pasid = pdev->pasid_cap;
Joerg Roedel086ac112011-09-27 15:57:16 +0200428
Kuppuswamy Sathyanarayanan2b0ae7c2019-09-05 14:31:43 -0500429 if (pdev->is_virtfn)
430 pdev = pci_physfn(pdev);
431
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500432 if (!pasid)
Joerg Roedel086ac112011-09-27 15:57:16 +0200433 return -EINVAL;
434
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500435 pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
Joerg Roedel086ac112011-09-27 15:57:16 +0200436
Alex Williamson91f57d52011-11-11 10:07:36 -0700437 supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
Joerg Roedel086ac112011-09-27 15:57:16 +0200438
439 return supported;
440}
Joerg Roedel086ac112011-09-27 15:57:16 +0200441
442#define PASID_NUMBER_SHIFT 8
443#define PASID_NUMBER_MASK (0x1f << PASID_NUMBER_SHIFT)
444/**
445 * pci_max_pasid - Get maximum number of PASIDs supported by device
446 * @pdev: PCI device structure
447 *
448 * Returns negative value when PASID capability is not present.
Bjorn Helgaasf6b6aef2019-05-30 08:05:58 -0500449 * Otherwise it returns the number of supported PASIDs.
Joerg Roedel086ac112011-09-27 15:57:16 +0200450 */
451int pci_max_pasids(struct pci_dev *pdev)
452{
453 u16 supported;
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500454 int pasid = pdev->pasid_cap;
Joerg Roedel086ac112011-09-27 15:57:16 +0200455
Kuppuswamy Sathyanarayanan2b0ae7c2019-09-05 14:31:43 -0500456 if (pdev->is_virtfn)
457 pdev = pci_physfn(pdev);
458
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500459 if (!pasid)
Joerg Roedel086ac112011-09-27 15:57:16 +0200460 return -EINVAL;
461
Kuppuswamy Sathyanarayanan751035b2019-09-05 14:31:46 -0500462 pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
Joerg Roedel086ac112011-09-27 15:57:16 +0200463
464 supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
465
466 return (1 << supported);
467}
Joerg Roedel086ac112011-09-27 15:57:16 +0200468#endif /* CONFIG_PCI_PASID */