1 // SPDX-License-Identifier: GPL-2.0
3 * intel-pasid.c - PASID idr, table and entry manipulation
5 * Copyright (C) 2018 Intel Corporation
7 * Author: Lu Baolu <baolu.lu@linux.intel.com>
10 #define pr_fmt(fmt) "DMAR: " fmt
12 #include <linux/dmar.h>
13 #include <linux/intel-iommu.h>
14 #include <linux/iommu.h>
15 #include <linux/memory.h>
16 #include <linux/pci.h>
17 #include <linux/pci-ats.h>
18 #include <linux/spinlock.h>
20 #include "intel-pasid.h"
23 * Intel IOMMU system wide PASID name space:
25 static DEFINE_SPINLOCK(pasid_lock
);
26 u32 intel_pasid_max_id
= PASID_MAX
;
27 static DEFINE_IDR(pasid_idr
);
29 int intel_pasid_alloc_id(void *ptr
, int start
, int end
, gfp_t gfp
)
33 min
= max_t(int, start
, PASID_MIN
);
34 max
= min_t(int, end
, intel_pasid_max_id
);
36 WARN_ON(in_interrupt());
38 spin_lock(&pasid_lock
);
39 ret
= idr_alloc(&pasid_idr
, ptr
, min
, max
, GFP_ATOMIC
);
40 spin_unlock(&pasid_lock
);
46 void intel_pasid_free_id(int pasid
)
48 spin_lock(&pasid_lock
);
49 idr_remove(&pasid_idr
, pasid
);
50 spin_unlock(&pasid_lock
);
53 void *intel_pasid_lookup_id(int pasid
)
57 spin_lock(&pasid_lock
);
58 p
= idr_find(&pasid_idr
, pasid
);
59 spin_unlock(&pasid_lock
);
65 * Per device pasid table management:
68 device_attach_pasid_table(struct device_domain_info
*info
,
69 struct pasid_table
*pasid_table
)
71 info
->pasid_table
= pasid_table
;
72 list_add(&info
->table
, &pasid_table
->dev
);
76 device_detach_pasid_table(struct device_domain_info
*info
,
77 struct pasid_table
*pasid_table
)
79 info
->pasid_table
= NULL
;
80 list_del(&info
->table
);
83 struct pasid_table_opaque
{
84 struct pasid_table
**pasid_table
;
90 static int search_pasid_table(struct device_domain_info
*info
, void *opaque
)
92 struct pasid_table_opaque
*data
= opaque
;
94 if (info
->iommu
->segment
== data
->segment
&&
95 info
->bus
== data
->bus
&&
96 info
->devfn
== data
->devfn
&&
98 *data
->pasid_table
= info
->pasid_table
;
105 static int get_alias_pasid_table(struct pci_dev
*pdev
, u16 alias
, void *opaque
)
107 struct pasid_table_opaque
*data
= opaque
;
109 data
->segment
= pci_domain_nr(pdev
->bus
);
110 data
->bus
= PCI_BUS_NUM(alias
);
111 data
->devfn
= alias
& 0xff;
113 return for_each_device_domain(&search_pasid_table
, data
);
117 * Allocate a pasid table for @dev. It should be called in a
118 * single-thread context.
120 int intel_pasid_alloc_table(struct device
*dev
)
122 struct device_domain_info
*info
;
123 struct pasid_table
*pasid_table
;
124 struct pasid_table_opaque data
;
129 info
= dev
->archdata
.iommu
;
130 if (WARN_ON(!info
|| !dev_is_pci(dev
) ||
131 !info
->pasid_supported
|| info
->pasid_table
))
134 /* DMA alias device already has a pasid table, use it: */
135 data
.pasid_table
= &pasid_table
;
136 ret
= pci_for_each_dma_alias(to_pci_dev(dev
),
137 &get_alias_pasid_table
, &data
);
141 pasid_table
= kzalloc(sizeof(*pasid_table
), GFP_ATOMIC
);
144 INIT_LIST_HEAD(&pasid_table
->dev
);
146 size
= sizeof(struct pasid_entry
);
147 count
= min_t(int, pci_max_pasids(to_pci_dev(dev
)), intel_pasid_max_id
);
148 order
= get_order(size
* count
);
149 pages
= alloc_pages_node(info
->iommu
->node
,
150 GFP_ATOMIC
| __GFP_ZERO
,
155 pasid_table
->table
= page_address(pages
);
156 pasid_table
->order
= order
;
157 pasid_table
->max_pasid
= count
;
160 device_attach_pasid_table(info
, pasid_table
);
165 void intel_pasid_free_table(struct device
*dev
)
167 struct device_domain_info
*info
;
168 struct pasid_table
*pasid_table
;
170 info
= dev
->archdata
.iommu
;
171 if (!info
|| !dev_is_pci(dev
) ||
172 !info
->pasid_supported
|| !info
->pasid_table
)
175 pasid_table
= info
->pasid_table
;
176 device_detach_pasid_table(info
, pasid_table
);
178 if (!list_empty(&pasid_table
->dev
))
181 free_pages((unsigned long)pasid_table
->table
, pasid_table
->order
);
185 struct pasid_table
*intel_pasid_get_table(struct device
*dev
)
187 struct device_domain_info
*info
;
189 info
= dev
->archdata
.iommu
;
193 return info
->pasid_table
;
196 int intel_pasid_get_dev_max_id(struct device
*dev
)
198 struct device_domain_info
*info
;
200 info
= dev
->archdata
.iommu
;
201 if (!info
|| !info
->pasid_table
)
204 return info
->pasid_table
->max_pasid
;
207 struct pasid_entry
*intel_pasid_get_entry(struct device
*dev
, int pasid
)
209 struct pasid_table
*pasid_table
;
210 struct pasid_entry
*entries
;
212 pasid_table
= intel_pasid_get_table(dev
);
213 if (WARN_ON(!pasid_table
|| pasid
< 0 ||
214 pasid
>= intel_pasid_get_dev_max_id(dev
)))
217 entries
= pasid_table
->table
;
219 return &entries
[pasid
];
223 * Interfaces for PASID table entry manipulation:
225 static inline void pasid_clear_entry(struct pasid_entry
*pe
)
227 WRITE_ONCE(pe
->val
, 0);
230 void intel_pasid_clear_entry(struct device
*dev
, int pasid
)
232 struct pasid_entry
*pe
;
234 pe
= intel_pasid_get_entry(dev
, pasid
);
238 pasid_clear_entry(pe
);