Commit 2b9ee79d authored by Federico Vaga's avatar Federico Vaga

kernel: bugfix IRQ release

Interrupt resources are not properly released. Mainly two problems:

  1. on IRQ free the driver was using the IRQ number instead of the the
     component base address. So, the component IRQ handlers were never
     released

  2. on IRQ free, supposing that the first problem was not there, when
     all component's IRQ handlers were released the PCI IRQ handler (VIC
     dispatcher) should have released, but it was not. In consequence of this
     even if the driver was removed an interrupt can be handled by a
     ghost handler.
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 3cfe8864
......@@ -100,12 +100,13 @@ int svec_irq_free(struct fmc_device *fmc)
if (!test_bit(SVEC_FLAG_IRQS_REQUESTED, &svec->flags))
return -EINVAL;
if (svec->vic)
return svec_vic_irq_free(svec, fmc->irq);
spin_lock(&svec->irq_lock);
svec->fmc_handlers[fmc->slot_id] = NULL;
spin_unlock(&svec->irq_lock);
if (svec->vic) {
svec_vic_irq_free(svec, fmc->irq);
} else {
spin_lock(&svec->irq_lock);
svec->fmc_handlers[fmc->slot_id] = NULL;
spin_unlock(&svec->irq_lock);
}
/* shared IRQ mode: disable VME interrupt when freeing last FMC handler */
if (!svec->vic && !svec->fmc_handlers[0] && !svec->fmc_handlers[1]) {
......@@ -127,7 +128,4 @@ void svec_irq_exit(struct svec_dev *svec)
vme_free_irq(svec->current_vector);
memset(svec->fmc_handlers, 0, sizeof(svec->fmc_handlers));
if (svec->vic)
svec_vic_cleanup(svec);
}
......@@ -180,6 +180,21 @@ int svec_vic_irq_request(struct svec_dev *svec, struct fmc_device *fmc,
}
/*
* vic_handler_count
* It counts how many handlers are registered within the VIC controller
*/
static inline int vic_handler_count(struct vic_irq_controller *vic)
{
int i, count;
for (i = 0, count = 0; i < VIC_MAX_VECTORS; ++i)
if (vic->vectors[i].handler)
count++;
return count;
}
int svec_vic_irq_free(struct svec_dev *svec, unsigned long id)
{
int i;
......@@ -197,6 +212,12 @@ int svec_vic_irq_free(struct svec_dev *svec, unsigned long id)
}
}
/* Clean up the VIC if there are no more handlers */
if (!vic_handler_count(svec->vic)) {
svec_vic_cleanup(svec);
svec->vic = NULL;
}
return 0;
}
......
......@@ -149,7 +149,6 @@ irqreturn_t svec_vic_irq_dispatch(struct svec_dev *svec);
int svec_vic_irq_request(struct svec_dev *svec, struct fmc_device *fmc, unsigned long id, irq_handler_t handler);
int svec_vic_irq_free(struct svec_dev *svec, unsigned long id);
void svec_vic_irq_ack(struct svec_dev *svec, unsigned long id);
void svec_vic_cleanup(struct svec_dev *svec);
/* Generic IRQ routines */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment