[PATCH 4/4] ppc/pnv: Add OCC FLAG registers

Caleb Schlossin posted 4 patches 1 month, 3 weeks ago
Maintainers: Nicholas Piggin <npiggin@gmail.com>, Aditya Gupta <adityag@linux.ibm.com>, Glenn Miles <milesg@linux.ibm.com>
There is a newer version of this series
[PATCH 4/4] ppc/pnv: Add OCC FLAG registers
Posted by Caleb Schlossin 1 month, 3 weeks ago
OCCFLG are scratch registers that can be shared with OCC firmware.
Log reads and writes to the registers as a reminder when we run
into more OCC code.

Add RW, WO_CLEAR and WO_OR SCOM Type enums in pnv_occ.c

Signed-off-by: Chalapathi V <chalapathi.v@linux.ibm.com>
Signed-off-by: Caleb Schlossin <calebs@linux.ibm.com>
---
 hw/ppc/pnv_occ.c         | 55 +++++++++++++++++++++++++++++++++++++---
 include/hw/ppc/pnv_occ.h |  4 +++
 2 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
index 24b789c191..e605ae0fbc 100644
--- a/hw/ppc/pnv_occ.c
+++ b/hw/ppc/pnv_occ.c
@@ -195,6 +195,49 @@ static const TypeInfo pnv_occ_power8_type_info = {
 #define P9_OCB_OCI_OCCMISC_CLEAR        0x6081
 #define P9_OCB_OCI_OCCMISC_OR           0x6082
 
+/* OCC scratch registers for flag setting */
+#define P9_OCCFLG0                      0x60ac
+#define P9_OCCFLG7_OR                   0x60c3
+
+enum ScomType {
+    SCOM_TYPE_RW          = 0,
+    SCOM_TYPE_WO_CLEAR    = 1,
+    SCOM_TYPE_WO_OR       = 2,
+};
+
+static void rw_occ_flag_regs(PnvOCC *occ, uint32_t offset, bool read,
+        uint64_t *val)
+{
+    int flag_num;
+    int flag_type;
+
+    /*
+     * Each OCCFLG register has SCOM0 - RW, SCOM1 - WO_CLEAR, SCOM2 - WO_OR
+     * hence devide by 3 to get flag index and mod 3 to get SCOM type.
+     */
+    flag_num = (offset - P9_OCCFLG0) / 3;
+    flag_type = (offset - P9_OCCFLG0) % 3;
+
+    if (read) {
+        if (flag_type) {
+            qemu_log_mask(LOG_GUEST_ERROR, "OCC: Write only register: Ox%"
+                      PRIx32 "\n", offset);
+            return;
+        }
+        *val = occ->occflags[flag_num];
+    } else {
+        switch (flag_type) {
+        case SCOM_TYPE_RW:
+            occ->occflags[flag_num] = *val;
+            break;
+        case SCOM_TYPE_WO_CLEAR:
+            occ->occflags[flag_num] &= ~(*val);
+            break;
+        case SCOM_TYPE_WO_OR:
+            occ->occflags[flag_num] |= *val;
+        }
+    }
+}
 
 static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
                                           unsigned size)
@@ -207,8 +250,11 @@ static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
     case P9_OCB_OCI_OCCMISC:
         val = occ->occmisc;
         break;
+    case P9_OCCFLG0 ... P9_OCCFLG7_OR:
+        rw_occ_flag_regs(occ, offset, 1, &val);
+        break;
     default:
-        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
+        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register read: Ox%"
                       HWADDR_PRIx "\n", addr >> 3);
     }
     return val;
@@ -229,9 +275,12 @@ static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr,
         break;
     case P9_OCB_OCI_OCCMISC:
         pnv_occ_set_misc(occ, val);
-       break;
+        break;
+    case P9_OCCFLG0 ... P9_OCCFLG7_OR:
+        rw_occ_flag_regs(occ, offset, 0, &val);
+        break;
     default:
-        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
+        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register write: Ox%"
                       HWADDR_PRIx "\n", addr >> 3);
     }
 }
diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h
index 013ea2e53e..8c9f1416eb 100644
--- a/include/hw/ppc/pnv_occ.h
+++ b/include/hw/ppc/pnv_occ.h
@@ -47,6 +47,10 @@ struct PnvOCC {
     /* OCC Misc interrupt */
     uint64_t occmisc;
 
+    /* OCC Flags */
+#define NR_FLAG_REGS 8
+    uint32_t occflags[NR_FLAG_REGS];
+
     qemu_irq psi_irq;
 
     /* OCCs operate on regions of HOMER memory */
-- 
2.47.3
Re: [PATCH 4/4] ppc/pnv: Add OCC FLAG registers
Posted by Aditya Gupta 2 weeks, 1 day ago
On 25/12/18 02:03PM, Caleb Schlossin wrote:
> OCCFLG are scratch registers that can be shared with OCC firmware.
> Log reads and writes to the registers as a reminder when we run
> into more OCC code.
> 
> Add RW, WO_CLEAR and WO_OR SCOM Type enums in pnv_occ.c
> 
> Signed-off-by: Chalapathi V <chalapathi.v@linux.ibm.com>
> Signed-off-by: Caleb Schlossin <calebs@linux.ibm.com>
> ---
>  hw/ppc/pnv_occ.c         | 55 +++++++++++++++++++++++++++++++++++++---
>  include/hw/ppc/pnv_occ.h |  4 +++
>  2 files changed, 56 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
> index 24b789c191..e605ae0fbc 100644
> --- a/hw/ppc/pnv_occ.c
> +++ b/hw/ppc/pnv_occ.c
> @@ -195,6 +195,49 @@ static const TypeInfo pnv_occ_power8_type_info = {
>  #define P9_OCB_OCI_OCCMISC_CLEAR        0x6081
>  #define P9_OCB_OCI_OCCMISC_OR           0x6082
>  
> +/* OCC scratch registers for flag setting */
> +#define P9_OCCFLG0                      0x60ac
> +#define P9_OCCFLG7_OR                   0x60c3
> +
> +enum ScomType {
> +    SCOM_TYPE_RW          = 0,
> +    SCOM_TYPE_WO_CLEAR    = 1,
> +    SCOM_TYPE_WO_OR       = 2,
> +};
> +
> +static void rw_occ_flag_regs(PnvOCC *occ, uint32_t offset, bool read,
> +        uint64_t *val)
> +{
> +    int flag_num;
> +    int flag_type;
> +
> +    /*
> +     * Each OCCFLG register has SCOM0 - RW, SCOM1 - WO_CLEAR, SCOM2 - WO_OR
> +     * hence devide by 3 to get flag index and mod 3 to get SCOM type.

nitpick: s/devide/divide

> +     */
> +    flag_num = (offset - P9_OCCFLG0) / 3;
> +    flag_type = (offset - P9_OCCFLG0) % 3;

flag_num can be negative if offset is invalid, but since the function
is static, the current usage ensure that never happens. So, it's okay
with me.

Reviewed-by: Aditya Gupta <adityag@linux.ibm.com>

Thanks,
- Aditya G
Re: [PATCH 4/4] ppc/pnv: Add OCC FLAG registers
Posted by Miles Glenn 1 month ago
Reviewed-by: Glenn Miles <milesg@linux.ibm.com>

Thanks,

Glenn

On Thu, 2025-12-18 at 14:03 -0600, Caleb Schlossin wrote:
> OCCFLG are scratch registers that can be shared with OCC firmware.
> Log reads and writes to the registers as a reminder when we run
> into more OCC code.
> 
> Add RW, WO_CLEAR and WO_OR SCOM Type enums in pnv_occ.c
> 
> Signed-off-by: Chalapathi V <chalapathi.v@linux.ibm.com>
> Signed-off-by: Caleb Schlossin <calebs@linux.ibm.com>
> ---
>  hw/ppc/pnv_occ.c         | 55 +++++++++++++++++++++++++++++++++++++---
>  include/hw/ppc/pnv_occ.h |  4 +++
>  2 files changed, 56 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
> index 24b789c191..e605ae0fbc 100644
> --- a/hw/ppc/pnv_occ.c
> +++ b/hw/ppc/pnv_occ.c
> @@ -195,6 +195,49 @@ static const TypeInfo pnv_occ_power8_type_info = {
>  #define P9_OCB_OCI_OCCMISC_CLEAR        0x6081
>  #define P9_OCB_OCI_OCCMISC_OR           0x6082
>  
> +/* OCC scratch registers for flag setting */
> +#define P9_OCCFLG0                      0x60ac
> +#define P9_OCCFLG7_OR                   0x60c3
> +
> +enum ScomType {
> +    SCOM_TYPE_RW          = 0,
> +    SCOM_TYPE_WO_CLEAR    = 1,
> +    SCOM_TYPE_WO_OR       = 2,
> +};
> +
> +static void rw_occ_flag_regs(PnvOCC *occ, uint32_t offset, bool read,
> +        uint64_t *val)
> +{
> +    int flag_num;
> +    int flag_type;
> +
> +    /*
> +     * Each OCCFLG register has SCOM0 - RW, SCOM1 - WO_CLEAR, SCOM2 - WO_OR
> +     * hence devide by 3 to get flag index and mod 3 to get SCOM type.
> +     */
> +    flag_num = (offset - P9_OCCFLG0) / 3;
> +    flag_type = (offset - P9_OCCFLG0) % 3;
> +
> +    if (read) {
> +        if (flag_type) {
> +            qemu_log_mask(LOG_GUEST_ERROR, "OCC: Write only register: Ox%"
> +                      PRIx32 "\n", offset);
> +            return;
> +        }
> +        *val = occ->occflags[flag_num];
> +    } else {
> +        switch (flag_type) {
> +        case SCOM_TYPE_RW:
> +            occ->occflags[flag_num] = *val;
> +            break;
> +        case SCOM_TYPE_WO_CLEAR:
> +            occ->occflags[flag_num] &= ~(*val);
> +            break;
> +        case SCOM_TYPE_WO_OR:
> +            occ->occflags[flag_num] |= *val;
> +        }
> +    }
> +}
>  
>  static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
>                                            unsigned size)
> @@ -207,8 +250,11 @@ static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
>      case P9_OCB_OCI_OCCMISC:
>          val = occ->occmisc;
>          break;
> +    case P9_OCCFLG0 ... P9_OCCFLG7_OR:
> +        rw_occ_flag_regs(occ, offset, 1, &val);
> +        break;
>      default:
> -        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
> +        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register read: Ox%"
>                        HWADDR_PRIx "\n", addr >> 3);
>      }
>      return val;
> @@ -229,9 +275,12 @@ static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr,
>          break;
>      case P9_OCB_OCI_OCCMISC:
>          pnv_occ_set_misc(occ, val);
> -       break;
> +        break;
> +    case P9_OCCFLG0 ... P9_OCCFLG7_OR:
> +        rw_occ_flag_regs(occ, offset, 0, &val);
> +        break;
>      default:
> -        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
> +        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register write: Ox%"
>                        HWADDR_PRIx "\n", addr >> 3);
>      }
>  }
> diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h
> index 013ea2e53e..8c9f1416eb 100644
> --- a/include/hw/ppc/pnv_occ.h
> +++ b/include/hw/ppc/pnv_occ.h
> @@ -47,6 +47,10 @@ struct PnvOCC {
>      /* OCC Misc interrupt */
>      uint64_t occmisc;
>  
> +    /* OCC Flags */
> +#define NR_FLAG_REGS 8
> +    uint32_t occflags[NR_FLAG_REGS];
> +
>      qemu_irq psi_irq;
>  
>      /* OCCs operate on regions of HOMER memory */
Re: [PATCH 4/4] ppc/pnv: Add OCC FLAG registers
Posted by Chalapathi V 1 month, 2 weeks ago
Reviewed-by: Chalapathi V <chalapathi.v@linux.ibm.com 
<mailto:milesg@linux.ibm.com>


On 19/12/25 1:33 am, Caleb Schlossin wrote:
> OCCFLG are scratch registers that can be shared with OCC firmware.
> Log reads and writes to the registers as a reminder when we run
> into more OCC code.
>
> Add RW, WO_CLEAR and WO_OR SCOM Type enums in pnv_occ.c
>
> Signed-off-by: Chalapathi V<chalapathi.v@linux.ibm.com>
> Signed-off-by: Caleb Schlossin<calebs@linux.ibm.com>
> ---
>   hw/ppc/pnv_occ.c         | 55 +++++++++++++++++++++++++++++++++++++---
>   include/hw/ppc/pnv_occ.h |  4 +++
>   2 files changed, 56 insertions(+), 3 deletions(-)
>
> diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
> index 24b789c191..e605ae0fbc 100644
> --- a/hw/ppc/pnv_occ.c
> +++ b/hw/ppc/pnv_occ.c
> @@ -195,6 +195,49 @@ static const TypeInfo pnv_occ_power8_type_info = {
>   #define P9_OCB_OCI_OCCMISC_CLEAR        0x6081
>   #define P9_OCB_OCI_OCCMISC_OR           0x6082
>   
> +/* OCC scratch registers for flag setting */
> +#define P9_OCCFLG0                      0x60ac
> +#define P9_OCCFLG7_OR                   0x60c3
> +
> +enum ScomType {
> +    SCOM_TYPE_RW          = 0,
> +    SCOM_TYPE_WO_CLEAR    = 1,
> +    SCOM_TYPE_WO_OR       = 2,
> +};
> +
> +static void rw_occ_flag_regs(PnvOCC *occ, uint32_t offset, bool read,
> +        uint64_t *val)
> +{
> +    int flag_num;
> +    int flag_type;
> +
> +    /*
> +     * Each OCCFLG register has SCOM0 - RW, SCOM1 - WO_CLEAR, SCOM2 - WO_OR
> +     * hence devide by 3 to get flag index and mod 3 to get SCOM type.
> +     */
> +    flag_num = (offset - P9_OCCFLG0) / 3;
> +    flag_type = (offset - P9_OCCFLG0) % 3;
> +
> +    if (read) {
> +        if (flag_type) {
> +            qemu_log_mask(LOG_GUEST_ERROR, "OCC: Write only register: Ox%"
> +                      PRIx32 "\n", offset);
> +            return;
> +        }
> +        *val = occ->occflags[flag_num];
> +    } else {
> +        switch (flag_type) {
> +        case SCOM_TYPE_RW:
> +            occ->occflags[flag_num] = *val;
> +            break;
> +        case SCOM_TYPE_WO_CLEAR:
> +            occ->occflags[flag_num] &= ~(*val);
> +            break;
> +        case SCOM_TYPE_WO_OR:
> +            occ->occflags[flag_num] |= *val;
> +        }
> +    }
> +}
>   
>   static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
>                                             unsigned size)
> @@ -207,8 +250,11 @@ static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
>       case P9_OCB_OCI_OCCMISC:
>           val = occ->occmisc;
>           break;
> +    case P9_OCCFLG0 ... P9_OCCFLG7_OR:
> +        rw_occ_flag_regs(occ, offset, 1, &val);
> +        break;
>       default:
> -        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
> +        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register read: Ox%"
>                         HWADDR_PRIx "\n", addr >> 3);
>       }
>       return val;
> @@ -229,9 +275,12 @@ static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr,
>           break;
>       case P9_OCB_OCI_OCCMISC:
>           pnv_occ_set_misc(occ, val);
> -       break;
> +        break;
> +    case P9_OCCFLG0 ... P9_OCCFLG7_OR:
> +        rw_occ_flag_regs(occ, offset, 0, &val);
> +        break;
>       default:
> -        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
> +        qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register write: Ox%"
>                         HWADDR_PRIx "\n", addr >> 3);
>       }
>   }
> diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h
> index 013ea2e53e..8c9f1416eb 100644
> --- a/include/hw/ppc/pnv_occ.h
> +++ b/include/hw/ppc/pnv_occ.h
> @@ -47,6 +47,10 @@ struct PnvOCC {
>       /* OCC Misc interrupt */
>       uint64_t occmisc;
>   
> +    /* OCC Flags */
> +#define NR_FLAG_REGS 8
> +    uint32_t occflags[NR_FLAG_REGS];
> +
>       qemu_irq psi_irq;
>   
>       /* OCCs operate on regions of HOMER memory */