ia64/xen-unstable

changeset 17623:4afc6023e8ec

x86 hvm: Support MSI-X for HVM domains.
Signed-off-by: Shan Haitao <Haitao.shan@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon May 12 10:07:26 2008 +0100 (2008-05-12)
parents 5c00188dd159
children e3be00bd6aa9
files tools/ioemu/hw/pass-through.c tools/ioemu/hw/pass-through.h tools/ioemu/hw/pt-msi.c tools/ioemu/hw/pt-msi.h tools/libxc/xc_physdev.c tools/libxc/xenctrl.h
line diff
     1.1 --- a/tools/ioemu/hw/pass-through.c	Mon May 12 10:06:40 2008 +0100
     1.2 +++ b/tools/ioemu/hw/pass-through.c	Mon May 12 10:07:26 2008 +0100
     1.3 @@ -205,6 +205,7 @@ void pt_iomem_map(PCIDevice *d, int i, u
     1.4  
     1.5      if ( !first_map )
     1.6      {
     1.7 +        add_msix_mapping(assigned_device, i);
     1.8          /* Remove old mapping */
     1.9          ret = xc_domain_memory_mapping(xc_handle, domid,
    1.10                  old_ebase >> XC_PAGE_SHIFT,
    1.11 @@ -227,6 +228,9 @@ void pt_iomem_map(PCIDevice *d, int i, u
    1.12      if ( ret != 0 )
    1.13          PT_LOG("Error: create new mapping failed!\n");
    1.14  
    1.15 +    ret = remove_msix_mapping(assigned_device, i);
    1.16 +    if ( ret != 0 )
    1.17 +        PT_LOG("Error: remove MSX-X mmio mapping failed!\n");
    1.18  }
    1.19  
    1.20  /* Being called each time a pio region has been updated */
    1.21 @@ -291,6 +295,9 @@ static void pt_pci_write_config(PCIDevic
    1.22      if ( pt_msi_write(assigned_device, address, val, len) )
    1.23          return;
    1.24  
    1.25 +    if ( pt_msix_write(assigned_device, address, val, len) )
    1.26 +        return;
    1.27 +
    1.28      /* PCI config pass-through */
    1.29      if (address == 0x4) {
    1.30          switch (len){
    1.31 @@ -338,6 +345,7 @@ static uint32_t pt_pci_read_config(PCIDe
    1.32      }
    1.33  
    1.34      pt_msi_read(assigned_device, address, len, &val);
    1.35 +    pt_msix_read(assigned_device, address, len, &val);
    1.36  exit:
    1.37  
    1.38  #ifdef PT_DEBUG_PCI_CONFIG_ACCESS
    1.39 @@ -549,6 +557,9 @@ struct pt_dev * register_real_device(PCI
    1.40      if ( (pos = find_cap_offset(pci_dev, PCI_CAP_ID_MSI)) )
    1.41          pt_msi_init(assigned_device, pos);
    1.42  
    1.43 +    if ( (pos = find_cap_offset(pci_dev, PCI_CAP_ID_MSIX)) )
    1.44 +        pt_msix_init(assigned_device, pos);
    1.45 +
    1.46      /* Handle real device's MMIO/PIO BARs */
    1.47      pt_register_regions(assigned_device);
    1.48  
     2.1 --- a/tools/ioemu/hw/pass-through.h	Mon May 12 10:06:40 2008 +0100
     2.2 +++ b/tools/ioemu/hw/pass-through.h	Mon May 12 10:07:26 2008 +0100
     2.3 @@ -61,10 +61,28 @@ struct pt_msi_info {
     2.4      uint32_t flags;
     2.5      int offset;
     2.6      int size;
     2.7 -    int pvec;   /* physical vector used */
     2.8      int pirq;  /* guest pirq corresponding */
     2.9  };
    2.10  
    2.11 +struct msix_entry_info {
    2.12 +    int pirq;   /* -1 means unmapped */
    2.13 +    int flags;  /* flags indicting whether MSI ADDR or DATA is updated */
    2.14 +    uint32_t io_mem[4];
    2.15 +};
    2.16 +
    2.17 +struct pt_msix_info {
    2.18 +    int enabled;
    2.19 +    int offset;
    2.20 +    int total_entries;
    2.21 +    int bar_index;
    2.22 +    uint32_t table_off;
    2.23 +    u64 mmio_base_addr;
    2.24 +    int mmio_index;
    2.25 +    int fd;
    2.26 +    void *phys_iomem_base;
    2.27 +    struct msix_entry_info msix_entry[0];
    2.28 +};
    2.29 +
    2.30  /*
    2.31      This structure holds the context of the mapping functions
    2.32      and data that is relevant for qemu device management.
    2.33 @@ -74,6 +92,7 @@ struct pt_dev {
    2.34      struct pci_dev *pci_dev;                     /* libpci struct */
    2.35      struct pt_region bases[PCI_NUM_REGIONS];    /* Access regions */
    2.36      struct pt_msi_info *msi;                    /* MSI virtualization */
    2.37 +    struct pt_msix_info *msix;                  /* MSI-X virtualization */
    2.38  };
    2.39  
    2.40  /* Used for formatting PCI BDF into cf8 format */
     3.1 --- a/tools/ioemu/hw/pt-msi.c	Mon May 12 10:06:40 2008 +0100
     3.2 +++ b/tools/ioemu/hw/pt-msi.c	Mon May 12 10:07:26 2008 +0100
     3.3 @@ -20,7 +20,9 @@
     3.4   */
     3.5  
     3.6  #include "pt-msi.h"
     3.7 +#include <sys/mman.h>
     3.8  
     3.9 +/* MSI virtuailization functions */
    3.10  #define PT_MSI_CTRL_WR_MASK_HI      (0x1)
    3.11  #define PT_MSI_CTRL_WR_MASK_LO      (0x8E)
    3.12  #define PT_MSI_DATA_WR_MASK         (0x38)
    3.13 @@ -76,7 +78,7 @@ int pt_msi_init(struct pt_dev *dev, int 
    3.14   */
    3.15  static int pt_msi_setup(struct pt_dev *dev)
    3.16  {
    3.17 -    int vector = -1, pirq = -1;
    3.18 +    int pirq = -1;
    3.19  
    3.20      if ( !(dev->msi->flags & MSI_FLAG_UNINIT) )
    3.21      {
    3.22 @@ -85,15 +87,15 @@ static int pt_msi_setup(struct pt_dev *d
    3.23      }
    3.24  
    3.25      if ( xc_physdev_map_pirq_msi(xc_handle, domid, MAP_PIRQ_TYPE_MSI,
    3.26 -                            vector, &pirq,
    3.27 +                            AUTO_ASSIGN, &pirq,
    3.28  							dev->pci_dev->dev << 3 | dev->pci_dev->func,
    3.29 -							dev->pci_dev->bus, 1) )
    3.30 +							dev->pci_dev->bus, 0, 1) )
    3.31      {
    3.32 -        PT_LOG("error map vector %x\n", vector);
    3.33 +        PT_LOG("error map msi\n");
    3.34          return -1;
    3.35      }
    3.36      dev->msi->pirq = pirq;
    3.37 -    PT_LOG("vector %x pirq %x\n", vector, pirq);
    3.38 +    PT_LOG("msi mapped with pirq %x\n", pirq);
    3.39  
    3.40      return 0;
    3.41  }
    3.42 @@ -147,15 +149,10 @@ static uint8_t get_msi_gctrl(struct pt_d
    3.43      return  *(uint8_t *)(pd->config + d->msi->offset + PCI_MSI_FLAGS);
    3.44  }
    3.45  
    3.46 -static uint32_t get_msi_gflags(struct pt_dev *d)
    3.47 +static uint32_t __get_msi_gflags(uint32_t data, uint64_t addr)
    3.48  {
    3.49      uint32_t result = 0;
    3.50      int rh, dm, dest_id, deliv_mode, trig_mode;
    3.51 -    uint16_t data;
    3.52 -    uint64_t addr;
    3.53 -
    3.54 -    data = get_msi_gdata(d);
    3.55 -    addr = get_msi_gaddr(d);
    3.56  
    3.57      rh = (addr >> MSI_ADDR_REDIRECTION_SHIFT) & 0x1;
    3.58      dm = (addr >> MSI_ADDR_DESTMODE_SHIFT) & 0x1;
    3.59 @@ -170,6 +167,14 @@ static uint32_t get_msi_gflags(struct pt
    3.60      return result;
    3.61  }
    3.62  
    3.63 +static uint32_t get_msi_gflags(struct pt_dev *d)
    3.64 +{
    3.65 +    uint16_t data = get_msi_gdata(d);
    3.66 +    uint64_t addr = get_msi_gaddr(d);
    3.67 +
    3.68 +    return __get_msi_gflags(data, addr);
    3.69 +}
    3.70 +
    3.71  /*
    3.72   * This may be arch different
    3.73   */
    3.74 @@ -178,19 +183,6 @@ static inline uint8_t get_msi_gvec(struc
    3.75      return get_msi_gdata(d) & 0xff;
    3.76  }
    3.77  
    3.78 -static inline uint8_t get_msi_hvec(struct pt_dev *d)
    3.79 -{
    3.80 -    struct pci_dev *pd = d->pci_dev;
    3.81 -    uint16_t data;
    3.82 -
    3.83 -    if ( d->msi->flags & PCI_MSI_FLAGS_64BIT )
    3.84 -        data = pci_read_word(pd, PCI_MSI_DATA_64);
    3.85 -    else
    3.86 -        data = pci_read_word(pd, PCI_MSI_DATA_32);
    3.87 -
    3.88 -    return data & 0xff;
    3.89 -}
    3.90 -
    3.91  /*
    3.92   * Update msi mapping, usually called when MSI enabled,
    3.93   * except the first time
    3.94 @@ -198,7 +190,7 @@ static inline uint8_t get_msi_hvec(struc
    3.95  static int pt_msi_update(struct pt_dev *d)
    3.96  {
    3.97      PT_LOG("now update msi with pirq %x gvec %x\n",
    3.98 -            get_msi_gvec(d), d->msi->pirq);
    3.99 +            d->msi->pirq, get_msi_gvec(d));
   3.100      return xc_domain_update_msi_irq(xc_handle, domid, get_msi_gvec(d),
   3.101                                       d->msi->pirq, get_msi_gflags(d));
   3.102  }
   3.103 @@ -266,7 +258,6 @@ static int pt_msi_control_update(struct 
   3.104  static int
   3.105  pt_msi_map_update(struct pt_dev *d, uint32_t old_data, uint64_t old_addr)
   3.106  {
   3.107 -    uint16_t pctrl;
   3.108      uint32_t data;
   3.109      uint64_t addr;
   3.110  
   3.111 @@ -301,6 +292,8 @@ static int pt_msi_mask_update(struct pt_
   3.112  
   3.113      if ( old_mask != mask )
   3.114          pci_write_long(pd, offset, mask);
   3.115 +
   3.116 +    return 0;
   3.117  }
   3.118  
   3.119  #define ACCESSED_DATA 0x2
   3.120 @@ -486,3 +479,378 @@ int pt_msi_read(struct pt_dev *d, int ad
   3.121      return e_len;
   3.122  }
   3.123  
   3.124 +/* MSI-X virtulization functions */
   3.125 +#define PT_MSIX_CTRL_WR_MASK_HI      (0xC0)
   3.126 +static void mask_physical_msix_entry(struct pt_dev *dev, int entry_nr, int mask)
   3.127 +{
   3.128 +    void *phys_off;
   3.129 +
   3.130 +    phys_off = dev->msix->phys_iomem_base + 16 * entry_nr + 12;
   3.131 +    *(uint32_t *)phys_off = mask;
   3.132 +}
   3.133 +
   3.134 +static int pt_msix_update_one(struct pt_dev *dev, int entry_nr)
   3.135 +{
   3.136 +    struct msix_entry_info *entry = &dev->msix->msix_entry[entry_nr];
   3.137 +    int pirq = entry->pirq;
   3.138 +    int gvec = entry->io_mem[2] & 0xff;
   3.139 +    uint64_t gaddr = *(uint64_t *)&entry->io_mem[0];
   3.140 +    uint32_t gflags = __get_msi_gflags(entry->io_mem[2], gaddr);
   3.141 +    int ret;
   3.142 +
   3.143 +    if ( !entry->flags )
   3.144 +        return 0;
   3.145 +
   3.146 +    /* Check if this entry is already mapped */
   3.147 +    if ( entry->pirq == -1 )
   3.148 +    {
   3.149 +        ret = xc_physdev_map_pirq_msi(xc_handle, domid, MAP_PIRQ_TYPE_MSI,
   3.150 +                                AUTO_ASSIGN, &pirq,
   3.151 +                                dev->pci_dev->dev << 3 | dev->pci_dev->func,
   3.152 +                                dev->pci_dev->bus, entry_nr, 0);
   3.153 +        if ( ret )
   3.154 +        {
   3.155 +            PT_LOG("error map msix entry %x\n", entry_nr);
   3.156 +            return ret;
   3.157 +        }
   3.158 +        entry->pirq = pirq;
   3.159 +    }
   3.160 +
   3.161 +    PT_LOG("now update msix entry %x with pirq %x gvec %x\n",
   3.162 +            entry_nr, pirq, gvec);
   3.163 +
   3.164 +    ret = xc_domain_update_msi_irq(xc_handle, domid, gvec, pirq, gflags);
   3.165 +    if ( ret )
   3.166 +    {
   3.167 +        PT_LOG("error update msix irq info for entry %d\n", entry_nr);
   3.168 +        return ret;
   3.169 +    }
   3.170 +
   3.171 +    entry->flags = 0;
   3.172 +
   3.173 +    return 0;
   3.174 +}
   3.175 +
   3.176 +static int pt_msix_update(struct pt_dev *dev)
   3.177 +{
   3.178 +    struct pt_msix_info *msix = dev->msix;
   3.179 +    int i;
   3.180 +
   3.181 +    for ( i = 0; i < msix->total_entries; i++ )
   3.182 +    {
   3.183 +        pt_msix_update_one(dev, i);
   3.184 +    }
   3.185 +
   3.186 +    return 0;
   3.187 +}
   3.188 +
   3.189 +static void pci_msix_invalid_write(void *opaque, target_phys_addr_t addr,
   3.190 +                                   uint32_t val)
   3.191 +{
   3.192 +    PT_LOG("invalid write to MSI-X table, \
   3.193 +            only dword access is allowed.\n");
   3.194 +}
   3.195 +
   3.196 +static void pci_msix_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
   3.197 +{
   3.198 +    struct pt_dev *dev = (struct pt_dev *)opaque;
   3.199 +    struct pt_msix_info *msix = dev->msix;
   3.200 +    struct msix_entry_info *entry;
   3.201 +    int entry_nr, offset;
   3.202 +
   3.203 +    if ( addr % 4 )
   3.204 +    {
   3.205 +        PT_LOG("unaligned dword access to MSI-X table, addr %016lx\n",
   3.206 +                addr);
   3.207 +        return;
   3.208 +    }
   3.209 +
   3.210 +    entry_nr = (addr - msix->mmio_base_addr) / 16;
   3.211 +    entry = &msix->msix_entry[entry_nr];
   3.212 +    offset = ((addr - msix->mmio_base_addr) % 16) / 4;
   3.213 +
   3.214 +    if ( offset != 3 && msix->enabled && entry->io_mem[3] & 0x1 )
   3.215 +    {
   3.216 +        PT_LOG("can not update msix entry %d since MSI-X is already \
   3.217 +                function now.\n", entry_nr);
   3.218 +        return;
   3.219 +    }
   3.220 +
   3.221 +    if ( offset != 3 && entry->io_mem[offset] != val )
   3.222 +        entry->flags = 1;
   3.223 +    entry->io_mem[offset] = val;
   3.224 +
   3.225 +    if ( offset == 3 )
   3.226 +    {
   3.227 +        if ( !(val & 0x1) )
   3.228 +            pt_msix_update_one(dev, entry_nr);
   3.229 +        mask_physical_msix_entry(dev, entry_nr, entry->io_mem[3] & 0x1);
   3.230 +    }
   3.231 +}
   3.232 +
   3.233 +static CPUWriteMemoryFunc *pci_msix_write[] = {
   3.234 +    pci_msix_invalid_write,
   3.235 +    pci_msix_invalid_write,
   3.236 +    pci_msix_writel
   3.237 +};
   3.238 +
   3.239 +static uint32_t pci_msix_invalid_read(void *opaque, target_phys_addr_t addr)
   3.240 +{
   3.241 +    PT_LOG("invalid read to MSI-X table, \
   3.242 +            only dword access is allowed.\n");
   3.243 +    return 0;
   3.244 +}
   3.245 +
   3.246 +static uint32_t pci_msix_readl(void *opaque, target_phys_addr_t addr)
   3.247 +{
   3.248 +    struct pt_dev *dev = (struct pt_dev *)opaque;
   3.249 +    struct pt_msix_info *msix = dev->msix;
   3.250 +    int entry_nr, offset;
   3.251 +
   3.252 +    if ( addr % 4 )
   3.253 +    {
   3.254 +        PT_LOG("unaligned dword access to MSI-X table, addr %016lx\n",
   3.255 +                addr);
   3.256 +        return 0;
   3.257 +    }
   3.258 +
   3.259 +    entry_nr = (addr - msix->mmio_base_addr) / 16;
   3.260 +    offset = ((addr - msix->mmio_base_addr) % 16) / 4;
   3.261 +
   3.262 +    return msix->msix_entry[entry_nr].io_mem[offset];
   3.263 +}
   3.264 +
   3.265 +static CPUReadMemoryFunc *pci_msix_read[] = {
   3.266 +    pci_msix_invalid_read,
   3.267 +    pci_msix_invalid_read,
   3.268 +    pci_msix_readl
   3.269 +};
   3.270 +
   3.271 +int add_msix_mapping(struct pt_dev *dev, int bar_index)
   3.272 +{
   3.273 +    if ( !(dev->msix && dev->msix->bar_index == bar_index) )
   3.274 +        return 0;
   3.275 +
   3.276 +    return xc_domain_memory_mapping(xc_handle, domid,
   3.277 +                dev->msix->mmio_base_addr >> XC_PAGE_SHIFT,
   3.278 +                (dev->bases[bar_index].access.maddr
   3.279 +                + dev->msix->table_off) >> XC_PAGE_SHIFT,
   3.280 +                (dev->msix->total_entries * 16
   3.281 +                + XC_PAGE_SIZE -1) >> XC_PAGE_SHIFT,
   3.282 +                DPCI_ADD_MAPPING);
   3.283 +}
   3.284 +
   3.285 +int remove_msix_mapping(struct pt_dev *dev, int bar_index)
   3.286 +{
   3.287 +    if ( !(dev->msix && dev->msix->bar_index == bar_index) )
   3.288 +        return 0;
   3.289 +
   3.290 +    dev->msix->mmio_base_addr = dev->bases[bar_index].e_physbase
   3.291 +                                + dev->msix->table_off;
   3.292 +
   3.293 +    cpu_register_physical_memory(dev->msix->mmio_base_addr,
   3.294 +                                 dev->msix->total_entries * 16,
   3.295 +                                 dev->msix->mmio_index);
   3.296 +
   3.297 +    return xc_domain_memory_mapping(xc_handle, domid,
   3.298 +                dev->msix->mmio_base_addr >> XC_PAGE_SHIFT,
   3.299 +                (dev->bases[bar_index].access.maddr
   3.300 +                + dev->msix->table_off) >> XC_PAGE_SHIFT,
   3.301 +                (dev->msix->total_entries * 16
   3.302 +                + XC_PAGE_SIZE -1) >> XC_PAGE_SHIFT,
   3.303 +                DPCI_REMOVE_MAPPING);
   3.304 +}
   3.305 +
   3.306 +int pt_msix_init(struct pt_dev *dev, int pos)
   3.307 +{
   3.308 +    uint8_t id;
   3.309 +    uint16_t flags, control;
   3.310 +    int i, total_entries, table_off, bar_index;
   3.311 +    u64 bar_base;
   3.312 +    struct pci_dev *pd = dev->pci_dev;
   3.313 +
   3.314 +    id = pci_read_byte(pd, pos + PCI_CAP_LIST_ID);
   3.315 +
   3.316 +    if ( id != PCI_CAP_ID_MSIX )
   3.317 +    {
   3.318 +        PT_LOG("error id %x pos %x\n", id, pos);
   3.319 +        return -1;
   3.320 +    }
   3.321 +
   3.322 +    control = pci_read_word(pd, pos + 2);
   3.323 +    total_entries = control & 0x7ff;
   3.324 +    total_entries += 1;
   3.325 +
   3.326 +    dev->msix = malloc(sizeof(struct pt_msix_info)
   3.327 +                       + total_entries*sizeof(struct msix_entry_info));
   3.328 +    if ( !dev->msix )
   3.329 +    {
   3.330 +        PT_LOG("error allocation pt_msix_info\n");
   3.331 +        return -1;
   3.332 +    }
   3.333 +    memset(dev->msix, 0, sizeof(struct pt_msix_info)
   3.334 +                         + total_entries*sizeof(struct msix_entry_info));
   3.335 +    dev->msix->total_entries = total_entries;
   3.336 +    dev->msix->offset = pos;
   3.337 +    for ( i = 0; i < total_entries; i++ )
   3.338 +        dev->msix->msix_entry[i].pirq = -1;
   3.339 +
   3.340 +    dev->msix->mmio_index =
   3.341 +        cpu_register_io_memory(0, pci_msix_read, pci_msix_write, dev);
   3.342 +
   3.343 +    flags = pci_read_word(pd, pos + PCI_MSI_FLAGS);
   3.344 +    if ( flags & PCI_MSIX_ENABLE )
   3.345 +    {
   3.346 +        PT_LOG("MSIX enabled already, disable first\n");
   3.347 +        pci_write_word(pd, pos + PCI_MSI_FLAGS, flags & ~PCI_MSIX_ENABLE);
   3.348 +        *(uint16_t *)&dev->dev.config[pos + PCI_MSI_FLAGS]
   3.349 +            = flags & ~(PCI_MSIX_ENABLE | PCI_MSIX_MASK);
   3.350 +    }
   3.351 +
   3.352 +    table_off = pci_read_long(pd, pos + PCI_MSIX_TABLE);
   3.353 +    bar_index = dev->msix->bar_index = table_off & PCI_MSIX_BIR;
   3.354 +    table_off &= table_off & ~PCI_MSIX_BIR;
   3.355 +    bar_base = pci_read_long(pd, 0x10 + 4 * bar_index);
   3.356 +    if ( (bar_base & 0x6) == 0x4 )
   3.357 +    {
   3.358 +        bar_base &= ~0xf;
   3.359 +        bar_base += (u64)pci_read_long(pd, 0x10 + 4 * (bar_index + 1)) << 32;
   3.360 +    }
   3.361 +    PT_LOG("get MSI-X table bar base %lx\n", bar_base);
   3.362 +
   3.363 +    dev->msix->fd = open("/dev/mem", O_RDWR);
   3.364 +    dev->msix->phys_iomem_base = mmap(0, total_entries * 16,
   3.365 +                          PROT_WRITE | PROT_READ, MAP_SHARED | MAP_LOCKED,
   3.366 +                          dev->msix->fd, bar_base + table_off);
   3.367 +    PT_LOG("mapping physical MSI-X table to %lx\n",
   3.368 +           (unsigned long)dev->msix->phys_iomem_base);
   3.369 +    return 0;
   3.370 +}
   3.371 +
   3.372 +static int pt_msix_enable(struct pt_dev *d, int enable)
   3.373 +{
   3.374 +    uint16_t ctrl;
   3.375 +    struct pci_dev *pd = d->pci_dev;
   3.376 +
   3.377 +    if ( !pd )
   3.378 +        return -1;
   3.379 +
   3.380 +    ctrl = pci_read_word(pd, d->msix->offset + PCI_MSI_FLAGS);
   3.381 +    if ( enable )
   3.382 +        ctrl |= PCI_MSIX_ENABLE;
   3.383 +    else
   3.384 +        ctrl &= ~PCI_MSIX_ENABLE;
   3.385 +    pci_write_word(pd, d->msix->offset + PCI_MSI_FLAGS, ctrl);
   3.386 +    d->msix->enabled = !!enable;
   3.387 +
   3.388 +    return 0;
   3.389 +}
   3.390 +
   3.391 +static int pt_msix_func_mask(struct pt_dev *d, int mask)
   3.392 +{
   3.393 +    uint16_t ctrl;
   3.394 +    struct pci_dev *pd = d->pci_dev;
   3.395 +
   3.396 +    if ( !pd )
   3.397 +        return -1;
   3.398 +
   3.399 +    ctrl = pci_read_word(pd, d->msix->offset + PCI_MSI_FLAGS);
   3.400 +
   3.401 +    if ( mask )
   3.402 +        ctrl |= PCI_MSIX_MASK;
   3.403 +    else
   3.404 +        ctrl &= ~PCI_MSIX_MASK;
   3.405 +
   3.406 +    pci_write_word(pd, d->msix->offset + PCI_MSI_FLAGS, ctrl);
   3.407 +    return 0;
   3.408 +}
   3.409 +
   3.410 +static int pt_msix_control_update(struct pt_dev *d)
   3.411 +{
   3.412 +    PCIDevice *pd = (PCIDevice *)d;
   3.413 +    uint16_t ctrl = *(uint16_t *)(&pd->config[d->msix->offset + 2]);
   3.414 +
   3.415 +    if ( ctrl & PCI_MSIX_ENABLE && !(ctrl & PCI_MSIX_MASK ) )
   3.416 +        pt_msix_update(d);
   3.417 +
   3.418 +    pt_msix_func_mask(d, ctrl & PCI_MSIX_MASK);
   3.419 +    pt_msix_enable(d, ctrl & PCI_MSIX_ENABLE);
   3.420 +
   3.421 +    return 0;
   3.422 +}
   3.423 +
   3.424 +int pt_msix_write(struct pt_dev *d, uint32_t addr, uint32_t val, uint32_t len)
   3.425 +{
   3.426 +    struct pci_dev *pd;
   3.427 +    int i, cur = addr;
   3.428 +    uint8_t value;
   3.429 +    PCIDevice *dev = (PCIDevice *)d;
   3.430 +
   3.431 +    if ( !d || !d->msix )
   3.432 +        return 0;
   3.433 +
   3.434 +    if ( (addr >= (d->msix->offset + 4) ) ||
   3.435 +         (addr + len) < d->msix->offset)
   3.436 +        return 0;
   3.437 +
   3.438 +    PT_LOG("addr %x val %x len %x offset %x\n",
   3.439 +            addr, val, len, d->msix->offset);
   3.440 +
   3.441 +    pd = d->pci_dev;
   3.442 +
   3.443 +    for ( i = 0; i < len; i++, cur++ )
   3.444 +    {
   3.445 +        uint8_t orig_value;
   3.446 +
   3.447 +        if ( cur != d->msix->offset + 3 )
   3.448 +            continue;
   3.449 +
   3.450 +        value = (val >> (i * 8)) & 0xff;
   3.451 +
   3.452 +        orig_value = pci_read_byte(pd, cur);
   3.453 +        value = (orig_value & ~PT_MSIX_CTRL_WR_MASK_HI) |
   3.454 +                (value & PT_MSIX_CTRL_WR_MASK_HI);
   3.455 +        dev->config[cur] = value;
   3.456 +        pt_msix_control_update(d);
   3.457 +        return 1;
   3.458 +    }
   3.459 +
   3.460 +    return 0;
   3.461 +}
   3.462 +
   3.463 +int pt_msix_read(struct pt_dev *d, int addr, int len, uint32_t *val)
   3.464 +{
   3.465 +    int e_addr = addr, e_len = len, offset = 0, i;
   3.466 +    uint8_t e_val = 0;
   3.467 +    PCIDevice *pd = (PCIDevice *)d;
   3.468 +
   3.469 +    if ( !d || !d->msix )
   3.470 +        return 0;
   3.471 +
   3.472 +    if ( (addr > (d->msix->offset + 3) ) ||
   3.473 +         (addr + len) <= d->msix->offset )
   3.474 +        return 0;
   3.475 +
   3.476 +    if ( (addr + len ) > (d->msix->offset + 3) )
   3.477 +        e_len -= addr + len - d->msix->offset - 3;
   3.478 +
   3.479 +    if ( addr < d->msix->offset )
   3.480 +    {
   3.481 +        e_addr = d->msix->offset;
   3.482 +        offset = d->msix->offset - addr;
   3.483 +        e_len -= offset;
   3.484 +    }
   3.485 +
   3.486 +    for ( i = 0; i < e_len; i++ )
   3.487 +    {
   3.488 +        e_val = *(uint8_t *)(&pd->config[e_addr] + i);
   3.489 +        *val &= ~(0xff << ( (offset + i) * 8));
   3.490 +        *val |= (e_val << ( (offset + i) * 8));
   3.491 +    }
   3.492 +
   3.493 +    PT_LOG("addr %x len %x val %x offset %x\n",
   3.494 +            addr, len, *val, d->msix->offset);
   3.495 +
   3.496 +    return e_len;
   3.497 +}
   3.498 +
     4.1 --- a/tools/ioemu/hw/pt-msi.h	Mon May 12 10:06:40 2008 +0100
     4.2 +++ b/tools/ioemu/hw/pt-msi.h	Mon May 12 10:07:26 2008 +0100
     4.3 @@ -62,4 +62,19 @@ pt_msi_write(struct pt_dev *d, uint32_t 
     4.4  int
     4.5  pt_msi_read(struct pt_dev *d, int addr, int len, uint32_t *val);
     4.6  
     4.7 +int
     4.8 +remove_msix_mapping(struct pt_dev *dev, int bar_index);
     4.9 +
    4.10 +int
    4.11 +add_msix_mapping(struct pt_dev *dev, int bar_index);
    4.12 +
    4.13 +int
    4.14 +pt_msix_init(struct pt_dev *dev, int pos);
    4.15 +
    4.16 +int
    4.17 +pt_msix_write(struct pt_dev *d, uint32_t addr, uint32_t val, uint32_t len);
    4.18 +
    4.19 +int
    4.20 +pt_msix_read(struct pt_dev *d, int addr, int len, uint32_t *val);
    4.21 +
    4.22  #endif
     5.1 --- a/tools/libxc/xc_physdev.c	Mon May 12 10:06:40 2008 +0100
     5.2 +++ b/tools/libxc/xc_physdev.c	Mon May 12 10:07:26 2008 +0100
     5.3 @@ -52,6 +52,7 @@ int xc_physdev_map_pirq_msi(int xc_handl
     5.4                              int *pirq,
     5.5                              int devfn,
     5.6                              int bus,
     5.7 +                            int entry_nr,
     5.8                              int msi_type)
     5.9  {
    5.10      int rc;
    5.11 @@ -66,6 +67,7 @@ int xc_physdev_map_pirq_msi(int xc_handl
    5.12      map.pirq = *pirq;
    5.13      map.msi_info.devfn = devfn;
    5.14      map.msi_info.bus = bus;
    5.15 +    map.msi_info.entry_nr = entry_nr;
    5.16      map.msi_info.msi = msi_type;
    5.17  
    5.18      rc = do_physdev_op(xc_handle, PHYSDEVOP_map_pirq, &map);
     6.1 --- a/tools/libxc/xenctrl.h	Mon May 12 10:06:40 2008 +0100
     6.2 +++ b/tools/libxc/xenctrl.h	Mon May 12 10:07:26 2008 +0100
     6.3 @@ -859,6 +859,7 @@ int xc_physdev_map_pirq_msi(int xc_handl
     6.4                              int *pirq,
     6.5                              int devfn,
     6.6                              int bus,
     6.7 +                            int entry_nr,
     6.8                              int msi_type);
     6.9  
    6.10  int xc_physdev_unmap_pirq(int xc_handle,