Here are the interrupt handler code and irq_request code. This is a PCI
driver as I put it in my first post. It's a DVB ASI driver that receives
ASI data. Please let me know if you need more information. lsdma is the
DMA information.
static irqreturn_t
dvbm_qlf_irq_handler (int irq,
void *dev_id,
struct pt_regs *regs)
{
struct master_dev *card = dev_id;
struct list_head *p = &card->iface_list;
struct master_iface *iface;
unsigned int dmaintsrc = readl (card->bridge_addr + LSDMA_INTSRC);
unsigned int status, interrupting_iface = 0, i;
for (i = 0; i < 4; i++) {
p = p->next;
iface = list_entry (p, struct master_iface, list);
/* Clear ASI interrupts */
spin_lock (&card->irq_lock);
status = readl (card->core_addr + DVBM_QLF_ICSR(i));
if ((status & DVBM_QLF_ICSR_ISMASK) != 0) {
writel (status, card->core_addr + DVBM_QLF_ICSR(i));
spin_unlock (&card->irq_lock);
if (status & DVBM_QLF_ICSR_RXCDIS) {
set_bit (ASI_EVENT_RX_CARRIER_ORDER,
&iface->events);
interrupting_iface |= (0x1 << i);
}
if (status & DVBM_QLF_ICSR_RXAOSIS) {
set_bit (ASI_EVENT_RX_AOS_ORDER,
&iface->events);
interrupting_iface |= (0x1 << i);
}
if (status & DVBM_QLF_ICSR_RXLOSIS) {
set_bit (ASI_EVENT_RX_LOS_ORDER,
&iface->events);
interrupting_iface |= (0x1 << i);
}
if (status & DVBM_QLF_ICSR_RXOIS) {
set_bit (ASI_EVENT_RX_FIFO_ORDER,
&iface->events);
interrupting_iface |= (0x1 << i);
}
if (status & DVBM_QLF_ICSR_RXDIS) {
set_bit (ASI_EVENT_RX_DATA_ORDER,
&iface->events);
interrupting_iface |= (0x1 << i);
}
} else {
spin_unlock (&card->irq_lock);
}
/* Clear DMA interrupts */
if (dmaintsrc & LSDMA_INTSRC_CH(i)) {
/* Read the interrupt type and clear it */
spin_lock (&card->irq_lock);
status = readl (card->bridge_addr + LSDMA_CSR(i));
writel (status, card->bridge_addr + LSDMA_CSR(i));
spin_unlock (&card->irq_lock);
/* Increment the buffer pointer */
if (status & LSDMA_CH_CSR_INTSRCBUFFER) {
lsdma_advance (iface->dma);
if (lsdma_rx_isempty (iface->dma)) {
set_bit (ASI_EVENT_RX_BUFFER_ORDER,
&iface->events);
}
}
/* Flag end-of-chain */
if (status & LSDMA_CH_CSR_INTSRCDONE) {
set_bit (0, &iface->dma_done);
}
/* Flag DMA abort */
if (status & LSDMA_CH_CSR_INTSRCSTOP) {
set_bit (0, &iface->dma_done);
}
interrupting_iface |= (0x1 << i);
}
if (interrupting_iface & (0x1 << i)) {
wake_up (&iface->queue);
}
}
if (interrupting_iface) {
/* Dummy read to flush PCI posted writes */
readl (card->bridge_addr + LSDMA_INTMSK);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
The open method where I request the IRQ is here.
static int
dvbm_qi_open (struct inode *inode, struct file *filp)
{
struct master_iface *iface =
container_of(inode->i_cdev,struct master_iface,cdev);
struct master_dev *card = iface->card;
const unsigned int channel = mdev_index (card, &iface->list);
filp->private_data = iface;
if (down_interruptible (&card->users_sem)) {
return -ERESTARTSYS;
}
if (iface->users) {
if (((iface->owner != current->uid) &&
(iface->owner != current->euid) &&
!capable (CAP_DAC_OVERRIDE))) {
up (&card->users_sem);
return -EBUSY;
}
} else {
/* Reset flags */
iface->events = 0;
__set_bit (0, &iface->dma_done);
/* Create a DMA buffer management structure */
if ((iface->dma = gt64_alloc (card->pdev,
0x1c000000 + DVBM_QI_FIFO(channel),
iface->buffers,
iface->bufsize,
PCI_DMA_FROMDEVICE)) == NULL) {
up (&card->users_sem);
return -ENOMEM;
}
/* Initialize the interface */
dvbm_qi_init (iface);
/* If we are the first user, install the interrupt handler */
if (!mdev_users (card) &&
(request_irq (card->pdev->irq,
card->irq_handler,
SA_SHIRQ,
card->name,
card) != 0)) {
gt64_free (iface->dma);
up (&card->users_sem);
return -EBUSY;
}
/* Activate the interface */
dvbm_qi_start (iface);
iface->owner = current->uid;
}
iface->users++;
up (&card->users_sem);
return nonseekable_open (inode, filp);
}
Thanks,
Dinesh
Arjan van de Ven wrote:
On Fri, 2006-11-10 at 09:23 -0600, Dinesh wrote:
Hello there,
My PCI device driver disables ethernet card IRQ upon loading and thus
causing ethernet to fail to connect to Internet. This is on Fedora Core
5, 2.6.11 onwards. I have not checked any previous kernel versions. Most
unfortunate is that the irq is not being shared by the devices. But, my
driver implements SA_SHIRQ to enable sharing.
Do you think using spin_lock_irq_save and restore functions be of any
help? If so, where exactly do you think I should use them. Should it be
used in the interrupt handler method or in the open method where I have
request_irq? I read the interrupt handling chapter of device drivers 3rd
edition. I could not find a real good explanation in there.
I doubt anyone can help you if you don't even say which driver this is,
or how to get a look at the source code for it...
--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive: http://mail.nl.linux.org/kernelnewbies/
FAQ: http://kernelnewbies.org/faq/