Commit c4391382 authored by Federico Vaga's avatar Federico Vaga

Merge commit 'vic-fix-improve'

parents 3cfe8864 877b4ecb
...@@ -368,8 +368,6 @@ static int svec_remove(struct device *pdev, unsigned int ndev) ...@@ -368,8 +368,6 @@ static int svec_remove(struct device *pdev, unsigned int ndev)
clear_bit(SVEC_FLAG_FMCS_REGISTERED, &svec->flags); clear_bit(SVEC_FLAG_FMCS_REGISTERED, &svec->flags);
} }
svec_irq_exit(svec);
svec_unmap_window(svec, MAP_CR_CSR); svec_unmap_window(svec, MAP_CR_CSR);
svec_unmap_window(svec, MAP_REG); svec_unmap_window(svec, MAP_REG);
svec_remove_sysfs_files(svec); svec_remove_sysfs_files(svec);
...@@ -653,8 +651,6 @@ int svec_reconfigure(struct svec_dev *svec) ...@@ -653,8 +651,6 @@ int svec_reconfigure(struct svec_dev *svec)
if (svec->map[MAP_REG]) if (svec->map[MAP_REG])
svec_unmap_window(svec, MAP_REG); svec_unmap_window(svec, MAP_REG);
svec_irq_exit(svec);
error = svec_setup_csr(svec); error = svec_setup_csr(svec);
if (error) if (error)
return error; return error;
......
...@@ -274,6 +274,12 @@ void svec_fmc_destroy(struct svec_dev *svec) ...@@ -274,6 +274,12 @@ void svec_fmc_destroy(struct svec_dev *svec)
return; return;
fmc_device_unregister_n(svec->fmcs, svec->fmcs_n); fmc_device_unregister_n(svec->fmcs, svec->fmcs_n);
WARN(test_bit(SVEC_FLAG_IRQS_REQUESTED, &svec->flags) || svec->vic,
"A Mezzanine driver didn't release all its IRQ handlers (VIC %p, FLAG 0x%x)\n",
svec->vic, svec->flags);
memset(svec->fmcs, 0, sizeof(struct fmc_devices *) * SVEC_N_SLOTS);
if(svec->verbose) if(svec->verbose)
dev_info(svec->dev, "%d fmc devices unregistered\n", svec->fmcs_n); dev_info(svec->dev, "%d fmc devices unregistered\n", svec->fmcs_n);
......
...@@ -100,12 +100,13 @@ int svec_irq_free(struct fmc_device *fmc) ...@@ -100,12 +100,13 @@ int svec_irq_free(struct fmc_device *fmc)
if (!test_bit(SVEC_FLAG_IRQS_REQUESTED, &svec->flags)) if (!test_bit(SVEC_FLAG_IRQS_REQUESTED, &svec->flags))
return -EINVAL; return -EINVAL;
if (svec->vic) if (svec->vic) {
return svec_vic_irq_free(svec, fmc->irq); svec_vic_irq_free(svec, fmc->irq);
} else {
spin_lock(&svec->irq_lock); spin_lock(&svec->irq_lock);
svec->fmc_handlers[fmc->slot_id] = NULL; svec->fmc_handlers[fmc->slot_id] = NULL;
spin_unlock(&svec->irq_lock); spin_unlock(&svec->irq_lock);
}
/* shared IRQ mode: disable VME interrupt when freeing last FMC handler */ /* shared IRQ mode: disable VME interrupt when freeing last FMC handler */
if (!svec->vic && !svec->fmc_handlers[0] && !svec->fmc_handlers[1]) { if (!svec->vic && !svec->fmc_handlers[0] && !svec->fmc_handlers[1]) {
...@@ -118,16 +119,3 @@ int svec_irq_free(struct fmc_device *fmc) ...@@ -118,16 +119,3 @@ int svec_irq_free(struct fmc_device *fmc)
return 0; return 0;
} }
/* cleanup function, disables VME master interrupt when the driver is unloaded */
void svec_irq_exit(struct svec_dev *svec)
{
if (!test_bit(SVEC_FLAG_IRQS_REQUESTED, &svec->flags))
return;
vme_free_irq(svec->current_vector);
memset(svec->fmc_handlers, 0, sizeof(svec->fmc_handlers));
if (svec->vic)
svec_vic_cleanup(svec);
}
...@@ -33,10 +33,7 @@ static int svec_fw_cmd_reset (struct svec_dev * card) ...@@ -33,10 +33,7 @@ static int svec_fw_cmd_reset (struct svec_dev * card)
{ {
int err = 0; int err = 0;
if (test_bit (SVEC_FLAG_FMCS_REGISTERED, &card->flags)) if (test_bit (SVEC_FLAG_FMCS_REGISTERED, &card->flags))
{
svec_fmc_destroy (card); svec_fmc_destroy (card);
svec_irq_exit (card);
}
if (!card->map[MAP_CR_CSR]) if (!card->map[MAP_CR_CSR])
err = svec_map_window (card, MAP_CR_CSR); err = svec_map_window (card, MAP_CR_CSR);
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
/* A Vectored Interrupt Controller object */ /* A Vectored Interrupt Controller object */
struct vic_irq_controller { struct vic_irq_controller {
/* It protects the handlers' vector */
spinlock_t vec_lock;
/* already-initialized flag */ /* already-initialized flag */
int initialized; int initialized;
/* Base address (FPGA-relative) */ /* Base address (FPGA-relative) */
...@@ -78,6 +80,7 @@ static int svec_vic_init(struct svec_dev *svec, struct fmc_device *fmc) ...@@ -78,6 +80,7 @@ static int svec_vic_init(struct svec_dev *svec, struct fmc_device *fmc)
if (!vic) if (!vic)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&vic->vec_lock);
vic->kernel_va = svec->map[MAP_REG]->kernel_va + vic_base; vic->kernel_va = svec->map[MAP_REG]->kernel_va + vic_base;
vic->base = (uint32_t) vic_base; vic->base = (uint32_t) vic_base;
...@@ -98,16 +101,15 @@ static int svec_vic_init(struct svec_dev *svec, struct fmc_device *fmc) ...@@ -98,16 +101,15 @@ static int svec_vic_init(struct svec_dev *svec, struct fmc_device *fmc)
return 0; return 0;
} }
void svec_vic_cleanup(struct svec_dev *svec) void svec_vic_exit(struct vic_irq_controller *vic)
{ {
if (!svec->vic) if (!vic)
return; return;
/* Disable all irq lines and the VIC in general */ /* Disable all irq lines and the VIC in general */
vic_writel(svec->vic, 0xffffffff, VIC_REG_IDR); vic_writel(vic, 0xffffffff, VIC_REG_IDR);
vic_writel(svec->vic, 0, VIC_REG_CTL); vic_writel(vic, 0, VIC_REG_CTL);
kfree(svec->vic); kfree(vic);
svec->vic = NULL;
} }
irqreturn_t svec_vic_irq_dispatch(struct svec_dev * svec) irqreturn_t svec_vic_irq_dispatch(struct svec_dev * svec)
...@@ -162,15 +164,14 @@ int svec_vic_irq_request(struct svec_dev *svec, struct fmc_device *fmc, ...@@ -162,15 +164,14 @@ int svec_vic_irq_request(struct svec_dev *svec, struct fmc_device *fmc,
for (i = 0; i < VIC_MAX_VECTORS; i++) { for (i = 0; i < VIC_MAX_VECTORS; i++) {
/* find the vector in the stored table, assign handler and enable the line if exists */ /* find the vector in the stored table, assign handler and enable the line if exists */
if (vic->vectors[i].saved_id == id) { if (vic->vectors[i].saved_id == id) {
spin_lock(&svec->irq_lock); spin_lock(&svec->vic->vec_lock);
vic_writel(vic, i, VIC_IVT_RAM_BASE + 4 * i); vic_writel(vic, i, VIC_IVT_RAM_BASE + 4 * i);
vic->vectors[i].requestor = fmc; vic->vectors[i].requestor = fmc;
vic->vectors[i].handler = handler; vic->vectors[i].handler = handler;
vic_writel(vic, (1 << i), VIC_REG_IER); vic_writel(vic, (1 << i), VIC_REG_IER);
spin_unlock(&svec->irq_lock); spin_unlock(&svec->vic->vec_lock);
return 0; return 0;
} }
...@@ -180,24 +181,43 @@ int svec_vic_irq_request(struct svec_dev *svec, struct fmc_device *fmc, ...@@ -180,24 +181,43 @@ int svec_vic_irq_request(struct svec_dev *svec, struct fmc_device *fmc,
} }
int svec_vic_irq_free(struct svec_dev *svec, unsigned long id)
/*
* 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;
}
void svec_vic_irq_free(struct svec_dev *svec, unsigned long id)
{ {
int i; int i;
for (i = 0; i < VIC_MAX_VECTORS; i++) { for (i = 0; i < VIC_MAX_VECTORS; i++) {
uint32_t vec = svec->vic->vectors[i].saved_id; if (svec->vic->vectors[i].saved_id == id) {
if (vec == id) { spin_lock(&svec->vic->vec_lock);
spin_lock(&svec->irq_lock);
vic_writel(svec->vic, 1 << i, VIC_REG_IDR); vic_writel(svec->vic, 1 << i, VIC_REG_IDR);
vic_writel(svec->vic, vec, VIC_IVT_RAM_BASE + 4 * i); vic_writel(svec->vic, id, VIC_IVT_RAM_BASE + 4 * i);
svec->vic->vectors[i].handler = NULL; svec->vic->vectors[i].handler = NULL;
spin_unlock(&svec->irq_lock); spin_unlock(&svec->vic->vec_lock);
} }
} }
return 0; /* Clean up the VIC if there are no more handlers */
if (!vic_handler_count(svec->vic)) {
svec_vic_exit(svec->vic);
svec->vic = NULL;
}
} }
void svec_vic_irq_ack(struct svec_dev *svec, unsigned long id) void svec_vic_irq_ack(struct svec_dev *svec, unsigned long id)
......
...@@ -147,9 +147,8 @@ int svec_load_golden(struct svec_dev *svec); ...@@ -147,9 +147,8 @@ int svec_load_golden(struct svec_dev *svec);
/* VIC interrupt controller stuff */ /* VIC interrupt controller stuff */
irqreturn_t svec_vic_irq_dispatch(struct svec_dev *svec); 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_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_free(struct svec_dev *svec, unsigned long id);
void svec_vic_irq_ack(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 */ /* Generic IRQ routines */
...@@ -157,7 +156,6 @@ int svec_irq_request(struct fmc_device *fmc, irq_handler_t handler, char *name, ...@@ -157,7 +156,6 @@ int svec_irq_request(struct fmc_device *fmc, irq_handler_t handler, char *name,
int flags); int flags);
void svec_irq_ack(struct fmc_device *fmc); void svec_irq_ack(struct fmc_device *fmc);
int svec_irq_free(struct fmc_device *fmc); int svec_irq_free(struct fmc_device *fmc);
void svec_irq_exit(struct svec_dev *svec);
#endif /* __SVEC_H__ */ #endif /* __SVEC_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