Skip to content

Commit ec031e1

Browse files
nicolincjgunthorpe
authored andcommitted
iommufd: Move iommufd_sw_msi and related functions to driver.c
To provide the iommufd_sw_msi() to the iommu core that is under a different Kconfig, move it and its related functions to driver.c. Then, stub it into the iommu-priv header. The iommufd_sw_msi_install() continues to be used by iommufd internal, so put it in the private header. Note that iommufd_sw_msi() will be called in the iommu core, replacing the sw_msi function pointer. Given that IOMMU_API is "bool" in Kconfig, change IOMMUFD_DRIVER_CORE to "bool" as well. Since this affects the module size, here is before-n-after size comparison: [Before] text data bss dec hex filename 18797 848 56 19701 4cf5 drivers/iommu/iommufd/device.o 722 44 0 766 2fe drivers/iommu/iommufd/driver.o [After] text data bss dec hex filename 17735 808 56 18599 48a7 drivers/iommu/iommufd/device.o 3020 180 0 3200 c80 drivers/iommu/iommufd/driver.o Link: https://patch.msgid.link/r/374c159592dba7852bee20968f3f66fa0ee8ca93.1742871535.git.nicolinc@nvidia.com Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
1 parent 6aa63a4 commit ec031e1

5 files changed

Lines changed: 153 additions & 126 deletions

File tree

drivers/iommu/iommu-priv.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define __LINUX_IOMMU_PRIV_H
66

77
#include <linux/iommu.h>
8+
#include <linux/msi.h>
89

