Re: spin_lock_irq_save and restore functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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/


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux