[Skiboot] [PATCH] Add P9 DIO interrupt support

Oliver oohall at gmail.com
Wed Jan 16 11:02:38 AEDT 2019


On Tue, Jan 15, 2019 at 8:33 PM Lei YU <mine260309 at gmail.com> wrote:
>
> On P9 there are GPIO port 0, 1, 2 for GPIO interrupt, and DIO interrupt
> is used to handle the interrupts.
>
> Add support to the DIO interrupts:
> 1. Add dio_interrupt_register(port, callback) to register the interrupt;
> 2. Add dio_interrupt_deregister(port, callback) to deregister;
> 3. When interrupt on the port occurs, callback is invoked, and the
>    interrupt status is cleared.
>
> Signed-off-by: Lei YU <mine260309 at gmail.com>
> ---
>  hw/Makefile.inc         |   2 +-
>  hw/dio-p9.c             | 123 ++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/psi.c                |   2 +
>  include/dio-p9.h        |  36 ++++++++++++++
>  include/xscom-p9-regs.h |   5 +-
>  5 files changed, 166 insertions(+), 2 deletions(-)
>  create mode 100644 hw/dio-p9.c
>  create mode 100644 include/dio-p9.h
>
> diff --git a/hw/Makefile.inc b/hw/Makefile.inc
> index 005772a..e9fdb4c 100644
> --- a/hw/Makefile.inc
> +++ b/hw/Makefile.inc
> @@ -9,7 +9,7 @@ HW_OBJS += dts.o lpc-rtc.o npu.o npu-hw-procedures.o xive.o phb4.o
>  HW_OBJS += fake-nvram.o lpc-mbox.o npu2.o npu2-hw-procedures.o
>  HW_OBJS += npu2-common.o phys-map.o sbe-p9.o capp.o occ-sensor.o vas.o
>  HW_OBJS += npu2-common.o npu2-opencapi.o phys-map.o sbe-p9.o capp.o occ-sensor.o
> -HW_OBJS += vas.o sbe-p8.o
> +HW_OBJS += vas.o sbe-p8.o dio-p9.o
>  HW=hw/built-in.a
>
>  include $(SRC)/hw/fsp/Makefile.inc
> diff --git a/hw/dio-p9.c b/hw/dio-p9.c
> new file mode 100644
> index 0000000..1b8b1d7
> --- /dev/null
> +++ b/hw/dio-p9.c
> @@ -0,0 +1,123 @@
> +/* Copyright 2019 IBM Corp.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> + * implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +
> +#define pr_fmt(fmt) "DIO: " fmt
> +
> +#include <chip.h>
> +#include <dio-p9.h>
> +#include <opal.h>
> +#include <xscom.h>
> +#include <xscom-p9-regs.h>
> +
> +#define NUM_OF_PORTS   3 /* P9 has GPIO port 0~2 for interrupts */
> +
> +static dio_interrupt_callback callbacks[NUM_OF_PORTS];
> +
> +int dio_interrupt_register(int port, dio_interrupt_callback callback)
> +{
> +       struct proc_chip *chip;
> +       u64 val;
> +       int rc;
> +
> +       if (port < 0 || port >= NUM_OF_PORTS)
> +               return OPAL_PARAMETER;
> +
> +       if (callbacks[port]) /* This port already has a callback */
> +               return OPAL_PARAMETER;
> +
> +       chip = next_chip(NULL);

The chip should probably be passed in as a function parameter. I could
see people being interested in using the GPIOs on the 2nd chip too.
You'll need to move the callback array into a per-chip structure too.

Looks fine otherwise.

> +       rc = xscom_read(chip->id, P9_GPIO_INTERRUPT_ENABLE, &val);
> +       if (rc != OPAL_SUCCESS) {
> +               prlog(PR_ERR, "XSCOM error %d reading reg 0x%llx\n",
> +                               rc, P9_GPIO_INTERRUPT_ENABLE);
> +               return OPAL_HARDWARE;
> +       }
> +
> +       val |= PPC_BIT(port);
> +       rc = xscom_write(chip->id, P9_GPIO_INTERRUPT_ENABLE, val);
> +       if (rc != OPAL_SUCCESS) {
> +               prlog(PR_ERR, "XSCOM error %d writing reg 0x%llx\n",
> +                               rc, P9_GPIO_INTERRUPT_ENABLE);
> +               return OPAL_HARDWARE;
> +       }
> +
> +       callbacks[port] = callback;
> +
> +       return OPAL_SUCCESS;
> +}
> +
> +int dio_interrupt_deregister(int port, dio_interrupt_callback callback)
> +{
> +       struct proc_chip *chip;
> +       u64 val;
> +       int rc;
> +
> +       if (port < 0 || port >= NUM_OF_PORTS)
> +               return OPAL_PARAMETER;
> +
> +       if (callbacks[port] != callback)
> +               return OPAL_PARAMETER;
> +
> +       chip = next_chip(NULL);
> +
> +       rc = xscom_read(chip->id, P9_GPIO_INTERRUPT_ENABLE, &val);
> +       if (rc != OPAL_SUCCESS) {
> +               prlog(PR_ERR, "XSCOM error %d reading reg 0x%llx\n",
> +                               rc, P9_GPIO_INTERRUPT_ENABLE);
> +               return OPAL_HARDWARE;
> +       }
> +
> +       val &= ~PPC_BIT(port);
> +       rc = xscom_write(chip->id, P9_GPIO_INTERRUPT_ENABLE, val);
> +       if (rc != OPAL_SUCCESS) {
> +               prlog(PR_ERR, "XSCOM error %d writing reg 0x%llx\n",
> +                               rc, P9_GPIO_INTERRUPT_ENABLE);
> +               return OPAL_HARDWARE;
> +       }
> +
> +       callbacks[port] = NULL;
> +
> +       return OPAL_SUCCESS;
> +}
> +
> +void dio_interrupt_handler(void)
> +{
> +       struct proc_chip *chip;
> +       u64 val;
> +       int rc;
> +       int i;
> +
> +       chip = next_chip(NULL);
> +       rc = xscom_read(chip->id, P9_GPIO_INTERRUPT_STATUS, &val);
> +       if (rc != OPAL_SUCCESS) {
> +               prlog(PR_ERR, "XSCOM error %d reading reg 0x%llx\n",
> +                               rc, P9_GPIO_INTERRUPT_STATUS);
> +               return;
> +       }
> +
> +       for (i = 0; i < NUM_OF_PORTS; ++i) {
> +               if (val & PPC_BIT(i)) {
> +                       if (callbacks[i])
> +                               callbacks[i]();
> +                       else
> +                               prlog(PR_ERR, "DIO interrupt triggerd on port %d but no handler\n", i);
> +                       /* Write 1 to clear the interrupt status */
> +                       xscom_write(chip->id, P9_GPIO_INTERRUPT_CONDITION, val & PPC_BIT(i));
> +               }
> +       }
> +}
> diff --git a/hw/psi.c b/hw/psi.c
> index cbdbeaa..074f283 100644
> --- a/hw/psi.c
> +++ b/hw/psi.c
> @@ -24,6 +24,7 @@
>  #include <gx.h>
>  #include <interrupts.h>
>  #include <cpu.h>
> +#include <dio-p9.h>
>  #include <trace.h>
>  #include <xscom.h>
>  #include <chip.h>
> @@ -604,6 +605,7 @@ static void psihb_p9_interrupt(struct irq_source *is, uint32_t isn)
>                 break;
>         case P9_PSI_IRQ_DIO:
>                 printf("PSI: DIO irq received\n");
> +               dio_interrupt_handler();
>                 break;
>         case P9_PSI_IRQ_PSU:
>                 p9_sbe_interrupt(psi->chip_id);
> diff --git a/include/dio-p9.h b/include/dio-p9.h
> new file mode 100644
> index 0000000..50d6f2a
> --- /dev/null
> +++ b/include/dio-p9.h
> @@ -0,0 +1,36 @@
> +
> +/* Copyright 2019 IBM Corp.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> + * implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#ifndef __DIO_H
> +#define __DIO_H
> +
> +/* The function typedef for dio interrupt callback */
> +typedef void (*dio_interrupt_callback)(void);
> +
> +/* Register dio interrupt on GPIO port.
> + * This effectively enables the DIO interrupt on the GPIO port,
> + * and callback will be called when the interrupt is triggered */
> +extern int dio_interrupt_register(int port, dio_interrupt_callback c);
> +
> +/* Deregister dio interrupt on GPIO port.
> + * This effectively disables the DIO interrupt on the GPIO port. */
> +extern int dio_interrupt_deregister(int port, dio_interrupt_callback c);
> +
> +/* The function to be called when DIO interrupt is triggered */
> +extern void dio_interrupt_handler(void);
> +
> +#endif /* __DIO_H */
> diff --git a/include/xscom-p9-regs.h b/include/xscom-p9-regs.h
> index 42dd426..d47c222 100644
> --- a/include/xscom-p9-regs.h
> +++ b/include/xscom-p9-regs.h
> @@ -18,8 +18,11 @@
>  #define P9X_EX_NCU_DARN_BAR                    0x11011
>  #define  P9X_EX_NCU_DARN_BAR_EN                        PPC_BIT(0)
>
> -#define P9_GPIO_DATA_OUT_ENABLE                        0x00000000000B0054ull
>  #define P9_GPIO_DATA_OUT                       0x00000000000B0051ull
> +#define P9_GPIO_DATA_OUT_ENABLE                        0x00000000000B0054ull
> +#define P9_GPIO_INTERRUPT_STATUS               0x00000000000B0057ull
> +#define P9_GPIO_INTERRUPT_ENABLE               0x00000000000B005Dull
> +#define P9_GPIO_INTERRUPT_CONDITION            0x00000000000B005Eull
>
>  /* xscom address for SCOM Control and data Register */
>  /* bits 54:60 of SCOM SPRC register is used for core specific SPR selection. */
> --
> 2.7.4
>


More information about the Skiboot mailing list