Commit 5979e0c9 authored by Julien Grall's avatar Julien Grall Committed by Jan Beulich

iommu: split generic code

The generic IOMMU framework code (xen/drivers/passthrough/iommu.c) contains
functions specific to x86 and PCI.

Split the framework in 3 distincts files:
    - iommu.c: contains generic functions shared between x86 and ARM
               (when it will be supported)
    - pci.c: contains specific functions for PCI passthrough
    - x86/iommu.c: contains specific functions for x86

io.c contains x86 HVM specific code. Only compile for x86.

This patch is mostly code movement in new files.
Signed-off-by: default avatarJulien Grall <julien.grall@linaro.org>
Acked-by: default avatarJan Beulich <jbeulich@suse.com>
parent fc49666e
......@@ -3,5 +3,5 @@ subdir-$(x86) += amd
subdir-$(x86_64) += x86
obj-y += iommu.o
obj-y += io.o
obj-y += pci.o
obj-$(x86) += io.o
obj-$(HAS_PCI) += pci.o
This diff is collapsed.
This diff is collapsed.
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
#include <xen/sched.h>
#include <xen/iommu.h>
#include <xen/paging.h>
#include <xen/guest_access.h>
#include <xen/event.h>
#include <xen/softirq.h>
#include <xsm/xsm.h>
void iommu_update_ire_from_apic(
unsigned int apic, unsigned int reg, unsigned int value)
{
const struct iommu_ops *ops = iommu_get_ops();
ops->update_ire_from_apic(apic, reg, value);
}
unsigned int iommu_read_apic_from_ire(unsigned int apic, unsigned int reg)
{
const struct iommu_ops *ops = iommu_get_ops();
return ops->read_apic_from_ire(apic, reg);
}
int __init iommu_setup_hpet_msi(struct msi_desc *msi)
{
const struct iommu_ops *ops = iommu_get_ops();
return ops->setup_hpet_msi ? ops->setup_hpet_msi(msi) : -ENODEV;
}
int arch_iommu_populate_page_table(struct domain *d)
{
struct hvm_iommu *hd = domain_hvm_iommu(d);
struct page_info *page;
int rc = 0, n = 0;
d->need_iommu = -1;
this_cpu(iommu_dont_flush_iotlb) = 1;
spin_lock(&d->page_alloc_lock);
if ( unlikely(d->is_dying) )
rc = -ESRCH;
while ( !rc && (page = page_list_remove_head(&d->page_list)) )
{
if ( is_hvm_domain(d) ||
(page->u.inuse.type_info & PGT_type_mask) == PGT_writable_page )
{
BUG_ON(SHARED_M2P(mfn_to_gmfn(d, page_to_mfn(page))));
rc = hd->platform_ops->map_page(
d, mfn_to_gmfn(d, page_to_mfn(page)), page_to_mfn(page),
IOMMUF_readable|IOMMUF_writable);
if ( rc )
{
page_list_add(page, &d->page_list);
break;
}
}
page_list_add_tail(page, &d->arch.relmem_list);
if ( !(++n & 0xff) && !page_list_empty(&d->page_list) &&
hypercall_preempt_check() )
rc = -ERESTART;
}
if ( !rc )
{
/*
* The expectation here is that generally there are many normal pages
* on relmem_list (the ones we put there) and only few being in an
* offline/broken state. The latter ones are always at the head of the
* list. Hence we first move the whole list, and then move back the
* first few entries.
*/
page_list_move(&d->page_list, &d->arch.relmem_list);
while ( (page = page_list_first(&d->page_list)) != NULL &&
(page->count_info & (PGC_state|PGC_broken)) )
{
page_list_del(page, &d->page_list);
page_list_add_tail(page, &d->arch.relmem_list);
}
}
spin_unlock(&d->page_alloc_lock);
this_cpu(iommu_dont_flush_iotlb) = 0;
if ( !rc )
iommu_iotlb_flush_all(d);
else if ( rc != -ERESTART )
iommu_teardown(d);
return rc;
}
void __hwdom_init arch_iommu_check_autotranslated_hwdom(struct domain *d)
{
if ( !iommu_enabled )
panic("Presently, iommu must be enabled for PVH hardware domain\n");
}
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef __ARCH_X86_IOMMU_H__
#define __ARCH_X86_IOMMU_H__
#define MAX_IOMMUS 32
#include <asm/msi.h>
void iommu_update_ire_from_apic(unsigned int apic, unsigned int reg, unsigned int value);
unsigned int iommu_read_apic_from_ire(unsigned int apic, unsigned int reg);
int iommu_setup_hpet_msi(struct msi_desc *);
/* While VT-d specific, this must get declared in a generic header. */
int adjust_vtd_irq_affinities(void);
void iommu_pte_flush(struct domain *d, u64 gfn, u64 *pte, int order, int present);
int iommu_supports_eim(void);
int iommu_enable_x2apic_IR(void);
void iommu_disable_x2apic_IR(void);
#endif /* !__ARCH_X86_IOMMU_H__ */
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/
......@@ -21,6 +21,7 @@
#define __XEN_HVM_IOMMU_H__
#include <xen/iommu.h>
#include <asm/hvm/iommu.h>
struct g2m_ioport {
struct list_head list;
......
......@@ -25,6 +25,7 @@
#include <xen/pci.h>
#include <public/hvm/ioreq.h>
#include <public/domctl.h>
#include <asm/iommu.h>
extern bool_t iommu_enable, iommu_enabled;
extern bool_t force_iommu, iommu_verbose;
......@@ -39,17 +40,12 @@ extern bool_t amd_iommu_perdev_intremap;
#define domain_hvm_iommu(d) (&d->arch.hvm_domain.hvm_iommu)
#define MAX_IOMMUS 32
#define PAGE_SHIFT_4K (12)
#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
int iommu_setup(void);
int iommu_supports_eim(void);
int iommu_enable_x2apic_IR(void);
void iommu_disable_x2apic_IR(void);
int iommu_add_device(struct pci_dev *pdev);
int iommu_enable_device(struct pci_dev *pdev);
......@@ -59,6 +55,12 @@ void iommu_hwdom_init(struct domain *d);
void iommu_domain_destroy(struct domain *d);
int deassign_device(struct domain *d, u16 seg, u8 bus, u8 devfn);
int arch_iommu_populate_page_table(struct domain *d);
void arch_iommu_check_autotranslated_hwdom(struct domain *d);
/* Function used internally, use iommu_domain_destroy */
void iommu_teardown(struct domain *d);
/* iommu_map_page() takes flags to direct the mapping operation. */
#define _IOMMUF_readable 0
#define IOMMUF_readable (1u<<_IOMMUF_readable)
......@@ -67,8 +69,8 @@ int deassign_device(struct domain *d, u16 seg, u8 bus, u8 devfn);
int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn,
unsigned int flags);
int iommu_unmap_page(struct domain *d, unsigned long gfn);
void iommu_pte_flush(struct domain *d, u64 gfn, u64 *pte, int order, int present);
#ifdef HAS_PCI
void pt_pci_init(void);
struct pirq;
......@@ -82,32 +84,41 @@ struct hvm_irq_dpci *domain_get_irq_dpci(const struct domain *);
void free_hvm_irq_dpci(struct hvm_irq_dpci *dpci);
bool_t pt_irq_need_timer(uint32_t flags);
#define PT_IRQ_TIME_OUT MILLISECS(8)
struct msi_desc;
struct msi_msg;
int iommu_update_ire_from_msi(struct msi_desc *msi_desc, struct msi_msg *msg);
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 */
struct page_info;
struct iommu_ops {
int (*init)(struct domain *d);
void (*hwdom_init)(struct domain *d);
#ifdef HAS_PCI
int (*add_device)(u8 devfn, struct pci_dev *);
int (*enable_device)(struct pci_dev *pdev);
int (*remove_device)(u8 devfn, struct pci_dev *);
int (*assign_device)(struct domain *, u8 devfn, struct pci_dev *);
int (*reassign_device)(struct domain *s, struct domain *t,
u8 devfn, struct pci_dev *);
int (*get_device_group_id)(u16 seg, u8 bus, u8 devfn);
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 */
void (*teardown)(struct domain *d);
int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn,
unsigned int flags);
int (*unmap_page)(struct domain *d, unsigned long gfn);
void (*free_page_table)(struct page_info *);
int (*reassign_device)(struct domain *s, struct domain *t,
u8 devfn, struct pci_dev *);
int (*get_device_group_id)(u16 seg, u8 bus, u8 devfn);
#ifdef CONFIG_X86
void (*update_ire_from_apic)(unsigned int apic, unsigned int reg, unsigned int value);
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);
unsigned int (*read_apic_from_ire)(unsigned int apic, unsigned int reg);
int (*setup_hpet_msi)(struct msi_desc *);
#endif /* CONFIG_X86 */
void (*suspend)(void);
void (*resume)(void);
void (*share_p2m)(struct domain *d);
......@@ -117,27 +128,23 @@ struct iommu_ops {
void (*dump_p2m_table)(struct domain *d);
};
void iommu_update_ire_from_apic(unsigned int apic, unsigned int reg, unsigned int value);
int iommu_update_ire_from_msi(struct msi_desc *msi_desc, struct msi_msg *msg);
void iommu_read_msi_from_ire(struct msi_desc *msi_desc, struct msi_msg *msg);
unsigned int iommu_read_apic_from_ire(unsigned int apic, unsigned int reg);
int iommu_setup_hpet_msi(struct msi_desc *);
void iommu_suspend(void);
void iommu_resume(void);
void iommu_crash_shutdown(void);
void iommu_share_p2m_table(struct domain *d);
#ifdef HAS_PCI
int iommu_do_pci_domctl(struct xen_domctl *, struct domain *d,
XEN_GUEST_HANDLE_PARAM(xen_domctl_t));
#endif
int iommu_do_domctl(struct xen_domctl *, struct domain *d,
XEN_GUEST_HANDLE_PARAM(xen_domctl_t));
void iommu_iotlb_flush(struct domain *d, unsigned long gfn, unsigned int page_count);
void iommu_iotlb_flush_all(struct domain *d);
/* While VT-d specific, this must get declared in a generic header. */
int adjust_vtd_irq_affinities(void);
/*
* The purpose of the iommu_dont_flush_iotlb optional cpu flag is to
* avoid unecessary iotlb_flush in the low level IOMMU code.
......
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