All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dan Williams <dan.j.williams@intel.com>
To: "Alastair D'Silva" <alastair@d-silva.org>
Cc: "Aneesh Kumar K . V" <aneesh.kumar@linux.ibm.com>,
	"Benjamin Herrenschmidt" <benh@kernel.crashing.org>,
	"Paul Mackerras" <paulus@samba.org>,
	"Michael Ellerman" <mpe@ellerman.id.au>,
	"Frederic Barrat" <fbarrat@linux.ibm.com>,
	"Andrew Donnellan" <ajd@linux.ibm.com>,
	"Arnd Bergmann" <arnd@arndb.de>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Mauro Carvalho Chehab" <mchehab+samsung@kernel.org>,
	"David S. Miller" <davem@davemloft.net>,
	"Rob Herring" <robh@kernel.org>,
	"Anton Blanchard" <anton@ozlabs.org>,
	"Krzysztof Kozlowski" <krzk@kernel.org>,
	"Mahesh Salgaonkar" <mahesh@linux.vnet.ibm.com>,
	"Madhavan Srinivasan" <maddy@linux.vnet.ibm.com>,
	"Cédric Le Goater" <clg@kaod.org>,
	"Anju T Sudhakar" <anju@linux.vnet.ibm.com>,
	"Hari Bathini" <hbathini@linux.ibm.com>,
	"Thomas Gleixner" <tglx@linutronix.de>,
	"Greg Kurz" <groug@kaod.org>,
	"Nicholas Piggin" <npiggin@gmail.com>,
	"Masahiro Yamada" <yamada.masahiro@socionext.com>,
	"Alexey Kardashevskiy" <aik@ozlabs.ru>,
	"Linux Kernel Mailing List" <linux-kernel@vger.kernel.org>,
	linuxppc-dev <linuxppc-dev@lists.ozlabs.org>,
	linux-nvdimm <linux-nvdimm@lists.01.org>,
	"Linux MM" <linux-mm@kvack.org>
Subject: Re: [PATCH v4 19/25] nvdimm/ocxl: Forward events to userspace
Date: Wed, 1 Apr 2020 19:08:08 -0700	[thread overview]
Message-ID: <CAPcyv4gfDAbABq9wxKd05AWTduDy2udBXS4Y6qcWyUzOBv-xTg@mail.gmail.com> (raw)
In-Reply-To: <20200327071202.2159885-20-alastair@d-silva.org>

On Tue, Mar 31, 2020 at 1:59 AM Alastair D'Silva <alastair@d-silva.org> wrote:
>
> Some of the interrupts that the card generates are better handled
> by the userspace daemon, in particular:
> Controller Hardware/Firmware Fatal
> Controller Dump Available
> Error Log available
>
> This patch allows a userspace application to register an eventfd with
> the driver via SCM_IOCTL_EVENTFD to receive notifications of these
> interrupts.
>
> Userspace can then identify what events have occurred by calling
> SCM_IOCTL_EVENT_CHECK and checking against the SCM_IOCTL_EVENT_FOO
> masks.

The amount new ioctl's in this driver is too high, it seems much of
this data can be exported via sysfs attributes which are more
maintainable that ioctls. Then sysfs also has the ability to signal
events on sysfs attributes, see sys_notify_dirent.

Can you step back and review the ABI exposure of the driver and what
can be moved to sysfs? If you need to have bus specific attributes
ordered underneath the libnvdimm generic attributes you can create a
sysfs attribute subdirectory.

In general a roadmap document of all the proposed ABI is needed to
make sure it is both sufficient and necessary. See the libnvdimm
document that introduced the initial libnvdimm ABI:

https://www.kernel.org/doc/Documentation/nvdimm/nvdimm.txt

