ia64/xen-unstable

changeset 17431:85848be18ba2

VT-d: Share VT-d code between x86 and IA64

Declare arch-dependent functions in vtd.h, and implement them for x86.

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Apr 10 09:20:07 2008 +0100 (2008-04-10)
parents 3105a548e2f5
children 1d3aaa6a8b87
files xen/drivers/passthrough/io.c xen/drivers/passthrough/iommu.c xen/drivers/passthrough/vtd/Makefile xen/drivers/passthrough/vtd/iommu.c xen/drivers/passthrough/vtd/vtd.h xen/drivers/passthrough/vtd/x86/Makefile xen/drivers/passthrough/vtd/x86/vtd.c xen/include/xen/iommu.h
line diff
     1.1 --- a/xen/drivers/passthrough/io.c	Thu Apr 10 09:12:44 2008 +0100
     1.2 +++ b/xen/drivers/passthrough/io.c	Thu Apr 10 09:20:07 2008 +0100
     1.3 @@ -25,7 +25,7 @@ static void pt_irq_time_out(void *data)
     1.4  {
     1.5      struct hvm_mirq_dpci_mapping *irq_map = data;
     1.6      unsigned int guest_gsi, machine_gsi = 0;
     1.7 -    struct hvm_irq_dpci *dpci = irq_map->dom->arch.hvm_domain.irq.dpci;
     1.8 +    struct hvm_irq_dpci *dpci = domain_get_irq_dpci(irq_map->dom);
     1.9      struct dev_intx_gsi_link *digl;
    1.10      uint32_t device, intx;
    1.11  
    1.12 @@ -49,7 +49,7 @@ static void pt_irq_time_out(void *data)
    1.13  int pt_irq_create_bind_vtd(
    1.14      struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
    1.15  {
    1.16 -    struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
    1.17 +    struct hvm_irq_dpci *hvm_irq_dpci = domain_get_irq_dpci(d);
    1.18      uint32_t machine_gsi, guest_gsi;
    1.19      uint32_t device, intx, link;
    1.20      struct dev_intx_gsi_link *digl;
    1.21 @@ -65,11 +65,8 @@ int pt_irq_create_bind_vtd(
    1.22          for ( int i = 0; i < NR_IRQS; i++ )
    1.23              INIT_LIST_HEAD(&hvm_irq_dpci->mirq[i].digl_list);
    1.24  
    1.25 -        if ( cmpxchg((unsigned long *)&d->arch.hvm_domain.irq.dpci,
    1.26 -                     0, (unsigned long)hvm_irq_dpci) != 0 )
    1.27 +        if ( domain_set_irq_dpci(d, hvm_irq_dpci) == 0 )
    1.28              xfree(hvm_irq_dpci);
    1.29 -
    1.30 -        hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
    1.31      }
    1.32  
    1.33      machine_gsi = pt_irq_bind->machine_irq;
    1.34 @@ -116,7 +113,7 @@ int pt_irq_create_bind_vtd(
    1.35  int pt_irq_destroy_bind_vtd(
    1.36      struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
    1.37  {
    1.38 -    struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
    1.39 +    struct hvm_irq_dpci *hvm_irq_dpci = domain_get_irq_dpci(d);
    1.40      uint32_t machine_gsi, guest_gsi;
    1.41      uint32_t device, intx, link;
    1.42      struct list_head *digl_list, *tmp;
    1.43 @@ -133,14 +130,15 @@ int pt_irq_destroy_bind_vtd(
    1.44      hvm_irq_dpci->link_cnt[link]--;
    1.45  
    1.46      gdprintk(XENLOG_INFO,
    1.47 -            "pt_irq_destroy_bind_vtd: machine_gsi=%d, guest_gsi=%d, device=%d, intx=%d.\n",
    1.48 -            machine_gsi, guest_gsi, device, intx);
    1.49 -    memset(&hvm_irq_dpci->girq[guest_gsi], 0, sizeof(struct hvm_girq_dpci_mapping));
    1.50 +             "pt_irq_destroy_bind_vtd: machine_gsi=%d "
    1.51 +             "guest_gsi=%d, device=%d, intx=%d.\n",
    1.52 +             machine_gsi, guest_gsi, device, intx);
    1.53 +    memset(&hvm_irq_dpci->girq[guest_gsi], 0,
    1.54 +           sizeof(struct hvm_girq_dpci_mapping));
    1.55  
    1.56      /* clear the mirq info */
    1.57      if ( hvm_irq_dpci->mirq[machine_gsi].valid )
    1.58      {
    1.59 -
    1.60          list_for_each_safe ( digl_list, tmp,
    1.61                  &hvm_irq_dpci->mirq[machine_gsi].digl_list )
    1.62          {
    1.63 @@ -174,10 +172,10 @@ int pt_irq_destroy_bind_vtd(
    1.64  
    1.65  int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
    1.66  {
    1.67 -    struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
    1.68 +    struct hvm_irq_dpci *dpci = domain_get_irq_dpci(d);
    1.69  
    1.70 -    if ( !iommu_enabled || (d == dom0) || (hvm_irq->dpci == NULL) ||
    1.71 -         !hvm_irq->dpci->mirq[mirq].valid )
    1.72 +    if ( !iommu_enabled || (d == dom0) || !dpci ||
    1.73 +         !dpci->mirq[mirq].valid )
    1.74          return 0;
    1.75  
    1.76      /*
    1.77 @@ -186,58 +184,18 @@ int hvm_do_IRQ_dpci(struct domain *d, un
    1.78       * this case the guest may not pick up the interrupt (e.g., masked at the
    1.79       * PIC) and we need to detect that.
    1.80       */
    1.81 -    set_bit(mirq, hvm_irq->dpci->dirq_mask);
    1.82 -    set_timer(&hvm_irq->dpci->hvm_timer[irq_to_vector(mirq)],
    1.83 +    set_bit(mirq, dpci->dirq_mask);
    1.84 +    set_timer(&dpci->hvm_timer[irq_to_vector(mirq)],
    1.85                NOW() + PT_IRQ_TIME_OUT);
    1.86      vcpu_kick(d->vcpu[0]);
    1.87  
    1.88      return 1;
    1.89  }
    1.90  
    1.91 -static void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq)
    1.92 -{
    1.93 -    struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
    1.94 -    struct hvm_irq_dpci *dpci = hvm_irq->dpci;
    1.95 -    struct dev_intx_gsi_link *digl, *tmp;
    1.96 -    int i;
    1.97 -
    1.98 -    ASSERT(isairq < NR_ISAIRQS);
    1.99 -    if ( !iommu_enabled || !dpci ||
   1.100 -         !test_bit(isairq, dpci->isairq_map) )
   1.101 -        return;
   1.102 -
   1.103 -    /* Multiple mirq may be mapped to one isa irq */
   1.104 -    for ( i = 0; i < NR_IRQS; i++ )
   1.105 -    {
   1.106 -        if ( !dpci->mirq[i].valid )
   1.107 -            continue;
   1.108 -
   1.109 -        list_for_each_entry_safe ( digl, tmp,
   1.110 -            &dpci->mirq[i].digl_list, list )
   1.111 -        {
   1.112 -            if ( hvm_irq->pci_link.route[digl->link] == isairq )
   1.113 -            {
   1.114 -                hvm_pci_intx_deassert(d, digl->device, digl->intx);
   1.115 -                spin_lock(&dpci->dirq_lock);
   1.116 -                if ( --dpci->mirq[i].pending == 0 )
   1.117 -                {
   1.118 -                    spin_unlock(&dpci->dirq_lock);
   1.119 -                    gdprintk(XENLOG_INFO VTDPREFIX,
   1.120 -                             "hvm_dpci_isairq_eoi:: mirq = %x\n", i);
   1.121 -                    stop_timer(&dpci->hvm_timer[irq_to_vector(i)]);
   1.122 -                    pirq_guest_eoi(d, i);
   1.123 -                }
   1.124 -                else
   1.125 -                    spin_unlock(&dpci->dirq_lock);
   1.126 -            }
   1.127 -        }
   1.128 -    }
   1.129 -}
   1.130 -
   1.131  void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
   1.132                    union vioapic_redir_entry *ent)
   1.133  {
   1.134 -    struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
   1.135 +    struct hvm_irq_dpci *hvm_irq_dpci = domain_get_irq_dpci(d);
   1.136      uint32_t device, intx, machine_gsi;
   1.137  
   1.138      if ( !iommu_enabled || (hvm_irq_dpci == NULL) ||
     2.1 --- a/xen/drivers/passthrough/iommu.c	Thu Apr 10 09:12:44 2008 +0100
     2.2 +++ b/xen/drivers/passthrough/iommu.c	Thu Apr 10 09:20:07 2008 +0100
     2.3 @@ -58,7 +58,7 @@ int assign_device(struct domain *d, u8 b
     2.4  
     2.5  void iommu_domain_destroy(struct domain *d)
     2.6  {
     2.7 -    struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
     2.8 +    struct hvm_irq_dpci *hvm_irq_dpci = domain_get_irq_dpci(d);
     2.9      uint32_t i;
    2.10      struct hvm_iommu *hd  = domain_hvm_iommu(d);
    2.11      struct list_head *ioport_list, *digl_list, *tmp;
     3.1 --- a/xen/drivers/passthrough/vtd/Makefile	Thu Apr 10 09:12:44 2008 +0100
     3.2 +++ b/xen/drivers/passthrough/vtd/Makefile	Thu Apr 10 09:20:07 2008 +0100
     3.3 @@ -1,3 +1,5 @@
     3.4 +subdir-$(x86) += x86
     3.5 +
     3.6  obj-y += iommu.o
     3.7  obj-y += dmar.o
     3.8  obj-y += utils.o
     4.1 --- a/xen/drivers/passthrough/vtd/iommu.c	Thu Apr 10 09:12:44 2008 +0100
     4.2 +++ b/xen/drivers/passthrough/vtd/iommu.c	Thu Apr 10 09:20:07 2008 +0100
     4.3 @@ -32,6 +32,7 @@
     4.4  #include "../pci_regs.h"
     4.5  #include "msi.h"
     4.6  #include "extern.h"
     4.7 +#include "vtd.h"
     4.8  
     4.9  #define domain_iommu_domid(d) ((d)->arch.hvm_domain.hvm_iommu.iommu_domid)
    4.10  
    4.11 @@ -158,11 +159,11 @@ struct iommu_flush *iommu_get_flush(stru
    4.12      return &(iommu->intel->flush);
    4.13  }
    4.14  
    4.15 -unsigned int x86_clflush_size;
    4.16 +unsigned int clflush_size;
    4.17  void clflush_cache_range(void *adr, int size)
    4.18  {
    4.19      int i;
    4.20 -    for ( i = 0; i < size; i += x86_clflush_size )
    4.21 +    for ( i = 0; i < size; i += clflush_size )
    4.22          clflush(adr + i);
    4.23  }
    4.24  
    4.25 @@ -172,10 +173,15 @@ static void __iommu_flush_cache(struct i
    4.26          clflush_cache_range(addr, size);
    4.27  }
    4.28  
    4.29 -#define iommu_flush_cache_entry(iommu, addr) \
    4.30 -       __iommu_flush_cache(iommu, addr, 8)
    4.31 -#define iommu_flush_cache_page(iommu, addr) \
    4.32 -       __iommu_flush_cache(iommu, addr, PAGE_SIZE_4K)
    4.33 +void iommu_flush_cache_entry(struct iommu *iommu, void *addr)
    4.34 +{
    4.35 +    __iommu_flush_cache(iommu, addr, 8);
    4.36 +}
    4.37 +
    4.38 +void iommu_flush_cache_page(struct iommu *iommu, void *addr)
    4.39 +{
    4.40 +    __iommu_flush_cache(iommu, addr, PAGE_SIZE_4K);
    4.41 +}
    4.42  
    4.43  int nr_iommus;
    4.44  /* context entry handling */
    4.45 @@ -1954,7 +1960,7 @@ int iommu_setup(void)
    4.46      INIT_LIST_HEAD(&hd->pdev_list);
    4.47  
    4.48      /* setup clflush size */
    4.49 -    x86_clflush_size = ((cpuid_ebx(1) >> 8) & 0xff) * 8;
    4.50 +    clflush_size = get_clflush_size();
    4.51  
    4.52      /* Allocate IO page directory page for the domain. */
    4.53      drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
     5.1 --- a/xen/drivers/passthrough/vtd/vtd.h	Thu Apr 10 09:12:44 2008 +0100
     5.2 +++ b/xen/drivers/passthrough/vtd/vtd.h	Thu Apr 10 09:20:07 2008 +0100
     5.3 @@ -42,4 +42,13 @@ struct IO_APIC_route_remap_entry {
     5.4      };
     5.5  };
     5.6  
     5.7 +unsigned int get_clflush_size(void);
     5.8 +u64 alloc_pgtable_maddr(void);
     5.9 +void free_pgtable_maddr(u64 maddr);
    5.10 +void *map_vtd_domain_page(u64 maddr);
    5.11 +void unmap_vtd_domain_page(void *va);
    5.12 +
    5.13 +void iommu_flush_cache_entry(struct iommu *iommu, void *addr);
    5.14 +void iommu_flush_cache_page(struct iommu *iommu, void *addr);
    5.15 +
    5.16  #endif // _VTD_H_
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/xen/drivers/passthrough/vtd/x86/Makefile	Thu Apr 10 09:20:07 2008 +0100
     6.3 @@ -0,0 +1,1 @@
     6.4 +obj-y += vtd.o
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/xen/drivers/passthrough/vtd/x86/vtd.c	Thu Apr 10 09:20:07 2008 +0100
     7.3 @@ -0,0 +1,126 @@
     7.4 +/*
     7.5 + * Copyright (c) 2008, Intel Corporation.
     7.6 + *
     7.7 + * This program is free software; you can redistribute it and/or modify it
     7.8 + * under the terms and conditions of the GNU General Public License,
     7.9 + * version 2, as published by the Free Software Foundation.
    7.10 + *
    7.11 + * This program is distributed in the hope it will be useful, but WITHOUT
    7.12 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    7.13 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
    7.14 + * more details.
    7.15 + *
    7.16 + * You should have received a copy of the GNU General Public License along with
    7.17 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
    7.18 + * Place - Suite 330, Boston, MA 02111-1307 USA.
    7.19 + *
    7.20 + * Copyright (C) Allen Kay <allen.m.kay@intel.com>
    7.21 + * Copyright (C) Weidong Han <weidong.han@intel.com>
    7.22 + */
    7.23 +
    7.24 +#include <xen/sched.h>
    7.25 +#include <xen/domain_page.h>
    7.26 +#include <xen/iommu.h>
    7.27 +#include "../iommu.h"
    7.28 +#include "../dmar.h"
    7.29 +#include "../vtd.h"
    7.30 +
    7.31 +void *map_vtd_domain_page(u64 maddr)
    7.32 +{
    7.33 +    return map_domain_page(maddr >> PAGE_SHIFT_4K);
    7.34 +}
    7.35 +
    7.36 +void unmap_vtd_domain_page(void *va)
    7.37 +{
    7.38 +    unmap_domain_page(va);
    7.39 +}
    7.40 +
    7.41 +/* Allocate page table, return its machine address */
    7.42 +u64 alloc_pgtable_maddr(void)
    7.43 +{
    7.44 +    struct page_info *pg;
    7.45 +    u64 *vaddr;
    7.46 +    struct acpi_drhd_unit *drhd;
    7.47 +    struct iommu *iommu;
    7.48 +
    7.49 +    pg = alloc_domheap_page(NULL, 0);
    7.50 +    vaddr = map_domain_page(page_to_mfn(pg));
    7.51 +    if ( !vaddr )
    7.52 +        return 0;
    7.53 +    memset(vaddr, 0, PAGE_SIZE);
    7.54 +
    7.55 +    drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
    7.56 +    iommu = drhd->iommu;
    7.57 +    iommu_flush_cache_page(iommu, vaddr);
    7.58 +    unmap_domain_page(vaddr);
    7.59 +
    7.60 +    return page_to_maddr(pg);
    7.61 +}
    7.62 +
    7.63 +void free_pgtable_maddr(u64 maddr)
    7.64 +{
    7.65 +    if ( maddr != 0 )
    7.66 +        free_domheap_page(maddr_to_page(maddr));
    7.67 +}
    7.68 +
    7.69 +unsigned int get_clflush_size(void)
    7.70 +{
    7.71 +    return ((cpuid_ebx(1) >> 8) & 0xff) * 8;
    7.72 +}
    7.73 +
    7.74 +struct hvm_irq_dpci *domain_get_irq_dpci(struct domain *domain)
    7.75 +{
    7.76 +    if ( !domain )
    7.77 +        return NULL;
    7.78 +
    7.79 +    return domain->arch.hvm_domain.irq.dpci;
    7.80 +}
    7.81 +
    7.82 +int domain_set_irq_dpci(struct domain *domain, struct hvm_irq_dpci *dpci)
    7.83 +{
    7.84 +    if ( !domain || !dpci )
    7.85 +        return 0;
    7.86 +
    7.87 +    domain->arch.hvm_domain.irq.dpci = dpci;
    7.88 +    return 1;
    7.89 +}
    7.90 +
    7.91 +void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq)
    7.92 +{
    7.93 +    struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
    7.94 +    struct hvm_irq_dpci *dpci = domain_get_irq_dpci(d);
    7.95 +    struct dev_intx_gsi_link *digl, *tmp;
    7.96 +    int i;
    7.97 +
    7.98 +    ASSERT(isairq < NR_ISAIRQS);
    7.99 +    if ( !vtd_enabled || !dpci ||
   7.100 +         !test_bit(isairq, dpci->isairq_map) )
   7.101 +        return;
   7.102 +
   7.103 +    /* Multiple mirq may be mapped to one isa irq */
   7.104 +    for ( i = 0; i < NR_IRQS; i++ )
   7.105 +    {
   7.106 +        if ( !dpci->mirq[i].valid )
   7.107 +            continue;
   7.108 +
   7.109 +        list_for_each_entry_safe ( digl, tmp,
   7.110 +            &dpci->mirq[i].digl_list, list )
   7.111 +        {
   7.112 +            if ( hvm_irq->pci_link.route[digl->link] == isairq )
   7.113 +            {
   7.114 +                hvm_pci_intx_deassert(d, digl->device, digl->intx);
   7.115 +                spin_lock(&dpci->dirq_lock);
   7.116 +                if ( --dpci->mirq[i].pending == 0 )
   7.117 +                {
   7.118 +                    spin_unlock(&dpci->dirq_lock);
   7.119 +                    gdprintk(XENLOG_INFO VTDPREFIX,
   7.120 +                             "hvm_dpci_isairq_eoi:: mirq = %x\n", i);
   7.121 +                    stop_timer(&dpci->hvm_timer[irq_to_vector(i)]);
   7.122 +                    pirq_guest_eoi(d, i);
   7.123 +                }
   7.124 +                else
   7.125 +                    spin_unlock(&dpci->dirq_lock);
   7.126 +            }
   7.127 +        }
   7.128 +    }
   7.129 +}
     8.1 --- a/xen/include/xen/iommu.h	Thu Apr 10 09:12:44 2008 +0100
     8.2 +++ b/xen/include/xen/iommu.h	Thu Apr 10 09:20:07 2008 +0100
     8.3 @@ -98,6 +98,9 @@ void io_apic_write_remap_rte(unsigned in
     8.4  struct qi_ctrl *iommu_qi_ctrl(struct iommu *iommu);
     8.5  struct ir_ctrl *iommu_ir_ctrl(struct iommu *iommu);
     8.6  struct iommu_flush *iommu_get_flush(struct iommu *iommu);
     8.7 +void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq);
     8.8 +struct hvm_irq_dpci *domain_get_irq_dpci(struct domain *domain);
     8.9 +int domain_set_irq_dpci(struct domain *domain, struct hvm_irq_dpci *dpci);
    8.10  
    8.11  #define PT_IRQ_TIME_OUT MILLISECS(8)
    8.12  #define VTDPREFIX "[VT-D]"