From 0c072b46ecc8689be160bfdc750e95ad9879d706 Mon Sep 17 00:00:00 2001 From: Akhil Goyal Date: Thu, 5 Jul 2018 20:14:21 +0530 Subject: [PATCH] staging: fsl_ppfe: enable hif event from userspace HIF interrupts are enabled using ioctl from user space, and epoll wait from user space wakes up when there is an HIF interrupt. Signed-off-by: Akhil Goyal --- drivers/staging/fsl_ppfe/pfe_cdev.c | 57 +++++++++++++++++++++++++++++++++++++ drivers/staging/fsl_ppfe/pfe_cdev.h | 5 ++-- 2 files changed, 60 insertions(+), 2 deletions(-) --- a/drivers/staging/fsl_ppfe/pfe_cdev.c +++ b/drivers/staging/fsl_ppfe/pfe_cdev.c @@ -20,11 +20,18 @@ * - used for interacting with the kernel layer for link status */ +#include +#include +#include +#include + #include "pfe_cdev.h" +#include "pfe_mod.h" static int pfe_majno; static struct class *pfe_char_class; static struct device *pfe_char_dev; +struct eventfd_ctx *g_trigger; struct pfe_shared_info link_states[PFE_CDEV_ETH_COUNT]; @@ -80,10 +87,44 @@ static ssize_t pfe_cdev_write(struct fil static int pfe_cdev_release(struct inode *inp, struct file *fp) { + if (g_trigger) { + free_irq(pfe->hif_irq, g_trigger); + eventfd_ctx_put(g_trigger); + g_trigger = NULL; + } + pr_info("PFE_CDEV: Device successfully closed\n"); return 0; } +/* + * hif_us_isr- + * This ISR routine processes Rx/Tx done interrupts from the HIF hardware block + */ +static irqreturn_t hif_us_isr(int irq, void *arg) +{ + struct eventfd_ctx *trigger = (struct eventfd_ctx *)arg; + int int_status; + int int_enable_mask; + + /*Read hif interrupt source register */ + int_status = readl_relaxed(HIF_INT_SRC); + int_enable_mask = readl_relaxed(HIF_INT_ENABLE); + + if ((int_status & HIF_INT) == 0) + return IRQ_NONE; + + if (int_status & HIF_RXPKT_INT) { + int_enable_mask &= ~(HIF_RXPKT_INT); + eventfd_signal(trigger, 1); + } + + /*Disable interrupts, they will be enabled after they are serviced */ + writel_relaxed(int_enable_mask, HIF_INT_ENABLE); + + return IRQ_HANDLED; +} + static long pfe_cdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { @@ -105,6 +146,22 @@ static long pfe_cdev_ioctl(struct file * pr_debug("Returning state=%d for ETH1\n", *argp); ret = 0; break; + case PFE_CDEV_HIF_INTR_EN: + /* Return success/failure */ + g_trigger = eventfd_ctx_fdget(*argp); + if (IS_ERR(g_trigger)) + return PTR_ERR(g_trigger); + ret = request_irq(pfe->hif_irq, hif_us_isr, 0, "pfe_hif", + g_trigger); + if (ret) { + pr_err("%s: failed to get the hif IRQ = %d\n", + __func__, pfe->hif_irq); + eventfd_ctx_put(g_trigger); + g_trigger = NULL; + } + pr_debug("request_irq for hif interrupt: %d\n", pfe->hif_irq); + ret = 0; + break; default: pr_info("Unsupport cmd (%d) for PFE CDEV.\n", cmd); break; --- a/drivers/staging/fsl_ppfe/pfe_cdev.h +++ b/drivers/staging/fsl_ppfe/pfe_cdev.h @@ -43,8 +43,9 @@ struct pfe_shared_info { extern struct pfe_shared_info link_states[PFE_CDEV_ETH_COUNT]; /* IOCTL Commands */ -#define PFE_CDEV_ETH0_STATE_GET 0 -#define PFE_CDEV_ETH1_STATE_GET 1 +#define PFE_CDEV_ETH0_STATE_GET _IOR('R', 0, int) +#define PFE_CDEV_ETH1_STATE_GET _IOR('R', 1, int) +#define PFE_CDEV_HIF_INTR_EN _IOWR('R', 2, int) int pfe_cdev_init(void); void pfe_cdev_exit(void);