[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [RFC PATCH 5/5] ioreq-server: bring the PCI hotplug controller implementation into Xen



On 30/01/14 14:19, Paul Durrant wrote:
> Because we may now have more than one emulator, the implementation of the
> PCI hotplug controller needs to be done by Xen. Happily the code is very
> short and simple and it also removes the need for a different ACPI DSDT
> when using different variants of QEMU.
>
> Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
> ---
>  tools/firmware/hvmloader/acpi/mk_dsdt.c |  147 ++++------------------
>  tools/libxc/xc_domain.c                 |   46 +++++++
>  tools/libxc/xenctrl.h                   |   11 ++
>  tools/libxl/libxl_pci.c                 |   15 +++
>  xen/arch/x86/hvm/Makefile               |    1 +
>  xen/arch/x86/hvm/hotplug.c              |  207 
> +++++++++++++++++++++++++++++++
>  xen/arch/x86/hvm/hvm.c                  |   40 +++++-
>  xen/include/asm-x86/hvm/domain.h        |   12 ++
>  xen/include/asm-x86/hvm/io.h            |    6 +
>  xen/include/public/hvm/hvm_op.h         |    9 ++
>  xen/include/public/hvm/ioreq.h          |    2 +
>  11 files changed, 373 insertions(+), 123 deletions(-)
>  create mode 100644 xen/arch/x86/hvm/hotplug.c
>
> diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c 
> b/tools/firmware/hvmloader/acpi/mk_dsdt.c
> index a4b693b..6408b44 100644
> --- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
> +++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
> @@ -58,28 +58,6 @@ static void pop_block(void)
>      printf("}\n");
>  }
>  
> -static void pci_hotplug_notify(unsigned int slt)
> -{
> -    stmt("Notify", "\\_SB.PCI0.S%02X, EVT", slt);
> -}
> -
> -static void decision_tree(
> -    unsigned int s, unsigned int e, char *var, void (*leaf)(unsigned int))
> -{
> -    if ( s == (e-1) )
> -    {
> -        (*leaf)(s);
> -        return;
> -    }
> -
> -    push_block("If", "And(%s, 0x%02x)", var, (e-s)/2);
> -    decision_tree((s+e)/2, e, var, leaf);
> -    pop_block();
> -    push_block("Else", NULL);
> -    decision_tree(s, (s+e)/2, var, leaf);
> -    pop_block();
> -}
> -
>  static struct option options[] = {
>      { "maxcpu", 1, 0, 'c' },
>      { "dm-version", 1, 0, 'q' },
> @@ -322,64 +300,21 @@ int main(int argc, char **argv)
>                     dev, intx, ((dev*4+dev/8+intx)&31)+16);
>      printf("})\n");
>  
> -    /*
> -     * Each PCI hotplug slot needs at least two methods to handle
> -     * the ACPI event:
> -     *  _EJ0: eject a device
> -     *  _STA: return a device's status, e.g. enabled or removed
> -     * 
> -     * Eject button would generate a general-purpose event, then the
> -     * control method for this event uses Notify() to inform OSPM which
> -     * action happened and on which device.
> -     *
> -     * Pls. refer "6.3 Device Insertion, Removal, and Status Objects"
> -     * in ACPI spec 3.0b for details.
> -     *
> -     * QEMU provides a simple hotplug controller with some I/O to handle
> -     * the hotplug action and status, which is beyond the ACPI scope.
> -     */
> -    if (dm_version == QEMU_XEN_TRADITIONAL) {
> -        for ( slot = 0; slot < 0x100; slot++ )
> -        {
> -            push_block("Device", "S%02X", slot);
> -            /* _ADR == dev:fn (16:16) */
> -            stmt("Name", "_ADR, 0x%08x", ((slot & ~7) << 13) | (slot & 7));
> -            /* _SUN == dev */
> -            stmt("Name", "_SUN, 0x%08x", slot >> 3);
> -            push_block("Method", "_EJ0, 1");
> -            stmt("Store", "0x%02x, \\_GPE.DPT1", slot);
> -            stmt("Store", "0x88, \\_GPE.DPT2");
> -            stmt("Store", "0x%02x, \\_GPE.PH%02X", /* eject */
> -                 (slot & 1) ? 0x10 : 0x01, slot & ~1);
> -            pop_block();
> -            push_block("Method", "_STA, 0");
> -            stmt("Store", "0x%02x, \\_GPE.DPT1", slot);
> -            stmt("Store", "0x89, \\_GPE.DPT2");
> -            if ( slot & 1 )
> -                stmt("ShiftRight", "0x4, \\_GPE.PH%02X, Local1", slot & ~1);
> -            else
> -                stmt("And", "\\_GPE.PH%02X, 0x0f, Local1", slot & ~1);
> -            stmt("Return", "Local1"); /* IN status as the _STA */
> -            pop_block();
> -            pop_block();
> -        }
> -    } else {
> -        stmt("OperationRegion", "SEJ, SystemIO, 0xae08, 0x04");
> -        push_block("Field", "SEJ, DWordAcc, NoLock, WriteAsZeros");
> -        indent(); printf("B0EJ, 32,\n");
> -        pop_block();
> +    stmt("OperationRegion", "SEJ, SystemIO, 0xae08, 0x04");
> +    push_block("Field", "SEJ, DWordAcc, NoLock, WriteAsZeros");
> +    indent(); printf("B0EJ, 32,\n");
> +    pop_block();
>  
> -        /* hotplug_slot */
> -        for (slot = 1; slot <= 31; slot++) {
> -            push_block("Device", "S%i", slot); {
> -                stmt("Name", "_ADR, %#06x0000", slot);
> -                push_block("Method", "_EJ0,1"); {
> -                    stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
> -                    stmt("Return", "0x0");
> -                } pop_block();
> -                stmt("Name", "_SUN, %i", slot);
> +    /* hotplug_slot */
> +    for (slot = 1; slot <= 31; slot++) {
> +        push_block("Device", "S%i", slot); {
> +            stmt("Name", "_ADR, %#06x0000", slot);
> +            push_block("Method", "_EJ0,1"); {
> +                stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
> +                stmt("Return", "0x0");
>              } pop_block();
> -        }
> +            stmt("Name", "_SUN, %i", slot);
> +        } pop_block();
>      }
>  
>      pop_block();
> @@ -389,26 +324,11 @@ int main(int argc, char **argv)
>      /**** GPE start ****/
>      push_block("Scope", "\\_GPE");
>  
> -    if (dm_version == QEMU_XEN_TRADITIONAL) {
> -        stmt("OperationRegion", "PHP, SystemIO, 0x10c0, 0x82");
> -
> -        push_block("Field", "PHP, ByteAcc, NoLock, Preserve");
> -        indent(); printf("PSTA, 8,\n"); /* hotplug controller event reg */
> -        indent(); printf("PSTB, 8,\n"); /* hotplug controller slot reg */
> -        for ( slot = 0; slot < 0x100; slot += 2 )
> -        {
> -            indent();
> -            /* Each hotplug control register manages a pair of pci 
> functions. */
> -            printf("PH%02X, 8,\n", slot);
> -        }
> -        pop_block();
> -    } else {
> -        stmt("OperationRegion", "PCST, SystemIO, 0xae00, 0x08");
> -        push_block("Field", "PCST, DWordAcc, NoLock, WriteAsZeros");
> -        indent(); printf("PCIU, 32,\n");
> -        indent(); printf("PCID, 32,\n");
> -        pop_block();
> -    }
> +    stmt("OperationRegion", "PCST, SystemIO, 0xae00, 0x08");
> +    push_block("Field", "PCST, DWordAcc, NoLock, WriteAsZeros");
> +    indent(); printf("PCIU, 32,\n");
> +    indent(); printf("PCID, 32,\n");
> +    pop_block();
>  
>      stmt("OperationRegion", "DG1, SystemIO, 0xb044, 0x04");
>  
> @@ -416,33 +336,16 @@ int main(int argc, char **argv)
>      indent(); printf("DPT1, 8, DPT2, 8\n");
>      pop_block();
>  
> -    if (dm_version == QEMU_XEN_TRADITIONAL) {
> -        push_block("Method", "_L03, 0, Serialized");
> -        /* Detect slot and event (remove/add). */
> -        stmt("Name", "SLT, 0x0");
> -        stmt("Name", "EVT, 0x0");
> -        stmt("Store", "PSTA, Local1");
> -        stmt("And", "Local1, 0xf, EVT");
> -        stmt("Store", "PSTB, Local1"); /* XXX: Store (PSTB, SLT) ? */
> -        stmt("And", "Local1, 0xff, SLT");
> -        /* Debug */
> -        stmt("Store", "SLT, DPT1");
> -        stmt("Store", "EVT, DPT2");
> -        /* Decision tree */
> -        decision_tree(0x00, 0x100, "SLT", pci_hotplug_notify);
> +    push_block("Method", "_E01");
> +    for (slot = 1; slot <= 31; slot++) {
> +        push_block("If", "And(PCIU, ShiftLeft(1, %i))", slot);
> +        stmt("Notify", "\\_SB.PCI0.S%i, 1", slot);
>          pop_block();
> -    } else {
> -        push_block("Method", "_E01");
> -        for (slot = 1; slot <= 31; slot++) {
> -            push_block("If", "And(PCIU, ShiftLeft(1, %i))", slot);
> -            stmt("Notify", "\\_SB.PCI0.S%i, 1", slot);
> -            pop_block();
> -            push_block("If", "And(PCID, ShiftLeft(1, %i))", slot);
> -            stmt("Notify", "\\_SB.PCI0.S%i, 3", slot);
> -            pop_block();
> -        }
> +        push_block("If", "And(PCID, ShiftLeft(1, %i))", slot);
> +        stmt("Notify", "\\_SB.PCI0.S%i, 3", slot);
>          pop_block();
>      }
> +    pop_block();
>  
>      pop_block();
>      /**** GPE end ****/
> diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
> index c64d15a..c89068e 100644
> --- a/tools/libxc/xc_domain.c
> +++ b/tools/libxc/xc_domain.c
> @@ -1421,6 +1421,52 @@ int xc_hvm_destroy_ioreq_server(xc_interface *xch,
>      return rc;
>  }
>  
> +int xc_hvm_pci_hotplug_enable(xc_interface *xch,
> +                              domid_t domid,
> +                              uint32_t slot)

Take enable as a parameter and save having 2 almost identical functions?

> +{
> +    DECLARE_HYPERCALL;
> +    DECLARE_HYPERCALL_BUFFER(xen_hvm_pci_hotplug_t, arg);
> +    int rc;
> +
> +    arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
> +    if ( arg == NULL )
> +        return -1;
> +
> +    hypercall.op     = __HYPERVISOR_hvm_op;
> +    hypercall.arg[0] = HVMOP_pci_hotplug;
> +    hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg);
> +    arg->domid = domid;
> +    arg->enable = 1;
> +    arg->slot = slot;
> +    rc = do_xen_hypercall(xch, &hypercall);
> +    xc_hypercall_buffer_free(xch, arg);
> +    return rc;
> +}
> +
> +int xc_hvm_pci_hotplug_disable(xc_interface *xch,
> +                               domid_t domid,
> +                               uint32_t slot)
> +{
> +    DECLARE_HYPERCALL;
> +    DECLARE_HYPERCALL_BUFFER(xen_hvm_pci_hotplug_t, arg);
> +    int rc;
> +
> +    arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
> +    if ( arg == NULL )
> +        return -1;
> +
> +    hypercall.op     = __HYPERVISOR_hvm_op;
> +    hypercall.arg[0] = HVMOP_pci_hotplug;
> +    hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg);
> +    arg->domid = domid;
> +    arg->enable = 0;
> +    arg->slot = slot;
> +    rc = do_xen_hypercall(xch, &hypercall);
> +    xc_hypercall_buffer_free(xch, arg);
> +    return rc;
> +}
> +
>  int xc_domain_setdebugging(xc_interface *xch,
>                             uint32_t domid,
>                             unsigned int enable)
> diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
> index 142aaea..c3e35a9 100644
> --- a/tools/libxc/xenctrl.h
> +++ b/tools/libxc/xenctrl.h
> @@ -1842,6 +1842,17 @@ int xc_hvm_destroy_ioreq_server(xc_interface *xch,
>                               domid_t domid,
>                               ioservid_t id);
>  
> +/*
> + * PCI hotplug API
> + */
> +int xc_hvm_pci_hotplug_enable(xc_interface *xch,
> +                           domid_t domid,
> +                           uint32_t slot);
> +
> +int xc_hvm_pci_hotplug_disable(xc_interface *xch,
> +                            domid_t domid,
> +                            uint32_t slot);
> +

tabs/spaces

>  /* HVM guest pass-through */
>  int xc_assign_device(xc_interface *xch,
>                       uint32_t domid,
> diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c
> index 2e52470..4176440 100644
> --- a/tools/libxl/libxl_pci.c
> +++ b/tools/libxl/libxl_pci.c
> @@ -867,6 +867,13 @@ static int do_pci_add(libxl__gc *gc, uint32_t domid, 
> libxl_device_pci *pcidev, i
>          }
>          if ( rc )
>              return ERROR_FAIL;
> +
> +        rc = xc_hvm_pci_hotplug_enable(ctx->xch, domid, pcidev->dev);
> +        if (rc < 0) {
> +            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Error: 
> xc_hvm_pci_hotplug_enable failed");
> +            return ERROR_FAIL;
> +        }
> +
>          break;
>      case LIBXL_DOMAIN_TYPE_PV:
>      {
> @@ -1182,6 +1189,14 @@ static int do_pci_remove(libxl__gc *gc, uint32_t domid,
>                                           NULL, NULL, NULL) < 0)
>              goto out_fail;
>  
> +        rc = xc_hvm_pci_hotplug_disable(ctx->xch, domid, pcidev->dev);
> +        if (rc < 0) {
> +            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
> +                             "Error: xc_hvm_pci_hotplug_disable failed");
> +            rc = ERROR_FAIL;
> +            goto out_fail;
> +        }
> +
>          switch (libxl__device_model_version_running(gc, domid)) {
>          case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
>              rc = qemu_pci_remove_xenstore(gc, domid, pcidev, force);
> diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile
> index eea5555..48efddb 100644
> --- a/xen/arch/x86/hvm/Makefile
> +++ b/xen/arch/x86/hvm/Makefile
> @@ -3,6 +3,7 @@ subdir-y += vmx
>  
>  obj-y += asid.o
>  obj-y += emulate.o
> +obj-y += hotplug.o
>  obj-y += hpet.o
>  obj-y += hvm.o
>  obj-y += i8254.o
> diff --git a/xen/arch/x86/hvm/hotplug.c b/xen/arch/x86/hvm/hotplug.c
> new file mode 100644
> index 0000000..253d435
> --- /dev/null
> +++ b/xen/arch/x86/hvm/hotplug.c
> @@ -0,0 +1,207 @@
> +/*
> + * hvm/hotplug.c
> + *
> + * Copyright (c) 2013, Citrix Systems Inc.
> + *
> + * 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/types.h>
> +#include <xen/spinlock.h>
> +#include <xen/xmalloc.h>
> +#include <asm/hvm/io.h>
> +#include <asm/hvm/support.h>
> +
> +#define SCI_IRQ 9
> +
> +#define GPE_BASE            (ACPI_GPE0_BLK_ADDRESS_V1)
> +#define GPE_LEN             (ACPI_GPE0_BLK_LEN_V1)
> +
> +#define GPE_PCI_HOTPLUG_STATUS  2
> +
> +#define PCI_HOTPLUG_BASE    (ACPI_PCI_HOTPLUG_ADDRESS_V1)
> +#define PCI_HOTPLUG_LEN     (ACPI_PCI_HOTPLUG_LEN_V1)
> +
> +#define PCI_UP      0
> +#define PCI_DOWN    4
> +#define PCI_EJECT   8
> +
> +static void gpe_update_sci(struct hvm_hotplug *hp)
> +{
> +    if ( (hp->gpe_sts[0] & hp->gpe_en[0]) & GPE_PCI_HOTPLUG_STATUS )
> +        hvm_isa_irq_assert(hp->domain, SCI_IRQ);
> +    else
> +        hvm_isa_irq_deassert(hp->domain, SCI_IRQ);
> +}
> +
> +static int handle_gpe_io(
> +    int dir, uint32_t port, uint32_t bytes, uint32_t *val)
> +{
> +    struct vcpu *v = current;
> +    struct domain *d = v->domain;
> +    struct hvm_hotplug  *hp = &d->arch.hvm_domain.hotplug;
> +
> +    if ( bytes != 1 )
> +    {
> +        gdprintk(XENLOG_WARNING, "%s: bad access\n", __func__);
> +        goto done;
> +    }
> +
> +    port -= GPE_BASE;
> +
> +    if ( dir == IOREQ_READ )
> +    {
> +        if ( port < GPE_LEN / 2 )
> +        {
> +            *val = hp->gpe_sts[port];
> +        }
> +        else
> +        {
> +            port -= GPE_LEN / 2;
> +            *val = hp->gpe_en[port];
> +        }
> +    } else {
> +        if ( port < GPE_LEN / 2 )
> +        {
> +            hp->gpe_sts[port] &= ~*val;
> +        }
> +        else
> +        {
> +            port -= GPE_LEN / 2;
> +            hp->gpe_en[port] = *val;
> +        }
> +
> +        gpe_update_sci(hp);
> +    }
> +
> +done:
> +    return X86EMUL_OKAY;
> +}
> +
> +static void pci_hotplug_eject(struct hvm_hotplug *hp, uint32_t mask)
> +{
> +    int slot = ffs(mask) - 1;
> +
> +    gdprintk(XENLOG_INFO, "%s: %d\n", __func__, slot);
> +
> +    hp->slot_down &= ~(1u  << slot);
> +    hp->slot_up &= ~(1u  << slot);
> +}
> +
> +static int handle_pci_hotplug_io(
> +    int dir, uint32_t port, uint32_t bytes, uint32_t *val)
> +{
> +    struct vcpu *v = current;
> +    struct domain *d = v->domain;
> +    struct hvm_hotplug  *hp = &d->arch.hvm_domain.hotplug;
> +
> +    if ( bytes != 4 )
> +    {
> +        gdprintk(XENLOG_WARNING, "%s: bad access\n", __func__);
> +        goto done;
> +    }
> +
> +    port -= PCI_HOTPLUG_BASE;
> +
> +    if ( dir == IOREQ_READ )
> +    {
> +        switch ( port )
> +        {
> +        case PCI_UP:
> +            *val = hp->slot_up;
> +            break;
> +        case PCI_DOWN:
> +            *val = hp->slot_down;
> +            break;
> +        default:
> +            break;
> +        }
> +    }
> +    else
> +    {   
> +        switch ( port )
> +        {
> +        case PCI_EJECT:
> +            pci_hotplug_eject(hp, *val);
> +            break;
> +        default:
> +            break;
> +        }
> +    }
> +
> +done:
> +    return X86EMUL_OKAY;
> +}
> +
> +void pci_hotplug(struct domain *d, int slot, bool_t enable)
> +{
> +    struct hvm_hotplug  *hp = &d->arch.hvm_domain.hotplug;
> +
> +    gdprintk(XENLOG_INFO, "%s: %s %d\n", __func__,
> +             ( enable ) ? "enable" : "disable", slot);
> +
> +    if ( enable )
> +        hp->slot_up |= (1u << slot);
> +    else
> +        hp->slot_down |= (1u << slot);
> +
> +    hp->gpe_sts[0] |= GPE_PCI_HOTPLUG_STATUS;
> +    gpe_update_sci(hp);
> +}
> +
> +int gpe_init(struct domain *d)
> +{
> +    struct hvm_hotplug  *hp = &d->arch.hvm_domain.hotplug;
> +
> +    hp->domain = d;
> +
> +    hp->gpe_sts = xzalloc_array(uint8_t, GPE_LEN / 2);

This size is known at compile time - what about arrays inside
hvm_hotplug and forgo the small memory allocations?

> +    if ( hp->gpe_sts == NULL )
> +        goto fail1;
> +
> +    hp->gpe_en = xzalloc_array(uint8_t, GPE_LEN / 2);
> +    if ( hp->gpe_en == NULL )
> +        goto fail2;
> +
> +    register_portio_handler(d, GPE_BASE, GPE_LEN, handle_gpe_io);
> +    register_portio_handler(d, PCI_HOTPLUG_BASE, PCI_HOTPLUG_LEN,
> +                            handle_pci_hotplug_io);
> +
> +    return 0;
> +
> +fail2:
> +    xfree(hp->gpe_sts);
> +
> +fail1:
> +    return -ENOMEM;
> +}
> +
> +void gpe_deinit(struct domain *d)
> +{
> +    struct hvm_hotplug  *hp = &d->arch.hvm_domain.hotplug;
> +
> +    xfree(hp->gpe_en);
> +    xfree(hp->gpe_sts);
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * tab-width: 4
> + * indent-tabs-mode: nil
> + * c-tab-always-indent: nil
> + * End:
> + */
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index 5f9e728..ff7b259 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -1298,15 +1298,21 @@ int hvm_domain_initialise(struct domain *d)
>  
>      rtc_init(d);
>  
> +    rc = gpe_init(d);
> +    if ( rc != 0 )
> +        goto fail2;
> +
>      register_portio_handler(d, 0xe9, 1, hvm_print_line);
>      register_portio_handler(d, 0xcf8, 4, hvm_access_cf8);
>  
>      rc = hvm_funcs.domain_initialise(d);
>      if ( rc != 0 )
> -        goto fail2;
> +        goto fail3;
>  
>      return 0;
>  
> + fail3:
> +    gpe_deinit(d);
>   fail2:
>      rtc_deinit(d);
>      stdvga_deinit(d);
> @@ -1352,6 +1358,7 @@ void hvm_domain_destroy(struct domain *d)
>          return;
>  
>      hvm_funcs.domain_destroy(d);
> +    gpe_deinit(d);
>      rtc_deinit(d);
>      stdvga_deinit(d);
>      vioapic_deinit(d);
> @@ -5015,6 +5022,32 @@ out:
>      return rc;
>  }
>  
> +static int hvmop_pci_hotplug(
> +    XEN_GUEST_HANDLE_PARAM(xen_hvm_pci_hotplug_t) uop)
> +{
> +    xen_hvm_pci_hotplug_t op;
> +    struct domain *d;
> +    int rc;
> +
> +    if ( copy_from_guest(&op, uop, 1) )
> +        return -EFAULT;
> +
> +    rc = rcu_lock_remote_domain_by_id(op.domid, &d);
> +    if ( rc != 0 )
> +        return rc;
> +
> +    rc = -EINVAL;
> +    if ( !is_hvm_domain(d) )
> +        goto out;
> +
> +    pci_hotplug(d, op.slot, op.enable);
> +    rc = 0;
> +
> +out:
> +    rcu_unlock_domain(d);
> +    return rc;
> +}
> +
>  long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
>  
>  {
> @@ -5058,6 +5091,11 @@ long do_hvm_op(unsigned long op, 
> XEN_GUEST_HANDLE_PARAM(void) arg)
>              guest_handle_cast(arg, xen_hvm_destroy_ioreq_server_t));
>          break;
>      
> +    case HVMOP_pci_hotplug:
> +        rc = hvmop_pci_hotplug(
> +            guest_handle_cast(arg, xen_hvm_pci_hotplug_t));
> +        break;
> +
>      case HVMOP_set_param:
>      case HVMOP_get_param:
>      {
> diff --git a/xen/include/asm-x86/hvm/domain.h 
> b/xen/include/asm-x86/hvm/domain.h
> index 93dcec1..13dd24d 100644
> --- a/xen/include/asm-x86/hvm/domain.h
> +++ b/xen/include/asm-x86/hvm/domain.h
> @@ -66,6 +66,16 @@ struct hvm_ioreq_server {
>      struct hvm_pcidev      *pcidev_list;
>  };
>  
> +struct hvm_hotplug {
> +    struct domain   *domain;

This appears to be found by using container_of(), which will help keep
the size of struct domain down.

> +    uint8_t         *gpe_sts;
> +    uint8_t         *gpe_en;
> +
> +    /* PCI hotplug */
> +    uint32_t        slot_up;
> +    uint32_t        slot_down;
> +};
> +
>  struct hvm_domain {
>      struct list_head        ioreq_server_list;
>      spinlock_t              ioreq_server_lock;
> @@ -73,6 +83,8 @@ struct hvm_domain {
>      uint32_t                pci_cf8;
>      spinlock_t              pci_lock;
>  
> +    struct hvm_hotplug      hotplug;
> +
>      struct pl_time         pl_time;
>  
>      struct hvm_io_handler *io_handler;
> diff --git a/xen/include/asm-x86/hvm/io.h b/xen/include/asm-x86/hvm/io.h
> index 86db58d..072bfe7 100644
> --- a/xen/include/asm-x86/hvm/io.h
> +++ b/xen/include/asm-x86/hvm/io.h
> @@ -142,5 +142,11 @@ void stdvga_init(struct domain *d);
>  void stdvga_deinit(struct domain *d);
>  
>  extern void hvm_dpci_msi_eoi(struct domain *d, int vector);
> +
> +int gpe_init(struct domain *d);
> +void gpe_deinit(struct domain *d);
> +
> +void pci_hotplug(struct domain *d, int slot, bool_t enable);
> +
>  #endif /* __ASM_X86_HVM_IO_H__ */
>  
> diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h
> index 6b31189..20a53ab 100644
> --- a/xen/include/public/hvm/hvm_op.h
> +++ b/xen/include/public/hvm/hvm_op.h
> @@ -340,6 +340,15 @@ struct xen_hvm_destroy_ioreq_server {
>  typedef struct xen_hvm_destroy_ioreq_server xen_hvm_destroy_ioreq_server_t;
>  DEFINE_XEN_GUEST_HANDLE(xen_hvm_destroy_ioreq_server_t);
>  
> +#define HVMOP_pci_hotplug 24
> +struct xen_hvm_pci_hotplug {
> +    domid_t domid;          /* IN - domain to be serviced */
> +    uint8_t enable;         /* IN - enable or disable? */
> +    uint32_t slot;          /* IN - slot to enable/disable */

Reordering these two will make the structure smaller.

~Andrew

> +};
> +typedef struct xen_hvm_pci_hotplug xen_hvm_pci_hotplug_t;
> +DEFINE_XEN_GUEST_HANDLE(xen_hvm_pci_hotplug_t);
> +
>  #endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */
>  
>  #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */
> diff --git a/xen/include/public/hvm/ioreq.h b/xen/include/public/hvm/ioreq.h
> index e84fa75..40bfa61 100644
> --- a/xen/include/public/hvm/ioreq.h
> +++ b/xen/include/public/hvm/ioreq.h
> @@ -101,6 +101,8 @@ typedef struct buffered_iopage buffered_iopage_t;
>  #define ACPI_PM_TMR_BLK_ADDRESS_V1   (ACPI_PM1A_EVT_BLK_ADDRESS_V1 + 0x08)
>  #define ACPI_GPE0_BLK_ADDRESS_V1     0xafe0
>  #define ACPI_GPE0_BLK_LEN_V1         0x04
> +#define ACPI_PCI_HOTPLUG_ADDRESS_V1  0xae00
> +#define ACPI_PCI_HOTPLUG_LEN_V1      0x10
>  
>  /* Compatibility definitions for the default location (version 0). */
>  #define ACPI_PM1A_EVT_BLK_ADDRESS    ACPI_PM1A_EVT_BLK_ADDRESS_V0


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.