Commit df6d39cb authored by Julien Grall's avatar Julien Grall Committed by Ian Campbell

xen/passthrough: iommu: Basic support of device tree assignment

Add IOMMU helpers to support device tree assignment/deassignment. This patch
introduces 2 new fields in the dt_device_node:
    - is_protected: Does the device is protected by an IOMMU
    - domain_list: Pointer to the next device assigned to the same
    domain

This commit contains only support to protected a device with DOM0.
Device passthrough to another guest won't work out-of-box.
Signed-off-by: default avatarJulien Grall <julien.grall@linaro.org>
Acked-by: default avatarJan Beulich <jbeulich@suse.com>
Acked-by: default avatarIan Campbell <ian.campbell@citrix.com>
Cc: Xiantao Zhang <xiantao.zhang@intel.com>
parent dfd60b07
......@@ -1695,6 +1695,10 @@ static unsigned long __init unflatten_dt_node(const void *fdt,
np->full_name = ((char *)np) + sizeof(struct dt_device_node);
/* By default dom0 owns the device */
np->used_by = 0;
/* By default the device is not protected */
np->is_protected = false;
INIT_LIST_HEAD(&np->domain_list);
if ( new_format )
{
char *fn = np->full_name;
......
......@@ -5,3 +5,4 @@ subdir-$(x86_64) += x86
obj-y += iommu.o
obj-$(x86) += io.o
obj-$(HAS_PCI) += pci.o
obj-$(HAS_DEVICE_TREE) += device_tree.o
/*
* Code to passthrough a device tree node to a guest
*
* TODO: This contains only the necessary code to protected device passed to
* dom0. It will need some updates when device passthrough will is added.
*
* Julien Grall <julien.grall@linaro.org>
* Copyright (c) 2014 Linaro Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <xen/lib.h>
#include <xen/sched.h>
#include <xen/iommu.h>
#include <xen/device_tree.h>
static spinlock_t dtdevs_lock = SPIN_LOCK_UNLOCKED;
int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev)
{
int rc = -EBUSY;
struct hvm_iommu *hd = domain_hvm_iommu(d);
if ( !iommu_enabled || !hd->platform_ops )
return -EINVAL;
if ( !dt_device_is_protected(dev) )
return -EINVAL;
spin_lock(&dtdevs_lock);
if ( !list_empty(&dev->domain_list) )
goto fail;
rc = hd->platform_ops->assign_dt_device(d, dev);
if ( rc )
goto fail;
list_add(&dev->domain_list, &hd->dt_devices);
dt_device_set_used_by(dev, d->domain_id);
fail:
spin_unlock(&dtdevs_lock);
return rc;
}
int iommu_deassign_dt_device(struct domain *d, struct dt_device_node *dev)
{
struct hvm_iommu *hd = domain_hvm_iommu(d);
int rc;
if ( !iommu_enabled || !hd->platform_ops )
return -EINVAL;
if ( !dt_device_is_protected(dev) )
return -EINVAL;
spin_lock(&dtdevs_lock);
rc = hd->platform_ops->reassign_dt_device(d, hardware_domain, dev);
if ( rc )
goto fail;
list_del(&dev->domain_list);
dt_device_set_used_by(dev, hardware_domain->domain_id);
list_add(&dev->domain_list, &domain_hvm_iommu(hardware_domain)->dt_devices);
fail:
spin_unlock(&dtdevs_lock);
return rc;
}
int iommu_dt_domain_init(struct domain *d)
{
struct hvm_iommu *hd = domain_hvm_iommu(d);
INIT_LIST_HEAD(&hd->dt_devices);
return 0;
}
void iommu_dt_domain_destroy(struct domain *d)
{
struct hvm_iommu *hd = domain_hvm_iommu(d);
struct dt_device_node *dev, *_dev;
int rc;
list_for_each_entry_safe(dev, _dev, &hd->dt_devices, domain_list)
{
rc = iommu_deassign_dt_device(d, dev);
if ( rc )
dprintk(XENLOG_ERR, "Failed to deassign %s in domain %u\n",
dt_node_full_name(dev), d->domain_id);
}
}
......@@ -16,6 +16,7 @@
#include <xen/string.h>
#include <xen/types.h>
#include <xen/stdbool.h>
#include <xen/list.h>
#define DEVICE_TREE_MAX_DEPTH 16
......@@ -111,6 +112,9 @@ struct dt_device_node {
struct dt_device_node *next; /* TODO: Remove it. Only use to know the last children */
struct dt_device_node *allnext;
/* IOMMU specific fields */
bool is_protected;
struct list_head domain_list;
};
#define MAX_PHANDLE_ARGS 16
......@@ -326,6 +330,16 @@ static inline domid_t dt_device_used_by(const struct dt_device_node *device)
return device->used_by;
}
static inline void dt_device_set_protected(struct dt_device_node *device)
{
device->is_protected = true;
}
static inline bool dt_device_is_protected(const struct dt_device_node *device)
{
return device->is_protected;
}
static inline bool_t dt_property_name_is_equal(const struct dt_property *pp,
const char *name)
{
......
......@@ -21,6 +21,7 @@
#define __XEN_HVM_IOMMU_H__
#include <xen/iommu.h>
#include <xen/list.h>
#include <asm/hvm/iommu.h>
struct hvm_iommu {
......@@ -28,6 +29,11 @@ struct hvm_iommu {
/* iommu_ops */
const struct iommu_ops *platform_ops;
#ifdef HAS_DEVICE_TREE
/* List of DT devices assigned to this domain */
struct list_head dt_devices;
#endif
};
#endif /* __XEN_HVM_IOMMU_H__ */
......@@ -90,6 +90,16 @@ void iommu_read_msi_from_ire(struct msi_desc *msi_desc, struct msi_msg *msg);
#define PT_IRQ_TIME_OUT MILLISECS(8)
#endif /* HAS_PCI */
#ifdef HAS_DEVICE_TREE
#include <xen/device_tree.h>
int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev);
int iommu_deassign_dt_device(struct domain *d, struct dt_device_node *dev);
int iommu_dt_domain_init(struct domain *d);
void iommu_dt_domain_destroy(struct domain *d);
#endif /* HAS_DEVICE_TREE */
struct page_info;
struct iommu_ops {
......@@ -106,6 +116,12 @@ struct iommu_ops {
int (*update_ire_from_msi)(struct msi_desc *msi_desc, struct msi_msg *msg);
void (*read_msi_from_ire)(struct msi_desc *msi_desc, struct msi_msg *msg);
#endif /* HAS_PCI */
#ifdef HAS_DEVICE_TREE
int (*assign_dt_device)(struct domain *d, const struct dt_device_node *dev);
int (*reassign_dt_device)(struct domain *s, struct domain *t,
const struct dt_device_node *dev);
#endif
void (*teardown)(struct domain *d);
int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn,
unsigned int flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment