diff mbox

[04/12] spapr_pci: add set-indicator RTAS interface

Message ID 1408407718-10835-5-git-send-email-mdroth@linux.vnet.ibm.com
State New
Headers show

Commit Message

Michael Roth Aug. 19, 2014, 12:21 a.m. UTC
From: Mike Day <ncmike@ncultra.org>

Signed-off-by: Mike Day <ncmike@ncultra.org>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 hw/ppc/spapr_pci.c     | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/ppc/spapr.h |   3 ++
 2 files changed, 122 insertions(+)

Comments

Alexander Graf Aug. 26, 2014, 11:36 a.m. UTC | #1
On 19.08.14 02:21, Michael Roth wrote:
> From: Mike Day <ncmike@ncultra.org>
> 
> Signed-off-by: Mike Day <ncmike@ncultra.org>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  hw/ppc/spapr_pci.c     | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/spapr.h |   3 ++
>  2 files changed, 122 insertions(+)
> 
> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
> index 924d488..23a3477 100644
> --- a/hw/ppc/spapr_pci.c
> +++ b/hw/ppc/spapr_pci.c
> @@ -36,6 +36,16 @@
>  
>  #include "hw/pci/pci_bus.h"
>  
> +/* #define DEBUG_SPAPR */
> +
> +#ifdef DEBUG_SPAPR
> +#define DPRINTF(fmt, ...) \
> +    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF(fmt, ...) \
> +    do { } while (0)
> +#endif
> +
>  /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
>  #define RTAS_QUERY_FN           0
>  #define RTAS_CHANGE_FN          1
> @@ -47,6 +57,31 @@
>  #define RTAS_TYPE_MSI           1
>  #define RTAS_TYPE_MSIX          2
>  
> +/* For set-indicator RTAS interface */
> +#define INDICATOR_ISOLATION_MASK            0x0001   /* 9001 one bit */
> +#define INDICATOR_GLOBAL_INTERRUPT_MASK     0x0002   /* 9005 one bit */
> +#define INDICATOR_ERROR_LOG_MASK            0x0004   /* 9006 one bit */
> +#define INDICATOR_IDENTIFY_MASK             0x0008   /* 9007 one bit */
> +#define INDICATOR_RESET_MASK                0x0010   /* 9009 one bit */
> +#define INDICATOR_DR_MASK                   0x00e0   /* 9002 three bits */
> +#define INDICATOR_ALLOCATION_MASK           0x0300   /* 9003 two bits */
> +#define INDICATOR_EPOW_MASK                 0x1c00   /* 9 three bits */
> +
> +#define INDICATOR_ISOLATION_SHIFT           0x00     /* bit 0 */
> +#define INDICATOR_GLOBAL_INTERRUPT_SHIFT    0x01     /* bit 1 */
> +#define INDICATOR_ERROR_LOG_SHIFT           0x02     /* bit 2 */
> +#define INDICATOR_IDENTIFY_SHIFT            0x03     /* bit 3 */
> +#define INDICATOR_RESET_SHIFT               0x04     /* bit 4 */
> +#define INDICATOR_DR_SHIFT                  0x05     /* bits 5-7 */
> +#define INDICATOR_ALLOCATION_SHIFT          0x08     /* bits 8-9 */
> +#define INDICATOR_EPOW_SHIFT                0x0a     /* bits 10-12 */
> +
> +#define DECODE_DRC_STATE(state, m, s)                  \
> +    ((((uint32_t)(state) & (uint32_t)(m))) >> (s))
> +
> +#define ENCODE_DRC_STATE(val, m, s) \
> +    (((uint32_t)(val) << (s)) & (uint32_t)(m))
> +
>  static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
>  {
>      sPAPRPHBState *sphb;
> @@ -402,6 +437,80 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
>      rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
>  }
>  
> +static void rtas_set_indicator(PowerPCCPU *cpu, sPAPREnvironment *spapr,
> +                               uint32_t token, uint32_t nargs,
> +                               target_ulong args, uint32_t nret,
> +                               target_ulong rets)
> +{
> +    uint32_t indicator = rtas_ld(args, 0);
> +    uint32_t drc_index = rtas_ld(args, 1);
> +    uint32_t indicator_state = rtas_ld(args, 2);
> +    uint32_t encoded = 0, shift = 0, mask = 0;
> +    uint32_t *pind;
> +    sPAPRDrcEntry *drc_entry = NULL;

This rtas call does not have any idea what a PHB is. Why does it live in
spapr_pci.c?

> +
> +    if (drc_index == 0) { /* platform indicator */
> +        pind = &spapr->state;
> +    } else {
> +        drc_entry = spapr_find_drc_entry(drc_index);
> +        if (!drc_entry) {
> +            DPRINTF("rtas_set_indicator: unable to find drc_entry for %x",
> +                    drc_index);
> +            rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> +            return;
> +        }
> +        pind = &drc_entry->state;
> +    }
> +
> +    switch (indicator) {
> +    case 9:  /* EPOW */
> +        shift = INDICATOR_EPOW_SHIFT;
> +        mask = INDICATOR_EPOW_MASK;
> +        break;
> +    case 9001: /* Isolation state */
> +        /* encode the new value into the correct bit field */
> +        shift = INDICATOR_ISOLATION_SHIFT;
> +        mask = INDICATOR_ISOLATION_MASK;
> +        break;
> +    case 9002: /* DR */
> +        shift = INDICATOR_DR_SHIFT;
> +        mask = INDICATOR_DR_MASK;
> +        break;
> +    case 9003: /* Allocation State */
> +        shift = INDICATOR_ALLOCATION_SHIFT;
> +        mask = INDICATOR_ALLOCATION_MASK;
> +        break;
> +    case 9005: /* global interrupt */
> +        shift = INDICATOR_GLOBAL_INTERRUPT_SHIFT;
> +        mask = INDICATOR_GLOBAL_INTERRUPT_MASK;
> +        break;
> +    case 9006: /* error log */
> +        shift = INDICATOR_ERROR_LOG_SHIFT;
> +        mask = INDICATOR_ERROR_LOG_MASK;
> +        break;
> +    case 9007: /* identify */
> +        shift = INDICATOR_IDENTIFY_SHIFT;
> +        mask = INDICATOR_IDENTIFY_MASK;
> +        break;
> +    case 9009: /* reset */
> +        shift = INDICATOR_RESET_SHIFT;
> +        mask = INDICATOR_RESET_MASK;
> +        break;
> +    default:
> +        DPRINTF("rtas_set_indicator: indicator not implemented: %d",
> +                indicator);
> +        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> +        return;
> +    }
> +
> +    encoded = ENCODE_DRC_STATE(indicator_state, mask, shift);
> +    /* clear the current indicator value */
> +    *pind &= ~mask;
> +    /* set the new value */
> +    *pind |= encoded;
> +    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
> +}
> +
>  static int pci_spapr_swizzle(int slot, int pin)
>  {
>      return (slot + pin) % PCI_NUM_PINS;
> @@ -624,6 +733,14 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
>          sphb->lsi_table[i].irq = irq;
>      }
>  
> +    /* make sure the platform EPOW sensor is initialized - the
> +     * guest will probe it when there is a hotplug event.
> +     */
> +    spapr->state &= ~(uint32_t)INDICATOR_EPOW_MASK;
> +    spapr->state |= ENCODE_DRC_STATE(0,
> +                                     INDICATOR_EPOW_MASK,
> +                                     INDICATOR_EPOW_SHIFT);
> +
>      if (!info->finish_realize) {
>          error_setg(errp, "finish_realize not defined");
>          return;
> @@ -1056,6 +1173,8 @@ void spapr_pci_rtas_init(void)
>          spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi",
>                              rtas_ibm_change_msi);
>      }
> +    spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
> +                        rtas_set_indicator);
>  }
>  
>  static void spapr_pci_register_types(void)
> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> index 0ac1a19..fac85f8 100644
> --- a/include/hw/ppc/spapr.h
> +++ b/include/hw/ppc/spapr.h
> @@ -72,6 +72,9 @@ typedef struct sPAPREnvironment {
>  
>      /* state for Dynamic Reconfiguration Connectors */
>      sPAPRDrcEntry drc_table[SPAPR_DRC_TABLE_SIZE];
> +
> +    /* Platform state - sensors and indicators */
> +    uint32_t state;

Do you think it'd be possible to create a special DRC device that
contains all of its tables and global state and also exposes sensors and
indicators? That device could then get linked via qom links to the PHBs
for their slots.


Alex
Nathan Fontenot Sept. 5, 2014, 2:55 a.m. UTC | #2
On 08/26/2014 06:36 AM, Alexander Graf wrote:
> 
> 
> On 19.08.14 02:21, Michael Roth wrote:
>> From: Mike Day <ncmike@ncultra.org>
>>
>> Signed-off-by: Mike Day <ncmike@ncultra.org>
>> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
>> ---
>>  hw/ppc/spapr_pci.c     | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
>>  include/hw/ppc/spapr.h |   3 ++
>>  2 files changed, 122 insertions(+)
>>
>> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
>> index 924d488..23a3477 100644
>> --- a/hw/ppc/spapr_pci.c
>> +++ b/hw/ppc/spapr_pci.c
>> @@ -36,6 +36,16 @@
>>  
>>  #include "hw/pci/pci_bus.h"
>>  
>> +/* #define DEBUG_SPAPR */
>> +
>> +#ifdef DEBUG_SPAPR
>> +#define DPRINTF(fmt, ...) \
>> +    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
>> +#else
>> +#define DPRINTF(fmt, ...) \
>> +    do { } while (0)
>> +#endif
>> +
>>  /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
>>  #define RTAS_QUERY_FN           0
>>  #define RTAS_CHANGE_FN          1
>> @@ -47,6 +57,31 @@
>>  #define RTAS_TYPE_MSI           1
>>  #define RTAS_TYPE_MSIX          2
>>  
>> +/* For set-indicator RTAS interface */
>> +#define INDICATOR_ISOLATION_MASK            0x0001   /* 9001 one bit */
>> +#define INDICATOR_GLOBAL_INTERRUPT_MASK     0x0002   /* 9005 one bit */
>> +#define INDICATOR_ERROR_LOG_MASK            0x0004   /* 9006 one bit */
>> +#define INDICATOR_IDENTIFY_MASK             0x0008   /* 9007 one bit */
>> +#define INDICATOR_RESET_MASK                0x0010   /* 9009 one bit */
>> +#define INDICATOR_DR_MASK                   0x00e0   /* 9002 three bits */
>> +#define INDICATOR_ALLOCATION_MASK           0x0300   /* 9003 two bits */
>> +#define INDICATOR_EPOW_MASK                 0x1c00   /* 9 three bits */
>> +
>> +#define INDICATOR_ISOLATION_SHIFT           0x00     /* bit 0 */
>> +#define INDICATOR_GLOBAL_INTERRUPT_SHIFT    0x01     /* bit 1 */
>> +#define INDICATOR_ERROR_LOG_SHIFT           0x02     /* bit 2 */
>> +#define INDICATOR_IDENTIFY_SHIFT            0x03     /* bit 3 */
>> +#define INDICATOR_RESET_SHIFT               0x04     /* bit 4 */
>> +#define INDICATOR_DR_SHIFT                  0x05     /* bits 5-7 */
>> +#define INDICATOR_ALLOCATION_SHIFT          0x08     /* bits 8-9 */
>> +#define INDICATOR_EPOW_SHIFT                0x0a     /* bits 10-12 */
>> +
>> +#define DECODE_DRC_STATE(state, m, s)                  \
>> +    ((((uint32_t)(state) & (uint32_t)(m))) >> (s))
>> +
>> +#define ENCODE_DRC_STATE(val, m, s) \
>> +    (((uint32_t)(val) << (s)) & (uint32_t)(m))
>> +
>>  static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
>>  {
>>      sPAPRPHBState *sphb;
>> @@ -402,6 +437,80 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
>>      rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
>>  }
>>  
>> +static void rtas_set_indicator(PowerPCCPU *cpu, sPAPREnvironment *spapr,
>> +                               uint32_t token, uint32_t nargs,
>> +                               target_ulong args, uint32_t nret,
>> +                               target_ulong rets)
>> +{
>> +    uint32_t indicator = rtas_ld(args, 0);
>> +    uint32_t drc_index = rtas_ld(args, 1);
>> +    uint32_t indicator_state = rtas_ld(args, 2);
>> +    uint32_t encoded = 0, shift = 0, mask = 0;
>> +    uint32_t *pind;
>> +    sPAPRDrcEntry *drc_entry = NULL;
> 
> This rtas call does not have any idea what a PHB is. Why does it live in
> spapr_pci.c?
> 

It probably shouldn't be there, we will need this call for memory and cpu hotplug
later on.

-Nathan

>> +
>> +    if (drc_index == 0) { /* platform indicator */
>> +        pind = &spapr->state;
>> +    } else {
>> +        drc_entry = spapr_find_drc_entry(drc_index);
>> +        if (!drc_entry) {
>> +            DPRINTF("rtas_set_indicator: unable to find drc_entry for %x",
>> +                    drc_index);
>> +            rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
>> +            return;
>> +        }
>> +        pind = &drc_entry->state;
>> +    }
>> +
>> +    switch (indicator) {
>> +    case 9:  /* EPOW */
>> +        shift = INDICATOR_EPOW_SHIFT;
>> +        mask = INDICATOR_EPOW_MASK;
>> +        break;
>> +    case 9001: /* Isolation state */
>> +        /* encode the new value into the correct bit field */
>> +        shift = INDICATOR_ISOLATION_SHIFT;
>> +        mask = INDICATOR_ISOLATION_MASK;
>> +        break;
>> +    case 9002: /* DR */
>> +        shift = INDICATOR_DR_SHIFT;
>> +        mask = INDICATOR_DR_MASK;
>> +        break;
>> +    case 9003: /* Allocation State */
>> +        shift = INDICATOR_ALLOCATION_SHIFT;
>> +        mask = INDICATOR_ALLOCATION_MASK;
>> +        break;
>> +    case 9005: /* global interrupt */
>> +        shift = INDICATOR_GLOBAL_INTERRUPT_SHIFT;
>> +        mask = INDICATOR_GLOBAL_INTERRUPT_MASK;
>> +        break;
>> +    case 9006: /* error log */
>> +        shift = INDICATOR_ERROR_LOG_SHIFT;
>> +        mask = INDICATOR_ERROR_LOG_MASK;
>> +        break;
>> +    case 9007: /* identify */
>> +        shift = INDICATOR_IDENTIFY_SHIFT;
>> +        mask = INDICATOR_IDENTIFY_MASK;
>> +        break;
>> +    case 9009: /* reset */
>> +        shift = INDICATOR_RESET_SHIFT;
>> +        mask = INDICATOR_RESET_MASK;
>> +        break;
>> +    default:
>> +        DPRINTF("rtas_set_indicator: indicator not implemented: %d",
>> +                indicator);
>> +        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
>> +        return;
>> +    }
>> +
>> +    encoded = ENCODE_DRC_STATE(indicator_state, mask, shift);
>> +    /* clear the current indicator value */
>> +    *pind &= ~mask;
>> +    /* set the new value */
>> +    *pind |= encoded;
>> +    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
>> +}
>> +
>>  static int pci_spapr_swizzle(int slot, int pin)
>>  {
>>      return (slot + pin) % PCI_NUM_PINS;
>> @@ -624,6 +733,14 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
>>          sphb->lsi_table[i].irq = irq;
>>      }
>>  
>> +    /* make sure the platform EPOW sensor is initialized - the
>> +     * guest will probe it when there is a hotplug event.
>> +     */
>> +    spapr->state &= ~(uint32_t)INDICATOR_EPOW_MASK;
>> +    spapr->state |= ENCODE_DRC_STATE(0,
>> +                                     INDICATOR_EPOW_MASK,
>> +                                     INDICATOR_EPOW_SHIFT);
>> +
>>      if (!info->finish_realize) {
>>          error_setg(errp, "finish_realize not defined");
>>          return;
>> @@ -1056,6 +1173,8 @@ void spapr_pci_rtas_init(void)
>>          spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi",
>>                              rtas_ibm_change_msi);
>>      }
>> +    spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
>> +                        rtas_set_indicator);
>>  }
>>  
>>  static void spapr_pci_register_types(void)
>> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
>> index 0ac1a19..fac85f8 100644
>> --- a/include/hw/ppc/spapr.h
>> +++ b/include/hw/ppc/spapr.h
>> @@ -72,6 +72,9 @@ typedef struct sPAPREnvironment {
>>  
>>      /* state for Dynamic Reconfiguration Connectors */
>>      sPAPRDrcEntry drc_table[SPAPR_DRC_TABLE_SIZE];
>> +
>> +    /* Platform state - sensors and indicators */
>> +    uint32_t state;
> 
> Do you think it'd be possible to create a special DRC device that
> contains all of its tables and global state and also exposes sensors and
> indicators? That device could then get linked via qom links to the PHBs
> for their slots.
> 
> 
> Alex
>
Michael Roth Sept. 30, 2014, 10:08 p.m. UTC | #3
Quoting Alexander Graf (2014-08-26 06:36:57)
> On 19.08.14 02:21, Michael Roth wrote:
> > From: Mike Day <ncmike@ncultra.org>
> > 
> > Signed-off-by: Mike Day <ncmike@ncultra.org>
> > Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> > ---
> >  hw/ppc/spapr_pci.c     | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  include/hw/ppc/spapr.h |   3 ++
> >  2 files changed, 122 insertions(+)
> > 
> > diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
> > index 924d488..23a3477 100644
> > --- a/hw/ppc/spapr_pci.c
> > +++ b/hw/ppc/spapr_pci.c
> > @@ -36,6 +36,16 @@
> >  
> >  #include "hw/pci/pci_bus.h"
> >  
> > +/* #define DEBUG_SPAPR */
> > +
> > +#ifdef DEBUG_SPAPR
> > +#define DPRINTF(fmt, ...) \
> > +    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
> > +#else
> > +#define DPRINTF(fmt, ...) \
> > +    do { } while (0)
> > +#endif
> > +
> >  /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
> >  #define RTAS_QUERY_FN           0
> >  #define RTAS_CHANGE_FN          1
> > @@ -47,6 +57,31 @@
> >  #define RTAS_TYPE_MSI           1
> >  #define RTAS_TYPE_MSIX          2
> >  
> > +/* For set-indicator RTAS interface */
> > +#define INDICATOR_ISOLATION_MASK            0x0001   /* 9001 one bit */
> > +#define INDICATOR_GLOBAL_INTERRUPT_MASK     0x0002   /* 9005 one bit */
> > +#define INDICATOR_ERROR_LOG_MASK            0x0004   /* 9006 one bit */
> > +#define INDICATOR_IDENTIFY_MASK             0x0008   /* 9007 one bit */
> > +#define INDICATOR_RESET_MASK                0x0010   /* 9009 one bit */
> > +#define INDICATOR_DR_MASK                   0x00e0   /* 9002 three bits */
> > +#define INDICATOR_ALLOCATION_MASK           0x0300   /* 9003 two bits */
> > +#define INDICATOR_EPOW_MASK                 0x1c00   /* 9 three bits */
> > +
> > +#define INDICATOR_ISOLATION_SHIFT           0x00     /* bit 0 */
> > +#define INDICATOR_GLOBAL_INTERRUPT_SHIFT    0x01     /* bit 1 */
> > +#define INDICATOR_ERROR_LOG_SHIFT           0x02     /* bit 2 */
> > +#define INDICATOR_IDENTIFY_SHIFT            0x03     /* bit 3 */
> > +#define INDICATOR_RESET_SHIFT               0x04     /* bit 4 */
> > +#define INDICATOR_DR_SHIFT                  0x05     /* bits 5-7 */
> > +#define INDICATOR_ALLOCATION_SHIFT          0x08     /* bits 8-9 */
> > +#define INDICATOR_EPOW_SHIFT                0x0a     /* bits 10-12 */
> > +
> > +#define DECODE_DRC_STATE(state, m, s)                  \
> > +    ((((uint32_t)(state) & (uint32_t)(m))) >> (s))
> > +
> > +#define ENCODE_DRC_STATE(val, m, s) \
> > +    (((uint32_t)(val) << (s)) & (uint32_t)(m))
> > +
> >  static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
> >  {
> >      sPAPRPHBState *sphb;
> > @@ -402,6 +437,80 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
> >      rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
> >  }
> >  
> > +static void rtas_set_indicator(PowerPCCPU *cpu, sPAPREnvironment *spapr,
> > +                               uint32_t token, uint32_t nargs,
> > +                               target_ulong args, uint32_t nret,
> > +                               target_ulong rets)
> > +{
> > +    uint32_t indicator = rtas_ld(args, 0);
> > +    uint32_t drc_index = rtas_ld(args, 1);
> > +    uint32_t indicator_state = rtas_ld(args, 2);
> > +    uint32_t encoded = 0, shift = 0, mask = 0;
> > +    uint32_t *pind;
> > +    sPAPRDrcEntry *drc_entry = NULL;
> 
> This rtas call does not have any idea what a PHB is. Why does it live in
> spapr_pci.c?

spapr_rtas.c does seem like a better home

> 
> > +
> > +    if (drc_index == 0) { /* platform indicator */
> > +        pind = &spapr->state;
> > +    } else {
> > +        drc_entry = spapr_find_drc_entry(drc_index);
> > +        if (!drc_entry) {
> > +            DPRINTF("rtas_set_indicator: unable to find drc_entry for %x",
> > +                    drc_index);
> > +            rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> > +            return;
> > +        }
> > +        pind = &drc_entry->state;
> > +    }
> > +
> > +    switch (indicator) {
> > +    case 9:  /* EPOW */
> > +        shift = INDICATOR_EPOW_SHIFT;
> > +        mask = INDICATOR_EPOW_MASK;
> > +        break;
> > +    case 9001: /* Isolation state */
> > +        /* encode the new value into the correct bit field */
> > +        shift = INDICATOR_ISOLATION_SHIFT;
> > +        mask = INDICATOR_ISOLATION_MASK;
> > +        break;
> > +    case 9002: /* DR */
> > +        shift = INDICATOR_DR_SHIFT;
> > +        mask = INDICATOR_DR_MASK;
> > +        break;
> > +    case 9003: /* Allocation State */
> > +        shift = INDICATOR_ALLOCATION_SHIFT;
> > +        mask = INDICATOR_ALLOCATION_MASK;
> > +        break;
> > +    case 9005: /* global interrupt */
> > +        shift = INDICATOR_GLOBAL_INTERRUPT_SHIFT;
> > +        mask = INDICATOR_GLOBAL_INTERRUPT_MASK;
> > +        break;
> > +    case 9006: /* error log */
> > +        shift = INDICATOR_ERROR_LOG_SHIFT;
> > +        mask = INDICATOR_ERROR_LOG_MASK;
> > +        break;
> > +    case 9007: /* identify */
> > +        shift = INDICATOR_IDENTIFY_SHIFT;
> > +        mask = INDICATOR_IDENTIFY_MASK;
> > +        break;
> > +    case 9009: /* reset */
> > +        shift = INDICATOR_RESET_SHIFT;
> > +        mask = INDICATOR_RESET_MASK;
> > +        break;
> > +    default:
> > +        DPRINTF("rtas_set_indicator: indicator not implemented: %d",
> > +                indicator);
> > +        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> > +        return;
> > +    }
> > +
> > +    encoded = ENCODE_DRC_STATE(indicator_state, mask, shift);
> > +    /* clear the current indicator value */
> > +    *pind &= ~mask;
> > +    /* set the new value */
> > +    *pind |= encoded;
> > +    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
> > +}
> > +
> >  static int pci_spapr_swizzle(int slot, int pin)
> >  {
> >      return (slot + pin) % PCI_NUM_PINS;
> > @@ -624,6 +733,14 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
> >          sphb->lsi_table[i].irq = irq;
> >      }
> >  
> > +    /* make sure the platform EPOW sensor is initialized - the
> > +     * guest will probe it when there is a hotplug event.
> > +     */
> > +    spapr->state &= ~(uint32_t)INDICATOR_EPOW_MASK;
> > +    spapr->state |= ENCODE_DRC_STATE(0,
> > +                                     INDICATOR_EPOW_MASK,
> > +                                     INDICATOR_EPOW_SHIFT);
> > +
> >      if (!info->finish_realize) {
> >          error_setg(errp, "finish_realize not defined");
> >          return;
> > @@ -1056,6 +1173,8 @@ void spapr_pci_rtas_init(void)
> >          spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi",
> >                              rtas_ibm_change_msi);
> >      }
> > +    spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
> > +                        rtas_set_indicator);
> >  }
> >  
> >  static void spapr_pci_register_types(void)
> > diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> > index 0ac1a19..fac85f8 100644
> > --- a/include/hw/ppc/spapr.h
> > +++ b/include/hw/ppc/spapr.h
> > @@ -72,6 +72,9 @@ typedef struct sPAPREnvironment {
> >  
> >      /* state for Dynamic Reconfiguration Connectors */
> >      sPAPRDrcEntry drc_table[SPAPR_DRC_TABLE_SIZE];
> > +
> > +    /* Platform state - sensors and indicators */
> > +    uint32_t state;
> 
> Do you think it'd be possible to create a special DRC device that
> contains all of its tables and global state and also exposes sensors and
> indicators? That device could then get linked via qom links to the PHBs
> for their slots.

Sorry for the delay, I've been going back through the code with this
suggestion in mind and there does seem to be a lot of state that
can be nicely encapsulated by modeling the DR Connectors as a QOM
"device" (though I haven't gone as far as to make them actual
DeviceState's since it's more of a firmware abstraction than real
hardware)

I'm not sure what the best way to plumb things together is, as a first
run, since each DRC must have a index drc_index as per spec, I've moved
put them under /machine/DRConnector as a flat list, where top-level
PHB/CPU/MEMORY DRCs would be allocated statically during sPAPR machine
init (since the corresponding DRC indexes/types/etc are hard-coded into
the top-level of the boot-time DT anyway, though I guess we could also
allocate these on the fly...seems messier though than just plugging new
resources into existing DRCs)

PHB's in turn will associate themselves with a DRC via an attach/detach
method as part of realize (and in the future, hotplug hooks, though
that's not part of the series). The PHBs in turn will create a DRC for each
hotpluggable PCI slot.

Creation is via:

sPAPRDRConnector *spapr_dr_connector_new(sPAPRDRConnectorType type,
                                         uint32_t id);

where the code computes the drc index based on <type> (one of phb, cpu, pci,
memory, etc) and <id>, and sticks them under /machine/dr-Connector/<drc_index>

Any pci/phb/cpu hotplug hooks can then fetch the DRC via type/id,
and hotplug/unplug via attach()/detach() methods. attach() adds
the attached/hotplugged DeviceState as a link property of the
DRC object, and sets the initial sensor state.

rtas calls can fetch DRCs via drc_index, and set/get sensor state
via DRC sensor get/set methods.

Hotplug event delivery still lives outside of DRC implementation for now. I
thought of moving them into DRC, but decisions like whether we should
emit events during coldplug/initial boot seemed to require pushing
a lot of general machine state into DRCs and making the encapsulation
seem superficial.

Things end up looking like this (2xxxxxxx are PHBs, 4xxxxxxx are PCI slots):

mdroth@loki:~/w/qom/machine/dr-connector$ ls
20000000  40000018  40000038  40000058  40000078  40000098  400000b8  400000d8  400000f8
40000000  40000020  40000040  40000060  40000080  400000a0  400000c0  400000e0  type
40000008  40000028  40000048  40000068  40000088  400000a8  400000c8  400000e8
40000010  40000030  40000050  40000070  40000090  400000b0  400000d0  400000f0
mdroth@loki:~/w/qom/machine/dr-connector$ cd 40000000/
mdroth@loki:~/w/qom/machine/dr-connector/40000000$ ls -l
total 0
-rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 allocation-state
lrwxr-xr-x 2 mdroth mdroth 4096 Dec 31  1969 device -> ../../../machine/peripheral/hp0
-rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 drc-index
-rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 entity-sense
-rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 indicator-state
-rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 isolation-state
-rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 type
mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat allocation-state 
1
mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat indicator-state 
1
mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat ../../../machine/peripheral/hp0/type 
virtio-net-pci
mdroth@loki:~/w/qom/machine/dr-connector/40000000$

Hopefully this is sort of the approach you were thinking of?

> 
> 
> Alex
Alexander Graf Oct. 1, 2014, 2:30 p.m. UTC | #4
On 01.10.14 00:08, Michael Roth wrote:
> Quoting Alexander Graf (2014-08-26 06:36:57)
>> On 19.08.14 02:21, Michael Roth wrote:
>>> From: Mike Day <ncmike@ncultra.org>
>>>
>>> Signed-off-by: Mike Day <ncmike@ncultra.org>
>>> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
>>> ---
>>>  hw/ppc/spapr_pci.c     | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>  include/hw/ppc/spapr.h |   3 ++
>>>  2 files changed, 122 insertions(+)
>>>
>>> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
>>> index 924d488..23a3477 100644
>>> --- a/hw/ppc/spapr_pci.c
>>> +++ b/hw/ppc/spapr_pci.c
>>> @@ -36,6 +36,16 @@
>>>  
>>>  #include "hw/pci/pci_bus.h"
>>>  
>>> +/* #define DEBUG_SPAPR */
>>> +
>>> +#ifdef DEBUG_SPAPR
>>> +#define DPRINTF(fmt, ...) \
>>> +    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
>>> +#else
>>> +#define DPRINTF(fmt, ...) \
>>> +    do { } while (0)
>>> +#endif
>>> +
>>>  /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
>>>  #define RTAS_QUERY_FN           0
>>>  #define RTAS_CHANGE_FN          1
>>> @@ -47,6 +57,31 @@
>>>  #define RTAS_TYPE_MSI           1
>>>  #define RTAS_TYPE_MSIX          2
>>>  
>>> +/* For set-indicator RTAS interface */
>>> +#define INDICATOR_ISOLATION_MASK            0x0001   /* 9001 one bit */
>>> +#define INDICATOR_GLOBAL_INTERRUPT_MASK     0x0002   /* 9005 one bit */
>>> +#define INDICATOR_ERROR_LOG_MASK            0x0004   /* 9006 one bit */
>>> +#define INDICATOR_IDENTIFY_MASK             0x0008   /* 9007 one bit */
>>> +#define INDICATOR_RESET_MASK                0x0010   /* 9009 one bit */
>>> +#define INDICATOR_DR_MASK                   0x00e0   /* 9002 three bits */
>>> +#define INDICATOR_ALLOCATION_MASK           0x0300   /* 9003 two bits */
>>> +#define INDICATOR_EPOW_MASK                 0x1c00   /* 9 three bits */
>>> +
>>> +#define INDICATOR_ISOLATION_SHIFT           0x00     /* bit 0 */
>>> +#define INDICATOR_GLOBAL_INTERRUPT_SHIFT    0x01     /* bit 1 */
>>> +#define INDICATOR_ERROR_LOG_SHIFT           0x02     /* bit 2 */
>>> +#define INDICATOR_IDENTIFY_SHIFT            0x03     /* bit 3 */
>>> +#define INDICATOR_RESET_SHIFT               0x04     /* bit 4 */
>>> +#define INDICATOR_DR_SHIFT                  0x05     /* bits 5-7 */
>>> +#define INDICATOR_ALLOCATION_SHIFT          0x08     /* bits 8-9 */
>>> +#define INDICATOR_EPOW_SHIFT                0x0a     /* bits 10-12 */
>>> +
>>> +#define DECODE_DRC_STATE(state, m, s)                  \
>>> +    ((((uint32_t)(state) & (uint32_t)(m))) >> (s))
>>> +
>>> +#define ENCODE_DRC_STATE(val, m, s) \
>>> +    (((uint32_t)(val) << (s)) & (uint32_t)(m))
>>> +
>>>  static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
>>>  {
>>>      sPAPRPHBState *sphb;
>>> @@ -402,6 +437,80 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
>>>      rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
>>>  }
>>>  
>>> +static void rtas_set_indicator(PowerPCCPU *cpu, sPAPREnvironment *spapr,
>>> +                               uint32_t token, uint32_t nargs,
>>> +                               target_ulong args, uint32_t nret,
>>> +                               target_ulong rets)
>>> +{
>>> +    uint32_t indicator = rtas_ld(args, 0);
>>> +    uint32_t drc_index = rtas_ld(args, 1);
>>> +    uint32_t indicator_state = rtas_ld(args, 2);
>>> +    uint32_t encoded = 0, shift = 0, mask = 0;
>>> +    uint32_t *pind;
>>> +    sPAPRDrcEntry *drc_entry = NULL;
>>
>> This rtas call does not have any idea what a PHB is. Why does it live in
>> spapr_pci.c?
> 
> spapr_rtas.c does seem like a better home
> 
>>
>>> +
>>> +    if (drc_index == 0) { /* platform indicator */
>>> +        pind = &spapr->state;
>>> +    } else {
>>> +        drc_entry = spapr_find_drc_entry(drc_index);
>>> +        if (!drc_entry) {
>>> +            DPRINTF("rtas_set_indicator: unable to find drc_entry for %x",
>>> +                    drc_index);
>>> +            rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
>>> +            return;
>>> +        }
>>> +        pind = &drc_entry->state;
>>> +    }
>>> +
>>> +    switch (indicator) {
>>> +    case 9:  /* EPOW */
>>> +        shift = INDICATOR_EPOW_SHIFT;
>>> +        mask = INDICATOR_EPOW_MASK;
>>> +        break;
>>> +    case 9001: /* Isolation state */
>>> +        /* encode the new value into the correct bit field */
>>> +        shift = INDICATOR_ISOLATION_SHIFT;
>>> +        mask = INDICATOR_ISOLATION_MASK;
>>> +        break;
>>> +    case 9002: /* DR */
>>> +        shift = INDICATOR_DR_SHIFT;
>>> +        mask = INDICATOR_DR_MASK;
>>> +        break;
>>> +    case 9003: /* Allocation State */
>>> +        shift = INDICATOR_ALLOCATION_SHIFT;
>>> +        mask = INDICATOR_ALLOCATION_MASK;
>>> +        break;
>>> +    case 9005: /* global interrupt */
>>> +        shift = INDICATOR_GLOBAL_INTERRUPT_SHIFT;
>>> +        mask = INDICATOR_GLOBAL_INTERRUPT_MASK;
>>> +        break;
>>> +    case 9006: /* error log */
>>> +        shift = INDICATOR_ERROR_LOG_SHIFT;
>>> +        mask = INDICATOR_ERROR_LOG_MASK;
>>> +        break;
>>> +    case 9007: /* identify */
>>> +        shift = INDICATOR_IDENTIFY_SHIFT;
>>> +        mask = INDICATOR_IDENTIFY_MASK;
>>> +        break;
>>> +    case 9009: /* reset */
>>> +        shift = INDICATOR_RESET_SHIFT;
>>> +        mask = INDICATOR_RESET_MASK;
>>> +        break;
>>> +    default:
>>> +        DPRINTF("rtas_set_indicator: indicator not implemented: %d",
>>> +                indicator);
>>> +        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
>>> +        return;
>>> +    }
>>> +
>>> +    encoded = ENCODE_DRC_STATE(indicator_state, mask, shift);
>>> +    /* clear the current indicator value */
>>> +    *pind &= ~mask;
>>> +    /* set the new value */
>>> +    *pind |= encoded;
>>> +    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
>>> +}
>>> +
>>>  static int pci_spapr_swizzle(int slot, int pin)
>>>  {
>>>      return (slot + pin) % PCI_NUM_PINS;
>>> @@ -624,6 +733,14 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
>>>          sphb->lsi_table[i].irq = irq;
>>>      }
>>>  
>>> +    /* make sure the platform EPOW sensor is initialized - the
>>> +     * guest will probe it when there is a hotplug event.
>>> +     */
>>> +    spapr->state &= ~(uint32_t)INDICATOR_EPOW_MASK;
>>> +    spapr->state |= ENCODE_DRC_STATE(0,
>>> +                                     INDICATOR_EPOW_MASK,
>>> +                                     INDICATOR_EPOW_SHIFT);
>>> +
>>>      if (!info->finish_realize) {
>>>          error_setg(errp, "finish_realize not defined");
>>>          return;
>>> @@ -1056,6 +1173,8 @@ void spapr_pci_rtas_init(void)
>>>          spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi",
>>>                              rtas_ibm_change_msi);
>>>      }
>>> +    spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
>>> +                        rtas_set_indicator);
>>>  }
>>>  
>>>  static void spapr_pci_register_types(void)
>>> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
>>> index 0ac1a19..fac85f8 100644
>>> --- a/include/hw/ppc/spapr.h
>>> +++ b/include/hw/ppc/spapr.h
>>> @@ -72,6 +72,9 @@ typedef struct sPAPREnvironment {
>>>  
>>>      /* state for Dynamic Reconfiguration Connectors */
>>>      sPAPRDrcEntry drc_table[SPAPR_DRC_TABLE_SIZE];
>>> +
>>> +    /* Platform state - sensors and indicators */
>>> +    uint32_t state;
>>
>> Do you think it'd be possible to create a special DRC device that
>> contains all of its tables and global state and also exposes sensors and
>> indicators? That device could then get linked via qom links to the PHBs
>> for their slots.
> 
> Sorry for the delay, I've been going back through the code with this
> suggestion in mind and there does seem to be a lot of state that
> can be nicely encapsulated by modeling the DR Connectors as a QOM
> "device" (though I haven't gone as far as to make them actual
> DeviceState's since it's more of a firmware abstraction than real
> hardware)
> 
> I'm not sure what the best way to plumb things together is, as a first
> run, since each DRC must have a index drc_index as per spec, I've moved
> put them under /machine/DRConnector as a flat list, where top-level
> PHB/CPU/MEMORY DRCs would be allocated statically during sPAPR machine
> init (since the corresponding DRC indexes/types/etc are hard-coded into
> the top-level of the boot-time DT anyway, though I guess we could also
> allocate these on the fly...seems messier though than just plugging new
> resources into existing DRCs)
> 
> PHB's in turn will associate themselves with a DRC via an attach/detach
> method as part of realize (and in the future, hotplug hooks, though
> that's not part of the series). The PHBs in turn will create a DRC for each
> hotpluggable PCI slot.
> 
> Creation is via:
> 
> sPAPRDRConnector *spapr_dr_connector_new(sPAPRDRConnectorType type,
>                                          uint32_t id);
> 
> where the code computes the drc index based on <type> (one of phb, cpu, pci,
> memory, etc) and <id>, and sticks them under /machine/dr-Connector/<drc_index>
> 
> Any pci/phb/cpu hotplug hooks can then fetch the DRC via type/id,
> and hotplug/unplug via attach()/detach() methods. attach() adds
> the attached/hotplugged DeviceState as a link property of the
> DRC object, and sets the initial sensor state.
> 
> rtas calls can fetch DRCs via drc_index, and set/get sensor state
> via DRC sensor get/set methods.
> 
> Hotplug event delivery still lives outside of DRC implementation for now. I
> thought of moving them into DRC, but decisions like whether we should
> emit events during coldplug/initial boot seemed to require pushing
> a lot of general machine state into DRCs and making the encapsulation
> seem superficial.
> 
> Things end up looking like this (2xxxxxxx are PHBs, 4xxxxxxx are PCI slots):
> 
> mdroth@loki:~/w/qom/machine/dr-connector$ ls
> 20000000  40000018  40000038  40000058  40000078  40000098  400000b8  400000d8  400000f8
> 40000000  40000020  40000040  40000060  40000080  400000a0  400000c0  400000e0  type
> 40000008  40000028  40000048  40000068  40000088  400000a8  400000c8  400000e8
> 40000010  40000030  40000050  40000070  40000090  400000b0  400000d0  400000f0
> mdroth@loki:~/w/qom/machine/dr-connector$ cd 40000000/
> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ ls -l
> total 0
> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 allocation-state
> lrwxr-xr-x 2 mdroth mdroth 4096 Dec 31  1969 device -> ../../../machine/peripheral/hp0
> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 drc-index
> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 entity-sense
> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 indicator-state
> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 isolation-state
> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 type
> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat allocation-state 
> 1
> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat indicator-state 
> 1
> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat ../../../machine/peripheral/hp0/type 
> virtio-net-pci
> mdroth@loki:~/w/qom/machine/dr-connector/40000000$
> 
> Hopefully this is sort of the approach you were thinking of?

This look quite neat so far, looking forward to the patches :).


Alex
Bharata B Rao Nov. 26, 2014, 4:51 a.m. UTC | #5
On Wed, Oct 1, 2014 at 8:00 PM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 01.10.14 00:08, Michael Roth wrote:
>> Quoting Alexander Graf (2014-08-26 06:36:57)
>>> On 19.08.14 02:21, Michael Roth wrote:
>>>> From: Mike Day <ncmike@ncultra.org>
>>>>
>>>> Signed-off-by: Mike Day <ncmike@ncultra.org>
>>>> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>> ---
>>>>  hw/ppc/spapr_pci.c     | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  include/hw/ppc/spapr.h |   3 ++
>>>>  2 files changed, 122 insertions(+)
>>>>
>>>> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
>>>> index 924d488..23a3477 100644
>>>> --- a/hw/ppc/spapr_pci.c
>>>> +++ b/hw/ppc/spapr_pci.c
>>>> @@ -36,6 +36,16 @@
>>>>
>>>>  #include "hw/pci/pci_bus.h"
>>>>
>>>> +/* #define DEBUG_SPAPR */
>>>> +
>>>> +#ifdef DEBUG_SPAPR
>>>> +#define DPRINTF(fmt, ...) \
>>>> +    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
>>>> +#else
>>>> +#define DPRINTF(fmt, ...) \
>>>> +    do { } while (0)
>>>> +#endif
>>>> +
>>>>  /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
>>>>  #define RTAS_QUERY_FN           0
>>>>  #define RTAS_CHANGE_FN          1
>>>> @@ -47,6 +57,31 @@
>>>>  #define RTAS_TYPE_MSI           1
>>>>  #define RTAS_TYPE_MSIX          2
>>>>
>>>> +/* For set-indicator RTAS interface */
>>>> +#define INDICATOR_ISOLATION_MASK            0x0001   /* 9001 one bit */
>>>> +#define INDICATOR_GLOBAL_INTERRUPT_MASK     0x0002   /* 9005 one bit */
>>>> +#define INDICATOR_ERROR_LOG_MASK            0x0004   /* 9006 one bit */
>>>> +#define INDICATOR_IDENTIFY_MASK             0x0008   /* 9007 one bit */
>>>> +#define INDICATOR_RESET_MASK                0x0010   /* 9009 one bit */
>>>> +#define INDICATOR_DR_MASK                   0x00e0   /* 9002 three bits */
>>>> +#define INDICATOR_ALLOCATION_MASK           0x0300   /* 9003 two bits */
>>>> +#define INDICATOR_EPOW_MASK                 0x1c00   /* 9 three bits */
>>>> +
>>>> +#define INDICATOR_ISOLATION_SHIFT           0x00     /* bit 0 */
>>>> +#define INDICATOR_GLOBAL_INTERRUPT_SHIFT    0x01     /* bit 1 */
>>>> +#define INDICATOR_ERROR_LOG_SHIFT           0x02     /* bit 2 */
>>>> +#define INDICATOR_IDENTIFY_SHIFT            0x03     /* bit 3 */
>>>> +#define INDICATOR_RESET_SHIFT               0x04     /* bit 4 */
>>>> +#define INDICATOR_DR_SHIFT                  0x05     /* bits 5-7 */
>>>> +#define INDICATOR_ALLOCATION_SHIFT          0x08     /* bits 8-9 */
>>>> +#define INDICATOR_EPOW_SHIFT                0x0a     /* bits 10-12 */
>>>> +
>>>> +#define DECODE_DRC_STATE(state, m, s)                  \
>>>> +    ((((uint32_t)(state) & (uint32_t)(m))) >> (s))
>>>> +
>>>> +#define ENCODE_DRC_STATE(val, m, s) \
>>>> +    (((uint32_t)(val) << (s)) & (uint32_t)(m))
>>>> +
>>>>  static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
>>>>  {
>>>>      sPAPRPHBState *sphb;
>>>> @@ -402,6 +437,80 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
>>>>      rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
>>>>  }
>>>>
>>>> +static void rtas_set_indicator(PowerPCCPU *cpu, sPAPREnvironment *spapr,
>>>> +                               uint32_t token, uint32_t nargs,
>>>> +                               target_ulong args, uint32_t nret,
>>>> +                               target_ulong rets)
>>>> +{
>>>> +    uint32_t indicator = rtas_ld(args, 0);
>>>> +    uint32_t drc_index = rtas_ld(args, 1);
>>>> +    uint32_t indicator_state = rtas_ld(args, 2);
>>>> +    uint32_t encoded = 0, shift = 0, mask = 0;
>>>> +    uint32_t *pind;
>>>> +    sPAPRDrcEntry *drc_entry = NULL;
>>>
>>> This rtas call does not have any idea what a PHB is. Why does it live in
>>> spapr_pci.c?
>>
>> spapr_rtas.c does seem like a better home
>>
>>>
>>>> +
>>>> +    if (drc_index == 0) { /* platform indicator */
>>>> +        pind = &spapr->state;
>>>> +    } else {
>>>> +        drc_entry = spapr_find_drc_entry(drc_index);
>>>> +        if (!drc_entry) {
>>>> +            DPRINTF("rtas_set_indicator: unable to find drc_entry for %x",
>>>> +                    drc_index);
>>>> +            rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
>>>> +            return;
>>>> +        }
>>>> +        pind = &drc_entry->state;
>>>> +    }
>>>> +
>>>> +    switch (indicator) {
>>>> +    case 9:  /* EPOW */
>>>> +        shift = INDICATOR_EPOW_SHIFT;
>>>> +        mask = INDICATOR_EPOW_MASK;
>>>> +        break;
>>>> +    case 9001: /* Isolation state */
>>>> +        /* encode the new value into the correct bit field */
>>>> +        shift = INDICATOR_ISOLATION_SHIFT;
>>>> +        mask = INDICATOR_ISOLATION_MASK;
>>>> +        break;
>>>> +    case 9002: /* DR */
>>>> +        shift = INDICATOR_DR_SHIFT;
>>>> +        mask = INDICATOR_DR_MASK;
>>>> +        break;
>>>> +    case 9003: /* Allocation State */
>>>> +        shift = INDICATOR_ALLOCATION_SHIFT;
>>>> +        mask = INDICATOR_ALLOCATION_MASK;
>>>> +        break;
>>>> +    case 9005: /* global interrupt */
>>>> +        shift = INDICATOR_GLOBAL_INTERRUPT_SHIFT;
>>>> +        mask = INDICATOR_GLOBAL_INTERRUPT_MASK;
>>>> +        break;
>>>> +    case 9006: /* error log */
>>>> +        shift = INDICATOR_ERROR_LOG_SHIFT;
>>>> +        mask = INDICATOR_ERROR_LOG_MASK;
>>>> +        break;
>>>> +    case 9007: /* identify */
>>>> +        shift = INDICATOR_IDENTIFY_SHIFT;
>>>> +        mask = INDICATOR_IDENTIFY_MASK;
>>>> +        break;
>>>> +    case 9009: /* reset */
>>>> +        shift = INDICATOR_RESET_SHIFT;
>>>> +        mask = INDICATOR_RESET_MASK;
>>>> +        break;
>>>> +    default:
>>>> +        DPRINTF("rtas_set_indicator: indicator not implemented: %d",
>>>> +                indicator);
>>>> +        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    encoded = ENCODE_DRC_STATE(indicator_state, mask, shift);
>>>> +    /* clear the current indicator value */
>>>> +    *pind &= ~mask;
>>>> +    /* set the new value */
>>>> +    *pind |= encoded;
>>>> +    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
>>>> +}
>>>> +
>>>>  static int pci_spapr_swizzle(int slot, int pin)
>>>>  {
>>>>      return (slot + pin) % PCI_NUM_PINS;
>>>> @@ -624,6 +733,14 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
>>>>          sphb->lsi_table[i].irq = irq;
>>>>      }
>>>>
>>>> +    /* make sure the platform EPOW sensor is initialized - the
>>>> +     * guest will probe it when there is a hotplug event.
>>>> +     */
>>>> +    spapr->state &= ~(uint32_t)INDICATOR_EPOW_MASK;
>>>> +    spapr->state |= ENCODE_DRC_STATE(0,
>>>> +                                     INDICATOR_EPOW_MASK,
>>>> +                                     INDICATOR_EPOW_SHIFT);
>>>> +
>>>>      if (!info->finish_realize) {
>>>>          error_setg(errp, "finish_realize not defined");
>>>>          return;
>>>> @@ -1056,6 +1173,8 @@ void spapr_pci_rtas_init(void)
>>>>          spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi",
>>>>                              rtas_ibm_change_msi);
>>>>      }
>>>> +    spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
>>>> +                        rtas_set_indicator);
>>>>  }
>>>>
>>>>  static void spapr_pci_register_types(void)
>>>> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
>>>> index 0ac1a19..fac85f8 100644
>>>> --- a/include/hw/ppc/spapr.h
>>>> +++ b/include/hw/ppc/spapr.h
>>>> @@ -72,6 +72,9 @@ typedef struct sPAPREnvironment {
>>>>
>>>>      /* state for Dynamic Reconfiguration Connectors */
>>>>      sPAPRDrcEntry drc_table[SPAPR_DRC_TABLE_SIZE];
>>>> +
>>>> +    /* Platform state - sensors and indicators */
>>>> +    uint32_t state;
>>>
>>> Do you think it'd be possible to create a special DRC device that
>>> contains all of its tables and global state and also exposes sensors and
>>> indicators? That device could then get linked via qom links to the PHBs
>>> for their slots.
>>
>> Sorry for the delay, I've been going back through the code with this
>> suggestion in mind and there does seem to be a lot of state that
>> can be nicely encapsulated by modeling the DR Connectors as a QOM
>> "device" (though I haven't gone as far as to make them actual
>> DeviceState's since it's more of a firmware abstraction than real
>> hardware)
>>
>> I'm not sure what the best way to plumb things together is, as a first
>> run, since each DRC must have a index drc_index as per spec, I've moved
>> put them under /machine/DRConnector as a flat list, where top-level
>> PHB/CPU/MEMORY DRCs would be allocated statically during sPAPR machine
>> init (since the corresponding DRC indexes/types/etc are hard-coded into
>> the top-level of the boot-time DT anyway, though I guess we could also
>> allocate these on the fly...seems messier though than just plugging new
>> resources into existing DRCs)
>>
>> PHB's in turn will associate themselves with a DRC via an attach/detach
>> method as part of realize (and in the future, hotplug hooks, though
>> that's not part of the series). The PHBs in turn will create a DRC for each
>> hotpluggable PCI slot.
>>
>> Creation is via:
>>
>> sPAPRDRConnector *spapr_dr_connector_new(sPAPRDRConnectorType type,
>>                                          uint32_t id);
>>
>> where the code computes the drc index based on <type> (one of phb, cpu, pci,
>> memory, etc) and <id>, and sticks them under /machine/dr-Connector/<drc_index>
>>
>> Any pci/phb/cpu hotplug hooks can then fetch the DRC via type/id,
>> and hotplug/unplug via attach()/detach() methods. attach() adds
>> the attached/hotplugged DeviceState as a link property of the
>> DRC object, and sets the initial sensor state.
>>
>> rtas calls can fetch DRCs via drc_index, and set/get sensor state
>> via DRC sensor get/set methods.
>>
>> Hotplug event delivery still lives outside of DRC implementation for now. I
>> thought of moving them into DRC, but decisions like whether we should
>> emit events during coldplug/initial boot seemed to require pushing
>> a lot of general machine state into DRCs and making the encapsulation
>> seem superficial.
>>
>> Things end up looking like this (2xxxxxxx are PHBs, 4xxxxxxx are PCI slots):
>>
>> mdroth@loki:~/w/qom/machine/dr-connector$ ls
>> 20000000  40000018  40000038  40000058  40000078  40000098  400000b8  400000d8  400000f8
>> 40000000  40000020  40000040  40000060  40000080  400000a0  400000c0  400000e0  type
>> 40000008  40000028  40000048  40000068  40000088  400000a8  400000c8  400000e8
>> 40000010  40000030  40000050  40000070  40000090  400000b0  400000d0  400000f0
>> mdroth@loki:~/w/qom/machine/dr-connector$ cd 40000000/
>> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ ls -l
>> total 0
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 allocation-state
>> lrwxr-xr-x 2 mdroth mdroth 4096 Dec 31  1969 device -> ../../../machine/peripheral/hp0
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 drc-index
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 entity-sense
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 indicator-state
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 isolation-state
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 type
>> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat allocation-state
>> 1
>> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat indicator-state
>> 1
>> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat ../../../machine/peripheral/hp0/type
>> virtio-net-pci
>> mdroth@loki:~/w/qom/machine/dr-connector/40000000$
>>
>> Hopefully this is sort of the approach you were thinking of?
>
> This look quite neat so far, looking forward to the patches :).

Michael,

Do you have this code/patches anywhere that I could use ? I have got
the initial working versions of both CPU and memory hotplug now for
sPAPR guests based on top of your old PCI hotplug patchset and it
would be good to rebase them on top of your DR connector device work.

Regards,
Bharata.
Bharata B Rao Nov. 26, 2014, 4:54 a.m. UTC | #6
On Wed, Oct 1, 2014 at 8:00 PM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 01.10.14 00:08, Michael Roth wrote:
>> Quoting Alexander Graf (2014-08-26 06:36:57)
>>> On 19.08.14 02:21, Michael Roth wrote:
>>>> From: Mike Day <ncmike@ncultra.org>
>>>>
>>>> Signed-off-by: Mike Day <ncmike@ncultra.org>
>>>> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>> ---
>>>>  hw/ppc/spapr_pci.c     | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  include/hw/ppc/spapr.h |   3 ++
>>>>  2 files changed, 122 insertions(+)
>>>>
>>>> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
>>>> index 924d488..23a3477 100644
>>>> --- a/hw/ppc/spapr_pci.c
>>>> +++ b/hw/ppc/spapr_pci.c
>>>> @@ -36,6 +36,16 @@
>>>>
>>>>  #include "hw/pci/pci_bus.h"
>>>>
>>>> +/* #define DEBUG_SPAPR */
>>>> +
>>>> +#ifdef DEBUG_SPAPR
>>>> +#define DPRINTF(fmt, ...) \
>>>> +    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
>>>> +#else
>>>> +#define DPRINTF(fmt, ...) \
>>>> +    do { } while (0)
>>>> +#endif
>>>> +
>>>>  /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
>>>>  #define RTAS_QUERY_FN           0
>>>>  #define RTAS_CHANGE_FN          1
>>>> @@ -47,6 +57,31 @@
>>>>  #define RTAS_TYPE_MSI           1
>>>>  #define RTAS_TYPE_MSIX          2
>>>>
>>>> +/* For set-indicator RTAS interface */
>>>> +#define INDICATOR_ISOLATION_MASK            0x0001   /* 9001 one bit */
>>>> +#define INDICATOR_GLOBAL_INTERRUPT_MASK     0x0002   /* 9005 one bit */
>>>> +#define INDICATOR_ERROR_LOG_MASK            0x0004   /* 9006 one bit */
>>>> +#define INDICATOR_IDENTIFY_MASK             0x0008   /* 9007 one bit */
>>>> +#define INDICATOR_RESET_MASK                0x0010   /* 9009 one bit */
>>>> +#define INDICATOR_DR_MASK                   0x00e0   /* 9002 three bits */
>>>> +#define INDICATOR_ALLOCATION_MASK           0x0300   /* 9003 two bits */
>>>> +#define INDICATOR_EPOW_MASK                 0x1c00   /* 9 three bits */
>>>> +
>>>> +#define INDICATOR_ISOLATION_SHIFT           0x00     /* bit 0 */
>>>> +#define INDICATOR_GLOBAL_INTERRUPT_SHIFT    0x01     /* bit 1 */
>>>> +#define INDICATOR_ERROR_LOG_SHIFT           0x02     /* bit 2 */
>>>> +#define INDICATOR_IDENTIFY_SHIFT            0x03     /* bit 3 */
>>>> +#define INDICATOR_RESET_SHIFT               0x04     /* bit 4 */
>>>> +#define INDICATOR_DR_SHIFT                  0x05     /* bits 5-7 */
>>>> +#define INDICATOR_ALLOCATION_SHIFT          0x08     /* bits 8-9 */
>>>> +#define INDICATOR_EPOW_SHIFT                0x0a     /* bits 10-12 */
>>>> +
>>>> +#define DECODE_DRC_STATE(state, m, s)                  \
>>>> +    ((((uint32_t)(state) & (uint32_t)(m))) >> (s))
>>>> +
>>>> +#define ENCODE_DRC_STATE(val, m, s) \
>>>> +    (((uint32_t)(val) << (s)) & (uint32_t)(m))
>>>> +
>>>>  static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
>>>>  {
>>>>      sPAPRPHBState *sphb;
>>>> @@ -402,6 +437,80 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
>>>>      rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
>>>>  }
>>>>
>>>> +static void rtas_set_indicator(PowerPCCPU *cpu, sPAPREnvironment *spapr,
>>>> +                               uint32_t token, uint32_t nargs,
>>>> +                               target_ulong args, uint32_t nret,
>>>> +                               target_ulong rets)
>>>> +{
>>>> +    uint32_t indicator = rtas_ld(args, 0);
>>>> +    uint32_t drc_index = rtas_ld(args, 1);
>>>> +    uint32_t indicator_state = rtas_ld(args, 2);
>>>> +    uint32_t encoded = 0, shift = 0, mask = 0;
>>>> +    uint32_t *pind;
>>>> +    sPAPRDrcEntry *drc_entry = NULL;
>>>
>>> This rtas call does not have any idea what a PHB is. Why does it live in
>>> spapr_pci.c?
>>
>> spapr_rtas.c does seem like a better home
>>
>>>
>>>> +
>>>> +    if (drc_index == 0) { /* platform indicator */
>>>> +        pind = &spapr->state;
>>>> +    } else {
>>>> +        drc_entry = spapr_find_drc_entry(drc_index);
>>>> +        if (!drc_entry) {
>>>> +            DPRINTF("rtas_set_indicator: unable to find drc_entry for %x",
>>>> +                    drc_index);
>>>> +            rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
>>>> +            return;
>>>> +        }
>>>> +        pind = &drc_entry->state;
>>>> +    }
>>>> +
>>>> +    switch (indicator) {
>>>> +    case 9:  /* EPOW */
>>>> +        shift = INDICATOR_EPOW_SHIFT;
>>>> +        mask = INDICATOR_EPOW_MASK;
>>>> +        break;
>>>> +    case 9001: /* Isolation state */
>>>> +        /* encode the new value into the correct bit field */
>>>> +        shift = INDICATOR_ISOLATION_SHIFT;
>>>> +        mask = INDICATOR_ISOLATION_MASK;
>>>> +        break;
>>>> +    case 9002: /* DR */
>>>> +        shift = INDICATOR_DR_SHIFT;
>>>> +        mask = INDICATOR_DR_MASK;
>>>> +        break;
>>>> +    case 9003: /* Allocation State */
>>>> +        shift = INDICATOR_ALLOCATION_SHIFT;
>>>> +        mask = INDICATOR_ALLOCATION_MASK;
>>>> +        break;
>>>> +    case 9005: /* global interrupt */
>>>> +        shift = INDICATOR_GLOBAL_INTERRUPT_SHIFT;
>>>> +        mask = INDICATOR_GLOBAL_INTERRUPT_MASK;
>>>> +        break;
>>>> +    case 9006: /* error log */
>>>> +        shift = INDICATOR_ERROR_LOG_SHIFT;
>>>> +        mask = INDICATOR_ERROR_LOG_MASK;
>>>> +        break;
>>>> +    case 9007: /* identify */
>>>> +        shift = INDICATOR_IDENTIFY_SHIFT;
>>>> +        mask = INDICATOR_IDENTIFY_MASK;
>>>> +        break;
>>>> +    case 9009: /* reset */
>>>> +        shift = INDICATOR_RESET_SHIFT;
>>>> +        mask = INDICATOR_RESET_MASK;
>>>> +        break;
>>>> +    default:
>>>> +        DPRINTF("rtas_set_indicator: indicator not implemented: %d",
>>>> +                indicator);
>>>> +        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    encoded = ENCODE_DRC_STATE(indicator_state, mask, shift);
>>>> +    /* clear the current indicator value */
>>>> +    *pind &= ~mask;
>>>> +    /* set the new value */
>>>> +    *pind |= encoded;
>>>> +    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
>>>> +}
>>>> +
>>>>  static int pci_spapr_swizzle(int slot, int pin)
>>>>  {
>>>>      return (slot + pin) % PCI_NUM_PINS;
>>>> @@ -624,6 +733,14 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
>>>>          sphb->lsi_table[i].irq = irq;
>>>>      }
>>>>
>>>> +    /* make sure the platform EPOW sensor is initialized - the
>>>> +     * guest will probe it when there is a hotplug event.
>>>> +     */
>>>> +    spapr->state &= ~(uint32_t)INDICATOR_EPOW_MASK;
>>>> +    spapr->state |= ENCODE_DRC_STATE(0,
>>>> +                                     INDICATOR_EPOW_MASK,
>>>> +                                     INDICATOR_EPOW_SHIFT);
>>>> +
>>>>      if (!info->finish_realize) {
>>>>          error_setg(errp, "finish_realize not defined");
>>>>          return;
>>>> @@ -1056,6 +1173,8 @@ void spapr_pci_rtas_init(void)
>>>>          spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi",
>>>>                              rtas_ibm_change_msi);
>>>>      }
>>>> +    spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
>>>> +                        rtas_set_indicator);
>>>>  }
>>>>
>>>>  static void spapr_pci_register_types(void)
>>>> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
>>>> index 0ac1a19..fac85f8 100644
>>>> --- a/include/hw/ppc/spapr.h
>>>> +++ b/include/hw/ppc/spapr.h
>>>> @@ -72,6 +72,9 @@ typedef struct sPAPREnvironment {
>>>>
>>>>      /* state for Dynamic Reconfiguration Connectors */
>>>>      sPAPRDrcEntry drc_table[SPAPR_DRC_TABLE_SIZE];
>>>> +
>>>> +    /* Platform state - sensors and indicators */
>>>> +    uint32_t state;
>>>
>>> Do you think it'd be possible to create a special DRC device that
>>> contains all of its tables and global state and also exposes sensors and
>>> indicators? That device could then get linked via qom links to the PHBs
>>> for their slots.
>>
>> Sorry for the delay, I've been going back through the code with this
>> suggestion in mind and there does seem to be a lot of state that
>> can be nicely encapsulated by modeling the DR Connectors as a QOM
>> "device" (though I haven't gone as far as to make them actual
>> DeviceState's since it's more of a firmware abstraction than real
>> hardware)
>>
>> I'm not sure what the best way to plumb things together is, as a first
>> run, since each DRC must have a index drc_index as per spec, I've moved
>> put them under /machine/DRConnector as a flat list, where top-level
>> PHB/CPU/MEMORY DRCs would be allocated statically during sPAPR machine
>> init (since the corresponding DRC indexes/types/etc are hard-coded into
>> the top-level of the boot-time DT anyway, though I guess we could also
>> allocate these on the fly...seems messier though than just plugging new
>> resources into existing DRCs)
>>
>> PHB's in turn will associate themselves with a DRC via an attach/detach
>> method as part of realize (and in the future, hotplug hooks, though
>> that's not part of the series). The PHBs in turn will create a DRC for each
>> hotpluggable PCI slot.
>>
>> Creation is via:
>>
>> sPAPRDRConnector *spapr_dr_connector_new(sPAPRDRConnectorType type,
>>                                          uint32_t id);
>>
>> where the code computes the drc index based on <type> (one of phb, cpu, pci,
>> memory, etc) and <id>, and sticks them under /machine/dr-Connector/<drc_index>
>>
>> Any pci/phb/cpu hotplug hooks can then fetch the DRC via type/id,
>> and hotplug/unplug via attach()/detach() methods. attach() adds
>> the attached/hotplugged DeviceState as a link property of the
>> DRC object, and sets the initial sensor state.
>>
>> rtas calls can fetch DRCs via drc_index, and set/get sensor state
>> via DRC sensor get/set methods.
>>
>> Hotplug event delivery still lives outside of DRC implementation for now. I
>> thought of moving them into DRC, but decisions like whether we should
>> emit events during coldplug/initial boot seemed to require pushing
>> a lot of general machine state into DRCs and making the encapsulation
>> seem superficial.
>>
>> Things end up looking like this (2xxxxxxx are PHBs, 4xxxxxxx are PCI slots):
>>
>> mdroth@loki:~/w/qom/machine/dr-connector$ ls
>> 20000000  40000018  40000038  40000058  40000078  40000098  400000b8  400000d8  400000f8
>> 40000000  40000020  40000040  40000060  40000080  400000a0  400000c0  400000e0  type
>> 40000008  40000028  40000048  40000068  40000088  400000a8  400000c8  400000e8
>> 40000010  40000030  40000050  40000070  40000090  400000b0  400000d0  400000f0
>> mdroth@loki:~/w/qom/machine/dr-connector$ cd 40000000/
>> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ ls -l
>> total 0
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 allocation-state
>> lrwxr-xr-x 2 mdroth mdroth 4096 Dec 31  1969 device -> ../../../machine/peripheral/hp0
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 drc-index
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 entity-sense
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 indicator-state
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 isolation-state
>> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 type
>> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat allocation-state
>> 1
>> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat indicator-state
>> 1
>> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat ../../../machine/peripheral/hp0/type
>> virtio-net-pci
>> mdroth@loki:~/w/qom/machine/dr-connector/40000000$
>>
>> Hopefully this is sort of the approach you were thinking of?
>
> This look quite neat so far, looking forward to the patches :).

Michael,

Do you have this code/patches anywhere that I could use ? I have got
the initial working versions of both CPU and memory hotplug now for
sPAPR guests based on top of your old PCI hotplug patchset and it
would be good to rebase them on top of your DR connector device work.

Regards,
Bharata.
Michael Roth Nov. 26, 2014, 6:27 a.m. UTC | #7
Quoting Bharata B Rao (2014-11-25 22:54:12)
> On Wed, Oct 1, 2014 at 8:00 PM, Alexander Graf <agraf@suse.de> wrote:
> >
> >
> > On 01.10.14 00:08, Michael Roth wrote:
> >> Quoting Alexander Graf (2014-08-26 06:36:57)
> >>> On 19.08.14 02:21, Michael Roth wrote:
> >>>> From: Mike Day <ncmike@ncultra.org>
> >>>>
> >>>> Signed-off-by: Mike Day <ncmike@ncultra.org>
> >>>> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> >>>> ---
> >>>>  hw/ppc/spapr_pci.c     | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
> >>>>  include/hw/ppc/spapr.h |   3 ++
> >>>>  2 files changed, 122 insertions(+)
> >>>>
> >>>> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
> >>>> index 924d488..23a3477 100644
> >>>> --- a/hw/ppc/spapr_pci.c
> >>>> +++ b/hw/ppc/spapr_pci.c
> >>>> @@ -36,6 +36,16 @@
> >>>>
> >>>>  #include "hw/pci/pci_bus.h"
> >>>>
> >>>> +/* #define DEBUG_SPAPR */
> >>>> +
> >>>> +#ifdef DEBUG_SPAPR
> >>>> +#define DPRINTF(fmt, ...) \
> >>>> +    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
> >>>> +#else
> >>>> +#define DPRINTF(fmt, ...) \
> >>>> +    do { } while (0)
> >>>> +#endif
> >>>> +
> >>>>  /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
> >>>>  #define RTAS_QUERY_FN           0
> >>>>  #define RTAS_CHANGE_FN          1
> >>>> @@ -47,6 +57,31 @@
> >>>>  #define RTAS_TYPE_MSI           1
> >>>>  #define RTAS_TYPE_MSIX          2
> >>>>
> >>>> +/* For set-indicator RTAS interface */
> >>>> +#define INDICATOR_ISOLATION_MASK            0x0001   /* 9001 one bit */
> >>>> +#define INDICATOR_GLOBAL_INTERRUPT_MASK     0x0002   /* 9005 one bit */
> >>>> +#define INDICATOR_ERROR_LOG_MASK            0x0004   /* 9006 one bit */
> >>>> +#define INDICATOR_IDENTIFY_MASK             0x0008   /* 9007 one bit */
> >>>> +#define INDICATOR_RESET_MASK                0x0010   /* 9009 one bit */
> >>>> +#define INDICATOR_DR_MASK                   0x00e0   /* 9002 three bits */
> >>>> +#define INDICATOR_ALLOCATION_MASK           0x0300   /* 9003 two bits */
> >>>> +#define INDICATOR_EPOW_MASK                 0x1c00   /* 9 three bits */
> >>>> +
> >>>> +#define INDICATOR_ISOLATION_SHIFT           0x00     /* bit 0 */
> >>>> +#define INDICATOR_GLOBAL_INTERRUPT_SHIFT    0x01     /* bit 1 */
> >>>> +#define INDICATOR_ERROR_LOG_SHIFT           0x02     /* bit 2 */
> >>>> +#define INDICATOR_IDENTIFY_SHIFT            0x03     /* bit 3 */
> >>>> +#define INDICATOR_RESET_SHIFT               0x04     /* bit 4 */
> >>>> +#define INDICATOR_DR_SHIFT                  0x05     /* bits 5-7 */
> >>>> +#define INDICATOR_ALLOCATION_SHIFT          0x08     /* bits 8-9 */
> >>>> +#define INDICATOR_EPOW_SHIFT                0x0a     /* bits 10-12 */
> >>>> +
> >>>> +#define DECODE_DRC_STATE(state, m, s)                  \
> >>>> +    ((((uint32_t)(state) & (uint32_t)(m))) >> (s))
> >>>> +
> >>>> +#define ENCODE_DRC_STATE(val, m, s) \
> >>>> +    (((uint32_t)(val) << (s)) & (uint32_t)(m))
> >>>> +
> >>>>  static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
> >>>>  {
> >>>>      sPAPRPHBState *sphb;
> >>>> @@ -402,6 +437,80 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
> >>>>      rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
> >>>>  }
> >>>>
> >>>> +static void rtas_set_indicator(PowerPCCPU *cpu, sPAPREnvironment *spapr,
> >>>> +                               uint32_t token, uint32_t nargs,
> >>>> +                               target_ulong args, uint32_t nret,
> >>>> +                               target_ulong rets)
> >>>> +{
> >>>> +    uint32_t indicator = rtas_ld(args, 0);
> >>>> +    uint32_t drc_index = rtas_ld(args, 1);
> >>>> +    uint32_t indicator_state = rtas_ld(args, 2);
> >>>> +    uint32_t encoded = 0, shift = 0, mask = 0;
> >>>> +    uint32_t *pind;
> >>>> +    sPAPRDrcEntry *drc_entry = NULL;
> >>>
> >>> This rtas call does not have any idea what a PHB is. Why does it live in
> >>> spapr_pci.c?
> >>
> >> spapr_rtas.c does seem like a better home
> >>
> >>>
> >>>> +
> >>>> +    if (drc_index == 0) { /* platform indicator */
> >>>> +        pind = &spapr->state;
> >>>> +    } else {
> >>>> +        drc_entry = spapr_find_drc_entry(drc_index);
> >>>> +        if (!drc_entry) {
> >>>> +            DPRINTF("rtas_set_indicator: unable to find drc_entry for %x",
> >>>> +                    drc_index);
> >>>> +            rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> >>>> +            return;
> >>>> +        }
> >>>> +        pind = &drc_entry->state;
> >>>> +    }
> >>>> +
> >>>> +    switch (indicator) {
> >>>> +    case 9:  /* EPOW */
> >>>> +        shift = INDICATOR_EPOW_SHIFT;
> >>>> +        mask = INDICATOR_EPOW_MASK;
> >>>> +        break;
> >>>> +    case 9001: /* Isolation state */
> >>>> +        /* encode the new value into the correct bit field */
> >>>> +        shift = INDICATOR_ISOLATION_SHIFT;
> >>>> +        mask = INDICATOR_ISOLATION_MASK;
> >>>> +        break;
> >>>> +    case 9002: /* DR */
> >>>> +        shift = INDICATOR_DR_SHIFT;
> >>>> +        mask = INDICATOR_DR_MASK;
> >>>> +        break;
> >>>> +    case 9003: /* Allocation State */
> >>>> +        shift = INDICATOR_ALLOCATION_SHIFT;
> >>>> +        mask = INDICATOR_ALLOCATION_MASK;
> >>>> +        break;
> >>>> +    case 9005: /* global interrupt */
> >>>> +        shift = INDICATOR_GLOBAL_INTERRUPT_SHIFT;
> >>>> +        mask = INDICATOR_GLOBAL_INTERRUPT_MASK;
> >>>> +        break;
> >>>> +    case 9006: /* error log */
> >>>> +        shift = INDICATOR_ERROR_LOG_SHIFT;
> >>>> +        mask = INDICATOR_ERROR_LOG_MASK;
> >>>> +        break;
> >>>> +    case 9007: /* identify */
> >>>> +        shift = INDICATOR_IDENTIFY_SHIFT;
> >>>> +        mask = INDICATOR_IDENTIFY_MASK;
> >>>> +        break;
> >>>> +    case 9009: /* reset */
> >>>> +        shift = INDICATOR_RESET_SHIFT;
> >>>> +        mask = INDICATOR_RESET_MASK;
> >>>> +        break;
> >>>> +    default:
> >>>> +        DPRINTF("rtas_set_indicator: indicator not implemented: %d",
> >>>> +                indicator);
> >>>> +        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
> >>>> +        return;
> >>>> +    }
> >>>> +
> >>>> +    encoded = ENCODE_DRC_STATE(indicator_state, mask, shift);
> >>>> +    /* clear the current indicator value */
> >>>> +    *pind &= ~mask;
> >>>> +    /* set the new value */
> >>>> +    *pind |= encoded;
> >>>> +    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
> >>>> +}
> >>>> +
> >>>>  static int pci_spapr_swizzle(int slot, int pin)
> >>>>  {
> >>>>      return (slot + pin) % PCI_NUM_PINS;
> >>>> @@ -624,6 +733,14 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
> >>>>          sphb->lsi_table[i].irq = irq;
> >>>>      }
> >>>>
> >>>> +    /* make sure the platform EPOW sensor is initialized - the
> >>>> +     * guest will probe it when there is a hotplug event.
> >>>> +     */
> >>>> +    spapr->state &= ~(uint32_t)INDICATOR_EPOW_MASK;
> >>>> +    spapr->state |= ENCODE_DRC_STATE(0,
> >>>> +                                     INDICATOR_EPOW_MASK,
> >>>> +                                     INDICATOR_EPOW_SHIFT);
> >>>> +
> >>>>      if (!info->finish_realize) {
> >>>>          error_setg(errp, "finish_realize not defined");
> >>>>          return;
> >>>> @@ -1056,6 +1173,8 @@ void spapr_pci_rtas_init(void)
> >>>>          spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi",
> >>>>                              rtas_ibm_change_msi);
> >>>>      }
> >>>> +    spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
> >>>> +                        rtas_set_indicator);
> >>>>  }
> >>>>
> >>>>  static void spapr_pci_register_types(void)
> >>>> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> >>>> index 0ac1a19..fac85f8 100644
> >>>> --- a/include/hw/ppc/spapr.h
> >>>> +++ b/include/hw/ppc/spapr.h
> >>>> @@ -72,6 +72,9 @@ typedef struct sPAPREnvironment {
> >>>>
> >>>>      /* state for Dynamic Reconfiguration Connectors */
> >>>>      sPAPRDrcEntry drc_table[SPAPR_DRC_TABLE_SIZE];
> >>>> +
> >>>> +    /* Platform state - sensors and indicators */
> >>>> +    uint32_t state;
> >>>
> >>> Do you think it'd be possible to create a special DRC device that
> >>> contains all of its tables and global state and also exposes sensors and
> >>> indicators? That device could then get linked via qom links to the PHBs
> >>> for their slots.
> >>
> >> Sorry for the delay, I've been going back through the code with this
> >> suggestion in mind and there does seem to be a lot of state that
> >> can be nicely encapsulated by modeling the DR Connectors as a QOM
> >> "device" (though I haven't gone as far as to make them actual
> >> DeviceState's since it's more of a firmware abstraction than real
> >> hardware)
> >>
> >> I'm not sure what the best way to plumb things together is, as a first
> >> run, since each DRC must have a index drc_index as per spec, I've moved
> >> put them under /machine/DRConnector as a flat list, where top-level
> >> PHB/CPU/MEMORY DRCs would be allocated statically during sPAPR machine
> >> init (since the corresponding DRC indexes/types/etc are hard-coded into
> >> the top-level of the boot-time DT anyway, though I guess we could also
> >> allocate these on the fly...seems messier though than just plugging new
> >> resources into existing DRCs)
> >>
> >> PHB's in turn will associate themselves with a DRC via an attach/detach
> >> method as part of realize (and in the future, hotplug hooks, though
> >> that's not part of the series). The PHBs in turn will create a DRC for each
> >> hotpluggable PCI slot.
> >>
> >> Creation is via:
> >>
> >> sPAPRDRConnector *spapr_dr_connector_new(sPAPRDRConnectorType type,
> >>                                          uint32_t id);
> >>
> >> where the code computes the drc index based on <type> (one of phb, cpu, pci,
> >> memory, etc) and <id>, and sticks them under /machine/dr-Connector/<drc_index>
> >>
> >> Any pci/phb/cpu hotplug hooks can then fetch the DRC via type/id,
> >> and hotplug/unplug via attach()/detach() methods. attach() adds
> >> the attached/hotplugged DeviceState as a link property of the
> >> DRC object, and sets the initial sensor state.
> >>
> >> rtas calls can fetch DRCs via drc_index, and set/get sensor state
> >> via DRC sensor get/set methods.
> >>
> >> Hotplug event delivery still lives outside of DRC implementation for now. I
> >> thought of moving them into DRC, but decisions like whether we should
> >> emit events during coldplug/initial boot seemed to require pushing
> >> a lot of general machine state into DRCs and making the encapsulation
> >> seem superficial.
> >>
> >> Things end up looking like this (2xxxxxxx are PHBs, 4xxxxxxx are PCI slots):
> >>
> >> mdroth@loki:~/w/qom/machine/dr-connector$ ls
> >> 20000000  40000018  40000038  40000058  40000078  40000098  400000b8  400000d8  400000f8
> >> 40000000  40000020  40000040  40000060  40000080  400000a0  400000c0  400000e0  type
> >> 40000008  40000028  40000048  40000068  40000088  400000a8  400000c8  400000e8
> >> 40000010  40000030  40000050  40000070  40000090  400000b0  400000d0  400000f0
> >> mdroth@loki:~/w/qom/machine/dr-connector$ cd 40000000/
> >> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ ls -l
> >> total 0
> >> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 allocation-state
> >> lrwxr-xr-x 2 mdroth mdroth 4096 Dec 31  1969 device -> ../../../machine/peripheral/hp0
> >> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 drc-index
> >> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 entity-sense
> >> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 indicator-state
> >> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 isolation-state
> >> -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 type
> >> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat allocation-state
> >> 1
> >> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat indicator-state
> >> 1
> >> mdroth@loki:~/w/qom/machine/dr-connector/40000000$ cat ../../../machine/peripheral/hp0/type
> >> virtio-net-pci
> >> mdroth@loki:~/w/qom/machine/dr-connector/40000000$
> >>
> >> Hopefully this is sort of the approach you were thinking of?
> >
> > This look quite neat so far, looking forward to the patches :).
> 
> Michael,
> 
> Do you have this code/patches anywhere that I could use ? I have got
> the initial working versions of both CPU and memory hotplug now for
> sPAPR guests based on top of your old PCI hotplug patchset and it
> would be good to rebase them on top of your DR connector device work.

Hi Bharata,

Here's the latest branch:

https://github.com/mdroth/qemu/commits/spapr-pci-hotplug-ppc-next-cleanup4.2

The sPAPRDREntry stuff is now modeled by the sPAPRDRConnector QOM object in
hw/ppc/spapr_drc.c, which manages the device's life-cycle based on
rtas-set-sensor-state calls from the guest. As part of qemu-side hotplug/unplug
you use the attach/detach methods of the DRC to associate DT bits and callbacks
for things like device cleanup or rtas calls to fetch a DT node from the device
associated with a particular DRC.

I still need to fix endian issues, and am realizing the dr connectors and DT
bits for PHBs are not actually a prereq for PCI hotplug, so I may be pulling
that out to a separate series specific to enabling PHB hotplug (namely for
VFIO hotplug). I realize your CPU/MEM sort of depend on the top-level PHB
device tree code so I'm not sure how best to deal with that. Worse case we'd
roll the initial code into your series and base a follow-up series on that of
that instead.

Let me know if you have any questions.

> 
> Regards,
> Bharata.
Bharata B Rao Dec. 1, 2014, 4:57 a.m. UTC | #8
On Wed, Nov 26, 2014 at 11:57 AM, Michael Roth
<mdroth@linux.vnet.ibm.com> wrote:
> https://github.com/mdroth/qemu/commits/spapr-pci-hotplug-ppc-next-cleanup4.2
>
> The sPAPRDREntry stuff is now modeled by the sPAPRDRConnector QOM object in
> hw/ppc/spapr_drc.c, which manages the device's life-cycle based on
> rtas-set-sensor-state calls from the guest. As part of qemu-side hotplug/unplug
> you use the attach/detach methods of the DRC to associate DT bits and callbacks
> for things like device cleanup or rtas calls to fetch a DT node from the device
> associated with a particular DRC.
>
> I still need to fix endian issues, and am realizing the dr connectors and DT
> bits for PHBs are not actually a prereq for PCI hotplug, so I may be pulling
> that out to a separate series specific to enabling PHB hotplug (namely for
> VFIO hotplug). I realize your CPU/MEM sort of depend on the top-level PHB
> device tree code so I'm not sure how best to deal with that. Worse case we'd
> roll the initial code into your series and base a follow-up series on that of
> that instead.

Thanks Michael for pointing me to your git tree.

I started rebasing my patchset on top of yours and realized that the
generic DT setup code from the below commits of your branch are needed
for CPU and memory hotplug too. They all apply in the order I  have
listed below.

71b32999c4eb spapr_drc: initial implementation
255c50200848 spapr: populate DRC entries for root dt node (don't need
code that adds PHB DT entries)
408206fc627e3 spapr_rtas: add set-indicator RTAS interface
da7a232fa6a44 spapr_rtas: add get-sensor-state RTAS interface
1c575d5b29688 spapr_rtas: add ibm,configure-connector RTAS interface
0c5d72833666c spapr_events: re-use EPOW event infrastructure for hotplug events
82ee5a9c88155 spapr_events: event-scan RTAS interface

If you can make the above set an independent patchset, it will become
easy to maintain and post CPU and memory hotplug patchsets.

I am facing some endian issues in your patchset and I will send fixes
for those separately.

Regards,
Bharata.
Michael Roth Dec. 23, 2014, 3:12 p.m. UTC | #9
Quoting Bharata B Rao (2014-11-30 22:57:48)
> On Wed, Nov 26, 2014 at 11:57 AM, Michael Roth
> <mdroth@linux.vnet.ibm.com> wrote:
> > https://github.com/mdroth/qemu/commits/spapr-pci-hotplug-ppc-next-cleanup4.2
> >
> > The sPAPRDREntry stuff is now modeled by the sPAPRDRConnector QOM object in
> > hw/ppc/spapr_drc.c, which manages the device's life-cycle based on
> > rtas-set-sensor-state calls from the guest. As part of qemu-side hotplug/unplug
> > you use the attach/detach methods of the DRC to associate DT bits and callbacks
> > for things like device cleanup or rtas calls to fetch a DT node from the device
> > associated with a particular DRC.
> >
> > I still need to fix endian issues, and am realizing the dr connectors and DT
> > bits for PHBs are not actually a prereq for PCI hotplug, so I may be pulling
> > that out to a separate series specific to enabling PHB hotplug (namely for
> > VFIO hotplug). I realize your CPU/MEM sort of depend on the top-level PHB
> > device tree code so I'm not sure how best to deal with that. Worse case we'd
> > roll the initial code into your series and base a follow-up series on that of
> > that instead.
> 
> Thanks Michael for pointing me to your git tree.
> 
> I started rebasing my patchset on top of yours and realized that the
> generic DT setup code from the below commits of your branch are needed
> for CPU and memory hotplug too. They all apply in the order I  have
> listed below.
> 
> 71b32999c4eb spapr_drc: initial implementation
> 255c50200848 spapr: populate DRC entries for root dt node (don't need
> code that adds PHB DT entries)
> 408206fc627e3 spapr_rtas: add set-indicator RTAS interface
> da7a232fa6a44 spapr_rtas: add get-sensor-state RTAS interface
> 1c575d5b29688 spapr_rtas: add ibm,configure-connector RTAS interface
> 0c5d72833666c spapr_events: re-use EPOW event infrastructure for hotplug events
> 82ee5a9c88155 spapr_events: event-scan RTAS interface
> 
> If you can make the above set an independent patchset, it will become
> easy to maintain and post CPU and memory hotplug patchsets.

Hi Bharata,

I've submitted v4 of PCI hotplug. The development branch is here:

  https://github.com/mdroth/qemu/commits/spapr-hotplug-pci

and is based on top of a 'core' branch organized similar to what you proposed:

  https://github.com/mdroth/qemu/commits/spapr-hotplug-core

I'll be rolling changes for core/pci code into the branches as we go.
The endian fixes you provided are included, and PCI hotplug has been
tested on ppc64le.

There's a pseries-2.3 in the core patchset to enable/disable
dynamic-reconfiguration for individual resources on a machine basis to
maintain backward migration compatibility. There's a PHB hotplug patchset
based on core that might be a good reference for re-basing CPU/memory:

  https://github.com/mdroth/qemu/commits/spapr-hotplug-phb


> 
> I am facing some endian issues in your patchset and I will send fixes
> for those separately.
> 
> Regards,
> Bharata.
Bharata B Rao Jan. 1, 2015, 6:35 a.m. UTC | #10
On Tue, Dec 23, 2014 at 8:42 PM, Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
>
> Hi Bharata,
>
> I've submitted v4 of PCI hotplug. The development branch is here:
>
>   https://github.com/mdroth/qemu/commits/spapr-hotplug-pci
>
> and is based on top of a 'core' branch organized similar to what you proposed:
>
>   https://github.com/mdroth/qemu/commits/spapr-hotplug-core
>
> I'll be rolling changes for core/pci code into the branches as we go.
> The endian fixes you provided are included, and PCI hotplug has been
> tested on ppc64le.
>
> There's a pseries-2.3 in the core patchset to enable/disable
> dynamic-reconfiguration for individual resources on a machine basis to
> maintain backward migration compatibility. There's a PHB hotplug patchset
> based on core that might be a good reference for re-basing CPU/memory:
>
>   https://github.com/mdroth/qemu/commits/spapr-hotplug-phb

Thanks Michael for providing the 'core' branch. I shall be posting CPU
and memory hotplug patches based on your 'core' branch shortly.

Regards,
Bharata.
diff mbox

Patch

diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 924d488..23a3477 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -36,6 +36,16 @@ 
 
 #include "hw/pci/pci_bus.h"
 
+/* #define DEBUG_SPAPR */
+
+#ifdef DEBUG_SPAPR
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
 /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
 #define RTAS_QUERY_FN           0
 #define RTAS_CHANGE_FN          1
@@ -47,6 +57,31 @@ 
 #define RTAS_TYPE_MSI           1
 #define RTAS_TYPE_MSIX          2
 
+/* For set-indicator RTAS interface */
+#define INDICATOR_ISOLATION_MASK            0x0001   /* 9001 one bit */
+#define INDICATOR_GLOBAL_INTERRUPT_MASK     0x0002   /* 9005 one bit */
+#define INDICATOR_ERROR_LOG_MASK            0x0004   /* 9006 one bit */
+#define INDICATOR_IDENTIFY_MASK             0x0008   /* 9007 one bit */
+#define INDICATOR_RESET_MASK                0x0010   /* 9009 one bit */
+#define INDICATOR_DR_MASK                   0x00e0   /* 9002 three bits */
+#define INDICATOR_ALLOCATION_MASK           0x0300   /* 9003 two bits */
+#define INDICATOR_EPOW_MASK                 0x1c00   /* 9 three bits */
+
+#define INDICATOR_ISOLATION_SHIFT           0x00     /* bit 0 */
+#define INDICATOR_GLOBAL_INTERRUPT_SHIFT    0x01     /* bit 1 */
+#define INDICATOR_ERROR_LOG_SHIFT           0x02     /* bit 2 */
+#define INDICATOR_IDENTIFY_SHIFT            0x03     /* bit 3 */
+#define INDICATOR_RESET_SHIFT               0x04     /* bit 4 */
+#define INDICATOR_DR_SHIFT                  0x05     /* bits 5-7 */
+#define INDICATOR_ALLOCATION_SHIFT          0x08     /* bits 8-9 */
+#define INDICATOR_EPOW_SHIFT                0x0a     /* bits 10-12 */
+
+#define DECODE_DRC_STATE(state, m, s)                  \
+    ((((uint32_t)(state) & (uint32_t)(m))) >> (s))
+
+#define ENCODE_DRC_STATE(val, m, s) \
+    (((uint32_t)(val) << (s)) & (uint32_t)(m))
+
 static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
 {
     sPAPRPHBState *sphb;
@@ -402,6 +437,80 @@  static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
     rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
 }
 
+static void rtas_set_indicator(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                               uint32_t token, uint32_t nargs,
+                               target_ulong args, uint32_t nret,
+                               target_ulong rets)
+{
+    uint32_t indicator = rtas_ld(args, 0);
+    uint32_t drc_index = rtas_ld(args, 1);
+    uint32_t indicator_state = rtas_ld(args, 2);
+    uint32_t encoded = 0, shift = 0, mask = 0;
+    uint32_t *pind;
+    sPAPRDrcEntry *drc_entry = NULL;
+
+    if (drc_index == 0) { /* platform indicator */
+        pind = &spapr->state;
+    } else {
+        drc_entry = spapr_find_drc_entry(drc_index);
+        if (!drc_entry) {
+            DPRINTF("rtas_set_indicator: unable to find drc_entry for %x",
+                    drc_index);
+            rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+            return;
+        }
+        pind = &drc_entry->state;
+    }
+
+    switch (indicator) {
+    case 9:  /* EPOW */
+        shift = INDICATOR_EPOW_SHIFT;
+        mask = INDICATOR_EPOW_MASK;
+        break;
+    case 9001: /* Isolation state */
+        /* encode the new value into the correct bit field */
+        shift = INDICATOR_ISOLATION_SHIFT;
+        mask = INDICATOR_ISOLATION_MASK;
+        break;
+    case 9002: /* DR */
+        shift = INDICATOR_DR_SHIFT;
+        mask = INDICATOR_DR_MASK;
+        break;
+    case 9003: /* Allocation State */
+        shift = INDICATOR_ALLOCATION_SHIFT;
+        mask = INDICATOR_ALLOCATION_MASK;
+        break;
+    case 9005: /* global interrupt */
+        shift = INDICATOR_GLOBAL_INTERRUPT_SHIFT;
+        mask = INDICATOR_GLOBAL_INTERRUPT_MASK;
+        break;
+    case 9006: /* error log */
+        shift = INDICATOR_ERROR_LOG_SHIFT;
+        mask = INDICATOR_ERROR_LOG_MASK;
+        break;
+    case 9007: /* identify */
+        shift = INDICATOR_IDENTIFY_SHIFT;
+        mask = INDICATOR_IDENTIFY_MASK;
+        break;
+    case 9009: /* reset */
+        shift = INDICATOR_RESET_SHIFT;
+        mask = INDICATOR_RESET_MASK;
+        break;
+    default:
+        DPRINTF("rtas_set_indicator: indicator not implemented: %d",
+                indicator);
+        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+        return;
+    }
+
+    encoded = ENCODE_DRC_STATE(indicator_state, mask, shift);
+    /* clear the current indicator value */
+    *pind &= ~mask;
+    /* set the new value */
+    *pind |= encoded;
+    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
+}
+
 static int pci_spapr_swizzle(int slot, int pin)
 {
     return (slot + pin) % PCI_NUM_PINS;
@@ -624,6 +733,14 @@  static void spapr_phb_realize(DeviceState *dev, Error **errp)
         sphb->lsi_table[i].irq = irq;
     }
 
+    /* make sure the platform EPOW sensor is initialized - the
+     * guest will probe it when there is a hotplug event.
+     */
+    spapr->state &= ~(uint32_t)INDICATOR_EPOW_MASK;
+    spapr->state |= ENCODE_DRC_STATE(0,
+                                     INDICATOR_EPOW_MASK,
+                                     INDICATOR_EPOW_SHIFT);
+
     if (!info->finish_realize) {
         error_setg(errp, "finish_realize not defined");
         return;
@@ -1056,6 +1173,8 @@  void spapr_pci_rtas_init(void)
         spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi",
                             rtas_ibm_change_msi);
     }
+    spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
+                        rtas_set_indicator);
 }
 
 static void spapr_pci_register_types(void)
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 0ac1a19..fac85f8 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -72,6 +72,9 @@  typedef struct sPAPREnvironment {
 
     /* state for Dynamic Reconfiguration Connectors */
     sPAPRDrcEntry drc_table[SPAPR_DRC_TABLE_SIZE];
+
+    /* Platform state - sensors and indicators */
+    uint32_t state;
 } sPAPREnvironment;
 
 #define H_SUCCESS         0