static void ring_interrupt_active()

in nhi.c [53:110]


static void ring_interrupt_active(struct tb_ring *ring, bool active)
{
	int reg = REG_RING_INTERRUPT_BASE +
		  ring_interrupt_index(ring) / 32 * 4;
	int bit = ring_interrupt_index(ring) & 31;
	int mask = 1 << bit;
	u32 old, new;

	if (ring->irq > 0) {
		u32 step, shift, ivr, misc;
		void __iomem *ivr_base;
		int index;

		if (ring->is_tx)
			index = ring->hop;
		else
			index = ring->hop + ring->nhi->hop_count;

		if (ring->nhi->quirks & QUIRK_AUTO_CLEAR_INT) {
			/*
			 * Ask the hardware to clear interrupt status
			 * bits automatically since we already know
			 * which interrupt was triggered.
			 */
			misc = ioread32(ring->nhi->iobase + REG_DMA_MISC);
			if (!(misc & REG_DMA_MISC_INT_AUTO_CLEAR)) {
				misc |= REG_DMA_MISC_INT_AUTO_CLEAR;
				iowrite32(misc, ring->nhi->iobase + REG_DMA_MISC);
			}
		}

		ivr_base = ring->nhi->iobase + REG_INT_VEC_ALLOC_BASE;
		step = index / REG_INT_VEC_ALLOC_REGS * REG_INT_VEC_ALLOC_BITS;
		shift = index % REG_INT_VEC_ALLOC_REGS * REG_INT_VEC_ALLOC_BITS;
		ivr = ioread32(ivr_base + step);
		ivr &= ~(REG_INT_VEC_ALLOC_MASK << shift);
		if (active)
			ivr |= ring->vector << shift;
		iowrite32(ivr, ivr_base + step);
	}

	old = ioread32(ring->nhi->iobase + reg);
	if (active)
		new = old | mask;
	else
		new = old & ~mask;

	dev_dbg(&ring->nhi->pdev->dev,
		"%s interrupt at register %#x bit %d (%#x -> %#x)\n",
		active ? "enabling" : "disabling", reg, bit, old, new);

	if (new == old)
		dev_WARN(&ring->nhi->pdev->dev,
					 "interrupt for %s %d is already %s\n",
					 RING_TYPE(ring), ring->hop,
					 active ? "enabled" : "disabled");
	iowrite32(new, ring->nhi->iobase + reg);
}