Skip to content

Commit

Permalink
iommu: always enable the vfio backend
Browse files Browse the repository at this point in the history
Even if we have a kernel with iommufd vfio features enabled, the kernel
may not be configured for modern iommufd (i.e., no device cdevs).

In that case we want to fall back to legacy vfio.

Signed-off-by: Klaus Jensen <[email protected]>
  • Loading branch information
birkelund committed Oct 27, 2023
1 parent 54cfe0e commit 94c27f6
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 29 deletions.
4 changes: 2 additions & 2 deletions include/vfn/iommu/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
#define __VFN_IOVA_MIN 0x10000

/**
* get_iommu_context - create a new iommu context
* iommu_get_context - create a new iommu context
* @name: context identifier
*
* Create a new iommu context. The mechanism depends on the backend.
*
* Return: a new &struct iommu_ctx.
*/
struct iommu_ctx *get_iommu_context(const char *name);
struct iommu_ctx *iommu_get_context(const char *name);

#endif /* LIBVFN_IOMMU_CONTEXT_H */
65 changes: 65 additions & 0 deletions src/iommu/context.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: LGPL-2.1-or-later or MIT

/*
* This file is part of libvfn.
*
* Copyright (C) 2023 The libvfn Authors. All Rights Reserved.
*
* This library (libvfn) is dual licensed under the GNU Lesser General
* Public License version 2.1 or later or the MIT license. See the
* COPYING and LICENSE files for more information.
*/

#define log_fmt(fmt) "iommu/context: " fmt

#include <stddef.h>
#include <stdint.h>
#include <pthread.h>

#include <sys/stat.h>

#include "vfn/support.h"

#include "util/iova_map.h"
#include "context.h"

#ifdef HAVE_VFIO_DEVICE_BIND_IOMMUFD
static bool __iommufd_broken;

static void __attribute__((constructor)) __check_iommufd_broken(void)
{
struct stat sb;

if (stat("/dev/vfio/devices", &sb) || (sb.st_mode & S_IFDIR)) {
log_info("iommufd broken; probably missing CONFIG_VFIO_DEVICE_CDEV=y\n");

__iommufd_broken = true;
}
}
#endif

struct iommu_ctx *iommu_get_default_context(void)
{
#ifdef HAVE_VFIO_DEVICE_BIND_IOMMUFD
if (__iommufd_broken)
goto fallback;

return iommufd_get_default_iommu_context();

fallback:
#endif
return vfio_get_default_iommu_context();
}

struct iommu_ctx *iommu_get_context(const char *name)
{
#ifdef HAVE_VFIO_DEVICE_BIND_IOMMUFD
if (__iommufd_broken)
goto fallback;

return iommufd_get_iommu_context(name);

fallback:
#endif
return vfio_get_iommu_context(name);
}
10 changes: 9 additions & 1 deletion src/iommu/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,12 @@ struct iommu_ctx {
unsigned int flags;
};

struct iommu_ctx *get_default_iommu_ctx(void);
struct iommu_ctx *iommu_get_default_context(void);

struct iommu_ctx *vfio_get_default_iommu_context(void);
struct iommu_ctx *vfio_get_iommu_context(const char *name);

#ifdef HAVE_VFIO_DEVICE_BIND_IOMMUFD
struct iommu_ctx *iommufd_get_default_iommu_context(void);
struct iommu_ctx *iommufd_get_iommu_context(const char *name);
#endif
33 changes: 20 additions & 13 deletions src/iommu/iommufd.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,6 @@ static struct iommu_ioas iommu_default_ioas = {
.name = "default",
};

struct iommu_ctx *get_default_iommu_ctx(void)
{
return &iommu_default_ioas.ctx;
}