910
static inline const struct iommu_ops *dev_iommu_ops(struct device *dev)
1011
{
@@ -43,4 +44,16 @@ void iommu_detach_group_handle(struct iommu_domain *domain,
4344
int iommu_replace_group_handle(struct iommu_group *group,
4445
struct iommu_domain *new_domain,
4546
struct iommu_attach_handle *handle);
47+
48+
#if IS_ENABLED(CONFIG_IOMMUFD_DRIVER_CORE) && IS_ENABLED(CONFIG_IRQ_MSI_IOMMU)
49+
int iommufd_sw_msi(struct iommu_domain *domain, struct msi_desc *desc,
50+
phys_addr_t msi_addr);
51+
#else /* !CONFIG_IOMMUFD_DRIVER_CORE || !CONFIG_IRQ_MSI_IOMMU */
52+
static inline int iommufd_sw_msi(struct iommu_domain *domain,
53+
struct msi_desc *desc, phys_addr_t msi_addr)
54+
{
55+
return -EOPNOTSUPP;
56+
}
57+
#endif /* CONFIG_IOMMUFD_DRIVER_CORE && CONFIG_IRQ_MSI_IOMMU */
58+
4659
#endif /* __LINUX_IOMMU_PRIV_H */

drivers/iommu/iommufd/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
config IOMMUFD_DRIVER_CORE
3-
tristate
3+
bool
44
default (IOMMUFD_DRIVER || IOMMUFD) if IOMMUFD!=n
55

66
config IOMMUFD

drivers/iommu/iommufd/device.c

Lines changed: 8 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#include <linux/iommufd.h>
66
#include <linux/slab.h>
77
#include <uapi/linux/iommufd.h>
8-
#include <linux/msi.h>
98

109
#include "../iommu-priv.h"
1110
#include "io_pagetable.h"
@@ -294,129 +293,7 @@ u32 iommufd_device_to_id(struct iommufd_device *idev)
294293
}
295294
EXPORT_SYMBOL_NS_GPL(iommufd_device_to_id, "IOMMUFD");
296295

297-
/*
298-
* Get a iommufd_sw_msi_map for the msi physical address requested by the irq
299-
* layer. The mapping to IOVA is global to the iommufd file descriptor, every
300-
* domain that is attached to a device using the same MSI parameters will use
301-
* the same IOVA.
302-
*/
303-
static __maybe_unused struct iommufd_sw_msi_map *
304-
iommufd_sw_msi_get_map(struct iommufd_ctx *ictx, phys_addr_t msi_addr,
305-
phys_addr_t sw_msi_start)
306-
{
307-
struct iommufd_sw_msi_map *cur;
308-
unsigned int max_pgoff = 0;
309-
310-
lockdep_assert_held(&ictx->sw_msi_lock);
311-
312-
list_for_each_entry(cur, &ictx->sw_msi_list, sw_msi_item) {
313-
if (cur->sw_msi_start != sw_msi_start)
314-
continue;
315-
max_pgoff = max(max_pgoff, cur->pgoff + 1);
316-
if (cur->msi_addr == msi_addr)
317-
return cur;
318-
}
319-
320-
if (ictx->sw_msi_id >=
321-
BITS_PER_BYTE * sizeof_field(struct iommufd_sw_msi_maps, bitmap))
322-
return ERR_PTR(-EOVERFLOW);
323-
324-
cur = kzalloc(sizeof(*cur), GFP_KERNEL);
325-
if (!cur)
326-
return ERR_PTR(-ENOMEM);
327-
328-
cur->sw_msi_start = sw_msi_start;
329-
cur->msi_addr = msi_addr;
330-
cur->pgoff = max_pgoff;
331-
cur->id = ictx->sw_msi_id++;
332-
list_add_tail(&cur->sw_msi_item, &ictx->sw_msi_list);
333-
return cur;
334-
}
335-
336-
static int iommufd_sw_msi_install(struct iommufd_ctx *ictx,
337-
struct iommufd_hwpt_paging *hwpt_paging,
338-
struct iommufd_sw_msi_map *msi_map)
339-
{
340-
unsigned long iova;
341-
342-
lockdep_assert_held(&ictx->sw_msi_lock);
343-
344-
iova = msi_map->sw_msi_start + msi_map->pgoff * PAGE_SIZE;
345-
if (!test_bit(msi_map->id, hwpt_paging->present_sw_msi.bitmap)) {
346-
int rc;
347-
348-
rc = iommu_map(hwpt_paging->common.domain, iova,
349-
msi_map->msi_addr, PAGE_SIZE,
350-
IOMMU_WRITE | IOMMU_READ | IOMMU_MMIO,
351-
GFP_KERNEL_ACCOUNT);
352-
if (rc)
353-
return rc;
354-
__set_bit(msi_map->id, hwpt_paging->present_sw_msi.bitmap);
355-
}
356-
return 0;
357-
}
358-
359-
/*
360-
* Called by the irq code if the platform translates the MSI address through the
361-
* IOMMU. msi_addr is the physical address of the MSI page. iommufd will
362-
* allocate a fd global iova for the physical page that is the same on all
363-
* domains and devices.
364-
*/
365296
#ifdef CONFIG_IRQ_MSI_IOMMU
366-
int iommufd_sw_msi(struct iommu_domain *domain, struct msi_desc *desc,
367-
phys_addr_t msi_addr)
368-
{
369-
struct device *dev = msi_desc_to_dev(desc);
370-
struct iommufd_hwpt_paging *hwpt_paging;
371-
struct iommu_attach_handle *raw_handle;
372-
struct iommufd_attach_handle *handle;
373-
struct iommufd_sw_msi_map *msi_map;
374-
struct iommufd_ctx *ictx;
375-
unsigned long iova;
376-
int rc;
377-
378-
/*
379-
* It is safe to call iommu_attach_handle_get() here because the iommu
380-
* core code invokes this under the group mutex which also prevents any
381-
* change of the attach handle for the duration of this function.
382-
*/
383-
iommu_group_mutex_assert(dev);
384-
385-
raw_handle =
386-
iommu_attach_handle_get(dev->iommu_group, IOMMU_NO_PASID, 0);
387-
if (IS_ERR(raw_handle))
388-
return 0;
389-
hwpt_paging = find_hwpt_paging(domain->iommufd_hwpt);
390-
391-
handle = to_iommufd_handle(raw_handle);
392-
/* No IOMMU_RESV_SW_MSI means no change to the msi_msg */
393-
if (handle->idev->igroup->sw_msi_start == PHYS_ADDR_MAX)
394-
return 0;
395-
396-
ictx = handle->idev->ictx;
397-
guard(mutex)(&ictx->sw_msi_lock);
398-
/*
399-
* The input msi_addr is the exact byte offset of the MSI doorbell, we
400-
* assume the caller has checked that it is contained with a MMIO region
401-
* that is secure to map at PAGE_SIZE.
402-
*/
403-
msi_map = iommufd_sw_msi_get_map(handle->idev->ictx,
404-
msi_addr & PAGE_MASK,
405-
handle->idev->igroup->sw_msi_start);
406-
if (IS_ERR(msi_map))
407-
return PTR_ERR(msi_map);
408-
409-
rc = iommufd_sw_msi_install(ictx, hwpt_paging, msi_map);
410-
if (rc)
411-
return rc;
412-
__set_bit(msi_map->id, handle->idev->igroup->required_sw_msi.bitmap);
413-
414-
iova = msi_map->sw_msi_start + msi_map->pgoff * PAGE_SIZE;
415-
msi_desc_set_iommu_msi_iova(desc, iova, PAGE_SHIFT);
416-
return 0;
417-
}
418-
#endif
419-
420297
static int iommufd_group_setup_msi(struct iommufd_group *igroup,
421298
struct iommufd_hwpt_paging *hwpt_paging)
422299
{
@@ -443,6 +320,14 @@ static int iommufd_group_setup_msi(struct iommufd_group *igroup,
443320
}
444321
return 0;
445322
}
323+
#else
324+
static inline int
325+
iommufd_group_setup_msi(struct iommufd_group *igroup,
326+
struct iommufd_hwpt_paging *hwpt_paging)
327+
{
328+
return 0;
329+
}
330+
#endif
446331

447332
static int
448333
iommufd_device_attach_reserved_iova(struct iommufd_device *idev,

drivers/iommu/iommufd/driver.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,5 +121,131 @@ int iommufd_viommu_report_event(struct iommufd_viommu *viommu,
121121
}
122122
EXPORT_SYMBOL_NS_GPL(iommufd_viommu_report_event, "IOMMUFD");
123123

124+
#ifdef CONFIG_IRQ_MSI_IOMMU
125+
/*
126+
* Get a iommufd_sw_msi_map for the msi physical address requested by the irq
127+
* layer. The mapping to IOVA is global to the iommufd file descriptor, every
128+
* domain that is attached to a device using the same MSI parameters will use
129+
* the same IOVA.
130+
*/
131+
static struct iommufd_sw_msi_map *
132+
iommufd_sw_msi_get_map(struct iommufd_ctx *ictx, phys_addr_t msi_addr,
133+
phys_addr_t sw_msi_start)
134+
{
135+
struct iommufd_sw_msi_map *cur;
136+
unsigned int max_pgoff = 0;
137+
138+
lockdep_assert_held(&ictx->sw_msi_lock);
139+
140+
list_for_each_entry(cur, &ictx->sw_msi_list, sw_msi_item) {
141+
if (cur->sw_msi_start != sw_msi_start)
142+
continue;
143+
max_pgoff = max(max_pgoff, cur->pgoff + 1);
144+
if (cur->msi_addr == msi_addr)
145+
return cur;
146+
}
147+
148+
if (ictx->sw_msi_id >=
149+
BITS_PER_BYTE * sizeof_field(struct iommufd_sw_msi_maps, bitmap))
150+
return ERR_PTR(-EOVERFLOW);
151+
152+
cur = kzalloc(sizeof(*cur), GFP_KERNEL);
153+
if (!cur)
154+
return ERR_PTR(-ENOMEM);
155+
156+
cur->sw_msi_start = sw_msi_start;
157+
cur->msi_addr = msi_addr;
158+
cur->pgoff = max_pgoff;
159+
cur->id = ictx->sw_msi_id++;
160+
list_add_tail(&cur->sw_msi_item, &ictx->sw_msi_list);
161+
return cur;
162+
}
163+
164+
int iommufd_sw_msi_install(struct iommufd_ctx *ictx,
165+
struct iommufd_hwpt_paging *hwpt_paging,
166+
struct iommufd_sw_msi_map *msi_map)
167+
{
168+
unsigned long iova;
169+
170+
lockdep_assert_held(&ictx->sw_msi_lock);
171+
172+
iova = msi_map->sw_msi_start + msi_map->pgoff * PAGE_SIZE;
173+
if (!test_bit(msi_map->id, hwpt_paging->present_sw_msi.bitmap)) {
174+
int rc;
175+
176+
rc = iommu_map(hwpt_paging->common.domain, iova,
177+
msi_map->msi_addr, PAGE_SIZE,
178+
IOMMU_WRITE | IOMMU_READ | IOMMU_MMIO,
179+
GFP_KERNEL_ACCOUNT);
180+
if (rc)
181+
return rc;
182+
__set_bit(msi_map->id, hwpt_paging->present_sw_msi.bitmap);
183+
}
184+
return 0;
185+
}
186+
EXPORT_SYMBOL_NS_GPL(iommufd_sw_msi_install, "IOMMUFD_INTERNAL");
187+
188+
/*
189+
* Called by the irq code if the platform translates the MSI address through the
190+
* IOMMU. msi_addr is the physical address of the MSI page. iommufd will
191+
* allocate a fd global iova for the physical page that is the same on all
192+
* domains and devices.
193+
*/
194+
int iommufd_sw_msi(struct iommu_domain *domain, struct msi_desc *desc,
195+
phys_addr_t msi_addr)
196+
{
197+
struct device *dev = msi_desc_to_dev(desc);
198+
struct iommufd_hwpt_paging *hwpt_paging;
199+
struct iommu_attach_handle *raw_handle;
200+
struct iommufd_attach_handle *handle;
201+
struct iommufd_sw_msi_map *msi_map;
202+
struct iommufd_ctx *ictx;
203+
unsigned long iova;
204+
int rc;
205+
206+
/*
207+
* It is safe to call iommu_attach_handle_get() here because the iommu
208+
* core code invokes this under the group mutex which also prevents any
209+
* change of the attach handle for the duration of this function.
210+
*/
211+
iommu_group_mutex_assert(dev);
212+
213+
raw_handle =
214+
iommu_attach_handle_get(dev->iommu_group, IOMMU_NO_PASID, 0);
215+
if (IS_ERR(raw_handle))
216+
return 0;
217+
hwpt_paging = find_hwpt_paging(domain->iommufd_hwpt);
218+
219+
handle = to_iommufd_handle(raw_handle);
220+
/* No IOMMU_RESV_SW_MSI means no change to the msi_msg */
221+
if (handle->idev->igroup->sw_msi_start == PHYS_ADDR_MAX)
222+
return 0;
223+
224+
ictx = handle->idev->ictx;
225+
guard(mutex)(&ictx->sw_msi_lock);
226+
/*
227+
* The input msi_addr is the exact byte offset of the MSI doorbell, we
228+
* assume the caller has checked that it is contained with a MMIO region
229+
* that is secure to map at PAGE_SIZE.
230+
*/
231+
msi_map = iommufd_sw_msi_get_map(handle->idev->ictx,
232+
msi_addr & PAGE_MASK,
233+
handle->idev->igroup->sw_msi_start);
234+
if (IS_ERR(msi_map))
235+
return PTR_ERR(msi_map);
236+
237+
rc = iommufd_sw_msi_install(ictx, hwpt_paging, msi_map);
238+
if (rc)
239+
return rc;
240+
__set_bit(msi_map->id, handle->idev->igroup->required_sw_msi.bitmap);
241+
242+
iova = msi_map->sw_msi_start + msi_map->pgoff * PAGE_SIZE;
243+
msi_desc_set_iommu_msi_iova(desc, iova, PAGE_SHIFT);
244+
return 0;
245+
}
246+
EXPORT_SYMBOL_NS_GPL(iommufd_sw_msi, "IOMMUFD");
247+
#endif
248+
124249
MODULE_DESCRIPTION("iommufd code shared with builtin modules");
250+
MODULE_IMPORT_NS("IOMMUFD_INTERNAL");
125251
MODULE_LICENSE("GPL");

drivers/iommu/iommufd/iommufd_private.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,11 @@ struct iommufd_sw_msi_maps {
3232
DECLARE_BITMAP(bitmap, 64);
3333
};
3434

35-
int iommufd_sw_msi(struct iommu_domain *domain, struct msi_desc *desc,
36-
phys_addr_t msi_addr);
35+
#ifdef CONFIG_IRQ_MSI_IOMMU
36+
int iommufd_sw_msi_install(struct iommufd_ctx *ictx,
37+
struct iommufd_hwpt_paging *hwpt_paging,
38+
struct iommufd_sw_msi_map *msi_map);
39+
#endif
3740

3841
struct iommufd_ctx {
3942
struct file *file;

0 commit comments

Comments
 (0)