Commit d4bbcc73 authored by Federico Vaga's avatar Federico Vaga

kernel: protect VIC on request,free and dispatch

Protecting the handlers' vector is not enough. Managing the interrupts
involves other tasks that must be serialized. Mainly to handle the first
request and the last free of a VIC handler.

The VIC internal locking (vec_lock) is not useful anymore, but I do not
remove it because theoretically the VIC should be an independent bunch of
code.
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 8d4eba1d
......@@ -124,9 +124,12 @@ static void spec_shared_irq_ack(struct fmc_device *fmc);
static irqreturn_t spec_vic_irq_handler(int id, void *data)
{
struct fmc_device *fmc = (struct fmc_device *)data;
struct spec_dev *spec = (struct spec_dev *)fmc->carrier_data;
irqreturn_t rv;
rv = spec_vic_irq_dispatch((struct spec_dev *)fmc->carrier_data);
spin_lock(&spec->irq_lock);
rv = spec_vic_irq_dispatch(spec);
spin_unlock(&spec->irq_lock);
spec_shared_irq_ack(fmc);
return IRQ_HANDLED;
......@@ -154,25 +157,29 @@ static int spec_irq_request(struct fmc_device *fmc, irq_handler_t handler,
/* VIC mode interrupt */
if (!(flags & IRQF_SHARED)) {
spin_lock(&spec->irq_lock);
first_time = !spec->vic;
/* configure the VIC */
rv = spec_vic_irq_request(spec, fmc, fmc->irq, handler);
if (rv)
if (rv) {
spin_unlock(&spec->irq_lock);
return rv;
}
/* on first IRQ, configure VIC "master" handler and GPIO too */
if (first_time) {
rv = spec_shared_irq_request(fmc, spec_vic_irq_handler,
"spec-vic", IRQF_SHARED);
if (rv)
if (rv) {
spin_unlock(&spec->irq_lock);
return rv;
}
fmc->op->gpio_config(fmc, spec_vic_gpio_cfg,
ARRAY_SIZE(spec_vic_gpio_cfg));
}
spin_unlock(&spec->irq_lock);
} else {
rv = spec_shared_irq_request(fmc, handler, name, flags);
pr_debug("Requesting irq '%s' in shared mode (rv %d)\n", name,
......@@ -219,6 +226,7 @@ static int spec_irq_free(struct fmc_device *fmc)
{
struct spec_dev *spec = fmc->carrier_data;
spin_lock(&spec->irq_lock);
if (spec->vic)
spec_vic_irq_free(spec, fmc->irq);
......@@ -228,6 +236,7 @@ static int spec_irq_free(struct fmc_device *fmc)
*/
if (!spec->vic)
spec_shared_irq_free(fmc);
spin_unlock(&spec->irq_lock);
return 0;
}
......
......@@ -113,12 +113,15 @@ static void spec_vic_exit(struct vic_irq_controller *vic)
kfree(vic);
}
/* NOTE: this function must be called while holding irq_lock */
irqreturn_t spec_vic_irq_dispatch(struct spec_dev *spec)
{
struct vic_irq_controller *vic = spec->vic;
int index, rv;
struct vector *vec;
if (unlikely(!vic))
goto fail;
/*
* Our parent IRQ handler: read the index value
* from the Vector Address Register, and find matching handler
......@@ -141,6 +144,7 @@ fail:
return 0;
}
/* NOTE: this function must be called while holding irq_lock */
int spec_vic_irq_request(struct spec_dev *spec, struct fmc_device *fmc,
unsigned long id, irq_handler_t handler)
{
......@@ -190,7 +194,7 @@ static inline int vic_handler_count(struct vic_irq_controller *vic)
return count;
}
/* NOTE: this function must be called while holding irq_lock */
void spec_vic_irq_free(struct spec_dev *spec, unsigned long id)
{
int i;
......
......@@ -145,6 +145,7 @@ extern int spec_gpio_init(struct fmc_device *fmc);
extern void spec_gpio_exit(struct fmc_device *fmc);
/* Functions in spec-vic.c */
/* NOTE: these functions must be called while holding irq_lock */
int spec_vic_irq_request(struct spec_dev *spec, struct fmc_device *fmc,
unsigned long id, irq_handler_t handler);
void spec_vic_irq_free(struct spec_dev *spec, unsigned long id);
......
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