ia64/xen-unstable

changeset 19806:703ced548925

VT-d: fix MSI source-id of interrupt remapping

This patch fixes an issue of MSI source-id. Currently MSI source-ids
are all set device bdf. It's incorrect for PCI (not PCIe) devices. The
patch set correct requester-ids of MSI to source-id. And also, wrap
functions to clean ioapic source-id.

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 19 08:45:55 2009 +0100 (2009-06-19)
parents 2f1fa2215e60
children 468561f3c8ee
files xen/drivers/passthrough/vtd/intremap.c
line diff
     1.1 --- a/xen/drivers/passthrough/vtd/intremap.c	Fri Jun 19 08:45:20 2009 +0100
     1.2 +++ b/xen/drivers/passthrough/vtd/intremap.c	Fri Jun 19 08:45:55 2009 +0100
     1.3 @@ -39,6 +39,27 @@
     1.4  #define nr_ioapic_registers(i)  nr_ioapic_registers[i]
     1.5  #endif
     1.6  
     1.7 +/*
     1.8 + * source validation type (SVT)
     1.9 + */
    1.10 +#define SVT_NO_VERIFY       0x0  /* no verification is required */
    1.11 +#define SVT_VERIFY_SID_SQ   0x1  /* verify using SID and SQ fiels */
    1.12 +#define SVT_VERIFY_BUS      0x2  /* verify bus of request-id */
    1.13 +
    1.14 +/*
    1.15 + * source-id qualifier (SQ)
    1.16 + */
    1.17 +#define SQ_ALL_16           0x0  /* verify all 16 bits of request-id */
    1.18 +#define SQ_13_IGNORE_1      0x1  /* verify most significant 13 bits, ignore
    1.19 +                                  * the third least significant bit
    1.20 +                                  */
    1.21 +#define SQ_13_IGNORE_2      0x2  /* verify most significant 13 bits, ignore
    1.22 +                                  * the second and third least significant bits
    1.23 +                                  */
    1.24 +#define SQ_13_IGNORE_3      0x3  /* verify most significant 13 bits, ignore
    1.25 +                                  * the least three significant bits
    1.26 +                                  */
    1.27 +
    1.28  /* apic_pin_2_ir_idx[apicid][pin] = interrupt remapping table index */
    1.29  static unsigned int **apic_pin_2_ir_idx;
    1.30  
    1.31 @@ -86,6 +107,20 @@ u16 apicid_to_bdf(int apic_id)
    1.32      return 0;
    1.33  }
    1.34  
    1.35 +static void set_ire_sid(struct iremap_entry *ire,
    1.36 +                        unsigned int svt, unsigned int sq, unsigned int sid)
    1.37 +{
    1.38 +    ire->hi.svt = svt;
    1.39 +    ire->hi.sq = sq;
    1.40 +    ire->hi.sid = sid;
    1.41 +}
    1.42 +
    1.43 +static void set_ioapic_source_id(int apic_id, struct iremap_entry *ire)
    1.44 +{
    1.45 +    set_ire_sid(ire, SVT_VERIFY_SID_SQ, SQ_ALL_16,
    1.46 +                apicid_to_bdf(apic_id));
    1.47 +}
    1.48 +
    1.49  static int remap_entry_to_ioapic_rte(
    1.50      struct iommu *iommu, struct IO_xAPIC_route_entry *old_rte)
    1.51  {
    1.52 @@ -191,10 +226,8 @@ static int ioapic_rte_to_remap_entry(str
    1.53          new_ire.lo.res_1 = 0;
    1.54          new_ire.lo.vector = new_rte.vector;
    1.55          new_ire.lo.res_2 = 0;
    1.56 -        new_ire.hi.sid = apicid_to_bdf(IO_APIC_ID(apic));
    1.57  
    1.58 -        new_ire.hi.sq = 0;    /* comparing all 16-bit of SID */
    1.59 -        new_ire.hi.svt = 1;   /* requestor ID verification SID/SQ */
    1.60 +        set_ioapic_source_id(IO_APIC_ID(apic), &new_ire);
    1.61          new_ire.hi.res_1 = 0;
    1.62          new_ire.lo.p = 1;     /* finally, set present bit */
    1.63  
    1.64 @@ -345,6 +378,56 @@ void io_apic_write_remap_rte(
    1.65  }
    1.66  
    1.67  #if defined(__i386__) || defined(__x86_64__)
    1.68 +
    1.69 +static void set_msi_source_id(struct pci_dev *pdev, struct iremap_entry *ire)
    1.70 +{
    1.71 +    int type;
    1.72 +    u8 bus, devfn, secbus;
    1.73 +    int ret;
    1.74 +
    1.75 +    if ( !pdev || !ire )
    1.76 +        return;
    1.77 +
    1.78 +    bus = pdev->bus;
    1.79 +    devfn = pdev->devfn;
    1.80 +    type = pdev_type(bus, devfn);
    1.81 +    switch ( type )
    1.82 +    {
    1.83 +    case DEV_TYPE_PCIe_BRIDGE:
    1.84 +    case DEV_TYPE_PCIe2PCI_BRIDGE:
    1.85 +    case DEV_TYPE_LEGACY_PCI_BRIDGE:
    1.86 +        break;
    1.87 +
    1.88 +    case DEV_TYPE_PCIe_ENDPOINT:
    1.89 +        set_ire_sid(ire, SVT_VERIFY_SID_SQ, SQ_ALL_16, PCI_BDF2(bus, devfn));
    1.90 +        break;
    1.91 +
    1.92 +    case DEV_TYPE_PCI:
    1.93 +        ret = find_upstream_bridge(&bus, &devfn, &secbus);
    1.94 +        if ( ret == 0 ) /* integrated PCI device */
    1.95 +        {
    1.96 +            set_ire_sid(ire, SVT_VERIFY_SID_SQ, SQ_ALL_16,
    1.97 +                        PCI_BDF2(bus, devfn));
    1.98 +        }
    1.99 +        else if ( ret == 1 ) /* find upstream bridge */
   1.100 +        {
   1.101 +            if ( pdev_type(bus, devfn) == DEV_TYPE_PCIe2PCI_BRIDGE )
   1.102 +                set_ire_sid(ire, SVT_VERIFY_BUS, SQ_ALL_16,
   1.103 +                            (bus << 8) | pdev->bus);
   1.104 +            else if ( pdev_type(bus, devfn) == DEV_TYPE_LEGACY_PCI_BRIDGE )
   1.105 +                set_ire_sid(ire, SVT_VERIFY_BUS, SQ_ALL_16,
   1.106 +                            PCI_BDF2(bus, devfn));
   1.107 +        }
   1.108 +        break;
   1.109 +
   1.110 +    default:
   1.111 +        gdprintk(XENLOG_WARNING VTDPREFIX,
   1.112 +                 "set_msi_source_id: unknown type : bdf = %x:%x.%x\n",
   1.113 +                 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
   1.114 +        break;
   1.115 +   }
   1.116 +}
   1.117 +
   1.118  static int remap_entry_to_msi_msg(
   1.119      struct iommu *iommu, struct msi_msg *msg)
   1.120  {
   1.121 @@ -456,9 +539,7 @@ static int msi_msg_to_remap_entry(
   1.122      new_ire.lo.dst = ((msg->address_lo >> MSI_ADDR_DEST_ID_SHIFT)
   1.123                        & 0xff) << 8;
   1.124  
   1.125 -    new_ire.hi.sid = (pdev->bus << 8) | pdev->devfn;
   1.126 -    new_ire.hi.sq = 0;
   1.127 -    new_ire.hi.svt = 1;
   1.128 +    set_msi_source_id(pdev, &new_ire);
   1.129      new_ire.hi.res_1 = 0;
   1.130      new_ire.lo.p = 1;    /* finally, set present bit */
   1.131