|
@@ -705,6 +705,65 @@ static int ccp_assign_lsbs(struct ccp_device *ccp)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static void ccp5_disable_queue_interrupts(struct ccp_device *ccp)
|
|
|
+{
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ccp->cmd_q_count; i++)
|
|
|
+ iowrite32(0x0, ccp->cmd_q[i].reg_int_enable);
|
|
|
+}
|
|
|
+
|
|
|
+static void ccp5_enable_queue_interrupts(struct ccp_device *ccp)
|
|
|
+{
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ccp->cmd_q_count; i++)
|
|
|
+ iowrite32(SUPPORTED_INTERRUPTS, ccp->cmd_q[i].reg_int_enable);
|
|
|
+}
|
|
|
+
|
|
|
+static void ccp5_irq_bh(unsigned long data)
|
|
|
+{
|
|
|
+ struct ccp_device *ccp = (struct ccp_device *)data;
|
|
|
+ u32 status;
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ccp->cmd_q_count; i++) {
|
|
|
+ struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
|
|
|
+
|
|
|
+ status = ioread32(cmd_q->reg_interrupt_status);
|
|
|
+
|
|
|
+ if (status) {
|
|
|
+ cmd_q->int_status = status;
|
|
|
+ cmd_q->q_status = ioread32(cmd_q->reg_status);
|
|
|
+ cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
|
|
|
+
|
|
|
+ /* On error, only save the first error value */
|
|
|
+ if ((status & INT_ERROR) && !cmd_q->cmd_error)
|
|
|
+ cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
|
|
|
+
|
|
|
+ cmd_q->int_rcvd = 1;
|
|
|
+
|
|
|
+ /* Acknowledge the interrupt and wake the kthread */
|
|
|
+ iowrite32(status, cmd_q->reg_interrupt_status);
|
|
|
+ wake_up_interruptible(&cmd_q->int_queue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ccp5_enable_queue_interrupts(ccp);
|
|
|
+}
|
|
|
+
|
|
|
+static irqreturn_t ccp5_irq_handler(int irq, void *data)
|
|
|
+{
|
|
|
+ struct device *dev = data;
|
|
|
+ struct ccp_device *ccp = dev_get_drvdata(dev);
|
|
|
+
|
|
|
+ ccp5_disable_queue_interrupts(ccp);
|
|
|
+ if (ccp->use_tasklet)
|
|
|
+ tasklet_schedule(&ccp->irq_tasklet);
|
|
|
+ else
|
|
|
+ ccp5_irq_bh((unsigned long)ccp);
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|
|
|
static int ccp5_init(struct ccp_device *ccp)
|
|
|
{
|
|
|
struct device *dev = ccp->dev;
|
|
@@ -789,18 +848,17 @@ static int ccp5_init(struct ccp_device *ccp)
|
|
|
}
|
|
|
|
|
|
/* Turn off the queues and disable interrupts until ready */
|
|
|
+ ccp5_disable_queue_interrupts(ccp);
|
|
|
for (i = 0; i < ccp->cmd_q_count; i++) {
|
|
|
cmd_q = &ccp->cmd_q[i];
|
|
|
|
|
|
cmd_q->qcontrol = 0; /* Start with nothing */
|
|
|
iowrite32(cmd_q->qcontrol, cmd_q->reg_control);
|
|
|
|
|
|
- /* Disable the interrupts */
|
|
|
- iowrite32(0x00, cmd_q->reg_int_enable);
|
|
|
ioread32(cmd_q->reg_int_status);
|
|
|
ioread32(cmd_q->reg_status);
|
|
|
|
|
|
- /* Clear the interrupts */
|
|
|
+ /* Clear the interrupt status */
|
|
|
iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status);
|
|
|
}
|
|
|
|
|
@@ -811,6 +869,10 @@ static int ccp5_init(struct ccp_device *ccp)
|
|
|
dev_err(dev, "unable to allocate an IRQ\n");
|
|
|
goto e_pool;
|
|
|
}
|
|
|
+ /* Initialize the ISR tasklet */
|
|
|
+ if (ccp->use_tasklet)
|
|
|
+ tasklet_init(&ccp->irq_tasklet, ccp5_irq_bh,
|
|
|
+ (unsigned long)ccp);
|
|
|
|
|
|
dev_dbg(dev, "Loading LSB map...\n");
|
|
|
/* Copy the private LSB mask to the public registers */
|
|
@@ -879,11 +941,7 @@ static int ccp5_init(struct ccp_device *ccp)
|
|
|
}
|
|
|
|
|
|
dev_dbg(dev, "Enabling interrupts...\n");
|
|
|
- /* Enable interrupts */
|
|
|
- for (i = 0; i < ccp->cmd_q_count; i++) {
|
|
|
- cmd_q = &ccp->cmd_q[i];
|
|
|
- iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_int_enable);
|
|
|
- }
|
|
|
+ ccp5_enable_queue_interrupts(ccp);
|
|
|
|
|
|
dev_dbg(dev, "Registering device...\n");
|
|
|
/* Put this on the unit list to make it available */
|
|
@@ -935,15 +993,13 @@ static void ccp5_destroy(struct ccp_device *ccp)
|
|
|
ccp_del_device(ccp);
|
|
|
|
|
|
/* Disable and clear interrupts */
|
|
|
+ ccp5_disable_queue_interrupts(ccp);
|
|
|
for (i = 0; i < ccp->cmd_q_count; i++) {
|
|
|
cmd_q = &ccp->cmd_q[i];
|
|
|
|
|
|
/* Turn off the run bit */
|
|
|
iowrite32(cmd_q->qcontrol & ~CMD5_Q_RUN, cmd_q->reg_control);
|
|
|
|
|
|
- /* Disable the interrupts */
|
|
|
- iowrite32(0x00, cmd_q->reg_int_enable);
|
|
|
-
|
|
|
/* Clear the interrupt status */
|
|
|
iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status);
|
|
|
ioread32(cmd_q->reg_int_status);
|
|
@@ -978,39 +1034,6 @@ static void ccp5_destroy(struct ccp_device *ccp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static irqreturn_t ccp5_irq_handler(int irq, void *data)
|
|
|
-{
|
|
|
- struct device *dev = data;
|
|
|
- struct ccp_device *ccp = dev_get_drvdata(dev);
|
|
|
- u32 status;
|
|
|
- unsigned int i;
|
|
|
-
|
|
|
- for (i = 0; i < ccp->cmd_q_count; i++) {
|
|
|
- struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
|
|
|
-
|
|
|
- status = ioread32(cmd_q->reg_interrupt_status);
|
|
|
-
|
|
|
- if (status) {
|
|
|
- cmd_q->int_status = status;
|
|
|
- cmd_q->q_status = ioread32(cmd_q->reg_status);
|
|
|
- cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
|
|
|
-
|
|
|
- /* On error, only save the first error value */
|
|
|
- if ((status & INT_ERROR) && !cmd_q->cmd_error)
|
|
|
- cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
|
|
|
-
|
|
|
- cmd_q->int_rcvd = 1;
|
|
|
-
|
|
|
- /* Acknowledge the interrupt and wake the kthread */
|
|
|
- iowrite32(SUPPORTED_INTERRUPTS,
|
|
|
- cmd_q->reg_interrupt_status);
|
|
|
- wake_up_interruptible(&cmd_q->int_queue);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return IRQ_HANDLED;
|
|
|
-}
|
|
|
-
|
|
|
static void ccp5_config(struct ccp_device *ccp)
|
|
|
{
|
|
|
/* Public side */
|