mirror of
https://github.com/aolofsson/oh.git
synced 2025-01-17 20:02:53 +08:00
Updated mailbox test software and added trial kernel files
Signed-off-by: Peter Saunderson <peteasa@gmail.com>
This commit is contained in:
parent
51fb4ad4a4
commit
a442dd4171
660
elink/sw/mailbox/kernel/epiphany.c
Normal file
660
elink/sw/mailbox/kernel/epiphany.c
Normal file
@ -0,0 +1,660 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pid.h>
|
||||
#include <linux/fdtable.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/eventfd.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/* For open firmware. */
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#endif
|
||||
|
||||
#include <linux/epiphany.h>
|
||||
|
||||
MODULE_AUTHOR("Peter Saunderson");
|
||||
MODULE_DESCRIPTION("Adapteva Epiphany Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define UseReservedMem 1
|
||||
|
||||
#define DRIVER_NAME "epiphany"
|
||||
|
||||
/* The physical address of the start and end of the Epiphany device memory */
|
||||
#define EPIPHANY_MEM_START 0x80800000UL
|
||||
#define EPIPHANY_MEM_END 0xC0000000UL
|
||||
|
||||
/* The physical address of the DRAM shared between the host and Epiphany */
|
||||
#define HOST_MEM_START 0x3E000000UL
|
||||
#define HOST_MEM_END 0x40000000UL
|
||||
|
||||
/* Physical address range that can be mapped to FPGA logic */
|
||||
/* TODO: Define in devicetree */
|
||||
#define PL_MEM_START 0x40000000UL
|
||||
#define PL_MEM_END 0x80000000UL
|
||||
|
||||
#define ERX_REG_START 0x810F0300
|
||||
#define ERX_REG_END 0x810F03FF
|
||||
#define ERX_CFG_REG 0x0 // 0xF0300
|
||||
#define MAILBOX_LO_REG 0x20 // 0xF0320
|
||||
#define MAILBOX_HI_REG 0x24 // 0xF0324
|
||||
#define MAILBOX_STATE 0x28 // 0xF0328
|
||||
#define MAILBOX_ENABLE (0x1 << 28) // bit 28 in ERX_CFG_REG
|
||||
|
||||
static int major = 0;
|
||||
static dev_t dev_no = 0;
|
||||
static struct cdev epiphany_cdev;
|
||||
static struct class *class_epiphany = 0;
|
||||
static struct device *dev_epiphany = 0;
|
||||
static epiphany_alloc_t global_shm;
|
||||
|
||||
/* Work stucture */
|
||||
static struct workqueue_struct *irq_workqueue;
|
||||
typedef struct
|
||||
{
|
||||
struct work_struct work;
|
||||
struct task_struct * userspace_task;
|
||||
} irq_work_t;
|
||||
|
||||
typedef struct {
|
||||
irq_work_t irq_work; // @ start of structure so that work is at start
|
||||
unsigned int irq;
|
||||
void __iomem *reg_base;
|
||||
} epiphany_mailbox_t;
|
||||
static epiphany_mailbox_t mailbox;
|
||||
|
||||
static struct eventfd_ctx * efd_ctx = NULL;
|
||||
static int mailbox_notifier = -1;
|
||||
static int mailbox_lo = 0;
|
||||
static int mailbox_hi = 0;
|
||||
|
||||
// mailbox_notifier is the eventfd sent by ioctl to the driver.
|
||||
// Use epoll_wait on the user side to detect the arrival of
|
||||
// an interrupt. Note epoll_wait can be cancelled by
|
||||
// waiting on a second eventfd descriptor.
|
||||
DEVICE_INT_ATTR(mailbox_notifier, S_IRUGO, mailbox_notifier);
|
||||
|
||||
// mailbox content is read during interrupt servicing
|
||||
// the user side code can read the sysfs files for the messages
|
||||
DEVICE_INT_ATTR(mailbox_lo, S_IRUGO, mailbox_lo);
|
||||
DEVICE_INT_ATTR(mailbox_hi, S_IRUGO, mailbox_hi);
|
||||
|
||||
static struct attribute *attrs[] = {
|
||||
&dev_attr_mailbox_notifier.attr.attr,
|
||||
&dev_attr_mailbox_lo.attr.attr,
|
||||
&dev_attr_mailbox_hi.attr.attr, NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group attr_group = {
|
||||
.attrs = attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *attr_groups[] = {
|
||||
&attr_group, NULL,
|
||||
};
|
||||
|
||||
/* Function prototypes */
|
||||
static int epiphany_of_probe(struct platform_device *op);
|
||||
static int __init epiphany_init(void);
|
||||
static int epiphany_probe(struct platform_device *pdev);
|
||||
static int epiphany_remove(struct platform_device *pdev);
|
||||
static void __exit epiphany_exit(void);
|
||||
static int epiphany_open(struct inode *, struct file *);
|
||||
static int epiphany_release(struct inode *, struct file *);
|
||||
static int epiphany_map_host_memory(struct vm_area_struct *vma);
|
||||
static int epiphany_map_device_memory(struct vm_area_struct *vma);
|
||||
static int epiphany_mmap(struct file *, struct vm_area_struct *);
|
||||
static long epiphany_ioctl(struct file *, unsigned int, unsigned long);
|
||||
static void reg_write(epiphany_mailbox_t *mailbox, u32 reg, u32 val);
|
||||
static u32 reg_read(epiphany_mailbox_t *mailbox, u32 reg);
|
||||
static void enable_mailbox_irq(void);
|
||||
static void disable_mailbox_irq(void);
|
||||
static u32 read_mailbox_lo(void);
|
||||
static u32 read_mailbox_hi(void);
|
||||
static void irq_work_func(struct work_struct *work);
|
||||
static irqreturn_t mailbox_irq_handler(int irq, void *data);
|
||||
|
||||
static struct file_operations epiphany_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = epiphany_open,
|
||||
.release = epiphany_release,
|
||||
.mmap = epiphany_mmap,
|
||||
.unlocked_ioctl = epiphany_ioctl
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/* Match table for device tree binding */
|
||||
static const struct of_device_id epiphany_of_match[] = {
|
||||
{ .compatible = "xlnx,parallella-base-1.0"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, epiphany_of_match);
|
||||
#else
|
||||
#define epiphany_of_match NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int epiphany_of_probe(struct platform_device *op)
|
||||
{
|
||||
unsigned int elinkId;
|
||||
int retval;
|
||||
|
||||
retval = of_property_read_u32(op->dev.of_node, "xlnx,read-tag-addr", &elinkId);
|
||||
printk(KERN_INFO
|
||||
"epiphany_of_probe(): elinkId: 0x%x\n", elinkId);
|
||||
return retval;
|
||||
}
|
||||
#else
|
||||
static int epiphany_of_probe(struct platform_device *op)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static struct platform_driver epiphany_platform_driver = {
|
||||
.probe = epiphany_probe,
|
||||
.remove = epiphany_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = epiphany_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init epiphany_init(void)
|
||||
{
|
||||
int retval;
|
||||
void *ptr_err = 0;
|
||||
|
||||
// Allocate character device numbers
|
||||
// unregistered on error and in .exit
|
||||
retval = alloc_chrdev_region(&dev_no, 0, 1, DRIVER_NAME);
|
||||
if (retval < 0) {
|
||||
printk(KERN_ERR "Failed to register the epiphany driver\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
major = MAJOR(dev_no);
|
||||
dev_no = MKDEV(major, 0);
|
||||
|
||||
// Create device class for epiphany
|
||||
// destroyed on error and in .exit
|
||||
class_epiphany = class_create(THIS_MODULE, DRIVER_NAME);
|
||||
if (IS_ERR(ptr_err = class_epiphany)) {
|
||||
retval = PTR_ERR(ptr_err);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
// Assign the attribute groups to create the sysfs files
|
||||
class_epiphany->dev_groups = attr_groups;
|
||||
|
||||
// Register the driver with platform
|
||||
// unregistered in .exit
|
||||
retval = platform_driver_register(&epiphany_platform_driver);
|
||||
if (retval) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
||||
err:
|
||||
class_destroy(class_epiphany);
|
||||
err2:
|
||||
unregister_chrdev_region(dev_no, 1);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int epiphany_probe(struct platform_device *pdev)
|
||||
{
|
||||
int retval = 0;
|
||||
void *ptr_err = 0;
|
||||
const struct of_device_id *match;
|
||||
struct resource *io;
|
||||
|
||||
match = of_match_device(epiphany_of_match, &pdev->dev);
|
||||
if (!match)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
retval = epiphany_of_probe(pdev);
|
||||
if (retval)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#if UseReservedMem
|
||||
/*
|
||||
** Use the system reserved memory until we have a way
|
||||
** to tell epiphany what the dynamically allocated address is
|
||||
*/
|
||||
global_shm.size = GLOBAL_SHM_SIZE;
|
||||
global_shm.flags = 0;
|
||||
global_shm.bus_addr = 0x8e000000 + 0x01000000; /* From platform.hdf + shared_dram offset */
|
||||
global_shm.phy_addr = HOST_MEM_START + 0x01000000; /* From platform.hdf + shared_dram offset */
|
||||
global_shm.kvirt_addr = (unsigned long)ioremap_nocache(global_shm.phy_addr, 0x01000000); /* FIXME: not portable */
|
||||
global_shm.uvirt_addr = 0; /* Set by user when mmapped */
|
||||
global_shm.mmap_handle = global_shm.phy_addr;
|
||||
#else
|
||||
// Allocate shared memory
|
||||
// Zero the shared memory
|
||||
memset(&global_shm, 0, sizeof(global_shm));
|
||||
global_shm.size = GLOBAL_SHM_SIZE;
|
||||
global_shm.flags = GFP_KERNEL;
|
||||
global_shm.kvirt_addr = __get_free_pages(GFP_KERNEL,
|
||||
get_order(GLOBAL_SHM_SIZE));
|
||||
if (!global_shm.kvirt_addr) {
|
||||
printk(KERN_ERR
|
||||
"epiphany_probe() - Unable to allocate contiguous "
|
||||
"memory for global shared region\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
global_shm.phy_addr = __pa(global_shm.kvirt_addr);
|
||||
global_shm.bus_addr = global_shm.phys_addr;
|
||||
#endif
|
||||
|
||||
// Zero the Global Shared Memory region
|
||||
memset((void *)global_shm.kvirt_addr, 0, GLOBAL_SHM_SIZE);
|
||||
|
||||
printk(KERN_INFO
|
||||
"epiphany_probe() - shared memory: bus 0x%08lx, phy 0x%08lx, kvirt 0x%08lx\n",
|
||||
global_shm.bus_addr, global_shm.phy_addr, global_shm.kvirt_addr);
|
||||
|
||||
// Map the rx registers for mailbox access
|
||||
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
printk(KERN_INFO
|
||||
"epiphany_probe() - registers: start 0x%08lx, end 0x%08lx, name %s, flags %x\n",
|
||||
(unsigned long)io->start, (unsigned long)io->end, io->name, io->flags);
|
||||
|
||||
// for now keep it simple and dont reference the device tree stuff
|
||||
// not sure if ioremap here will prevent other user space mmap!
|
||||
io->start = ERX_REG_START;
|
||||
io->end = ERX_REG_END;
|
||||
mailbox.reg_base = devm_ioremap_resource(&pdev->dev, io);
|
||||
if (IS_ERR(mailbox.reg_base))
|
||||
{
|
||||
dev_err(&pdev->dev, "failed to map mailbox registers\n");
|
||||
return PTR_ERR(mailbox.reg_base);
|
||||
}
|
||||
|
||||
// Get the mailbox irq from device tree
|
||||
mailbox.irq = platform_get_irq(pdev, 0);
|
||||
if (0 > mailbox.irq) {
|
||||
dev_err(&pdev->dev, "irq resource not found\n");
|
||||
return mailbox.irq;
|
||||
}
|
||||
|
||||
printk(KERN_INFO
|
||||
"epiphany_probe(): mailbox irq: 0x%x\n", mailbox.irq);
|
||||
|
||||
// Register the mailbox irq handler
|
||||
// removed on error and in .remove
|
||||
retval = devm_request_irq(&pdev->dev, mailbox.irq, mailbox_irq_handler,
|
||||
0, pdev->name, &mailbox);
|
||||
if (0 > retval) {
|
||||
dev_err(&pdev->dev, "request_irq failed\n");
|
||||
printk(KERN_ERR
|
||||
"epiphany_probe() - Unable to request IRQ %d\n", mailbox.irq);
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Initialize the workqueue
|
||||
// Killed on error and in .remove
|
||||
irq_workqueue = create_workqueue("irq_work_queue");
|
||||
if (irq_workqueue)
|
||||
{
|
||||
INIT_WORK(((struct work_struct *)&mailbox), irq_work_func);
|
||||
}
|
||||
|
||||
// Initialize the cdev structure
|
||||
// deleted on error and in .remove
|
||||
cdev_init(&epiphany_cdev, &epiphany_fops);
|
||||
epiphany_cdev.owner = THIS_MODULE;
|
||||
|
||||
// Add the character driver to the system
|
||||
// deleted on error and in .remove
|
||||
retval = cdev_add(&epiphany_cdev, dev_no, 1);
|
||||
if (0 > retval) {
|
||||
printk(KERN_ERR
|
||||
"epiphany_probe() - Unable to add character device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
// Create the character device
|
||||
// deleted in .remove
|
||||
dev_epiphany = device_create(class_epiphany, NULL, dev_no, NULL,
|
||||
DRIVER_NAME);
|
||||
if (IS_ERR(ptr_err = dev_epiphany)) {
|
||||
retval = PTR_ERR(ptr_err);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
cdev_del(&epiphany_cdev);
|
||||
err1:
|
||||
destroy_workqueue(irq_workqueue);
|
||||
devm_free_irq(&pdev->dev, mailbox.irq, &mailbox);
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int epiphany_remove(struct platform_device *pdev)
|
||||
{
|
||||
// Disable the interrupt first
|
||||
disable_mailbox_irq();
|
||||
|
||||
// Remove interrupt handler
|
||||
if (mailbox.irq > 0)
|
||||
{
|
||||
devm_free_irq(&pdev->dev, mailbox.irq, &mailbox);
|
||||
}
|
||||
|
||||
// flush the queue
|
||||
flush_workqueue(irq_workqueue);
|
||||
|
||||
// destroy the queue
|
||||
destroy_workqueue(irq_workqueue);
|
||||
|
||||
#if (UseReservedMem == 0)
|
||||
free_pages(global_shm.kvirt_addr, get_order(global_shm.size));
|
||||
#endif
|
||||
device_destroy(class_epiphany, MKDEV(major, 0));
|
||||
cdev_del(&epiphany_cdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit epiphany_exit(void)
|
||||
{
|
||||
// Unregister driver from plaform
|
||||
platform_driver_unregister(&epiphany_platform_driver);
|
||||
|
||||
// Destroy the epiphany class
|
||||
class_destroy(class_epiphany);
|
||||
|
||||
// Unregister the character device numbers
|
||||
unregister_chrdev_region(dev_no, 1);
|
||||
}
|
||||
static int epiphany_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int epiphany_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct mmap_mem_ops = {
|
||||
#ifdef CONFIG_HAVE_IOREMAP_PROT
|
||||
.access = generic_access_phys
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Map memory that can be shared between the Epiphany
|
||||
* device and user-space
|
||||
*/
|
||||
static int epiphany_map_host_memory(struct vm_area_struct *vma)
|
||||
{
|
||||
int err;
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
|
||||
|
||||
err = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot);
|
||||
|
||||
if (err) {
|
||||
printk(KERN_ERR "Failed mapping host memory to vma 0x%08lx, "
|
||||
"size 0x%08lx, page offset 0x%08lx\n",
|
||||
vma->vm_start, vma->vm_end - vma->vm_start,
|
||||
vma->vm_pgoff);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int epiphany_map_device_memory(struct vm_area_struct *vma)
|
||||
{
|
||||
int err, retval = 0;
|
||||
unsigned long pfn = vma->vm_pgoff;
|
||||
unsigned long size = vma->vm_end - vma->vm_start;
|
||||
|
||||
vma->vm_flags |= (VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
|
||||
#ifdef EHalUsesOffsetsRatherThanAbsoluteAddress
|
||||
pfn = (EPIPHANY_MEM_START + off) >> PAGE_SHIFT;
|
||||
#endif
|
||||
|
||||
err = io_remap_pfn_range(vma, vma->vm_start, pfn, size,
|
||||
vma->vm_page_prot);
|
||||
|
||||
if (err) {
|
||||
printk(KERN_ERR "Failed mapping device memory to vma 0x%08lx, "
|
||||
"size 0x%08lx, page offset 0x%08lx\n",
|
||||
vma->vm_start, vma->vm_end - vma->vm_start,
|
||||
vma->vm_pgoff);
|
||||
retval = -EAGAIN;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int epiphany_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
int retval = 0;
|
||||
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
|
||||
unsigned long size = vma->vm_end - vma->vm_start;
|
||||
|
||||
vma->vm_ops = &mmap_mem_ops;
|
||||
|
||||
if ((EPIPHANY_MEM_START <= off ) && ((off + size) <= EPIPHANY_MEM_END)) {
|
||||
retval = epiphany_map_device_memory(vma);
|
||||
} else if ((PL_MEM_START <= off ) && ((off + size) <= PL_MEM_END)) {
|
||||
retval = epiphany_map_device_memory(vma);
|
||||
} else if ((HOST_MEM_START <= off) && ((off + size) <= HOST_MEM_END)) {
|
||||
retval = epiphany_map_host_memory(vma);
|
||||
} else {
|
||||
printk(KERN_DEBUG "epiphany_mmap - invalid request to map "
|
||||
"0x%08lx, length 0x%08lx bytes\n", off, size);
|
||||
retval = -EINVAL;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static long epiphany_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int retval = 0;
|
||||
int err = 0;
|
||||
epiphany_alloc_t *ealloc = NULL;
|
||||
mailbox_notifier_t notifier;
|
||||
|
||||
if (_IOC_TYPE(cmd) != EPIPHANY_IOC_MAGIC) {
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) > EPIPHANY_IOC_MAXNR) {
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
if (_IOC_DIR(cmd) & _IOC_READ) {
|
||||
err =
|
||||
!access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
|
||||
} else if (_IOC_DIR(cmd) & _IOC_WRITE) {
|
||||
err =
|
||||
!access_ok(VERIFY_WRITE, (void __user *)arg,
|
||||
_IOC_SIZE(cmd));
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case EPIPHANY_IOC_GETSHM:
|
||||
ealloc = (epiphany_alloc_t *) (arg);
|
||||
if (copy_to_user(ealloc, &global_shm, sizeof(*ealloc))) {
|
||||
printk(KERN_ERR "EPIPHANY_IOC_GETSHM - failed\n");
|
||||
retval = -EACCES;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EPIPHANY_IOC_MB_ENABLE:
|
||||
enable_mailbox_irq();
|
||||
break;
|
||||
|
||||
case EPIPHANY_IOC_MB_DISABLE:
|
||||
disable_mailbox_irq();
|
||||
break;
|
||||
|
||||
case EPIPHANY_IOC_MB_NOTIFIER:
|
||||
// TODO lock access
|
||||
if (copy_from_user(¬ifier, (void __user *)arg, sizeof(mailbox_notifier_t)))
|
||||
{
|
||||
printk(KERN_ERR "EPIPHANY_IOC_MB_NOTIFIER - failed\n");
|
||||
retval = -EACCES;
|
||||
}
|
||||
|
||||
if (notifier.old_notifier != mailbox_notifier)
|
||||
{
|
||||
printk(KERN_ERR "EPIPHANY_IOC_MB_NOTIFIER - %d != %d\n", notifier.old_notifier, mailbox_notifier);
|
||||
retval = -EACCES;
|
||||
}
|
||||
else
|
||||
{
|
||||
// flush the queue
|
||||
flush_workqueue(irq_workqueue);
|
||||
mailbox_notifier = notifier.new_notifier;
|
||||
}
|
||||
|
||||
if (0 < mailbox_notifier)
|
||||
{
|
||||
// Save the userspace task for later use
|
||||
mailbox.irq_work.userspace_task = pid_task(find_vpid(current->pid), PIDTYPE_PID);
|
||||
}
|
||||
|
||||
// TODO unlock
|
||||
break;
|
||||
|
||||
|
||||
default: /* Redundant, cmd was checked against MAXNR */
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline void reg_write(epiphany_mailbox_t *mailbox, u32 reg, u32 val)
|
||||
{
|
||||
iowrite32(val, mailbox->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline u32 reg_read(epiphany_mailbox_t *mailbox, u32 reg)
|
||||
{
|
||||
return ioread32(mailbox->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline void enable_mailbox_irq(void)
|
||||
{
|
||||
u32 cfg;
|
||||
|
||||
// How to lock ERX_CFG_REG access - could be used from user side at same time!
|
||||
cfg = reg_read(&mailbox, ERX_CFG_REG);
|
||||
reg_write(&mailbox, ERX_CFG_REG, cfg | MAILBOX_ENABLE);
|
||||
}
|
||||
|
||||
static inline void disable_mailbox_irq(void)
|
||||
{
|
||||
u32 cfg;
|
||||
|
||||
// How to lock ERX_CFG_REG access - could be used from user side at same time!
|
||||
cfg = reg_read(&mailbox, ERX_CFG_REG);
|
||||
reg_write(&mailbox, ERX_CFG_REG, cfg & ~MAILBOX_ENABLE);
|
||||
}
|
||||
|
||||
static inline u32 read_mailbox_lo(void)
|
||||
{
|
||||
return reg_read(&mailbox, (u32)MAILBOX_LO_REG);
|
||||
}
|
||||
|
||||
static inline u32 read_mailbox_hi(void)
|
||||
{
|
||||
return reg_read(&mailbox, (u32)MAILBOX_HI_REG);
|
||||
}
|
||||
|
||||
static void irq_work_func(struct work_struct *work)
|
||||
{
|
||||
irq_work_t * irq_work = (irq_work_t *)work;
|
||||
struct file * efd_file = NULL;
|
||||
|
||||
mailbox_lo = (int)read_mailbox_lo();
|
||||
mailbox_hi = (int)read_mailbox_hi();
|
||||
|
||||
// current file is always used at the time of the interrupt
|
||||
if (0 < mailbox_notifier)
|
||||
{
|
||||
rcu_read_lock();
|
||||
efd_file = fcheck_files(irq_work->userspace_task->files, mailbox_notifier);
|
||||
rcu_read_unlock();
|
||||
// printk(KERN_INFO "EPIPHANY_IOC_MB_NOTIFIER: %p\n", efd_file);
|
||||
|
||||
efd_ctx = eventfd_ctx_fileget(efd_file);
|
||||
if (!efd_ctx)
|
||||
{
|
||||
printk(KERN_ERR "EPIPHANY_IOC_MB_NOTIFIER: failed to get eventfd file\n");
|
||||
// TODO consider setting mailbox_notifier back to default
|
||||
// this might complicate the user side
|
||||
// mailbox_notifier = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// send the event
|
||||
eventfd_signal(efd_ctx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mailbox_irq_handler - Mailbox Interrupt handler
|
||||
* @irq: IRQ number
|
||||
* @data: Pointer to
|
||||
*
|
||||
* Return: IRQ_HANDLED/IRQ_NONE
|
||||
*/
|
||||
static irqreturn_t mailbox_irq_handler(int irq, void *data)
|
||||
{
|
||||
epiphany_mailbox_t *mailbox = (epiphany_mailbox_t *)data;
|
||||
|
||||
// disable the interrupt
|
||||
disable_mailbox_irq();
|
||||
|
||||
if (0 < mailbox_notifier && irq_workqueue)
|
||||
{
|
||||
queue_work(irq_workqueue, &mailbox->irq_work.work);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
module_init(epiphany_init);
|
||||
module_exit(epiphany_exit);
|
60
elink/sw/mailbox/kernel/epiphany.h
Normal file
60
elink/sw/mailbox/kernel/epiphany.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef EPIPHANY_H
|
||||
#define EPIPHANY_H
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
/** Length of the Global shared memory region */
|
||||
#define GLOBAL_SHM_SIZE (4<<20)
|
||||
#define SHM_LOCK_NAME "/eshmlock"
|
||||
|
||||
#define SHM_MAGIC 0xabcdef00
|
||||
|
||||
typedef struct _EPIPHANY_ALLOC
|
||||
{
|
||||
unsigned long size;
|
||||
unsigned long flags;
|
||||
unsigned long bus_addr; /* out */
|
||||
unsigned long phy_addr; /* out */
|
||||
unsigned long kvirt_addr; /* out */
|
||||
unsigned long uvirt_addr; /* out */
|
||||
unsigned long mmap_handle; /* Handle to use for mmap */
|
||||
} epiphany_alloc_t;
|
||||
|
||||
typedef struct _MAILBOX_NOTIFIER
|
||||
{
|
||||
int old_notifier;
|
||||
int new_notifier;
|
||||
} mailbox_notifier_t;
|
||||
|
||||
#define EPIPHANY_IOC_MAGIC 'k'
|
||||
|
||||
/**
|
||||
* If you add an IOC command, please update the
|
||||
* EPIPHANY_IOC_MAXNR macro
|
||||
*/
|
||||
|
||||
#define EPIPHANY_IOC_GETSHM_CMD 24
|
||||
#define EPIPHANY_IOC_MB_DISABLE_CMD 25
|
||||
#define EPIPHANY_IOC_MB_ENABLE_CMD 26
|
||||
#define EPIPHANY_IOC_MB_NOTIFIER_CMD 27
|
||||
|
||||
#define EPIPHANY_IOC_MAXNR 27
|
||||
|
||||
#define EPIPHANY_IOC_GETSHM _IOWR(EPIPHANY_IOC_MAGIC, EPIPHANY_IOC_GETSHM_CMD, epiphany_alloc_t *)
|
||||
#define EPIPHANY_IOC_MB_ENABLE _IO(EPIPHANY_IOC_MAGIC, EPIPHANY_IOC_MB_ENABLE_CMD)
|
||||
#define EPIPHANY_IOC_MB_DISABLE _IO(EPIPHANY_IOC_MAGIC, EPIPHANY_IOC_MB_DISABLE_CMD)
|
||||
#define EPIPHANY_IOC_MB_NOTIFIER _IOW(EPIPHANY_IOC_MAGIC, EPIPHANY_IOC_MB_NOTIFIER_CMD, mailbox_notifier_t *)
|
||||
|
||||
/**
|
||||
* mailbox notifier file
|
||||
*/
|
||||
#define MAILBOX_NOTIFIER "/sys/class/epiphany/epiphany/mailbox_notifier"
|
||||
/**
|
||||
* mailbox high byte valid after interrupt
|
||||
*/
|
||||
#define MAILBOX_HI "/sys/class/epiphany/epiphany/mailbox_hi"
|
||||
/**
|
||||
* mailbox low byte valid after interrupt
|
||||
*/
|
||||
#define MAILBOX_LO "/sys/class/epiphany/epiphany/mailbox_lo"
|
||||
|
||||
#endif
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <string.h>
|
||||
#include <e-hal.h>
|
||||
#include <e-loader.h>
|
||||
@ -11,96 +13,79 @@
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h> // for errno
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <uapi/linux/epiphany.h> // for ioctl numbers
|
||||
|
||||
#define TAPS 64
|
||||
|
||||
// Epiphany system registers
|
||||
typedef enum {
|
||||
E_SYS_RESET = 0xF0200,
|
||||
E_SYS_CLKCFG = 0xF0204,
|
||||
E_SYS_CHIPID = 0xF0208,
|
||||
E_SYS_VERSION = 0xF020c,
|
||||
E_SYS_TXCFG = 0xF0210,
|
||||
E_SYS_RXCFG = 0xF0300,
|
||||
E_SYS_RXDMACFG = 0xF0500,
|
||||
} e_sys_reg_id_t;
|
||||
#define E_SYS_TXSTATUS (0xF0214)
|
||||
#define E_SYS_RXSTATUS (0xF0304)
|
||||
#define E_SYS_RXIDELAY0 (0xF0310)
|
||||
#define E_SYS_RXIDELAY1 (0xF0314)
|
||||
#define EPIPHANY_DEV "/dev/epiphany"
|
||||
|
||||
typedef union {
|
||||
unsigned int reg;
|
||||
struct {
|
||||
unsigned int reset:1;
|
||||
// unsigned int chip_reset:1;
|
||||
// unsigned int reset:1;
|
||||
};
|
||||
} e_sys_reset_t;
|
||||
#ifdef EPIPHANY_IOC_MB_ENABLE
|
||||
typedef struct _MAILBOX_CONTROL
|
||||
{
|
||||
int running; // 1 if ready; otherwise not ready
|
||||
int devfd; // handle for epiphany device driver
|
||||
int epollfd; // handle for blocking wait on notification
|
||||
int kernelEventfd; // handle for kernel notification
|
||||
struct epoll_event *events;
|
||||
mailbox_notifier_t mailbox_notifier;
|
||||
} mailbox_control_t;
|
||||
static mailbox_control_t mc;
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
unsigned int reg;
|
||||
struct {
|
||||
unsigned int cclk_enable:1;
|
||||
unsigned int lclk_enable:1;
|
||||
unsigned int cclk_bypass:1;
|
||||
unsigned int lclk_bypass:1;
|
||||
unsigned int cclk_divider:4;
|
||||
unsigned int lclk_divider:4;
|
||||
};
|
||||
} e_sys_clkcfg_t;
|
||||
int InitialEpiphany();
|
||||
void CloseEpiphany();
|
||||
int InitialTestMessageStore();
|
||||
void CloseTestMessageStore();
|
||||
int InitialMailboxNotifier();
|
||||
int OpenEpiphanyDevice();
|
||||
int OpenKernelEventMonitor();
|
||||
void CloseMailboxNotifier();
|
||||
void CancelMailboxNotifier();
|
||||
int WaitForMailboxNotifier();
|
||||
void PrintStuffOfInterest();
|
||||
|
||||
typedef union {
|
||||
unsigned int reg;
|
||||
struct {
|
||||
unsigned int col:6;
|
||||
unsigned int row:6;
|
||||
};
|
||||
} e_sys_chipid_t;
|
||||
static int UseInterrupts = 0;
|
||||
static e_sys_rxcfg_t rxcfg = { .reg = 0 };
|
||||
|
||||
typedef union {
|
||||
unsigned int reg;
|
||||
struct {
|
||||
unsigned int platform:8;
|
||||
unsigned int revision:8;
|
||||
};
|
||||
} e_sys_version_t;
|
||||
|
||||
typedef union {
|
||||
unsigned int reg;
|
||||
struct {
|
||||
unsigned int enable:1;
|
||||
unsigned int mmu_enable:1;
|
||||
unsigned int remap_cfg:2;
|
||||
unsigned int ctrlmode:4;
|
||||
unsigned int ctrlmode_select:1;
|
||||
unsigned int transmit_mode:3;
|
||||
};
|
||||
} e_sys_txcfg_t;
|
||||
|
||||
typedef union {
|
||||
unsigned int reg;
|
||||
struct {
|
||||
unsigned int testmode:1;
|
||||
unsigned int mmu_enable:1;
|
||||
unsigned int remap_cfg:2;
|
||||
unsigned int remap_mask:12;
|
||||
unsigned int remap_base:12;
|
||||
unsigned int timeout:2;
|
||||
};
|
||||
} e_sys_rxcfg_t;
|
||||
|
||||
typedef union {
|
||||
unsigned int reg;
|
||||
struct {
|
||||
unsigned int enable:1;
|
||||
unsigned int master_mode:1;
|
||||
unsigned int __reserved1:3;
|
||||
unsigned int width:2;
|
||||
unsigned int __reserved2:3;
|
||||
unsigned int message_mode:1;
|
||||
unsigned int src_shift:1;
|
||||
unsigned int dst_shift:1;
|
||||
};
|
||||
} e_sys_rx_dmacfg_t;
|
||||
static int idelay[TAPS]={0x00000000,0x00000000,//0
|
||||
0x11111111,0x00000001,//1
|
||||
0x22222222,0x00000002,//2
|
||||
0x33333333,0x00000003,//3
|
||||
0x44444444,0x00000004,//4
|
||||
0x55555555,0x00000005,//5
|
||||
0x66666666,0x00000006,//6
|
||||
0x77777777,0x00000007,//7
|
||||
0x88888888,0x00000008,//8
|
||||
0x99999999,0x00000009,//9
|
||||
0xaaaaaaaa,0x0000000a,//10
|
||||
0xbbbbbbbb,0x0000000b,//11
|
||||
0xcccccccc,0x0000000c,//12
|
||||
0xdddddddd,0x0000000d,//13
|
||||
0xeeeeeeee,0x0000000e,//14
|
||||
0xffffffff,0x0000000f,//15
|
||||
0x00000000,0x00000010,//16
|
||||
0x11111111,0x00000011,//17
|
||||
0x22222222,0x00000012,//18
|
||||
0x33333333,0x00000013,//29
|
||||
0x44444444,0x00000014,//20
|
||||
0x55555555,0x00000015,//21
|
||||
0x66666666,0x00000016,//22
|
||||
0x77777777,0x00000017,//23
|
||||
0x88888888,0x00000018,//24
|
||||
0x99999999,0x00000019,//25
|
||||
0xaaaaaaaa,0x0000001a,//26
|
||||
0xbbbbbbbb,0x0000001b,//27
|
||||
0xcccccccc,0x0000001c,//28
|
||||
0xdddddddd,0x0000001d,//29
|
||||
0xeeeeeeee,0x0000001e,//30
|
||||
0xffffffff,0x0000001f};//31
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
e_loader_diag_t e_verbose;
|
||||
@ -116,7 +101,17 @@ int main(int argc, char *argv[]){
|
||||
unsigned result[N];
|
||||
unsigned data = 0xDEADBEEF;
|
||||
unsigned tmp,fail;
|
||||
|
||||
unsigned row, col, loopcount;
|
||||
int delayNo = 7;
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
if (UseInterrupts)
|
||||
{
|
||||
// Initialize the Mailbox notifier
|
||||
InitialMailboxNotifier();
|
||||
}
|
||||
|
||||
//Gets ELF file name from command line
|
||||
strcpy(elfFile, "./bin/e-task.elf");
|
||||
|
||||
@ -124,27 +119,98 @@ int main(int argc, char *argv[]){
|
||||
e_set_host_verbosity(H_D0);
|
||||
e_init(NULL);
|
||||
my_reset_system();
|
||||
e_get_platform_info(&platform);
|
||||
e_open(&dev, 0, 0, 1, 1); //open core 0,0
|
||||
e_get_platform_info(&platform);
|
||||
|
||||
//Start program
|
||||
e_load_group(elfFile, &dev, 0, 0, 1, 1, E_TRUE);
|
||||
for (loopcount=0; loopcount<50; loopcount++)
|
||||
{
|
||||
// Draw a random core
|
||||
row = rand() % platform.rows;
|
||||
col = rand() % platform.cols;
|
||||
|
||||
//This wait will be replaced by interrupt
|
||||
//how to enable interrupt in kernel?
|
||||
usleep(100000);
|
||||
if (!UseInterrupts)
|
||||
{
|
||||
// Without interrupts
|
||||
// For some reason fixed row and col is better
|
||||
row = 0;
|
||||
col = 0;
|
||||
|
||||
//Reading mailbox
|
||||
int pre_stat = ee_read_esys(0xF0328);
|
||||
int mbox_lo = ee_read_esys(0xF0320);
|
||||
int mbox_hi = ee_read_esys(0xF0324);
|
||||
int post_stat = ee_read_esys(0xF0328);
|
||||
// post_stat = ee_read_esys(0xF0304);
|
||||
// With interrupts fixed row and col fails earlier!
|
||||
}
|
||||
|
||||
printf("INFO: loopcount: %d, row: %d, col: %d\n", loopcount, row, col);
|
||||
|
||||
printf ("PRE_STAT=%08x POST_STAT=%08x LO=%08x HI=%08x\n", pre_stat, post_stat, mbox_lo, mbox_hi);
|
||||
|
||||
e_open(&dev, row, col, 1, 1); //open core 0,0
|
||||
e_reset_group(&dev);
|
||||
|
||||
if (sizeof(int) != ee_write_esys(E_SYS_RXIDELAY0, idelay[((delayNo+1)*2)-2]))
|
||||
{
|
||||
printf("INFO: setting idelay0 failed\n");
|
||||
}
|
||||
|
||||
if (sizeof(int) != ee_write_esys(E_SYS_RXIDELAY1, idelay[((delayNo+1)*2)-1]))
|
||||
{
|
||||
printf("INFO: setting idelay1 failed\n");
|
||||
}
|
||||
|
||||
if (UseInterrupts)
|
||||
{
|
||||
// Configure epoll to listen for interrupt event
|
||||
int rtn = ArmMailboxNotifier();
|
||||
if (rtn)
|
||||
{
|
||||
int rtns = errno;
|
||||
printf ("main(): EPOLL_CTL_ADD kernelEventfd failed! %s errno: %d\n", strerror(rtns), rtns);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Enable the mailbox interrupt
|
||||
rxcfg.reg = rxcfg.reg | (0x1 << 28);
|
||||
|
||||
if (sizeof(int) != ee_write_esys(E_SYS_RXCFG, rxcfg.reg))
|
||||
{
|
||||
printf("main(): Failed set rxcfg register\n");
|
||||
}
|
||||
}
|
||||
|
||||
//Start program
|
||||
printf("main(%d,%d): Load core\n", row, col);
|
||||
if (e_load_group(elfFile, &dev, 0, 0, 1, 1, E_TRUE))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
printf("main(%d,%d): Core Loaded\n", row, col);
|
||||
|
||||
if (UseInterrupts)
|
||||
{
|
||||
WaitForMailboxNotifier();
|
||||
}
|
||||
else
|
||||
{
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
//Reading mailbox
|
||||
int pre_stat = ee_read_esys(0xF0328);
|
||||
int mbox_lo = ee_read_esys(0xF0320);
|
||||
int mbox_hi = ee_read_esys(0xF0324);
|
||||
int post_stat = ee_read_esys(0xF0328);
|
||||
// post_stat = ee_read_esys(0xF0304);
|
||||
|
||||
printf ("PRE_STAT=%08x POST_STAT=%08x LO=%08x HI=%08x\n", pre_stat, post_stat, mbox_lo, mbox_hi);
|
||||
|
||||
PrintStuffOfInterest();
|
||||
|
||||
e_close(&dev);
|
||||
}
|
||||
|
||||
if (UseInterrupts)
|
||||
{
|
||||
CloseMailboxNotifier();
|
||||
}
|
||||
|
||||
//Close down Epiphany device
|
||||
e_close(&dev);
|
||||
e_finalize();
|
||||
|
||||
//self check
|
||||
@ -163,7 +229,6 @@ int my_reset_system(void)
|
||||
uint32_t divider;
|
||||
uint32_t chipid;
|
||||
e_sys_txcfg_t txcfg = { .reg = 0 };
|
||||
e_sys_rxcfg_t rxcfg = { .reg = 0 };
|
||||
e_sys_rx_dmacfg_t rx_dmacfg = { .reg = 0 };
|
||||
e_sys_clkcfg_t clkcfg = { .reg = 0 };
|
||||
e_sys_reset_t resetcfg = { .reg = 0 };
|
||||
@ -236,17 +301,277 @@ int my_reset_system(void)
|
||||
usleep(1000);
|
||||
if (sizeof(int) != ee_write_esys(E_SYS_TXCFG, txcfg.reg))
|
||||
goto cleanup_platform;
|
||||
|
||||
|
||||
rc = E_OK;
|
||||
|
||||
cleanup_platform:
|
||||
if (E_OK != rc) printf("e_reset_system(): fails\n");
|
||||
e_close(&dev);
|
||||
|
||||
usleep(1000);
|
||||
return E_OK;
|
||||
return rc;
|
||||
|
||||
err:
|
||||
warnx("e_reset_system(): Failed\n");
|
||||
usleep(1000);
|
||||
return E_ERR;
|
||||
}
|
||||
|
||||
void PrintStuffOfInterest()
|
||||
{
|
||||
// Print stuff of interest
|
||||
int etx_status = ee_read_esys(E_SYS_TXSTATUS);
|
||||
int etx_config = ee_read_esys(E_SYS_TXCFG);
|
||||
int erx_status = ee_read_esys(E_SYS_RXSTATUS);
|
||||
int erx_config = ee_read_esys(E_SYS_RXCFG);
|
||||
int erx_idelay0 = ee_read_esys(E_SYS_RXIDELAY0);
|
||||
int erx_idelay1 = ee_read_esys(E_SYS_RXIDELAY1);
|
||||
printf("INFO: etx_status: 0x%x, etx_config: 0x%x, erx_status: 0x%x, erx_config: 0x%x\n", etx_status, etx_config, erx_status, erx_config);
|
||||
printf("INFO: erx_idelay0: 0x%x, erx_idelay1: 0x%x\n", erx_idelay0, erx_idelay1);
|
||||
}
|
||||
|
||||
int InitialMailboxNotifier()
|
||||
{
|
||||
#ifdef EPIPHANY_IOC_MB_ENABLE
|
||||
int returns;
|
||||
|
||||
mc.running = 0;
|
||||
|
||||
// Open an epoll object
|
||||
mc.epollfd = epoll_create(1);
|
||||
if ( -1 == mc.epollfd ) {
|
||||
printf("InitialMailboxNotifier(): epoll open failure.");
|
||||
return E_ERR;
|
||||
}
|
||||
|
||||
returns = OpenEpiphanyDevice();
|
||||
if (returns)
|
||||
{
|
||||
printf("InitialMailboxNotifier(): epiphany open failure.");
|
||||
close(mc.epollfd);
|
||||
return returns;
|
||||
}
|
||||
|
||||
returns = OpenKernelEventMonitor();
|
||||
if (returns)
|
||||
{
|
||||
printf("InitialMailboxNotifier(): mailbox sysfs monitor open failure.");
|
||||
// Tidy up
|
||||
close(mc.devfd);
|
||||
close(mc.epollfd);
|
||||
return returns;
|
||||
}
|
||||
|
||||
// Now allocate the event list
|
||||
mc.events = calloc(2, sizeof(struct epoll_event));
|
||||
if (NULL == mc.events)
|
||||
{
|
||||
printf("InitialMailboxNotifier(): malloc of event memory failure.");
|
||||
// Tidy up
|
||||
struct epoll_event event;
|
||||
epoll_ctl (mc.epollfd, EPOLL_CTL_DEL, mc.kernelEventfd, &event);
|
||||
close(mc.kernelEventfd);
|
||||
close(mc.devfd);
|
||||
close(mc.epollfd);
|
||||
return returns;
|
||||
}
|
||||
|
||||
mc.running = 1;
|
||||
return returns;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OpenEpiphanyDevice()
|
||||
{
|
||||
#ifdef EPIPHANY_IOC_MB_ENABLE
|
||||
// Now open the epiphany device for mailbox interrupt control
|
||||
mc.devfd = open(EPIPHANY_DEV, O_RDWR | O_SYNC);
|
||||
// printf ("OpenEpiphanyDevice(): mc.devfd %d\n", mc.devfd);
|
||||
if ( -1 == mc.devfd )
|
||||
{
|
||||
int rtn = errno;
|
||||
printf ("InitialMaiboxNotifier(): epiphany device open failed! %s errno %d\n", strerror(rtn), rtn);
|
||||
|
||||
return E_ERR;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OpenKernelEventMonitor()
|
||||
{
|
||||
#ifdef EPIPHANY_IOC_MB_ENABLE
|
||||
int returns;
|
||||
char notifier[8];
|
||||
int notifierfd;
|
||||
int oldNotifier;
|
||||
|
||||
// Open the kernel Event Notifier
|
||||
mc.kernelEventfd = eventfd(0, EFD_NONBLOCK);
|
||||
if ( -1 == mc.kernelEventfd )
|
||||
{
|
||||
int rtn = errno;
|
||||
printf ("InitialMailboxNotifier(): Kernel Event Notifier open failure! %s errno: %d\n", strerror(rtn), rtn);
|
||||
|
||||
return E_ERR;
|
||||
}
|
||||
|
||||
// Add the kernelEventfd handle to epoll
|
||||
returns = ModifyNotifier(mc.kernelEventfd, EPOLL_CTL_ADD);
|
||||
if (returns)
|
||||
{
|
||||
int rtn = errno;
|
||||
printf ("InitialMailboxNotifier(): EPOLL_CTL_ADD kernelEventfd failed! %s errno: %d kernelEventfd: %d\n", strerror(rtn), rtn, mc.kernelEventfd);
|
||||
|
||||
// Tidy up
|
||||
close(mc.kernelEventfd);
|
||||
return rtn;
|
||||
}
|
||||
|
||||
// Starting from scratch with no other application running
|
||||
// read the current kernel mailbox_notifier fd handle
|
||||
// If the current kernel mailbox_notifier fd handle is -1 there is no
|
||||
// other application using the mailbox.
|
||||
notifierfd = open(MAILBOX_NOTIFIER, O_RDONLY);
|
||||
oldNotifier = -1;
|
||||
if (0 < notifierfd)
|
||||
{
|
||||
int rtn = read(notifierfd, notifier, 8);
|
||||
|
||||
// printf ("InitialMailboxNotifier(): returns: %d, Old notifier fd: %s\n", rtn, notifier);
|
||||
if (rtn)
|
||||
{
|
||||
sscanf(notifier, "%d", &oldNotifier);
|
||||
}
|
||||
|
||||
close(notifierfd);
|
||||
}
|
||||
|
||||
// Starting from scratch ignore other applications and override them
|
||||
// by passing the old kernel mailbox_notifier fd handle to the driver
|
||||
// and replace this with the new fd
|
||||
mc.mailbox_notifier.old_notifier = oldNotifier;
|
||||
mc.mailbox_notifier.new_notifier = mc.kernelEventfd;
|
||||
if ( -1 == ioctl(mc.devfd, EPIPHANY_IOC_MB_NOTIFIER, &mc.mailbox_notifier) )
|
||||
{
|
||||
int rtn = errno;
|
||||
printf("InitialMailboxNotifier(): Failed to send notifier to driver. %s errno: %d kernelEventfd: %d\n", strerror(rtn), rtn, mc.kernelEventfd);
|
||||
|
||||
// Tidy up
|
||||
struct epoll_event event;
|
||||
epoll_ctl (mc.epollfd, EPOLL_CTL_DEL, mc.kernelEventfd, &event);
|
||||
close(mc.kernelEventfd);
|
||||
mc.kernelEventfd = -1;
|
||||
return rtn;
|
||||
}
|
||||
|
||||
return returns;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ArmMailboxNotifier()
|
||||
{
|
||||
#ifdef EPIPHANY_IOC_MB_ENABLE
|
||||
if (mc.running)
|
||||
{
|
||||
return ModifyNotifier(mc.kernelEventfd, EPOLL_CTL_MOD);
|
||||
}
|
||||
|
||||
return E_ERR;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ModifyNotifier(int fd, int operation)
|
||||
{
|
||||
return UpdateEpoll(fd, operation, EPOLLIN | EPOLLET);
|
||||
}
|
||||
|
||||
int UpdateEpoll(int fd, int operation, uint32_t waitOnEvent)
|
||||
{
|
||||
#ifdef EPIPHANY_IOC_MB_ENABLE
|
||||
int returns;
|
||||
struct epoll_event event;
|
||||
|
||||
returns = E_ERR;
|
||||
|
||||
// Add the kernelEventfd handle to epoll
|
||||
event.data.fd = fd;
|
||||
event.events = waitOnEvent;
|
||||
returns = epoll_ctl (mc.epollfd, operation, fd, &event);
|
||||
if (returns)
|
||||
{
|
||||
returns = errno;
|
||||
printf ("InitialMailboxNotifier(): epoll_ctl failed! %s errno: %d operation: %d, event: %d, fd: %d\n", strerror(returns), returns, operation, waitOnEvent, fd);
|
||||
}
|
||||
|
||||
return returns;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WaitForMailboxNotifier()
|
||||
{
|
||||
#ifdef EPIPHANY_IOC_MB_ENABLE
|
||||
int numberOfEvents;
|
||||
size_t bytesRead;
|
||||
int64_t eventfdCount;
|
||||
|
||||
numberOfEvents = epoll_wait(mc.epollfd, mc.events, 2, -1);
|
||||
if ((1 < numberOfEvents) || (mc.events[0].data.fd != mc.kernelEventfd))
|
||||
{
|
||||
printf("INFO: WaitForMailboxNotifier(): Cancelled!\n");
|
||||
}
|
||||
|
||||
if (0 > numberOfEvents)
|
||||
{
|
||||
int epollerrno = errno;
|
||||
printf("WaitForMailboxNotifier(): epoll_wait failed! %s errno %d\n", strerror(epollerrno), epollerrno);
|
||||
}
|
||||
|
||||
bytesRead = read(mc.kernelEventfd, &eventfdCount, sizeof(int64_t));
|
||||
if (0 > bytesRead)
|
||||
{
|
||||
// failure to reset the eventfd counter to zero
|
||||
// can cause lockups!
|
||||
int eventfderrno = errno;
|
||||
printf("ERROR: WaitForMailboxNotifier(): lockup likely: eventfd counter reset failed! %s errno %d\n", strerror(eventfderrno), eventfderrno);
|
||||
}
|
||||
|
||||
// printf("WaitForMailboxNotifier(): bytesRead: %d, eventfdCount: %d\n", bytesRead, eventfdCount);
|
||||
|
||||
return numberOfEvents;
|
||||
#else
|
||||
// do the best we can and wait
|
||||
usleep(100000);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CloseMailboxNotifier()
|
||||
{
|
||||
#ifdef EPIPHANY_IOC_MB_ENABLE
|
||||
//printf ("INFO: MailboxNotifier Closing\n");
|
||||
if (mc.running)
|
||||
{
|
||||
if (0 < mc.kernelEventfd)
|
||||
{
|
||||
mc.mailbox_notifier.old_notifier = mc.kernelEventfd;
|
||||
mc.mailbox_notifier.new_notifier = -1;
|
||||
ioctl(mc.devfd, EPIPHANY_IOC_MB_NOTIFIER, &mc.mailbox_notifier);
|
||||
}
|
||||
|
||||
struct epoll_event event;
|
||||
epoll_ctl (mc.epollfd, EPOLL_CTL_DEL, mc.kernelEventfd, &event);
|
||||
free((void *)mc.events);
|
||||
close(mc.kernelEventfd);
|
||||
mc.kernelEventfd = -1;
|
||||
close(mc.devfd);
|
||||
close(mc.epollfd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user