You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2024/09/10 06:34:44 UTC

(nuttx) 07/10: pci/pci_uio_ivshmem: add pci uio ivshmem driver support

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit ccb17f2bb4a6c59800b7fa462e2a6522f048f6bc
Author: Bowen Wang <wa...@xiaomi.com>
AuthorDate: Wed Feb 28 21:14:01 2024 +0800

    pci/pci_uio_ivshmem: add pci uio ivshmem driver support
    
    Application can open "/dev/uioX" and use `mmap()` to get the
    memory provided by ivshmem device.
    
    Signed-off-by: Bowen Wang <wa...@xiaomi.com>
---
 drivers/pci/Kconfig                          |   9 +
 drivers/pci/Make.defs                        |   4 +
 drivers/pci/pci_drivers.c                    |  10 +
 drivers/pci/{pci_drivers.c => pci_drivers.h} |  60 +-----
 drivers/pci/pci_uio_ivshmem.c                | 310 +++++++++++++++++++++++++++
 5 files changed, 342 insertions(+), 51 deletions(-)

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index f6396b2e81..b100b19ec1 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -31,4 +31,13 @@ config PCI_QEMU_EDU
 	---help---
 		Driver for QEMU EDU test device
 
+config PCI_UIO_IVSHMEM
+	bool "Enable uio ivshmem driver support"
+	default n
+	---help---
+		When this option is enabled, char ivshmem driver will register
+		char device with name: "/dev/uioX" to the VFS, then
+		application can open this device and use `mmap()` to get the
+		share memory provided by ivshmem device.
+
 endif # PCI
diff --git a/drivers/pci/Make.defs b/drivers/pci/Make.defs
index efdfd66082..7b3b665859 100644
--- a/drivers/pci/Make.defs
+++ b/drivers/pci/Make.defs
@@ -29,6 +29,10 @@ ifeq ($(CONFIG_PCI_QEMU_EDU),y)
 CSRCS += pci_qemu_edu.c
 endif
 
+ifeq ($(CONFIG_PCI_UIO_IVSHMEM),y)
+CSRCS += pci_uio_ivshmem.c
+endif
+
 # Include PCI device driver build support
 
 DEPPATH += --dep-path pci
diff --git a/drivers/pci/pci_drivers.c b/drivers/pci/pci_drivers.c
index c7010b4179..454d51677a 100644
--- a/drivers/pci/pci_drivers.c
+++ b/drivers/pci/pci_drivers.c
@@ -29,6 +29,8 @@
 #include <nuttx/pci/pci_qemu_test.h>
 #include <nuttx/rptun/rptun_ivshmem.h>
 
+#include "pci_drivers.h"
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -45,6 +47,14 @@ int pci_register_drivers(void)
 {
   int ret;
 
+#ifdef CONFIG_PCI_UIO_IVSHMEM
+  ret = pci_register_uio_ivshmem_driver();
+  if (ret < 0)
+    {
+      pcierr("pci_register_uio_ivshmem_driver failed, ret=%d\n", ret);
+    }
+#endif
+
   /* Initialization pci qemu test driver */
 
 #ifdef CONFIG_PCI_QEMU_TEST
diff --git a/drivers/pci/pci_drivers.c b/drivers/pci/pci_drivers.h
similarity index 52%
copy from drivers/pci/pci_drivers.c
copy to drivers/pci/pci_drivers.h
index c7010b4179..f989c671cd 100644
--- a/drivers/pci/pci_drivers.c
+++ b/drivers/pci/pci_drivers.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * drivers/pci/pci_drivers.c
+ * drivers/pci/pci_drivers.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,63 +18,21 @@
  *
  ****************************************************************************/
 
+#ifndef __DRIVERS_PCI_PCI_DRIVERS_H
+#define __DRIVERS_PCI_PCI_DRIVERS_H
+
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
-#include <debug.h>
-
-#include <nuttx/pci/pci.h>
-#include <nuttx/pci/pci_qemu_edu.h>
-#include <nuttx/pci/pci_qemu_test.h>
-#include <nuttx/rptun/rptun_ivshmem.h>
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
+#include <nuttx/config.h>
 
 /****************************************************************************
- * Name: pci_register_drivers
- *
- * Description:
- *   Register all the pci drivers to pci bus
- *
+ * Public Function Prototypes
  ****************************************************************************/
 
-int pci_register_drivers(void)
-{
-  int ret;
-
-  /* Initialization pci qemu test driver */
-
-#ifdef CONFIG_PCI_QEMU_TEST
-  ret = pci_register_qemu_test_driver();
-  if (ret < 0)
-    {
-      pcierr("pci_register_qemu_test_driver failed, ret=%d\n", ret);
-    }
-#endif
-
-  /* Initialization qemu edu driver */
-
-#ifdef CONFIG_PCI_QEMU_EDU
-  ret = pci_register_qemu_edu_driver();
-  if (ret < 0)
-    {
-      pcierr("pci_register_qemu_edu_driver failed, ret=%d\n", ret);
-    }
-#endif
-
-  /* Initialization rptun ivshmem driver */
-
-#ifdef CONFIG_RPTUN_IVSHMEM
-  ret = pci_register_rptun_ivshmem_driver();
-  if (ret < 0)
-    {
-      pcierr("pci_register_rptun_ivshmem_driver failed, ret=%d\n", ret);
-    }
+#ifdef CONFIG_PCI_UIO_IVSHMEM
+int pci_register_uio_ivshmem_driver(void);
 #endif
 
-  UNUSED(ret);
-  return ret;
-}
+#endif /* __DRIVERS_PCI_PCI_DRIVERS_H */
diff --git a/drivers/pci/pci_uio_ivshmem.c b/drivers/pci/pci_uio_ivshmem.c
new file mode 100644
index 0000000000..2fa855f3f5
--- /dev/null
+++ b/drivers/pci/pci_uio_ivshmem.c
@@ -0,0 +1,310 @@
+/****************************************************************************
+ * drivers/pci/pci_uio_ivshmem.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/mm/map.h>
+#include <nuttx/pci/pci.h>
+
+#include "pci_drivers.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define UIO_IVSHMEM_SHMEM_BAR   2
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct uio_ivshmem_dev_s
+{
+  FAR void *shmem;
+  size_t    shmem_size;
+  char      name[32];
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int uio_ivshmem_open(FAR struct file *filep);
+static int uio_ivshmem_close(FAR struct file *filep);
+static ssize_t uio_ivshmem_read(FAR struct file *filep, FAR char *buffer,
+                                size_t buflen);
+static ssize_t uio_ivshmem_write(FAR struct file *filep,
+                                 FAR const char *buffer, size_t buflen);
+static int uio_ivshmem_unmap(FAR struct task_group_s *group,
+                             FAR struct mm_map_entry_s *entry,
+                             FAR void *start, size_t length);
+static int uio_ivshmem_mmap(FAR struct file *filep,
+                            FAR struct mm_map_entry_s *map);
+
+static int uio_ivshmem_probe(FAR struct pci_device_s *dev);
+static void uio_ivshmem_remove(FAR struct pci_device_s *dev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_uio_ivshmem_fops =
+{
+  uio_ivshmem_open,  /* open */
+  uio_ivshmem_close, /* close */
+  uio_ivshmem_read,  /* read */
+  uio_ivshmem_write, /* write */
+  NULL,              /* seek */
+  NULL,              /* ioctl */
+  uio_ivshmem_mmap,  /* mmap */
+  NULL,              /* truncate */
+  NULL               /* poll */
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  , NULL             /* unlink */
+#endif
+};
+
+static const struct pci_device_id_s g_uio_ivshmem_ids[] =
+{
+  { PCI_DEVICE(0x1af4, 0x1110) },
+  { 0, }
+};
+
+static struct pci_driver_s g_uio_ivshmem_drv =
+{
+  g_uio_ivshmem_ids,  /* PCI id_tables */
+  uio_ivshmem_probe,  /* Probe function */
+  uio_ivshmem_remove, /* Remove function */
+};
+
+static int g_uio_ivshmem_idx = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: uio_ivshmem_open
+ ****************************************************************************/
+
+static int uio_ivshmem_open(FAR struct file *filep)
+{
+  UNUSED(filep);
+  return 0;
+}
+
+/****************************************************************************
+ * Name: uio_ivshmem_close
+ ****************************************************************************/
+
+static int uio_ivshmem_close(FAR struct file *filep)
+{
+  UNUSED(filep);
+  return 0;
+}
+
+/****************************************************************************
+ * Name: uio_ivshmem_read
+ ****************************************************************************/
+
+static ssize_t uio_ivshmem_read(FAR struct file *filep, FAR char *buffer,
+                                size_t buflen)
+{
+  UNUSED(filep);
+  UNUSED(buffer);
+  return buflen;
+}
+
+/****************************************************************************
+ * Name: uio_ivshmem_write
+ ****************************************************************************/
+
+static ssize_t uio_ivshmem_write(FAR struct file *filep,
+                                 FAR const char *buffer, size_t buflen)
+{
+  UNUSED(filep);
+  UNUSED(buffer);
+  return buflen;
+}
+
+/****************************************************************************
+ * Name: uio_ivshmem_unmap
+ ****************************************************************************/
+
+static int uio_ivshmem_unmap(FAR struct task_group_s *group,
+                             FAR struct mm_map_entry_s *entry,
+                             FAR void *start, size_t length)
+{
+  off_t offset;
+  int ret;
+
+  offset = (uintptr_t)start - (uintptr_t)entry->vaddr;
+  if (offset + length < entry->length)
+    {
+      pcierr("ERROR: Cannot umap without unmapping to the end\n");
+      return -ENOSYS;
+    }
+
+  /* Okay.. the region is being unmapped to the end.  Make sure the length
+   * indicates the unmap length.
+   */
+
+  length = entry->length - offset;
+  if (length < entry->length)
+    {
+      pcierr("ERROR: Cannot umap portion of the memory\n");
+      return -ENOSYS;
+    }
+
+  ret = mm_map_remove(get_group_mm(group), entry);
+  if (ret < 0)
+    {
+      pcierr("ERROR: mm_map_remove failed, ret=%d\n", ret);
+      return ret;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: uio_ivshmem_mmap
+ ****************************************************************************/
+
+static int uio_ivshmem_mmap(FAR struct file *filep,
+                            FAR struct mm_map_entry_s *map)
+{
+  FAR struct uio_ivshmem_dev_s *priv;
+
+  DEBUGASSERT(filep->f_inode != NULL && filep->f_inode->i_private != NULL);
+
+  /* Recover our private data from the struct file instance */
+
+  priv = filep->f_inode->i_private;
+
+  if (map->offset < 0 || map->offset >= priv->shmem_size ||
+      map->length == 0 || map->offset + map->length > priv->shmem_size)
+    {
+      return -EINVAL;
+    }
+
+  map->vaddr = (FAR char *)priv->shmem + map->offset;
+  map->priv.p = priv;
+  map->munmap = uio_ivshmem_unmap;
+
+  /* Not allow mapped memory overlap */
+
+  if (mm_map_find(get_current_mm(), map->vaddr, map->length) != NULL)
+    {
+      return -EINVAL;
+    }
+
+  return mm_map_add(get_current_mm(), map);
+}
+
+/****************************************************************************
+ * Name: uio_ivshmem_probe
+ ****************************************************************************/
+
+static int uio_ivshmem_probe(FAR struct pci_device_s *dev)
+{
+  FAR struct uio_ivshmem_dev_s *priv;
+  int ret;
+
+  priv = kmm_zalloc(sizeof(*priv));
+  if (priv == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  /* Configure the ivshmem device and get share memory address */
+
+  ret = pci_enable_device(dev);
+  if (ret < 0)
+    {
+      pcierr("ERROR: Enable device failed, ret=%d\n", ret);
+      goto err_priv;
+    }
+
+  pci_set_master(dev);
+
+  priv->shmem = pci_map_bar(dev, UIO_IVSHMEM_SHMEM_BAR);
+  if (priv->shmem == NULL)
+    {
+      ret = -ENOTSUP;
+      pcierr("ERROR: Device not support share memory bar\n");
+      goto err_master;
+    }
+
+  priv->shmem_size = pci_resource_len(dev, UIO_IVSHMEM_SHMEM_BAR);
+
+  pciinfo("shmem addr=%p size=%zu\n", priv->shmem, priv->shmem_size);
+
+  snprintf(priv->name, sizeof(priv->name), "/dev/uio%d", g_uio_ivshmem_idx);
+  ret = register_driver(priv->name, &g_uio_ivshmem_fops, 0666, priv);
+  if (ret < 0)
+    {
+      pcierr("ERROR: Ivshmem register_driver failed, ret=%d\n", ret);
+      goto err_master;
+    }
+
+  g_uio_ivshmem_idx++;
+  return ret;
+
+err_master:
+  pci_clear_master(dev);
+  pci_disable_device(dev);
+err_priv:
+  kmm_free(priv);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: uio_ivshmem_remove
+ ****************************************************************************/
+
+static void uio_ivshmem_remove(FAR struct pci_device_s *dev)
+{
+  FAR struct uio_ivshmem_dev_s *priv = dev->priv;
+
+  dev->priv = NULL;
+  unregister_driver(priv->name);
+  pci_clear_master(dev);
+  pci_disable_device(dev);
+  kmm_free(priv);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int pci_register_uio_ivshmem_driver(void)
+{
+  return pci_register_driver(&g_uio_ivshmem_drv);
+}
+