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 <wangbowen6@xiaomi.com>
This commit is contained in:
parent
fa761a6be7
commit
ccb17f2bb4
@ -31,4 +31,13 @@ config PCI_QEMU_EDU
|
|||||||
---help---
|
---help---
|
||||||
Driver for QEMU EDU test device
|
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
|
endif # PCI
|
||||||
|
@ -29,6 +29,10 @@ ifeq ($(CONFIG_PCI_QEMU_EDU),y)
|
|||||||
CSRCS += pci_qemu_edu.c
|
CSRCS += pci_qemu_edu.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PCI_UIO_IVSHMEM),y)
|
||||||
|
CSRCS += pci_uio_ivshmem.c
|
||||||
|
endif
|
||||||
|
|
||||||
# Include PCI device driver build support
|
# Include PCI device driver build support
|
||||||
|
|
||||||
DEPPATH += --dep-path pci
|
DEPPATH += --dep-path pci
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
#include <nuttx/pci/pci_qemu_test.h>
|
#include <nuttx/pci/pci_qemu_test.h>
|
||||||
#include <nuttx/rptun/rptun_ivshmem.h>
|
#include <nuttx/rptun/rptun_ivshmem.h>
|
||||||
|
|
||||||
|
#include "pci_drivers.h"
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -45,6 +47,14 @@ int pci_register_drivers(void)
|
|||||||
{
|
{
|
||||||
int ret;
|
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 */
|
/* Initialization pci qemu test driver */
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_QEMU_TEST
|
#ifdef CONFIG_PCI_QEMU_TEST
|
||||||
|
38
drivers/pci/pci_drivers.h
Normal file
38
drivers/pci/pci_drivers.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* 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
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __DRIVERS_PCI_PCI_DRIVERS_H
|
||||||
|
#define __DRIVERS_PCI_PCI_DRIVERS_H
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Function Prototypes
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_PCI_UIO_IVSHMEM
|
||||||
|
int pci_register_uio_ivshmem_driver(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __DRIVERS_PCI_PCI_DRIVERS_H */
|
310
drivers/pci/pci_uio_ivshmem.c
Normal file
310
drivers/pci/pci_uio_ivshmem.c
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user