>
> Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> ---
>  drivers/nvdimm/ocxl/main.c     | 220 +++++++++++++++++++++++++++++++++
>  drivers/nvdimm/ocxl/ocxlpmem.h |   4 +
>  include/uapi/nvdimm/ocxlpmem.h |  12 ++
>  3 files changed, 236 insertions(+)
>
> diff --git a/drivers/nvdimm/ocxl/main.c b/drivers/nvdimm/ocxl/main.c
> index 0040fc09cceb..cb6cdc9eb899 100644
> --- a/drivers/nvdimm/ocxl/main.c
> +++ b/drivers/nvdimm/ocxl/main.c
> @@ -10,6 +10,7 @@
>  #include <misc/ocxl.h>
>  #include <linux/delay.h>
>  #include <linux/ndctl.h>
> +#include <linux/eventfd.h>
>  #include <linux/fs.h>
>  #include <linux/mm_types.h>
>  #include <linux/memory_hotplug.h>
> @@ -301,8 +302,19 @@ static void free_ocxlpmem(struct ocxlpmem *ocxlpmem)
>  {
>         int rc;
>
> +       // Disable doorbells
> +       (void)ocxl_global_mmio_set64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_CHIEC,
> +                                    OCXL_LITTLE_ENDIAN,
> +                                    GLOBAL_MMIO_CHI_ALL);
> +
>         free_minor(ocxlpmem);
>
> +       if (ocxlpmem->irq_addr[1])
> +               iounmap(ocxlpmem->irq_addr[1]);
> +
> +       if (ocxlpmem->irq_addr[0])
> +               iounmap(ocxlpmem->irq_addr[0]);
> +
>         if (ocxlpmem->ocxl_context) {
>                 rc = ocxl_context_detach(ocxlpmem->ocxl_context);
>                 if (rc == -EBUSY)
> @@ -398,6 +410,11 @@ static int file_release(struct inode *inode, struct file *file)
>  {
>         struct ocxlpmem *ocxlpmem = file->private_data;
>
> +       if (ocxlpmem->ev_ctx) {
> +               eventfd_ctx_put(ocxlpmem->ev_ctx);
> +               ocxlpmem->ev_ctx = NULL;
> +       }
> +
>         ocxlpmem_put(ocxlpmem);
>         return 0;
>  }
> @@ -928,6 +945,52 @@ static int ioctl_controller_stats(struct ocxlpmem *ocxlpmem,
>         return rc;
>  }
>
> +static int ioctl_eventfd(struct ocxlpmem *ocxlpmem,
> +                        struct ioctl_ocxlpmem_eventfd __user *uarg)
> +{
> +       struct ioctl_ocxlpmem_eventfd args;
> +
> +       if (copy_from_user(&args, uarg, sizeof(args)))
> +               return -EFAULT;
> +
> +       if (ocxlpmem->ev_ctx)
> +               return -EBUSY;
> +
> +       ocxlpmem->ev_ctx = eventfd_ctx_fdget(args.eventfd);
> +       if (IS_ERR(ocxlpmem->ev_ctx))
> +               return PTR_ERR(ocxlpmem->ev_ctx);
> +
> +       return 0;
> +}
> +
> +static int ioctl_event_check(struct ocxlpmem *ocxlpmem, u64 __user *uarg)
> +{
> +       u64 val = 0;
> +       int rc;
> +       u64 chi = 0;
> +
> +       rc = ocxlpmem_chi(ocxlpmem, &chi);
> +       if (rc < 0)
> +               return rc;
> +
> +       if (chi & GLOBAL_MMIO_CHI_ELA)
> +               val |= IOCTL_OCXLPMEM_EVENT_ERROR_LOG_AVAILABLE;
> +
> +       if (chi & GLOBAL_MMIO_CHI_CDA)
> +               val |= IOCTL_OCXLPMEM_EVENT_CONTROLLER_DUMP_AVAILABLE;
> +
> +       if (chi & GLOBAL_MMIO_CHI_CFFS)
> +               val |= IOCTL_OCXLPMEM_EVENT_FIRMWARE_FATAL;
> +
> +       if (chi & GLOBAL_MMIO_CHI_CHFS)
> +               val |= IOCTL_OCXLPMEM_EVENT_HARDWARE_FATAL;
> +
> +       if (copy_to_user((u64 __user *)uarg, &val, sizeof(val)))
> +               return -EFAULT;
> +
> +       return rc;
> +}
> +
>  static long file_ioctl(struct file *file, unsigned int cmd, unsigned long args)
>  {
>         struct ocxlpmem *ocxlpmem = file->private_data;
> @@ -956,6 +1019,15 @@ static long file_ioctl(struct file *file, unsigned int cmd, unsigned long args)
>                 rc = ioctl_controller_stats(ocxlpmem,
>                                             (struct ioctl_ocxlpmem_controller_stats __user *)args);
>                 break;
> +
> +       case IOCTL_OCXLPMEM_EVENTFD:
> +               rc = ioctl_eventfd(ocxlpmem,
> +                                  (struct ioctl_ocxlpmem_eventfd __user *)args);
> +               break;
> +
> +       case IOCTL_OCXLPMEM_EVENT_CHECK:
> +               rc = ioctl_event_check(ocxlpmem, (u64 __user *)args);
> +               break;
>         }
>
>         return rc;
> @@ -1109,6 +1181,148 @@ static void dump_error_log(struct ocxlpmem *ocxlpmem)
>         kfree(buf);
>  }
>
> +static irqreturn_t imn0_handler(void *private)
> +{
> +       struct ocxlpmem *ocxlpmem = private;
> +       u64 chi = 0;
> +
> +       (void)ocxlpmem_chi(ocxlpmem, &chi);
> +
> +       if (chi & GLOBAL_MMIO_CHI_ELA) {
> +               dev_warn(&ocxlpmem->dev, "Error log is available\n");
> +
> +               if (ocxlpmem->ev_ctx)
> +                       eventfd_signal(ocxlpmem->ev_ctx, 1);
> +       }
> +
> +       if (chi & GLOBAL_MMIO_CHI_CDA) {
> +               dev_warn(&ocxlpmem->dev, "Controller dump is available\n");
> +
> +               if (ocxlpmem->ev_ctx)
> +                       eventfd_signal(ocxlpmem->ev_ctx, 1);
> +       }
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t imn1_handler(void *private)
> +{
> +       struct ocxlpmem *ocxlpmem = private;
> +       u64 chi = 0;
> +
> +       (void)ocxlpmem_chi(ocxlpmem, &chi);
> +
> +       if (chi & (GLOBAL_MMIO_CHI_CFFS | GLOBAL_MMIO_CHI_CHFS)) {
> +               dev_err(&ocxlpmem->dev,
> +                       "Controller status is fatal, chi=0x%llx, going offline\n",
> +                       chi);
> +
> +               if (ocxlpmem->nvdimm_bus) {
> +                       nvdimm_bus_unregister(ocxlpmem->nvdimm_bus);
> +                       ocxlpmem->nvdimm_bus = NULL;
> +               }
> +
> +               if (ocxlpmem->ev_ctx)
> +                       eventfd_signal(ocxlpmem->ev_ctx, 1);
> +       }
> +
> +       return IRQ_HANDLED;
> +}
> +
> +/**
> + * ocxlpmem_setup_irq() - Set up the IRQs for the OpenCAPI Persistent Memory device
> + * @ocxlpmem: the device metadata
> + * Return: 0 on success, negative on failure
> + */
> +static int setup_irqs(struct ocxlpmem *ocxlpmem)
> +{
> +       int rc;
> +       u64 irq_addr;
> +
> +       rc = ocxl_afu_irq_alloc(ocxlpmem->ocxl_context,
> +                               &ocxlpmem->irq_id[0]);
> +       if (rc)
> +               return rc;
> +
> +       rc = ocxl_irq_set_handler(ocxlpmem->ocxl_context, ocxlpmem->irq_id[0],
> +                                 imn0_handler, NULL, ocxlpmem);
> +
> +       irq_addr = ocxl_afu_irq_get_addr(ocxlpmem->ocxl_context,
> +                                        ocxlpmem->irq_id[0]);
> +       if (!irq_addr)
> +               return -EFAULT;
> +
> +       ocxlpmem->irq_addr[0] = ioremap(irq_addr, PAGE_SIZE);
> +       if (!ocxlpmem->irq_addr[0])
> +               return -ENODEV;
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA0_OHP,
> +                                     OCXL_LITTLE_ENDIAN,
> +                                     (u64)ocxlpmem->irq_addr[0]);
> +       if (rc)
> +               goto out_irq0;
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA0_CFP,
> +                                     OCXL_LITTLE_ENDIAN, 0);
> +       if (rc)
> +               goto out_irq0;
> +
> +       rc = ocxl_afu_irq_alloc(ocxlpmem->ocxl_context, &ocxlpmem->irq_id[1]);
> +       if (rc)
> +               goto out_irq0;
> +
> +       rc = ocxl_irq_set_handler(ocxlpmem->ocxl_context, ocxlpmem->irq_id[1],
> +                                 imn1_handler, NULL, ocxlpmem);
> +       if (rc)
> +               goto out_irq0;
> +
> +       irq_addr = ocxl_afu_irq_get_addr(ocxlpmem->ocxl_context,
> +                                        ocxlpmem->irq_id[1]);
> +       if (!irq_addr) {
> +               rc = -EFAULT;
> +               goto out_irq0;
> +       }
> +
> +       ocxlpmem->irq_addr[1] = ioremap(irq_addr, PAGE_SIZE);
> +       if (!ocxlpmem->irq_addr[1]) {
> +               rc = -ENODEV;
> +               goto out_irq0;
> +       }
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA1_OHP,
> +                                     OCXL_LITTLE_ENDIAN,
> +                                     (u64)ocxlpmem->irq_addr[1]);
> +       if (rc)
> +               goto out_irq1;
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA1_CFP,
> +                                     OCXL_LITTLE_ENDIAN, 0);
> +       if (rc)
> +               goto out_irq1;
> +
> +       // Enable doorbells
> +       rc = ocxl_global_mmio_set64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_CHIE,
> +                                   OCXL_LITTLE_ENDIAN,
> +                                   GLOBAL_MMIO_CHI_ELA |
> +                                   GLOBAL_MMIO_CHI_CDA |
> +                                   GLOBAL_MMIO_CHI_CFFS |
> +                                   GLOBAL_MMIO_CHI_CHFS);
> +       if (rc)
> +               goto out_irq1;
> +
> +       return 0;
> +
> +out_irq1:
> +       iounmap(ocxlpmem->irq_addr[1]);
> +       ocxlpmem->irq_addr[1] = NULL;
> +
> +out_irq0:
> +       iounmap(ocxlpmem->irq_addr[0]);
> +       ocxlpmem->irq_addr[0] = NULL;
> +
> +       return rc;
> +}
> +
>  /**
>   * probe_function0() - Set up function 0 for an OpenCAPI persistent memory device
>   * This is important as it enables templates higher than 0 across all other
> @@ -1212,6 +1426,12 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>                 goto err;
>         }
>
> +       rc = setup_irqs(ocxlpmem);
> +       if (rc) {
> +               dev_err(&pdev->dev, "Could not set up OCXL IRQs\n");
> +               goto err;
> +       }
> +
>         rc = setup_command_metadata(ocxlpmem);
>         if (rc) {
>                 dev_err(&pdev->dev, "Could not read command metadata\n");
> diff --git a/drivers/nvdimm/ocxl/ocxlpmem.h b/drivers/nvdimm/ocxl/ocxlpmem.h
> index ee3bd651f254..01721596f982 100644
> --- a/drivers/nvdimm/ocxl/ocxlpmem.h
> +++ b/drivers/nvdimm/ocxl/ocxlpmem.h
> @@ -106,6 +106,9 @@ struct ocxlpmem {
>         struct pci_dev *pdev;
>         struct cdev cdev;
>         struct ocxl_fn *ocxl_fn;
> +#define SCM_IRQ_COUNT 2
> +       int irq_id[SCM_IRQ_COUNT];
> +       void __iomem *irq_addr[SCM_IRQ_COUNT];
>         struct nd_interleave_set nd_set;
>         struct nvdimm_bus_descriptor bus_desc;
>         struct nvdimm_bus *nvdimm_bus;
> @@ -117,6 +120,7 @@ struct ocxlpmem {
>         struct nd_region *nd_region;
>         char fw_version[8 + 1];
>         u32 timeouts[ADMIN_COMMAND_MAX + 1];
> +       struct eventfd_ctx *ev_ctx;
>         u32 max_controller_dump_size;
>         u16 scm_revision; // major/minor
>         u8 readiness_timeout;  /* The worst case time (in seconds) that the host
> diff --git a/include/uapi/nvdimm/ocxlpmem.h b/include/uapi/nvdimm/ocxlpmem.h
> index ca3a7098fa9d..d573bd307e35 100644
> --- a/include/uapi/nvdimm/ocxlpmem.h
> +++ b/include/uapi/nvdimm/ocxlpmem.h
> @@ -71,6 +71,16 @@ struct ioctl_ocxlpmem_controller_stats {
>         __u64 fast_write_count;
>  };
>
> +struct ioctl_ocxlpmem_eventfd {
> +       __s32 eventfd;
> +       __u32 reserved;
> +};
> +
> +#define IOCTL_OCXLPMEM_EVENT_CONTROLLER_DUMP_AVAILABLE (1ULL << (0))
> +#define IOCTL_OCXLPMEM_EVENT_ERROR_LOG_AVAILABLE       (1ULL << (1))
> +#define IOCTL_OCXLPMEM_EVENT_HARDWARE_FATAL            (1ULL << (2))
> +#define IOCTL_OCXLPMEM_EVENT_FIRMWARE_FATAL            (1ULL << (3))
> +
>  /* ioctl numbers */
>  #define OCXLPMEM_MAGIC 0xCA
>  /* OpenCAPI Persistent memory devices */
> @@ -79,5 +89,7 @@ struct ioctl_ocxlpmem_controller_stats {
>  #define IOCTL_OCXLPMEM_CONTROLLER_DUMP_DATA            _IOWR(OCXLPMEM_MAGIC, 0x32, struct ioctl_ocxlpmem_controller_dump_data)
>  #define IOCTL_OCXLPMEM_CONTROLLER_DUMP_COMPLETE                _IO(OCXLPMEM_MAGIC, 0x33)
>  #define IOCTL_OCXLPMEM_CONTROLLER_STATS                        _IO(OCXLPMEM_MAGIC, 0x34)
> +#define IOCTL_OCXLPMEM_EVENTFD                         _IOW(OCXLPMEM_MAGIC, 0x35, struct ioctl_ocxlpmem_eventfd)
> +#define IOCTL_OCXLPMEM_EVENT_CHECK                     _IOR(OCXLPMEM_MAGIC, 0x36, __u64)
>
>  #endif /* _UAPI_OCXL_SCM_H */
> --
> 2.24.1
>
_______________________________________________
Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org
To unsubscribe send an email to linux-nvdimm-leave@lists.01.org

WARNING: multiple messages have this Message-ID (diff)
From: Dan Williams <dan.j.williams@intel.com>
To: "Alastair D'Silva" <alastair@d-silva.org>
Cc: "Aneesh Kumar K . V" <aneesh.kumar@linux.ibm.com>,
	"Oliver O'Halloran" <oohall@gmail.com>,
	"Benjamin Herrenschmidt" <benh@kernel.crashing.org>,
	"Paul Mackerras" <paulus@samba.org>,
	"Michael Ellerman" <mpe@ellerman.id.au>,
	"Frederic Barrat" <fbarrat@linux.ibm.com>,
	"Andrew Donnellan" <ajd@linux.ibm.com>,
	"Arnd Bergmann" <arnd@arndb.de>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Vishal Verma" <vishal.l.verma@intel.com>,
	"Dave Jiang" <dave.jiang@intel.com>,
	"Ira Weiny" <ira.weiny@intel.com>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Mauro Carvalho Chehab" <mchehab+samsung@kernel.org>,
	"David S. Miller" <davem@davemloft.net>,
	"Rob Herring" <robh@kernel.org>,
	"Anton Blanchard" <anton@ozlabs.org>,
	"Krzysztof Kozlowski" <krzk@kernel.org>,
	"Mahesh Salgaonkar" <mahesh@linux.vnet.ibm.com>,
	"Madhavan Srinivasan" <maddy@linux.vnet.ibm.com>,
	"Cédric Le Goater" <clg@kaod.org>,
	"Anju T Sudhakar" <anju@linux.vnet.ibm.com>,
	"Hari Bathini" <hbathini@linux.ibm.com>,
	"Thomas Gleixner" <tglx@linutronix.de>,
	"Greg Kurz" <groug@kaod.org>,
	"Nicholas Piggin" <npiggin@gmail.com>,
	"Masahiro Yamada" <yamada.masahiro@socionext.com>,
	"Alexey Kardashevskiy" <aik@ozlabs.ru>,
	"Linux Kernel Mailing List" <linux-kernel@vger.kernel.org>,
	linuxppc-dev <linuxppc-dev@lists.ozlabs.org>,
	linux-nvdimm <linux-nvdimm@lists.01.org>,
	"Linux MM" <linux-mm@kvack.org>
Subject: Re: [PATCH v4 19/25] nvdimm/ocxl: Forward events to userspace
Date: Wed, 1 Apr 2020 19:08:08 -0700	[thread overview]
Message-ID: <CAPcyv4gfDAbABq9wxKd05AWTduDy2udBXS4Y6qcWyUzOBv-xTg@mail.gmail.com> (raw)
In-Reply-To: <20200327071202.2159885-20-alastair@d-silva.org>

On Tue, Mar 31, 2020 at 1:59 AM Alastair D'Silva <alastair@d-silva.org> wrote:
>
> Some of the interrupts that the card generates are better handled
> by the userspace daemon, in particular:
> Controller Hardware/Firmware Fatal
> Controller Dump Available
> Error Log available
>
> This patch allows a userspace application to register an eventfd with
> the driver via SCM_IOCTL_EVENTFD to receive notifications of these
> interrupts.
>
> Userspace can then identify what events have occurred by calling
> SCM_IOCTL_EVENT_CHECK and checking against the SCM_IOCTL_EVENT_FOO
> masks.

The amount new ioctl's in this driver is too high, it seems much of
this data can be exported via sysfs attributes which are more
maintainable that ioctls. Then sysfs also has the ability to signal
events on sysfs attributes, see sys_notify_dirent.

Can you step back and review the ABI exposure of the driver and what
can be moved to sysfs? If you need to have bus specific attributes
ordered underneath the libnvdimm generic attributes you can create a
sysfs attribute subdirectory.

In general a roadmap document of all the proposed ABI is needed to
make sure it is both sufficient and necessary. See the libnvdimm
document that introduced the initial libnvdimm ABI:

https://www.kernel.org/doc/Documentation/nvdimm/nvdimm.txt

>
> Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> ---
>  drivers/nvdimm/ocxl/main.c     | 220 +++++++++++++++++++++++++++++++++
>  drivers/nvdimm/ocxl/ocxlpmem.h |   4 +
>  include/uapi/nvdimm/ocxlpmem.h |  12 ++
>  3 files changed, 236 insertions(+)
>
> diff --git a/drivers/nvdimm/ocxl/main.c b/drivers/nvdimm/ocxl/main.c
> index 0040fc09cceb..cb6cdc9eb899 100644
> --- a/drivers/nvdimm/ocxl/main.c
> +++ b/drivers/nvdimm/ocxl/main.c
> @@ -10,6 +10,7 @@
>  #include <misc/ocxl.h>
>  #include <linux/delay.h>
>  #include <linux/ndctl.h>
> +#include <linux/eventfd.h>
>  #include <linux/fs.h>
>  #include <linux/mm_types.h>
>  #include <linux/memory_hotplug.h>
> @@ -301,8 +302,19 @@ static void free_ocxlpmem(struct ocxlpmem *ocxlpmem)
>  {
>         int rc;
>
> +       // Disable doorbells
> +       (void)ocxl_global_mmio_set64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_CHIEC,
> +                                    OCXL_LITTLE_ENDIAN,
> +                                    GLOBAL_MMIO_CHI_ALL);
> +
>         free_minor(ocxlpmem);
>
> +       if (ocxlpmem->irq_addr[1])
> +               iounmap(ocxlpmem->irq_addr[1]);
> +
> +       if (ocxlpmem->irq_addr[0])
> +               iounmap(ocxlpmem->irq_addr[0]);
> +
>         if (ocxlpmem->ocxl_context) {
>                 rc = ocxl_context_detach(ocxlpmem->ocxl_context);
>                 if (rc == -EBUSY)
> @@ -398,6 +410,11 @@ static int file_release(struct inode *inode, struct file *file)
>  {
>         struct ocxlpmem *ocxlpmem = file->private_data;
>
> +       if (ocxlpmem->ev_ctx) {
> +               eventfd_ctx_put(ocxlpmem->ev_ctx);
> +               ocxlpmem->ev_ctx = NULL;
> +       }
> +
>         ocxlpmem_put(ocxlpmem);
>         return 0;
>  }
> @@ -928,6 +945,52 @@ static int ioctl_controller_stats(struct ocxlpmem *ocxlpmem,
>         return rc;
>  }
>
> +static int ioctl_eventfd(struct ocxlpmem *ocxlpmem,
> +                        struct ioctl_ocxlpmem_eventfd __user *uarg)
> +{
> +       struct ioctl_ocxlpmem_eventfd args;
> +
> +       if (copy_from_user(&args, uarg, sizeof(args)))
> +               return -EFAULT;
> +
> +       if (ocxlpmem->ev_ctx)
> +               return -EBUSY;
> +
> +       ocxlpmem->ev_ctx = eventfd_ctx_fdget(args.eventfd);
> +       if (IS_ERR(ocxlpmem->ev_ctx))
> +               return PTR_ERR(ocxlpmem->ev_ctx);
> +
> +       return 0;
> +}
> +
> +static int ioctl_event_check(struct ocxlpmem *ocxlpmem, u64 __user *uarg)
> +{
> +       u64 val = 0;
> +       int rc;
> +       u64 chi = 0;
> +
> +       rc = ocxlpmem_chi(ocxlpmem, &chi);
> +       if (rc < 0)
> +               return rc;
> +
> +       if (chi & GLOBAL_MMIO_CHI_ELA)
> +               val |= IOCTL_OCXLPMEM_EVENT_ERROR_LOG_AVAILABLE;
> +
> +       if (chi & GLOBAL_MMIO_CHI_CDA)
> +               val |= IOCTL_OCXLPMEM_EVENT_CONTROLLER_DUMP_AVAILABLE;
> +
> +       if (chi & GLOBAL_MMIO_CHI_CFFS)
> +               val |= IOCTL_OCXLPMEM_EVENT_FIRMWARE_FATAL;
> +
> +       if (chi & GLOBAL_MMIO_CHI_CHFS)
> +               val |= IOCTL_OCXLPMEM_EVENT_HARDWARE_FATAL;
> +
> +       if (copy_to_user((u64 __user *)uarg, &val, sizeof(val)))
> +               return -EFAULT;
> +
> +       return rc;
> +}
> +
>  static long file_ioctl(struct file *file, unsigned int cmd, unsigned long args)
>  {
>         struct ocxlpmem *ocxlpmem = file->private_data;
> @@ -956,6 +1019,15 @@ static long file_ioctl(struct file *file, unsigned int cmd, unsigned long args)
>                 rc = ioctl_controller_stats(ocxlpmem,
>                                             (struct ioctl_ocxlpmem_controller_stats __user *)args);
>                 break;
> +
> +       case IOCTL_OCXLPMEM_EVENTFD:
> +               rc = ioctl_eventfd(ocxlpmem,
> +                                  (struct ioctl_ocxlpmem_eventfd __user *)args);
> +               break;
> +
> +       case IOCTL_OCXLPMEM_EVENT_CHECK:
> +               rc = ioctl_event_check(ocxlpmem, (u64 __user *)args);
> +               break;
>         }
>
>         return rc;
> @@ -1109,6 +1181,148 @@ static void dump_error_log(struct ocxlpmem *ocxlpmem)
>         kfree(buf);
>  }
>
> +static irqreturn_t imn0_handler(void *private)
> +{
> +       struct ocxlpmem *ocxlpmem = private;
> +       u64 chi = 0;
> +
> +       (void)ocxlpmem_chi(ocxlpmem, &chi);
> +
> +       if (chi & GLOBAL_MMIO_CHI_ELA) {
> +               dev_warn(&ocxlpmem->dev, "Error log is available\n");
> +
> +               if (ocxlpmem->ev_ctx)
> +                       eventfd_signal(ocxlpmem->ev_ctx, 1);
> +       }
> +
> +       if (chi & GLOBAL_MMIO_CHI_CDA) {
> +               dev_warn(&ocxlpmem->dev, "Controller dump is available\n");
> +
> +               if (ocxlpmem->ev_ctx)
> +                       eventfd_signal(ocxlpmem->ev_ctx, 1);
> +       }
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t imn1_handler(void *private)
> +{
> +       struct ocxlpmem *ocxlpmem = private;
> +       u64 chi = 0;
> +
> +       (void)ocxlpmem_chi(ocxlpmem, &chi);
> +
> +       if (chi & (GLOBAL_MMIO_CHI_CFFS | GLOBAL_MMIO_CHI_CHFS)) {
> +               dev_err(&ocxlpmem->dev,
> +                       "Controller status is fatal, chi=0x%llx, going offline\n",
> +                       chi);
> +
> +               if (ocxlpmem->nvdimm_bus) {
> +                       nvdimm_bus_unregister(ocxlpmem->nvdimm_bus);
> +                       ocxlpmem->nvdimm_bus = NULL;
> +               }
> +
> +               if (ocxlpmem->ev_ctx)
> +                       eventfd_signal(ocxlpmem->ev_ctx, 1);
> +       }
> +
> +       return IRQ_HANDLED;
> +}
> +
> +/**
> + * ocxlpmem_setup_irq() - Set up the IRQs for the OpenCAPI Persistent Memory device
> + * @ocxlpmem: the device metadata
> + * Return: 0 on success, negative on failure
> + */
> +static int setup_irqs(struct ocxlpmem *ocxlpmem)
> +{
> +       int rc;
> +       u64 irq_addr;
> +
> +       rc = ocxl_afu_irq_alloc(ocxlpmem->ocxl_context,
> +                               &ocxlpmem->irq_id[0]);
> +       if (rc)
> +               return rc;
> +
> +       rc = ocxl_irq_set_handler(ocxlpmem->ocxl_context, ocxlpmem->irq_id[0],
> +                                 imn0_handler, NULL, ocxlpmem);
> +
> +       irq_addr = ocxl_afu_irq_get_addr(ocxlpmem->ocxl_context,
> +                                        ocxlpmem->irq_id[0]);
> +       if (!irq_addr)
> +               return -EFAULT;
> +
> +       ocxlpmem->irq_addr[0] = ioremap(irq_addr, PAGE_SIZE);
> +       if (!ocxlpmem->irq_addr[0])
> +               return -ENODEV;
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA0_OHP,
> +                                     OCXL_LITTLE_ENDIAN,
> +                                     (u64)ocxlpmem->irq_addr[0]);
> +       if (rc)
> +               goto out_irq0;
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA0_CFP,
> +                                     OCXL_LITTLE_ENDIAN, 0);
> +       if (rc)
> +               goto out_irq0;
> +
> +       rc = ocxl_afu_irq_alloc(ocxlpmem->ocxl_context, &ocxlpmem->irq_id[1]);
> +       if (rc)
> +               goto out_irq0;
> +
> +       rc = ocxl_irq_set_handler(ocxlpmem->ocxl_context, ocxlpmem->irq_id[1],
> +                                 imn1_handler, NULL, ocxlpmem);
> +       if (rc)
> +               goto out_irq0;
> +
> +       irq_addr = ocxl_afu_irq_get_addr(ocxlpmem->ocxl_context,
> +                                        ocxlpmem->irq_id[1]);
> +       if (!irq_addr) {
> +               rc = -EFAULT;
> +               goto out_irq0;
> +       }
> +
> +       ocxlpmem->irq_addr[1] = ioremap(irq_addr, PAGE_SIZE);
> +       if (!ocxlpmem->irq_addr[1]) {
> +               rc = -ENODEV;
> +               goto out_irq0;
> +       }
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA1_OHP,
> +                                     OCXL_LITTLE_ENDIAN,
> +                                     (u64)ocxlpmem->irq_addr[1]);
> +       if (rc)
> +               goto out_irq1;
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA1_CFP,
> +                                     OCXL_LITTLE_ENDIAN, 0);
> +       if (rc)
> +               goto out_irq1;
> +
> +       // Enable doorbells
> +       rc = ocxl_global_mmio_set64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_CHIE,
> +                                   OCXL_LITTLE_ENDIAN,
> +                                   GLOBAL_MMIO_CHI_ELA |
> +                                   GLOBAL_MMIO_CHI_CDA |
> +                                   GLOBAL_MMIO_CHI_CFFS |
> +                                   GLOBAL_MMIO_CHI_CHFS);
> +       if (rc)
> +               goto out_irq1;
> +
> +       return 0;
> +
> +out_irq1:
> +       iounmap(ocxlpmem->irq_addr[1]);
> +       ocxlpmem->irq_addr[1] = NULL;
> +
> +out_irq0:
> +       iounmap(ocxlpmem->irq_addr[0]);
> +       ocxlpmem->irq_addr[0] = NULL;
> +
> +       return rc;
> +}
> +
>  /**
>   * probe_function0() - Set up function 0 for an OpenCAPI persistent memory device
>   * This is important as it enables templates higher than 0 across all other
> @@ -1212,6 +1426,12 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>                 goto err;
>         }
>
> +       rc = setup_irqs(ocxlpmem);
> +       if (rc) {
> +               dev_err(&pdev->dev, "Could not set up OCXL IRQs\n");
> +               goto err;
> +       }
> +
>         rc = setup_command_metadata(ocxlpmem);
>         if (rc) {
>                 dev_err(&pdev->dev, "Could not read command metadata\n");
> diff --git a/drivers/nvdimm/ocxl/ocxlpmem.h b/drivers/nvdimm/ocxl/ocxlpmem.h
> index ee3bd651f254..01721596f982 100644
> --- a/drivers/nvdimm/ocxl/ocxlpmem.h
> +++ b/drivers/nvdimm/ocxl/ocxlpmem.h
> @@ -106,6 +106,9 @@ struct ocxlpmem {
>         struct pci_dev *pdev;
>         struct cdev cdev;
>         struct ocxl_fn *ocxl_fn;
> +#define SCM_IRQ_COUNT 2
> +       int irq_id[SCM_IRQ_COUNT];
> +       void __iomem *irq_addr[SCM_IRQ_COUNT];
>         struct nd_interleave_set nd_set;
>         struct nvdimm_bus_descriptor bus_desc;
>         struct nvdimm_bus *nvdimm_bus;
> @@ -117,6 +120,7 @@ struct ocxlpmem {
>         struct nd_region *nd_region;
>         char fw_version[8 + 1];
>         u32 timeouts[ADMIN_COMMAND_MAX + 1];
> +       struct eventfd_ctx *ev_ctx;
>         u32 max_controller_dump_size;
>         u16 scm_revision; // major/minor
>         u8 readiness_timeout;  /* The worst case time (in seconds) that the host
> diff --git a/include/uapi/nvdimm/ocxlpmem.h b/include/uapi/nvdimm/ocxlpmem.h
> index ca3a7098fa9d..d573bd307e35 100644
> --- a/include/uapi/nvdimm/ocxlpmem.h
> +++ b/include/uapi/nvdimm/ocxlpmem.h
> @@ -71,6 +71,16 @@ struct ioctl_ocxlpmem_controller_stats {
>         __u64 fast_write_count;
>  };
>
> +struct ioctl_ocxlpmem_eventfd {
> +       __s32 eventfd;
> +       __u32 reserved;
> +};
> +
> +#define IOCTL_OCXLPMEM_EVENT_CONTROLLER_DUMP_AVAILABLE (1ULL << (0))
> +#define IOCTL_OCXLPMEM_EVENT_ERROR_LOG_AVAILABLE       (1ULL << (1))
> +#define IOCTL_OCXLPMEM_EVENT_HARDWARE_FATAL            (1ULL << (2))
> +#define IOCTL_OCXLPMEM_EVENT_FIRMWARE_FATAL            (1ULL << (3))
> +
>  /* ioctl numbers */
>  #define OCXLPMEM_MAGIC 0xCA
>  /* OpenCAPI Persistent memory devices */
> @@ -79,5 +89,7 @@ struct ioctl_ocxlpmem_controller_stats {
>  #define IOCTL_OCXLPMEM_CONTROLLER_DUMP_DATA            _IOWR(OCXLPMEM_MAGIC, 0x32, struct ioctl_ocxlpmem_controller_dump_data)
>  #define IOCTL_OCXLPMEM_CONTROLLER_DUMP_COMPLETE                _IO(OCXLPMEM_MAGIC, 0x33)
>  #define IOCTL_OCXLPMEM_CONTROLLER_STATS                        _IO(OCXLPMEM_MAGIC, 0x34)
> +#define IOCTL_OCXLPMEM_EVENTFD                         _IOW(OCXLPMEM_MAGIC, 0x35, struct ioctl_ocxlpmem_eventfd)
> +#define IOCTL_OCXLPMEM_EVENT_CHECK                     _IOR(OCXLPMEM_MAGIC, 0x36, __u64)
>
>  #endif /* _UAPI_OCXL_SCM_H */
> --
> 2.24.1
>

WARNING: multiple messages have this Message-ID (diff)
From: Dan Williams <dan.j.williams@intel.com>
To: "Alastair D'Silva" <alastair@d-silva.org>
Cc: "Madhavan Srinivasan" <maddy@linux.vnet.ibm.com>,
	"Alexey Kardashevskiy" <aik@ozlabs.ru>,
	"Masahiro Yamada" <yamada.masahiro@socionext.com>,
	"Oliver O'Halloran" <oohall@gmail.com>,
	"Mauro Carvalho Chehab" <mchehab+samsung@kernel.org>,
	"Ira Weiny" <ira.weiny@intel.com>,
	"Rob Herring" <robh@kernel.org>,
	"Dave Jiang" <dave.jiang@intel.com>,
	linux-nvdimm <linux-nvdimm@lists.01.org>,
	"Aneesh Kumar K . V" <aneesh.kumar@linux.ibm.com>,
	"Krzysztof Kozlowski" <krzk@kernel.org>,
	"Anju T Sudhakar" <anju@linux.vnet.ibm.com>,
	"Mahesh Salgaonkar" <mahesh@linux.vnet.ibm.com>,
	"Andrew Donnellan" <ajd@linux.ibm.com>,
	"Arnd Bergmann" <arnd@arndb.de>, "Greg Kurz" <groug@kaod.org>,
	"Nicholas Piggin" <npiggin@gmail.com>,
	"Cédric Le Goater" <clg@kaod.org>,
	"Thomas Gleixner" <tglx@linutronix.de>,
	"Hari Bathini" <hbathini@linux.ibm.com>,
	"Linux MM" <linux-mm@kvack.org>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Linux Kernel Mailing List" <linux-kernel@vger.kernel.org>,
	"Vishal Verma" <vishal.l.verma@intel.com>,
	"Frederic Barrat" <fbarrat@linux.ibm.com>,
	"Paul Mackerras" <paulus@samba.org>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	linuxppc-dev <linuxppc-dev@lists.ozlabs.org>,
	"David S. Miller" <davem@davemloft.net>
Subject: Re: [PATCH v4 19/25] nvdimm/ocxl: Forward events to userspace
Date: Wed, 1 Apr 2020 19:08:08 -0700	[thread overview]
Message-ID: <CAPcyv4gfDAbABq9wxKd05AWTduDy2udBXS4Y6qcWyUzOBv-xTg@mail.gmail.com> (raw)
In-Reply-To: <20200327071202.2159885-20-alastair@d-silva.org>

On Tue, Mar 31, 2020 at 1:59 AM Alastair D'Silva <alastair@d-silva.org> wrote:
>
> Some of the interrupts that the card generates are better handled
> by the userspace daemon, in particular:
> Controller Hardware/Firmware Fatal
> Controller Dump Available
> Error Log available
>
> This patch allows a userspace application to register an eventfd with
> the driver via SCM_IOCTL_EVENTFD to receive notifications of these
> interrupts.
>
> Userspace can then identify what events have occurred by calling
> SCM_IOCTL_EVENT_CHECK and checking against the SCM_IOCTL_EVENT_FOO
> masks.

The amount new ioctl's in this driver is too high, it seems much of
this data can be exported via sysfs attributes which are more
maintainable that ioctls. Then sysfs also has the ability to signal
events on sysfs attributes, see sys_notify_dirent.

Can you step back and review the ABI exposure of the driver and what
can be moved to sysfs? If you need to have bus specific attributes
ordered underneath the libnvdimm generic attributes you can create a
sysfs attribute subdirectory.

In general a roadmap document of all the proposed ABI is needed to
make sure it is both sufficient and necessary. See the libnvdimm
document that introduced the initial libnvdimm ABI:

https://www.kernel.org/doc/Documentation/nvdimm/nvdimm.txt

>
> Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> ---
>  drivers/nvdimm/ocxl/main.c     | 220 +++++++++++++++++++++++++++++++++
>  drivers/nvdimm/ocxl/ocxlpmem.h |   4 +
>  include/uapi/nvdimm/ocxlpmem.h |  12 ++
>  3 files changed, 236 insertions(+)
>
> diff --git a/drivers/nvdimm/ocxl/main.c b/drivers/nvdimm/ocxl/main.c
> index 0040fc09cceb..cb6cdc9eb899 100644
> --- a/drivers/nvdimm/ocxl/main.c
> +++ b/drivers/nvdimm/ocxl/main.c
> @@ -10,6 +10,7 @@
>  #include <misc/ocxl.h>
>  #include <linux/delay.h>
>  #include <linux/ndctl.h>
> +#include <linux/eventfd.h>
>  #include <linux/fs.h>
>  #include <linux/mm_types.h>
>  #include <linux/memory_hotplug.h>
> @@ -301,8 +302,19 @@ static void free_ocxlpmem(struct ocxlpmem *ocxlpmem)
>  {
>         int rc;
>
> +       // Disable doorbells
> +       (void)ocxl_global_mmio_set64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_CHIEC,
> +                                    OCXL_LITTLE_ENDIAN,
> +                                    GLOBAL_MMIO_CHI_ALL);
> +
>         free_minor(ocxlpmem);
>
> +       if (ocxlpmem->irq_addr[1])
> +               iounmap(ocxlpmem->irq_addr[1]);
> +
> +       if (ocxlpmem->irq_addr[0])
> +               iounmap(ocxlpmem->irq_addr[0]);
> +
>         if (ocxlpmem->ocxl_context) {
>                 rc = ocxl_context_detach(ocxlpmem->ocxl_context);
>                 if (rc == -EBUSY)
> @@ -398,6 +410,11 @@ static int file_release(struct inode *inode, struct file *file)
>  {
>         struct ocxlpmem *ocxlpmem = file->private_data;
>
> +       if (ocxlpmem->ev_ctx) {
> +               eventfd_ctx_put(ocxlpmem->ev_ctx);
> +               ocxlpmem->ev_ctx = NULL;
> +       }
> +
>         ocxlpmem_put(ocxlpmem);
>         return 0;
>  }
> @@ -928,6 +945,52 @@ static int ioctl_controller_stats(struct ocxlpmem *ocxlpmem,
>         return rc;
>  }
>
> +static int ioctl_eventfd(struct ocxlpmem *ocxlpmem,
> +                        struct ioctl_ocxlpmem_eventfd __user *uarg)
> +{
> +       struct ioctl_ocxlpmem_eventfd args;
> +
> +       if (copy_from_user(&args, uarg, sizeof(args)))
> +               return -EFAULT;
> +
> +       if (ocxlpmem->ev_ctx)
> +               return -EBUSY;
> +
> +       ocxlpmem->ev_ctx = eventfd_ctx_fdget(args.eventfd);
> +       if (IS_ERR(ocxlpmem->ev_ctx))
> +               return PTR_ERR(ocxlpmem->ev_ctx);
> +
> +       return 0;
> +}
> +
> +static int ioctl_event_check(struct ocxlpmem *ocxlpmem, u64 __user *uarg)
> +{
> +       u64 val = 0;
> +       int rc;
> +       u64 chi = 0;
> +
> +       rc = ocxlpmem_chi(ocxlpmem, &chi);
> +       if (rc < 0)
> +               return rc;
> +
> +       if (chi & GLOBAL_MMIO_CHI_ELA)
> +               val |= IOCTL_OCXLPMEM_EVENT_ERROR_LOG_AVAILABLE;
> +
> +       if (chi & GLOBAL_MMIO_CHI_CDA)
> +               val |= IOCTL_OCXLPMEM_EVENT_CONTROLLER_DUMP_AVAILABLE;
> +
> +       if (chi & GLOBAL_MMIO_CHI_CFFS)
> +               val |= IOCTL_OCXLPMEM_EVENT_FIRMWARE_FATAL;
> +
> +       if (chi & GLOBAL_MMIO_CHI_CHFS)
> +               val |= IOCTL_OCXLPMEM_EVENT_HARDWARE_FATAL;
> +
> +       if (copy_to_user((u64 __user *)uarg, &val, sizeof(val)))
> +               return -EFAULT;
> +
> +       return rc;
> +}
> +
>  static long file_ioctl(struct file *file, unsigned int cmd, unsigned long args)
>  {
>         struct ocxlpmem *ocxlpmem = file->private_data;
> @@ -956,6 +1019,15 @@ static long file_ioctl(struct file *file, unsigned int cmd, unsigned long args)
>                 rc = ioctl_controller_stats(ocxlpmem,
>                                             (struct ioctl_ocxlpmem_controller_stats __user *)args);
>                 break;
> +
> +       case IOCTL_OCXLPMEM_EVENTFD:
> +               rc = ioctl_eventfd(ocxlpmem,
> +                                  (struct ioctl_ocxlpmem_eventfd __user *)args);
> +               break;
> +
> +       case IOCTL_OCXLPMEM_EVENT_CHECK:
> +               rc = ioctl_event_check(ocxlpmem, (u64 __user *)args);
> +               break;
>         }
>
>         return rc;
> @@ -1109,6 +1181,148 @@ static void dump_error_log(struct ocxlpmem *ocxlpmem)
>         kfree(buf);
>  }
>
> +static irqreturn_t imn0_handler(void *private)
> +{
> +       struct ocxlpmem *ocxlpmem = private;
> +       u64 chi = 0;
> +
> +       (void)ocxlpmem_chi(ocxlpmem, &chi);
> +
> +       if (chi & GLOBAL_MMIO_CHI_ELA) {
> +               dev_warn(&ocxlpmem->dev, "Error log is available\n");
> +
> +               if (ocxlpmem->ev_ctx)
> +                       eventfd_signal(ocxlpmem->ev_ctx, 1);
> +       }
> +
> +       if (chi & GLOBAL_MMIO_CHI_CDA) {
> +               dev_warn(&ocxlpmem->dev, "Controller dump is available\n");
> +
> +               if (ocxlpmem->ev_ctx)
> +                       eventfd_signal(ocxlpmem->ev_ctx, 1);
> +       }
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t imn1_handler(void *private)
> +{
> +       struct ocxlpmem *ocxlpmem = private;
> +       u64 chi = 0;
> +
> +       (void)ocxlpmem_chi(ocxlpmem, &chi);
> +
> +       if (chi & (GLOBAL_MMIO_CHI_CFFS | GLOBAL_MMIO_CHI_CHFS)) {
> +               dev_err(&ocxlpmem->dev,
> +                       "Controller status is fatal, chi=0x%llx, going offline\n",
> +                       chi);
> +
> +               if (ocxlpmem->nvdimm_bus) {
> +                       nvdimm_bus_unregister(ocxlpmem->nvdimm_bus);
> +                       ocxlpmem->nvdimm_bus = NULL;
> +               }
> +
> +               if (ocxlpmem->ev_ctx)
> +                       eventfd_signal(ocxlpmem->ev_ctx, 1);
> +       }
> +
> +       return IRQ_HANDLED;
> +}
> +
> +/**
> + * ocxlpmem_setup_irq() - Set up the IRQs for the OpenCAPI Persistent Memory device
> + * @ocxlpmem: the device metadata
> + * Return: 0 on success, negative on failure
> + */
> +static int setup_irqs(struct ocxlpmem *ocxlpmem)
> +{
> +       int rc;
> +       u64 irq_addr;
> +
> +       rc = ocxl_afu_irq_alloc(ocxlpmem->ocxl_context,
> +                               &ocxlpmem->irq_id[0]);
> +       if (rc)
> +               return rc;
> +
> +       rc = ocxl_irq_set_handler(ocxlpmem->ocxl_context, ocxlpmem->irq_id[0],
> +                                 imn0_handler, NULL, ocxlpmem);
> +
> +       irq_addr = ocxl_afu_irq_get_addr(ocxlpmem->ocxl_context,
> +                                        ocxlpmem->irq_id[0]);
> +       if (!irq_addr)
> +               return -EFAULT;
> +
> +       ocxlpmem->irq_addr[0] = ioremap(irq_addr, PAGE_SIZE);
> +       if (!ocxlpmem->irq_addr[0])
> +               return -ENODEV;
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA0_OHP,
> +                                     OCXL_LITTLE_ENDIAN,
> +                                     (u64)ocxlpmem->irq_addr[0]);
> +       if (rc)
> +               goto out_irq0;
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA0_CFP,
> +                                     OCXL_LITTLE_ENDIAN, 0);
> +       if (rc)
> +               goto out_irq0;
> +
> +       rc = ocxl_afu_irq_alloc(ocxlpmem->ocxl_context, &ocxlpmem->irq_id[1]);
> +       if (rc)
> +               goto out_irq0;
> +
> +       rc = ocxl_irq_set_handler(ocxlpmem->ocxl_context, ocxlpmem->irq_id[1],
> +                                 imn1_handler, NULL, ocxlpmem);
> +       if (rc)
> +               goto out_irq0;
> +
> +       irq_addr = ocxl_afu_irq_get_addr(ocxlpmem->ocxl_context,
> +                                        ocxlpmem->irq_id[1]);
> +       if (!irq_addr) {
> +               rc = -EFAULT;
> +               goto out_irq0;
> +       }
> +
> +       ocxlpmem->irq_addr[1] = ioremap(irq_addr, PAGE_SIZE);
> +       if (!ocxlpmem->irq_addr[1]) {
> +               rc = -ENODEV;
> +               goto out_irq0;
> +       }
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA1_OHP,
> +                                     OCXL_LITTLE_ENDIAN,
> +                                     (u64)ocxlpmem->irq_addr[1]);
> +       if (rc)
> +               goto out_irq1;
> +
> +       rc = ocxl_global_mmio_write64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_IMA1_CFP,
> +                                     OCXL_LITTLE_ENDIAN, 0);
> +       if (rc)
> +               goto out_irq1;
> +
> +       // Enable doorbells
> +       rc = ocxl_global_mmio_set64(ocxlpmem->ocxl_afu, GLOBAL_MMIO_CHIE,
> +                                   OCXL_LITTLE_ENDIAN,
> +                                   GLOBAL_MMIO_CHI_ELA |
> +                                   GLOBAL_MMIO_CHI_CDA |
> +                                   GLOBAL_MMIO_CHI_CFFS |
> +                                   GLOBAL_MMIO_CHI_CHFS);
> +       if (rc)
> +               goto out_irq1;
> +
> +       return 0;
> +
> +out_irq1:
> +       iounmap(ocxlpmem->irq_addr[1]);
> +       ocxlpmem->irq_addr[1] = NULL;
> +
> +out_irq0:
> +       iounmap(ocxlpmem->irq_addr[0]);
> +       ocxlpmem->irq_addr[0] = NULL;
> +
> +       return rc;
> +}
> +
>  /**
>   * probe_function0() - Set up function 0 for an OpenCAPI persistent memory device
>   * This is important as it enables templates higher than 0 across all other
> @@ -1212,6 +1426,12 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>                 goto err;
>         }
>
> +       rc = setup_irqs(ocxlpmem);
> +       if (rc) {
> +               dev_err(&pdev->dev, "Could not set up OCXL IRQs\n");
> +               goto err;
> +       }
> +
>         rc = setup_command_metadata(ocxlpmem);
>         if (rc) {
>                 dev_err(&pdev->dev, "Could not read command metadata\n");
> diff --git a/drivers/nvdimm/ocxl/ocxlpmem.h b/drivers/nvdimm/ocxl/ocxlpmem.h
> index ee3bd651f254..01721596f982 100644
> --- a/drivers/nvdimm/ocxl/ocxlpmem.h
> +++ b/drivers/nvdimm/ocxl/ocxlpmem.h
> @@ -106,6 +106,9 @@ struct ocxlpmem {
>         struct pci_dev *pdev;
>         struct cdev cdev;
>         struct ocxl_fn *ocxl_fn;
> +#define SCM_IRQ_COUNT 2
> +       int irq_id[SCM_IRQ_COUNT];
> +       void __iomem *irq_addr[SCM_IRQ_COUNT];
>         struct nd_interleave_set nd_set;
>         struct nvdimm_bus_descriptor bus_desc;
>         struct nvdimm_bus *nvdimm_bus;
> @@ -117,6 +120,7 @@ struct ocxlpmem {
>         struct nd_region *nd_region;
>         char fw_version[8 + 1];
>         u32 timeouts[ADMIN_COMMAND_MAX + 1];
> +       struct eventfd_ctx *ev_ctx;
>         u32 max_controller_dump_size;
>         u16 scm_revision; // major/minor
>         u8 readiness_timeout;  /* The worst case time (in seconds) that the host
> diff --git a/include/uapi/nvdimm/ocxlpmem.h b/include/uapi/nvdimm/ocxlpmem.h
> index ca3a7098fa9d..d573bd307e35 100644
> --- a/include/uapi/nvdimm/ocxlpmem.h
> +++ b/include/uapi/nvdimm/ocxlpmem.h
> @@ -71,6 +71,16 @@ struct ioctl_ocxlpmem_controller_stats {
>         __u64 fast_write_count;
>  };
>
> +struct ioctl_ocxlpmem_eventfd {
> +       __s32 eventfd;
> +       __u32 reserved;
> +};
> +
> +#define IOCTL_OCXLPMEM_EVENT_CONTROLLER_DUMP_AVAILABLE (1ULL << (0))
> +#define IOCTL_OCXLPMEM_EVENT_ERROR_LOG_AVAILABLE       (1ULL << (1))
> +#define IOCTL_OCXLPMEM_EVENT_HARDWARE_FATAL            (1ULL << (2))
> +#define IOCTL_OCXLPMEM_EVENT_FIRMWARE_FATAL            (1ULL << (3))
> +
>  /* ioctl numbers */
>  #define OCXLPMEM_MAGIC 0xCA
>  /* OpenCAPI Persistent memory devices */
> @@ -79,5 +89,7 @@ struct ioctl_ocxlpmem_controller_stats {
>  #define IOCTL_OCXLPMEM_CONTROLLER_DUMP_DATA            _IOWR(OCXLPMEM_MAGIC, 0x32, struct ioctl_ocxlpmem_controller_dump_data)
>  #define IOCTL_OCXLPMEM_CONTROLLER_DUMP_COMPLETE                _IO(OCXLPMEM_MAGIC, 0x33)
>  #define IOCTL_OCXLPMEM_CONTROLLER_STATS                        _IO(OCXLPMEM_MAGIC, 0x34)
> +#define IOCTL_OCXLPMEM_EVENTFD                         _IOW(OCXLPMEM_MAGIC, 0x35, struct ioctl_ocxlpmem_eventfd)
> +#define IOCTL_OCXLPMEM_EVENT_CHECK                     _IOR(OCXLPMEM_MAGIC, 0x36, __u64)
>
>  #endif /* _UAPI_OCXL_SCM_H */
> --
> 2.24.1
>

  reply	other threads:[~2020-04-02  2:08 UTC|newest]

Thread overview: 179+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-27  7:11 [PATCH v4 00/25] Add support for OpenCAPI Persistent Memory devices Alastair D'Silva
2020-03-27  7:11 ` Alastair D'Silva
2020-03-27  7:11 ` Alastair D'Silva
2020-03-27  7:11 ` [PATCH v4 01/25] powerpc/powernv: Add OPAL calls for LPC memory alloc/release Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-01  8:48   ` Dan Williams
2020-04-01  8:48     ` Dan Williams
2020-04-01  8:48     ` Dan Williams
2020-04-01 22:51     ` Alastair D'Silva
2020-04-01 22:51       ` Alastair D'Silva
2020-04-01 22:51       ` Alastair D'Silva
2020-03-27  7:11 ` [PATCH v4 02/25] mm/memory_hotplug: Allow check_hotplug_memory_addressable to be called from drivers Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-01  8:48   ` Dan Williams
2020-04-01  8:48     ` Dan Williams
2020-04-01  8:48     ` Dan Williams
2020-04-02  4:33     ` Alastair D'Silva
2020-04-02  4:33       ` Alastair D'Silva
2020-04-02  4:33       ` Alastair D'Silva
2020-03-27  7:11 ` [PATCH v4 03/25] powerpc/powernv: Map & release OpenCAPI LPC memory Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-01  8:48   ` Dan Williams
2020-04-01  8:48     ` Dan Williams
2020-04-01  8:48     ` Dan Williams
2020-04-02  4:36     ` Alastair D'Silva
2020-04-02  4:36       ` Alastair D'Silva
2020-04-02  4:36       ` Alastair D'Silva
2020-04-02 10:41     ` Benjamin Herrenschmidt
2020-04-02 10:41       ` Benjamin Herrenschmidt
2020-04-03  4:27       ` Michael Ellerman
2020-04-03  4:27         ` Michael Ellerman
2020-04-03  4:27         ` Michael Ellerman
2020-03-27  7:11 ` [PATCH v4 04/25] ocxl: Remove unnecessary externs Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-01  8:48   ` Dan Williams
2020-04-01  8:48     ` Dan Williams
2020-04-01  8:48     ` Dan Williams
2020-03-27  7:11 ` [PATCH v4 05/25] ocxl: Address kernel doc errors & warnings Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-01  8:49   ` Dan Williams
2020-04-01  8:49     ` Dan Williams
2020-04-01  8:49     ` Dan Williams
2020-03-27  7:11 ` [PATCH v4 06/25] ocxl: Tally up the LPC memory on a link & allow it to be mapped Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-01  8:48   ` Dan Williams
2020-04-01  8:48     ` Dan Williams
2020-04-01  8:48     ` Dan Williams
2020-04-02  6:21     ` Andrew Donnellan
2020-04-02  6:21       ` Andrew Donnellan
2020-04-02  6:21       ` Andrew Donnellan
2020-03-27  7:11 ` [PATCH v4 07/25] ocxl: Add functions to map/unmap LPC memory Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-01  8:49   ` Dan Williams
2020-04-01  8:49     ` Dan Williams
2020-04-01  8:49     ` Dan Williams
2020-04-03  3:50     ` Alastair D'Silva
2020-04-03  3:50       ` Alastair D'Silva
2020-04-03  3:50       ` Alastair D'Silva
2020-03-27  7:11 ` [PATCH v4 08/25] ocxl: Emit a log message showing how much LPC memory was detected Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-01  8:49   ` Dan Williams
2020-04-01  8:49     ` Dan Williams
2020-04-01  8:49     ` Dan Williams
2020-04-02  1:29     ` Joe Perches
2020-04-02  1:29       ` Joe Perches
2020-04-02  1:29       ` Joe Perches
2020-04-03  3:52     ` Alastair D'Silva
2020-04-03  3:52       ` Alastair D'Silva
2020-04-03  3:52       ` Alastair D'Silva
2020-03-27  7:11 ` [PATCH v4 09/25] ocxl: Save the device serial number in ocxl_fn Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11 ` [PATCH v4 10/25] nvdimm: Add driver for OpenCAPI Persistent Memory Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-29  2:56   ` Matthew Wilcox
2020-03-29  2:56     ` Matthew Wilcox
2020-03-29  2:56     ` Matthew Wilcox
2020-03-29  2:59     ` Matthew Wilcox
2020-03-29  2:59       ` Matthew Wilcox
2020-03-29  2:59       ` Matthew Wilcox
2020-04-01  8:49   ` Dan Williams
2020-04-01  8:49     ` Dan Williams
2020-04-01  8:49     ` Dan Williams
2020-04-01 19:35     ` Dan Williams
2020-04-01 19:35       ` Dan Williams
2020-04-01 19:35       ` Dan Williams
2020-03-27  7:11 ` [PATCH v4 11/25] powerpc: Enable the OpenCAPI Persistent Memory driver for powernv_defconfig Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-01 20:26   ` Dan Williams
2020-04-01 20:26     ` Dan Williams
2020-04-01 20:26     ` Dan Williams
2020-03-27  7:11 ` [PATCH v4 12/25] nvdimm/ocxl: Add register addresses & status values to the header Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-01 20:27   ` Dan Williams
2020-04-01 20:27     ` Dan Williams
2020-04-01 20:27     ` Dan Williams
2020-03-27  7:11 ` [PATCH v4 13/25] nvdimm/ocxl: Read the capability registers & wait for device ready Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-02  0:20   ` Dan Williams
2020-04-02  0:20     ` Dan Williams
2020-04-02  0:20     ` Dan Williams
2020-03-27  7:11 ` [PATCH v4 14/25] nvdimm/ocxl: Add support for Admin commands Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-02  6:41   ` Dan Williams
2020-04-02  6:41     ` Dan Williams
2020-04-02  6:41     ` Dan Williams
2020-03-27  7:11 ` [PATCH v4 15/25] nvdimm/ocxl: Register a character device for userspace to interact with Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-02  0:27   ` Dan Williams
2020-04-02  0:27     ` Dan Williams
2020-04-02  0:27     ` Dan Williams
2020-03-27  7:11 ` [PATCH v4 16/25] nvdimm/ocxl: Implement the Read Error Log command Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-03  0:54   ` Dan Williams
2020-04-03  0:54     ` Dan Williams
2020-04-03  0:54     ` Dan Williams
2020-03-27  7:11 ` [PATCH v4 17/25] nvdimm/ocxl: Add controller dump IOCTLs Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11 ` [PATCH v4 18/25] nvdimm/ocxl: Add an IOCTL to report controller statistics Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11 ` [PATCH v4 19/25] nvdimm/ocxl: Forward events to userspace Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-04-02  2:08   ` Dan Williams [this message]
2020-04-02  2:08     ` Dan Williams
2020-04-02  2:08     ` Dan Williams
2020-03-27  7:11 ` [PATCH v4 20/25] nvdimm/ocxl: Add an IOCTL to request controller health & perf data Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11 ` [PATCH v4 21/25] nvdimm/ocxl: Implement the heartbeat command Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11 ` [PATCH v4 22/25] nvdimm/ocxl: Add debug IOCTLs Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:11   ` Alastair D'Silva
2020-03-27  7:12 ` [PATCH v4 23/25] nvdimm/ocxl: Expose SMART data via ndctl Alastair D'Silva
2020-03-27  7:12   ` Alastair D'Silva
2020-03-27  7:12   ` Alastair D'Silva
2020-03-27  7:12 ` [PATCH v4 24/25] nvdimm/ocxl: Expose the serial number & firmware version in sysfs Alastair D'Silva
2020-03-27  7:12   ` Alastair D'Silva
2020-03-27  7:12   ` Alastair D'Silva
2020-03-27  7:12 ` [PATCH v4 25/25] MAINTAINERS: Add myself & nvdimm/ocxl to ocxl Alastair D'Silva
2020-03-27  7:12   ` Alastair D'Silva
2020-03-27  7:12   ` Alastair D'Silva
2020-04-01  8:47 ` [PATCH v4 00/25] Add support for OpenCAPI Persistent Memory devices Dan Williams
2020-04-01  8:47   ` Dan Williams
2020-04-01  8:47   ` Dan Williams
2020-04-01 22:44   ` Alastair D'Silva
2020-04-01 22:44     ` Alastair D'Silva
2020-04-01 22:44     ` Alastair D'Silva
2020-04-02  3:42     ` Michael Ellerman
2020-04-02  3:42       ` Michael Ellerman
2020-04-02  3:42       ` Michael Ellerman
2020-04-02  3:50       ` Oliver O'Halloran
2020-04-02  3:50         ` Oliver O'Halloran
2020-04-02  3:50         ` Oliver O'Halloran
2020-04-02 10:06         ` Michael Ellerman
2020-04-02 10:06           ` Michael Ellerman
2020-04-02 10:06           ` Michael Ellerman
2020-04-02 11:10           ` Greg Kurz
2020-04-02 11:10             ` Greg Kurz
2020-04-02 11:10             ` Greg Kurz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAPcyv4gfDAbABq9wxKd05AWTduDy2udBXS4Y6qcWyUzOBv-xTg@mail.gmail.com \
    --to=dan.j.williams@intel.com \
    --cc=aik@ozlabs.ru \
    --cc=ajd@linux.ibm.com \
    --cc=akpm@linux-foundation.org \
    --cc=alastair@d-silva.org \
    --cc=aneesh.kumar@linux.ibm.com \
    --cc=anju@linux.vnet.ibm.com \
    --cc=anton@ozlabs.org \
    --cc=arnd@arndb.de \
    --cc=benh@kernel.crashing.org \
    --cc=clg@kaod.org \
    --cc=davem@davemloft.net \
    --cc=fbarrat@linux.ibm.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=groug@kaod.org \
    --cc=hbathini@linux.ibm.com \
    --cc=krzk@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-nvdimm@lists.01.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=maddy@linux.vnet.ibm.com \
    --cc=mahesh@linux.vnet.ibm.com \
    --cc=mchehab+samsung@kernel.org \
    --cc=mpe@ellerman.id.au \
    --cc=npiggin@gmail.com \
    --cc=paulus@samba.org \
    --cc=robh@kernel.org \
    --cc=tglx@linutronix.de \
    --cc=yamada.masahiro@socionext.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.