Commit 60dc7cd5 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 c791d5b0
......@@ -221,9 +221,15 @@ static int spec_irq_free(struct fmc_device *fmc)
struct spec_dev *spec = fmc->carrier_data;
if (spec->vic)
return spec_vic_irq_free(spec, spec->pdev->irq);
else
spec_vic_irq_free(spec, fmc->irq);
/*
* If we were not using the VIC, or we released all the VIC handler, then
* release the PCI IRQ handler
*/
if (!spec->vic)
return spec_shared_irq_free(fmc);
return 0;
}
/* This is the mapping from virtual GPIO pin numbers to raw gpio numbers */
......
......@@ -99,7 +99,7 @@ static int spec_vic_init(struct spec_dev *spec, struct fmc_device *fmc)
return 0;
}
void spec_vic_cleanup(struct spec_dev *spec)
static void spec_vic_cleanup(struct spec_dev *spec)
{
if (!spec->vic)
return;
......@@ -169,11 +169,26 @@ int spec_vic_irq_request(struct spec_dev *spec, struct fmc_device *fmc,
}
}
return -EINVAL;
}
/*
* 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 spec_vic_irq_free(struct spec_dev *spec, unsigned long id)
{
int i;
......@@ -191,6 +206,12 @@ int spec_vic_irq_free(struct spec_dev *spec, unsigned long id)
}
}
/* Clean up the VIC if there are no more handlers */
if (!vic_handler_count(spec->vic)) {
spec_vic_cleanup(spec);
spec->vic = NULL;
}
return 0;
}
......
......@@ -144,11 +144,10 @@ extern int spec_eeprom_write(struct fmc_device *fmc, uint32_t offset,
extern int spec_gpio_init(struct fmc_device *fmc);
extern void spec_gpio_exit(struct fmc_device *fmc);
/* Functions in spec-vic.c */
int spec_vic_irq_request(struct spec_dev *spec, struct fmc_device *fmc,
unsigned long id, irq_handler_t handler);
int spec_vic_irq_free(struct spec_dev *spec, unsigned long id);
irqreturn_t spec_vic_irq_dispatch(struct spec_dev *spec);
void spec_vic_cleanup(struct spec_dev *spec);
#endif /* __SPEC_H__ */
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