[PATCH v3 10/11] staging: fsl-mc: Added DPRC interrupt handler

2015-11-06 Thread J. German Rivera
The interrupt handler for DPRC IRQs is added. DPRC IRQs are
generated for hot plug events related to DPAA2 objects in a given
DPRC. These events include, creating/destroying DPAA2 objects in
the DPRC, changing the "plugged" state of DPAA2 objects and moving
objects between DPRCs.

Signed-off-by: J. German Rivera 
---
CHANGE HISTORY

Changes in v3: none

Changes in v2: none

 drivers/staging/fsl-mc/bus/dprc-driver.c | 247 +++
 1 file changed, 247 insertions(+)

diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c 
b/drivers/staging/fsl-mc/bus/dprc-driver.c
index 7f1ceb5..0bd2e63 100644
--- a/drivers/staging/fsl-mc/bus/dprc-driver.c
+++ b/drivers/staging/fsl-mc/bus/dprc-driver.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "dprc-cmd.h"

 struct dprc_child_objs {
@@ -386,6 +387,230 @@ error:
 EXPORT_SYMBOL_GPL(dprc_scan_container);

 /**
+ * dprc_irq0_handler - Regular ISR for DPRC interrupt 0
+ *
+ * @irq: IRQ number of the interrupt being handled
+ * @arg: Pointer to device structure
+ */
+static irqreturn_t dprc_irq0_handler(int irq_num, void *arg)
+{
+   return IRQ_WAKE_THREAD;
+}
+
+/**
+ * dprc_irq0_handler_thread - Handler thread function for DPRC interrupt 0
+ *
+ * @irq: IRQ number of the interrupt being handled
+ * @arg: Pointer to device structure
+ */
+static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg)
+{
+   int error;
+   u32 status;
+   struct device *dev = (struct device *)arg;
+   struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+   struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
+   struct fsl_mc_io *mc_io = mc_dev->mc_io;
+   struct msi_desc *msi_desc = mc_dev->irqs[0]->msi_desc;
+
+   dev_dbg(dev, "DPRC IRQ %d triggered on CPU %u\n",
+   irq_num, smp_processor_id());
+
+   if (WARN_ON(!(mc_dev->flags & FSL_MC_IS_DPRC)))
+   return IRQ_HANDLED;
+
+   mutex_lock(_bus->scan_mutex);
+   if (WARN_ON(!msi_desc || msi_desc->irq != (u32)irq_num))
+   goto out;
+
+   error = dprc_get_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
+   );
+   if (error < 0) {
+   dev_err(dev,
+   "dprc_get_irq_status() failed: %d\n", error);
+   goto out;
+   }
+
+   error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
+ status);
+   if (error < 0) {
+   dev_err(dev,
+   "dprc_clear_irq_status() failed: %d\n", error);
+   goto out;
+   }
+
+   if (status & (DPRC_IRQ_EVENT_OBJ_ADDED |
+ DPRC_IRQ_EVENT_OBJ_REMOVED |
+ DPRC_IRQ_EVENT_CONTAINER_DESTROYED |
+ DPRC_IRQ_EVENT_OBJ_DESTROYED |
+ DPRC_IRQ_EVENT_OBJ_CREATED)) {
+   unsigned int irq_count;
+
+   error = dprc_scan_objects(mc_dev, _count);
+   if (error < 0) {
+   /*
+* If the error is -ENXIO, we ignore it, as it indicates
+* that the object scan was aborted, as we detected that
+* an object was removed from the DPRC in the MC, while
+* we were scanning the DPRC.
+*/
+   if (error != -ENXIO) {
+   dev_err(dev, "dprc_scan_objects() failed: %d\n",
+   error);
+   }
+
+   goto out;
+   }
+
+   if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
+   dev_warn(dev,
+"IRQs needed (%u) exceed IRQs preallocated 
(%u)\n",
+irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
+   }
+   }
+
+out:
+   mutex_unlock(_bus->scan_mutex);
+   return IRQ_HANDLED;
+}
+
+/*
+ * Disable and clear interrupt for a given DPRC object
+ */
+static int disable_dprc_irq(struct fsl_mc_device *mc_dev)
+{
+   int error;
+   struct fsl_mc_io *mc_io = mc_dev->mc_io;
+
+   WARN_ON(mc_dev->obj_desc.irq_count != 1);
+
+   /*
+* Disable generation of interrupt, while we configure it:
+*/
+   error = dprc_set_irq_enable(mc_io, 0, mc_dev->mc_handle, 0, 0);
+   if (error < 0) {
+   dev_err(_dev->dev,
+   "Disabling DPRC IRQ failed: dprc_set_irq_enable() 
failed: %d\n",
+   error);
+   return error;
+   }
+
+   /*
+* Disable all interrupt causes for the interrupt:
+*/
+   error = dprc_set_irq_mask(mc_io, 0, mc_dev->mc_handle, 0, 0x0);
+   if (error < 0) {
+   dev_err(_dev->dev,
+   "Disabling DPRC IRQ failed: dprc_set_irq_mask() failed: 
%d\n",
+   error);
+   return 

[PATCH v3 10/11] staging: fsl-mc: Added DPRC interrupt handler

2015-11-06 Thread J. German Rivera
The interrupt handler for DPRC IRQs is added. DPRC IRQs are
generated for hot plug events related to DPAA2 objects in a given
DPRC. These events include, creating/destroying DPAA2 objects in
the DPRC, changing the "plugged" state of DPAA2 objects and moving
objects between DPRCs.

Signed-off-by: J. German Rivera 
---
CHANGE HISTORY

Changes in v3: none

Changes in v2: none

 drivers/staging/fsl-mc/bus/dprc-driver.c | 247 +++
 1 file changed, 247 insertions(+)

diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c 
b/drivers/staging/fsl-mc/bus/dprc-driver.c
index 7f1ceb5..0bd2e63 100644
--- a/drivers/staging/fsl-mc/bus/dprc-driver.c
+++ b/drivers/staging/fsl-mc/bus/dprc-driver.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "dprc-cmd.h"

 struct dprc_child_objs {
@@ -386,6 +387,230 @@ error:
 EXPORT_SYMBOL_GPL(dprc_scan_container);

 /**
+ * dprc_irq0_handler - Regular ISR for DPRC interrupt 0
+ *
+ * @irq: IRQ number of the interrupt being handled
+ * @arg: Pointer to device structure
+ */
+static irqreturn_t dprc_irq0_handler(int irq_num, void *arg)
+{
+   return IRQ_WAKE_THREAD;
+}
+
+/**
+ * dprc_irq0_handler_thread - Handler thread function for DPRC interrupt 0
+ *
+ * @irq: IRQ number of the interrupt being handled
+ * @arg: Pointer to device structure
+ */
+static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg)
+{
+   int error;
+   u32 status;
+   struct device *dev = (struct device *)arg;
+   struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+   struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
+   struct fsl_mc_io *mc_io = mc_dev->mc_io;
+   struct msi_desc *msi_desc = mc_dev->irqs[0]->msi_desc;
+
+   dev_dbg(dev, "DPRC IRQ %d triggered on CPU %u\n",
+   irq_num, smp_processor_id());
+
+   if (WARN_ON(!(mc_dev->flags & FSL_MC_IS_DPRC)))
+   return IRQ_HANDLED;
+
+   mutex_lock(_bus->scan_mutex);
+   if (WARN_ON(!msi_desc || msi_desc->irq != (u32)irq_num))
+   goto out;
+
+   error = dprc_get_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
+   );
+   if (error < 0) {
+   dev_err(dev,
+   "dprc_get_irq_status() failed: %d\n", error);
+   goto out;
+   }
+
+   error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
+ status);
+   if (error < 0) {
+   dev_err(dev,
+   "dprc_clear_irq_status() failed: %d\n", error);
+   goto out;
+   }
+
+   if (status & (DPRC_IRQ_EVENT_OBJ_ADDED |
+ DPRC_IRQ_EVENT_OBJ_REMOVED |
+ DPRC_IRQ_EVENT_CONTAINER_DESTROYED |
+ DPRC_IRQ_EVENT_OBJ_DESTROYED |
+ DPRC_IRQ_EVENT_OBJ_CREATED)) {
+   unsigned int irq_count;
+
+   error = dprc_scan_objects(mc_dev, _count);
+   if (error < 0) {
+   /*
+* If the error is -ENXIO, we ignore it, as it indicates
+* that the object scan was aborted, as we detected that
+* an object was removed from the DPRC in the MC, while
+* we were scanning the DPRC.
+*/
+   if (error != -ENXIO) {
+   dev_err(dev, "dprc_scan_objects() failed: %d\n",
+   error);
+   }
+
+   goto out;
+   }
+
+   if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
+   dev_warn(dev,
+"IRQs needed (%u) exceed IRQs preallocated 
(%u)\n",
+irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
+   }
+   }
+
+out:
+   mutex_unlock(_bus->scan_mutex);
+   return IRQ_HANDLED;
+}
+
+/*
+ * Disable and clear interrupt for a given DPRC object
+ */
+static int disable_dprc_irq(struct fsl_mc_device *mc_dev)
+{
+   int error;
+   struct fsl_mc_io *mc_io = mc_dev->mc_io;
+
+   WARN_ON(mc_dev->obj_desc.irq_count != 1);
+
+   /*
+* Disable generation of interrupt, while we configure it:
+*/
+   error = dprc_set_irq_enable(mc_io, 0, mc_dev->mc_handle, 0, 0);
+   if (error < 0) {
+   dev_err(_dev->dev,
+   "Disabling DPRC IRQ failed: dprc_set_irq_enable() 
failed: %d\n",
+   error);
+   return error;
+   }
+
+   /*
+* Disable all interrupt causes for the interrupt:
+*/
+   error = dprc_set_irq_mask(mc_io, 0, mc_dev->mc_handle, 0, 0x0);
+   if (error < 0) {
+   dev_err(_dev->dev,
+   "Disabling DPRC IRQ failed: dprc_set_irq_mask() failed: 
%d\n",
+