ia64/xen-unstable

changeset 17743:1e66fa5931ee

vtd: interrupt remapping for MSI/MSI-x.

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed May 28 09:29:05 2008 +0100 (2008-05-28)
parents 5de1048b884e
children 460f72ca97b6
files xen/arch/x86/msi.c xen/drivers/passthrough/vtd/intremap.c xen/drivers/passthrough/vtd/vtd.h xen/include/xen/iommu.h
line diff
     1.1 --- a/xen/arch/x86/msi.c	Wed May 28 09:28:42 2008 +0100
     1.2 +++ b/xen/arch/x86/msi.c	Wed May 28 09:29:05 2008 +0100
     1.3 @@ -25,6 +25,7 @@
     1.4  #include <mach_apic.h>
     1.5  #include <io_ports.h>
     1.6  #include <public/physdev.h>
     1.7 +#include <xen/iommu.h>
     1.8  
     1.9  extern int msi_irq_enable;
    1.10  
    1.11 @@ -156,6 +157,9 @@ void read_msi_msg(unsigned int irq, stru
    1.12      default:
    1.13          BUG();
    1.14      }
    1.15 +
    1.16 +    if ( vtd_enabled )
    1.17 +        msi_msg_read_remap_rte(entry, msg);
    1.18  }
    1.19  
    1.20  static int set_vector_msi(struct msi_desc *entry)
    1.21 @@ -202,6 +206,9 @@ void write_msi_msg(unsigned int irq, str
    1.22  {
    1.23      struct msi_desc *entry = irq_desc[irq].msi_desc;
    1.24  
    1.25 +    if ( vtd_enabled )
    1.26 +        msi_msg_write_remap_rte(entry, msg);
    1.27 +
    1.28      switch ( entry->msi_attrib.type )
    1.29      {
    1.30      case PCI_CAP_ID_MSI:
     2.1 --- a/xen/drivers/passthrough/vtd/intremap.c	Wed May 28 09:28:42 2008 +0100
     2.2 +++ b/xen/drivers/passthrough/vtd/intremap.c	Wed May 28 09:29:05 2008 +0100
     2.3 @@ -251,6 +251,176 @@ void io_apic_write_remap_rte(
     2.4      *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+1);
     2.5  }
     2.6  
     2.7 +static void remap_entry_to_msi_msg(
     2.8 +    struct iommu *iommu, struct msi_msg *msg)
     2.9 +{
    2.10 +    struct iremap_entry *iremap_entry = NULL, *iremap_entries;
    2.11 +    struct msi_msg_remap_entry *remap_rte;
    2.12 +    int index;
    2.13 +    unsigned long flags;
    2.14 +    struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
    2.15 +
    2.16 +    if ( ir_ctrl == NULL )
    2.17 +    {
    2.18 +        dprintk(XENLOG_ERR VTDPREFIX,
    2.19 +                "remap_entry_to_msi_msg: ir_ctl == NULL");
    2.20 +        return;
    2.21 +    }
    2.22 +
    2.23 +    remap_rte = (struct msi_msg_remap_entry *) msg;
    2.24 +    index = (remap_rte->address_lo.index_15 << 15) |
    2.25 +            remap_rte->address_lo.index_0_14;
    2.26 +
    2.27 +    if ( index > ir_ctrl->iremap_index )
    2.28 +        panic("%s: index (%d) is larger than remap table entry size (%d)\n",
    2.29 +              __func__, index, ir_ctrl->iremap_index);
    2.30 +
    2.31 +    spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
    2.32 +
    2.33 +    iremap_entries =
    2.34 +        (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr);
    2.35 +    iremap_entry = &iremap_entries[index];
    2.36 +
    2.37 +    msg->address_hi = MSI_ADDR_BASE_HI;
    2.38 +    msg->address_lo =
    2.39 +        MSI_ADDR_BASE_LO |
    2.40 +        ((iremap_entry->lo.dm == 0) ?
    2.41 +            MSI_ADDR_DESTMODE_PHYS:
    2.42 +            MSI_ADDR_DESTMODE_LOGIC) |
    2.43 +        ((iremap_entry->lo.dlm != dest_LowestPrio) ?
    2.44 +            MSI_ADDR_REDIRECTION_CPU:
    2.45 +            MSI_ADDR_REDIRECTION_LOWPRI) |
    2.46 +        iremap_entry->lo.dst >> 8;
    2.47 +
    2.48 +    msg->data =
    2.49 +        MSI_DATA_TRIGGER_EDGE |
    2.50 +        MSI_DATA_LEVEL_ASSERT |
    2.51 +        ((iremap_entry->lo.dlm != dest_LowestPrio) ?
    2.52 +            MSI_DATA_DELIVERY_FIXED:
    2.53 +            MSI_DATA_DELIVERY_LOWPRI) |
    2.54 +        iremap_entry->lo.vector;
    2.55 +
    2.56 +    unmap_vtd_domain_page(iremap_entries);
    2.57 +    spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
    2.58 +}
    2.59 +
    2.60 +static void msi_msg_to_remap_entry(
    2.61 +    struct iommu *iommu, struct pci_dev *pdev, struct msi_msg *msg)
    2.62 +{
    2.63 +    struct iremap_entry *iremap_entry = NULL, *iremap_entries;
    2.64 +    struct iremap_entry new_ire;
    2.65 +    struct msi_msg_remap_entry *remap_rte;
    2.66 +    unsigned int index;
    2.67 +    unsigned long flags;
    2.68 +    struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
    2.69 +    int i = 0;
    2.70 +
    2.71 +    remap_rte = (struct msi_msg_remap_entry *) msg;
    2.72 +    spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
    2.73 +
    2.74 +    iremap_entries =
    2.75 +        (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr);
    2.76 +
    2.77 +    /* If the entry for a PCI device has been there, use the old entry,
    2.78 +     * Or, assign a new entry for it.
    2.79 +     */
    2.80 +    for ( i = 0; i <= ir_ctrl->iremap_index; i++ )
    2.81 +    {
    2.82 +        iremap_entry = &iremap_entries[i];
    2.83 +        if ( iremap_entry->hi.sid ==
    2.84 +             ((pdev->bus << 8) | pdev->devfn) )
    2.85 +           break;
    2.86 +    }
    2.87 +
    2.88 +    if ( i > ir_ctrl->iremap_index )
    2.89 +    {
    2.90 +    	ir_ctrl->iremap_index++;
    2.91 +        index = ir_ctrl->iremap_index;
    2.92 +    }
    2.93 +    else
    2.94 +        index = i;
    2.95 +
    2.96 +    if ( index > IREMAP_ENTRY_NR - 1 )
    2.97 +        panic("msi_msg_to_remap_entry: intremap index is more than 256!\n");
    2.98 +
    2.99 +    iremap_entry = &iremap_entries[index];
   2.100 +    memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry));
   2.101 +
   2.102 +    /* Set interrupt remapping table entry */
   2.103 +    new_ire.lo.fpd = 0;
   2.104 +    new_ire.lo.dm = (msg->address_lo >> MSI_ADDR_DESTMODE_SHIFT) & 0x1;
   2.105 +    new_ire.lo.rh = 0;
   2.106 +    new_ire.lo.tm = (msg->data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
   2.107 +    new_ire.lo.dlm = (msg->data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x1;
   2.108 +    new_ire.lo.avail = 0;
   2.109 +    new_ire.lo.res_1 = 0;
   2.110 +    new_ire.lo.vector = (msg->data >> MSI_DATA_VECTOR_SHIFT) &
   2.111 +                        MSI_DATA_VECTOR_MASK;
   2.112 +    new_ire.lo.res_2 = 0;
   2.113 +    new_ire.lo.dst = ((msg->address_lo >> MSI_ADDR_DEST_ID_SHIFT)
   2.114 +                      & 0xff) << 8;
   2.115 +
   2.116 +    new_ire.hi.sid = (pdev->bus << 8) | pdev->devfn;
   2.117 +    new_ire.hi.sq = 0;
   2.118 +    new_ire.hi.svt = 1;
   2.119 +    new_ire.hi.res_1 = 0;
   2.120 +    new_ire.lo.p = 1;    /* finally, set present bit */
   2.121 +
   2.122 +    /* now construct new MSI/MSI-X rte entry */
   2.123 +    remap_rte->address_lo.dontcare = 0;
   2.124 +    remap_rte->address_lo.index_15 = index & 0x8000;
   2.125 +    remap_rte->address_lo.index_0_14 = index & 0x7fff;
   2.126 +    remap_rte->address_lo.SHV = 1;
   2.127 +    remap_rte->address_lo.format = 1;
   2.128 +
   2.129 +    remap_rte->address_hi = 0;
   2.130 +    remap_rte->data = 0;
   2.131 +
   2.132 +    memcpy(iremap_entry, &new_ire, sizeof(struct iremap_entry));
   2.133 +    iommu_flush_iec_index(iommu, 0, index);
   2.134 +    invalidate_sync(iommu);
   2.135 +
   2.136 +    unmap_vtd_domain_page(iremap_entries);
   2.137 +    spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
   2.138 +    return;
   2.139 +}
   2.140 +
   2.141 +void msi_msg_read_remap_rte(
   2.142 +    struct msi_desc *msi_desc, struct msi_msg *msg)
   2.143 +{
   2.144 +    struct pci_dev *pdev = msi_desc->dev;
   2.145 +    struct acpi_drhd_unit *drhd = NULL;
   2.146 +    struct iommu *iommu = NULL;
   2.147 +    struct ir_ctrl *ir_ctrl;
   2.148 +
   2.149 +    drhd = acpi_find_matched_drhd_unit(pdev);
   2.150 +    iommu = drhd->iommu;
   2.151 +
   2.152 +    ir_ctrl = iommu_ir_ctrl(iommu);
   2.153 +    if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 )
   2.154 +        return;
   2.155 +
   2.156 +    remap_entry_to_msi_msg(iommu, msg);
   2.157 +}
   2.158 +
   2.159 +void msi_msg_write_remap_rte(
   2.160 +    struct msi_desc *msi_desc, struct msi_msg *msg)
   2.161 +{
   2.162 +    struct pci_dev *pdev = msi_desc->dev;
   2.163 +    struct acpi_drhd_unit *drhd = NULL;
   2.164 +    struct iommu *iommu = NULL;
   2.165 +    struct ir_ctrl *ir_ctrl;
   2.166 +
   2.167 +    drhd = acpi_find_matched_drhd_unit(msi_desc->dev);
   2.168 +    iommu = drhd->iommu;
   2.169 +
   2.170 +    ir_ctrl = iommu_ir_ctrl(iommu);
   2.171 +    if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 )
   2.172 +        return;
   2.173 +
   2.174 +    msi_msg_to_remap_entry(iommu, pdev, msg);
   2.175 +}
   2.176 +
   2.177  int intremap_setup(struct iommu *iommu)
   2.178  {
   2.179      struct ir_ctrl *ir_ctrl;
     3.1 --- a/xen/drivers/passthrough/vtd/vtd.h	Wed May 28 09:28:42 2008 +0100
     3.2 +++ b/xen/drivers/passthrough/vtd/vtd.h	Wed May 28 09:29:05 2008 +0100
     3.3 @@ -42,6 +42,24 @@ struct IO_APIC_route_remap_entry {
     3.4      };
     3.5  };
     3.6  
     3.7 +struct msi_msg_remap_entry {
     3.8 +    union {
     3.9 +        u32 val;
    3.10 +        struct {
    3.11 +            u32 dontcare:2,
    3.12 +                index_15:1,
    3.13 +                SHV:1,
    3.14 +                format:1,
    3.15 +                index_0_14:15,
    3.16 +                addr_id_val:12; /* Interrupt address identifier value,
    3.17 +                                   must be 0FEEh */
    3.18 +        };
    3.19 +    } address_lo;   /* low 32 bits of msi message address */
    3.20 +
    3.21 +    u32	address_hi;	/* high 32 bits of msi message address */
    3.22 +    u32	data;		/* msi message data */
    3.23 +};
    3.24 +
    3.25  unsigned int get_clflush_size(void);
    3.26  u64 alloc_pgtable_maddr(void);
    3.27  void free_pgtable_maddr(u64 maddr);
     4.1 --- a/xen/include/xen/iommu.h	Wed May 28 09:28:42 2008 +0100
     4.2 +++ b/xen/include/xen/iommu.h	Wed May 28 09:29:05 2008 +0100
     4.3 @@ -26,6 +26,7 @@
     4.4  #include <xen/pci.h>
     4.5  #include <public/hvm/ioreq.h>
     4.6  #include <public/domctl.h>
     4.7 +#include <asm/msi.h>
     4.8  
     4.9  extern int vtd_enabled;
    4.10  extern int iommu_enabled;
    4.11 @@ -78,6 +79,8 @@ int pt_irq_destroy_bind_vtd(struct domai
    4.12  unsigned int io_apic_read_remap_rte(unsigned int apic, unsigned int reg);
    4.13  void io_apic_write_remap_rte(unsigned int apic,
    4.14                               unsigned int reg, unsigned int value);
    4.15 +void msi_msg_read_remap_rte(struct msi_desc *msi_desc, struct msi_msg *msg);
    4.16 +void msi_msg_write_remap_rte(struct msi_desc *msi_desc, struct msi_msg *msg);
    4.17  struct qi_ctrl *iommu_qi_ctrl(struct iommu *iommu);
    4.18  struct ir_ctrl *iommu_ir_ctrl(struct iommu *iommu);
    4.19  struct iommu_flush *iommu_get_flush(struct iommu *iommu);