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)
clear_bit(SVEC_FLAG_FMCS_REGISTERED, &svec->flags);
}
svec_irq_exit(svec);
svec_unmap_window(svec, MAP_CR_CSR);
svec_unmap_window(svec, MAP_REG);
svec_remove_sysfs_files(svec);
......@@ -653,8 +651,6 @@ int svec_reconfigure(struct svec_dev *svec)
if (svec->map[MAP_REG])
svec_unmap_window(svec, MAP_REG);
svec_irq_exit(svec);
error = svec_setup_csr(svec);
if (error)
return error;
......
......@@ -274,6 +274,12 @@ void svec_fmc_destroy(struct svec_dev *svec)
return;
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)
dev_info(svec->dev, "%d fmc devices unregistered\n", svec->fmcs_n);
......
......@@ -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]) {
......@@ -118,16 +119,3 @@ int svec_irq_free(struct fmc_device *fmc)
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)
{
int err = 0;
if (test_bit (SVEC_FLAG_FMCS_REGISTERED, &card->flags))
{
svec_fmc_destroy (card);
svec_irq_exit (card);
}
if (!card->map[MAP_CR_CSR])
err = svec_map_window (card, MAP_CR_CSR);
......
......@@ -24,6 +24,8 @@
/* A Vectored Interrupt Controller object */
struct vic_irq_controller {
/* It protects the handlers' vector */
spinlock_t vec_lock;
/* already-initialized flag */
int initialized;
/* Base address (FPGA-relative) */
......@@ -78,6 +80,7 @@ static int svec_vic_init(struct svec_dev *svec, struct fmc_device *fmc)
if (!vic)
return -ENOMEM;
spin_lock_init(&vic->vec_lock);
vic->kernel_va = svec->map[MAP_REG]->kernel_va + 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)
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;
/* Disable all irq lines and the VIC in general */
vic_writel(svec->vic, 0xffffffff, VIC_REG_IDR);
vic_writel(svec->vic, 0, VIC_REG_CTL);
kfree(svec->vic);
svec->vic = NULL;
vic_writel(vic, 0xffffffff, VIC_REG_IDR);
vic_writel(vic, 0, VIC_REG_CTL);
kfree(vic);
}
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,
for (i = 0; i < VIC_MAX_VECTORS; i++) {
/* find the vector in the stored table, assign handler and enable the line if exists */
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->vectors[i].requestor = fmc;
vic->vectors[i].handler = handler;
vic_writel(vic, (1 << i), VIC_REG_IER);
spin_unlock(&svec->irq_lock);
spin_unlock(&svec->vic->vec_lock);
return 0;
}
......@@ -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;
for (i = 0; i < VIC_MAX_VECTORS; i++) {
uint32_t vec = svec->vic->vectors[i].saved_id;
if (vec == id) {
spin_lock(&svec->irq_lock);
if (svec->vic->vectors[i].saved_id == id) {
spin_lock(&svec->vic->vec_lock);
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;
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)
......
......@@ -147,9 +147,8 @@ int svec_load_golden(struct svec_dev *svec);
/* VIC interrupt controller stuff */
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_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 */
......@@ -157,7 +156,6 @@ int svec_irq_request(struct fmc_device *fmc, irq_handler_t handler, char *name,
int flags);
void svec_irq_ack(struct fmc_device *fmc);
int svec_irq_free(struct fmc_device *fmc);
void svec_irq_exit(struct svec_dev *svec);
#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