Currently the VME callback infrastructure is replicated in each VME driver.
Move this common code into the VME core. Rename functions to fit in better
with naming of other VME functions.
Signed-off-by: Martyn Welch <martyn.welch@gefanuc.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
* Only one VME interrupt can be
* generated at a time, provide locking
*/
-struct mutex vme_irq; /* Locking for VME irq callback configuration */
-
-
static char driver_name[] = "vme_ca91cx42";
static u32 ca91cx42_VIRQ_irqhandler(int stat)
{
int vec, i, serviced = 0;
- void (*call)(int, int, void *);
- void *priv_data;
for (i = 7; i > 0; i--) {
if (stat & (1 << i)) {
vec = ioread32(ca91cx42_bridge->base +
CA91CX42_V_STATID[i]) & 0xff;
- call = ca91cx42_bridge->irq[i - 1].callback[vec].func;
- priv_data =
- ca91cx42_bridge->irq[i - 1].callback[vec].priv_data;
-
- if (call != NULL)
- call(i, vec, priv_data);
- else
- printk("Spurilous VME interrupt, level:%x, "
- "vector:%x\n", i, vec);
+ vme_irq_handler(ca91cx42_bridge, i, vec);
serviced |= (1 << i);
}
/* Initialise list for VME bus errors */
INIT_LIST_HEAD(&(bridge->vme_errors));
+ mutex_init(&(bridge->irq_mtx));
+
/* Disable interrupts from PCI to VME */
iowrite32(0, bridge->base + VINT_EN);
/*
* Set up an VME interrupt
*/
-int ca91cx42_request_irq(int level, int statid,
- void (*callback)(int level, int vector, void *priv_data),
- void *priv_data)
+void ca91cx42_irq_set(int level, int state, int sync)
+
{
+ struct pci_dev *pdev;
u32 tmp;
- mutex_lock(&(vme_irq));
-
- if (ca91cx42_bridge->irq[level - 1].callback[statid].func) {
- mutex_unlock(&(vme_irq));
- printk("VME Interrupt already taken\n");
- return -EBUSY;
- }
-
-
- ca91cx42_bridge->irq[level - 1].count++;
- ca91cx42_bridge->irq[level - 1].callback[statid].priv_data = priv_data;
- ca91cx42_bridge->irq[level - 1].callback[statid].func = callback;
-
/* Enable IRQ level */
tmp = ioread32(ca91cx42_bridge->base + LINT_EN);
- tmp |= CA91CX42_LINT_VIRQ[level];
- iowrite32(tmp, ca91cx42_bridge->base + LINT_EN);
- mutex_unlock(&(vme_irq));
-
- return 0;
-}
-
-/*
- * Free VME interrupt
- */
-void ca91cx42_free_irq(int level, int statid)
-{
- u32 tmp;
- struct pci_dev *pdev;
-
- mutex_lock(&(vme_irq));
-
- ca91cx42_bridge->irq[level - 1].count--;
-
- /* Disable IRQ level if no more interrupts attached at this level*/
- if (ca91cx42_bridge->irq[level - 1].count == 0) {
- tmp = ioread32(ca91cx42_bridge->base + LINT_EN);
+ if (state == 0)
tmp &= ~CA91CX42_LINT_VIRQ[level];
- iowrite32(tmp, ca91cx42_bridge->base + LINT_EN);
+ else
+ tmp |= CA91CX42_LINT_VIRQ[level];
+ iowrite32(tmp, ca91cx42_bridge->base + LINT_EN);
+
+ if ((state == 0) && (sync != 0)) {
pdev = container_of(ca91cx42_bridge->parent, struct pci_dev,
dev);
synchronize_irq(pdev->irq);
}
-
- ca91cx42_bridge->irq[level - 1].callback[statid].func = NULL;
- ca91cx42_bridge->irq[level - 1].callback[statid].priv_data = NULL;
-
- mutex_unlock(&(vme_irq));
}
-int ca91cx42_generate_irq(int level, int statid)
+int ca91cx42_irq_generate(int level, int statid)
{
u32 tmp;
init_waitqueue_head(&dma_queue);
init_waitqueue_head(&iack_queue);
mutex_init(&(vme_int));
- mutex_init(&(vme_irq));
mutex_init(&(vme_rmw));
ca91cx42_bridge->parent = &(pdev->dev);
ca91cx42_bridge->dma_list_exec = ca91cx42_dma_list_exec;
ca91cx42_bridge->dma_list_empty = ca91cx42_dma_list_empty;
#endif
- ca91cx42_bridge->request_irq = ca91cx42_request_irq;
- ca91cx42_bridge->free_irq = ca91cx42_free_irq;
- ca91cx42_bridge->generate_irq = ca91cx42_generate_irq;
+ ca91cx42_bridge->irq_set = ca91cx42_irq_set;
+ ca91cx42_bridge->irq_generate = ca91cx42_irq_generate;
#if 0
ca91cx42_bridge->lm_set = ca91cx42_lm_set;
ca91cx42_bridge->lm_get = ca91cx42_lm_get;
* Only one VME interrupt can be
* generated at a time, provide locking
*/
-struct mutex vme_irq; /* Locking for VME irq callback configuration */
-
static char driver_name[] = "vme_tsi148";
static u32 tsi148_VIRQ_irqhandler(u32 stat)
{
int vec, i, serviced = 0;
- void (*call)(int, int, void *);
- void *priv_data;
for (i = 7; i > 0; i--) {
if (stat & (1 << i)) {
vec = ioread8(tsi148_bridge->base +
TSI148_LCSR_VIACK[i] + 3);
- call = tsi148_bridge->irq[i - 1].callback[vec].func;
- priv_data =
- tsi148_bridge->irq[i-1].callback[vec].priv_data;
-
- if (call != NULL)
- call(i, vec, priv_data);
- else
- printk("Spurilous VME interrupt, level:%x, "
- "vector:%x\n", i, vec);
+ vme_irq_handler(tsi148_bridge, i, vec);
serviced |= (1 << i);
}
/* Initialise list for VME bus errors */
INIT_LIST_HEAD(&(bridge->vme_errors));
+ mutex_init(&(bridge->irq_mtx));
+
result = request_irq(pdev->irq,
tsi148_irqhandler,
IRQF_SHARED,
}
/*
- * Set up an VME interrupt
+ * Configure VME interrupt
*/
-int tsi148_request_irq(int level, int statid,
- void (*callback)(int level, int vector, void *priv_data),
- void *priv_data)
+void tsi148_irq_set(int level, int state, int sync)
{
- u32 tmp;
-
- mutex_lock(&(vme_irq));
-
- if(tsi148_bridge->irq[level - 1].callback[statid].func) {
- mutex_unlock(&(vme_irq));
- printk("VME Interrupt already taken\n");
- return -EBUSY;
- }
-
-
- tsi148_bridge->irq[level - 1].count++;
- tsi148_bridge->irq[level - 1].callback[statid].priv_data = priv_data;
- tsi148_bridge->irq[level - 1].callback[statid].func = callback;
-
- /* Enable IRQ level */
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
- tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
-
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
- tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
-
- mutex_unlock(&(vme_irq));
-
- return 0;
-}
-
-/*
- * Free VME interrupt
- */
-void tsi148_free_irq(int level, int statid)
-{
- u32 tmp;
struct pci_dev *pdev;
+ u32 tmp;
- mutex_lock(&(vme_irq));
-
- tsi148_bridge->irq[level - 1].count--;
-
- /* Disable IRQ level if no more interrupts attached at this level*/
- if (tsi148_bridge->irq[level - 1].count == 0) {
+ /* We need to do the ordering differently for enabling and disabling */
+ if (state == 0) {
tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
tmp &= ~TSI148_LCSR_INTEN_IRQEN[level - 1];
iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
tmp &= ~TSI148_LCSR_INTEO_IRQEO[level - 1];
iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
- pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
+ if (sync != 0) {
+ pdev = container_of(tsi148_bridge->parent,
+ struct pci_dev, dev);
- synchronize_irq(pdev->irq);
- }
-
- tsi148_bridge->irq[level - 1].callback[statid].func = NULL;
- tsi148_bridge->irq[level - 1].callback[statid].priv_data = NULL;
+ synchronize_irq(pdev->irq);
+ }
+ } else {
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
+ tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
- mutex_unlock(&(vme_irq));
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
+ tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
+ }
}
/*
* Generate a VME bus interrupt at the requested level & vector. Wait for
* interrupt to be acked.
*/
-int tsi148_generate_irq(int level, int statid)
+int tsi148_irq_generate(int level, int statid)
{
u32 tmp;
init_waitqueue_head(&dma_queue[1]);
init_waitqueue_head(&iack_queue);
mutex_init(&(vme_int));
- mutex_init(&(vme_irq));
mutex_init(&(vme_rmw));
tsi148_bridge->parent = &(pdev->dev);
tsi148_bridge->dma_list_add = tsi148_dma_list_add;
tsi148_bridge->dma_list_exec = tsi148_dma_list_exec;
tsi148_bridge->dma_list_empty = tsi148_dma_list_empty;
- tsi148_bridge->request_irq = tsi148_request_irq;
- tsi148_bridge->free_irq = tsi148_free_irq;
- tsi148_bridge->generate_irq = tsi148_generate_irq;
+ tsi148_bridge->irq_set = tsi148_irq_set;
+ tsi148_bridge->irq_generate = tsi148_irq_generate;
tsi148_bridge->lm_set = tsi148_lm_set;
tsi148_bridge->lm_get = tsi148_lm_get;
tsi148_bridge->lm_attach = tsi148_lm_attach;
}
EXPORT_SYMBOL(vme_dma_free);
-int vme_request_irq(struct device *dev, int level, int statid,
+void vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
+{
+ void (*call)(int, int, void *);
+ void *priv_data;
+
+ call = bridge->irq[level - 1].callback[statid].func;
+ priv_data = bridge->irq[level - 1].callback[statid].priv_data;
+
+ if (call != NULL)
+ call(level, statid, priv_data);
+ else
+ printk(KERN_WARNING "Spurilous VME interrupt, level:%x, "
+ "vector:%x\n", level, statid);
+}
+EXPORT_SYMBOL(vme_irq_handler);
+
+int vme_irq_request(struct device *dev, int level, int statid,
void (*callback)(int level, int vector, void *priv_data),
void *priv_data)
{
}
if((level < 1) || (level > 7)) {
- printk(KERN_WARNING "Invalid interrupt level\n");
+ printk(KERN_ERR "Invalid interrupt level\n");
return -EINVAL;
}
- if (bridge->request_irq == NULL) {
- printk("Registering interrupts not supported\n");
+ if (bridge->irq_set == NULL) {
+ printk(KERN_ERR "Configuring interrupts not supported\n");
return -EINVAL;
}
- return bridge->request_irq(level, statid, callback, priv_data);
+ mutex_lock(&(bridge->irq_mtx));
+
+ if (bridge->irq[level - 1].callback[statid].func) {
+ mutex_unlock(&(bridge->irq_mtx));
+ printk(KERN_WARNING "VME Interrupt already taken\n");
+ return -EBUSY;
+ }
+
+ bridge->irq[level - 1].count++;
+ bridge->irq[level - 1].callback[statid].priv_data = priv_data;
+ bridge->irq[level - 1].callback[statid].func = callback;
+
+ /* Enable IRQ level */
+ bridge->irq_set(level, 1, 1);
+
+ mutex_unlock(&(bridge->irq_mtx));
+
+ return 0;
}
-EXPORT_SYMBOL(vme_request_irq);
+EXPORT_SYMBOL(vme_irq_request);
-void vme_free_irq(struct device *dev, int level, int statid)
+void vme_irq_free(struct device *dev, int level, int statid)
{
struct vme_bridge *bridge;
}
if((level < 1) || (level > 7)) {
- printk(KERN_WARNING "Invalid interrupt level\n");
+ printk(KERN_ERR "Invalid interrupt level\n");
return;
}
- if (bridge->free_irq == NULL) {
- printk("Freeing interrupts not supported\n");
+ if (bridge->irq_set == NULL) {
+ printk(KERN_ERR "Configuring interrupts not supported\n");
return;
}
- bridge->free_irq(level, statid);
+ mutex_lock(&(bridge->irq_mtx));
+
+ bridge->irq[level - 1].count--;
+
+ /* Disable IRQ level if no more interrupts attached at this level*/
+ if (bridge->irq[level - 1].count == 0)
+ bridge->irq_set(level, 0, 1);
+
+ bridge->irq[level - 1].callback[statid].func = NULL;
+ bridge->irq[level - 1].callback[statid].priv_data = NULL;
+
+ mutex_unlock(&(bridge->irq_mtx));
}
-EXPORT_SYMBOL(vme_free_irq);
+EXPORT_SYMBOL(vme_irq_free);
-int vme_generate_irq(struct device *dev, int level, int statid)
+int vme_irq_generate(struct device *dev, int level, int statid)
{
struct vme_bridge *bridge;
return -EINVAL;
}
- if (bridge->generate_irq == NULL) {
+ if (bridge->irq_generate == NULL) {
printk("Interrupt generation not supported\n");
return -EINVAL;
}
- return bridge->generate_irq(level, statid);
+ return bridge->irq_generate(level, statid);
}
-EXPORT_SYMBOL(vme_generate_irq);
+EXPORT_SYMBOL(vme_irq_generate);
/*
* Request the location monitor, return resource or NULL
int vme_dma_list_free(struct vme_dma_list *);
int vme_dma_free(struct vme_resource *);
-int vme_request_irq(struct device *, int, int,
+int vme_irq_request(struct device *, int, int,
void (*callback)(int, int, void *), void *);
-void vme_free_irq(struct device *, int, int);
-int vme_generate_irq(struct device *, int, int);
+void vme_irq_free(struct device *, int, int);
+int vme_irq_generate(struct device *, int, int);
struct vme_resource * vme_lm_request(struct device *);
int vme_lm_count(struct vme_resource *);
callback function. A void pointer parameter is provided, the value of which is
passed to the callback function, the use of this pointer is user undefined:
- int vme_request_irq(struct device *dev, int level, int statid,
+ int vme_irq_request(struct device *dev, int level, int statid,
void (*callback)(int, int, void *), void *priv);
- void vme_free_irq(struct device *dev, int level, int statid);
+ void vme_irq_free(struct device *dev, int level, int statid);
The callback parameters are as follows. Care must be taken in writing a callback
function, callback functions run in interrupt context:
The following function can be used to generate a VME interrupt at a given VME
level and VME status ID:
- int vme_generate_irq(struct device *dev, int level, int statid);
+ int vme_irq_generate(struct device *dev, int level, int statid);
Location monitors
/* Interrupt callbacks */
struct vme_irq irq[7];
+ /* Locking for VME irq callback configuration */
+ struct mutex irq_mtx;
/* Slave Functions */
int (*slave_get) (struct vme_slave_resource *, int *,
int (*dma_list_empty) (struct vme_dma_list *);
/* Interrupt Functions */
- int (*request_irq) (int, int, void (*cback)(int, int, void*), void *);
- void (*free_irq) (int, int);
- int (*generate_irq) (int, int);
+ void (*irq_set) (int, int, int);
+ int (*irq_generate) (int, int);
/* Location monitor functions */
int (*lm_set) (struct vme_lm_resource *, unsigned long long,
#endif
};
+void vme_irq_handler(struct vme_bridge *, int, int);
+
int vme_register_bridge (struct vme_bridge *);
void vme_unregister_bridge (struct vme_bridge *);