static int iommu_ioas_update_iova_ranges(struct iommu_ioas *ioas)
{
struct iommu_ioas_iova_ranges iova_ranges = {
Expand Down Expand Up @@ -231,7 +226,7 @@ static int iommu_ioas_do_dma_unmap(struct iommu_ctx *ctx, uint64_t iova, size_t
return 0;
}

struct iommu_ctx_ops iommufd_ops = {
static const struct iommu_ctx_ops iommufd_ops = {
.get_device_fd = iommufd_get_device_fd,

.dma_map = iommu_ioas_do_dma_map,
Expand Down Expand Up @@ -259,10 +254,22 @@ static int iommu_ioas_init(struct iommu_ioas *ioas)
return 0;
}

struct iommu_ctx *get_iommu_ctx(const char *name)
static int iommufd_open(void)
{
__iommufd = open("/dev/iommu", O_RDWR);
if (__iommufd < 0)
return -1;

return 0;
}

struct iommu_ctx *iommufd_get_iommu_context(const char *name)
{
struct iommu_ioas *ioas = znew_t(struct iommu_ioas, 1);

if (__iommufd == -1)
log_fatal_if(iommufd_open(), "could not open /dev/iommu\n");

if (iommu_ioas_init(ioas) < 0) {
free(ioas);
return NULL;
Expand All @@ -273,12 +280,12 @@ struct iommu_ctx *get_iommu_ctx(const char *name)
return &ioas->ctx;
}

static void __attribute__((constructor)) init_iommufd(void)
struct iommu_ctx *iommufd_get_default_iommu_context(void)
{
__iommufd = open("/dev/iommu", O_RDWR);
if (__iommufd < 0)
log_fatal("could not open /dev/iommu\n");
if (__iommufd == -1) {
log_fatal_if(iommufd_open(), "could not open /dev/iommu\n");
log_fatal_if(iommu_ioas_init(&iommu_default_ioas), "iommu_ioas_init\n");
}

if (iommu_ioas_init(&iommu_default_ioas))
log_fatal("could not initialize default ioas: %s\n", strerror(errno));
return &iommu_default_ioas.ctx;
}
4 changes: 2 additions & 2 deletions src/iommu/meson.build
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
iommu_sources = files(
'context.c',
'dma.c',
'vfio.c',
)

if config_host.get('HAVE_VFIO_DEVICE_BIND_IOMMUFD', false)
iommu_sources += files('iommufd.c',)
else
iommu_sources += files('vfio.c')
endif

vfn_sources += iommu_sources
19 changes: 9 additions & 10 deletions src/iommu/vfio.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,10 @@ struct vfio_container {
};

static struct vfio_container vfio_default_container = {
.fd = -1,
.name = "default",
};

struct iommu_ctx *get_default_iommu_ctx(void)
{
return &vfio_default_container.ctx;
}

#ifdef VFIO_IOMMU_INFO_CAPS
# ifdef VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE
static void vfio_iommu_type1_get_cap_iova_ranges(struct iova_map *map,
Expand Down Expand Up @@ -392,7 +388,7 @@ static int vfio_iommu_type1_do_dma_unmap(struct iommu_ctx *ctx, uint64_t iova, s
return 0;
}

struct iommu_ctx_ops vfio_ops = {
static const struct iommu_ctx_ops vfio_ops = {
.get_device_fd = vfio_get_device_fd,

.dma_map = vfio_iommu_type1_do_dma_map,
Expand Down Expand Up @@ -422,7 +418,7 @@ static int vfio_init_container(struct vfio_container *vfio)
return 0;
}

struct iommu_ctx *get_iommu_context(const char *name)
struct iommu_ctx *vfio_get_iommu_context(const char *name)
{
struct vfio_container *vfio = znew_t(struct vfio_container, 1);

Expand All @@ -436,8 +432,11 @@ struct iommu_ctx *get_iommu_context(const char *name)
return &vfio->ctx;
}

static void __attribute__((constructor)) open_default_container(void)
struct iommu_ctx *vfio_get_default_iommu_context(void)
{
if (vfio_init_container(&vfio_default_container))
log_debug("default container not initialized\n");
if (vfio_default_container.fd == -1)
log_fatal_if(vfio_init_container(&vfio_default_container),
"init default container\n");

return &vfio_default_container.ctx;
}
2 changes: 1 addition & 1 deletion src/vfio/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ int vfio_pci_open(struct vfio_pci_device *pci, const char *bdf)
pci->bdf = bdf;

if (!pci->dev.ctx)
pci->dev.ctx = get_default_iommu_ctx();
pci->dev.ctx = iommu_get_default_context();

pci->dev.fd = pci->dev.ctx->ops.get_device_fd(pci->dev.ctx, bdf);
if (pci->dev.fd < 0) {
Expand Down

0 comments on commit 94c27f6

Please sign in to comment.