drivers/irqchip/irq-riscv-imsic-state.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-riscv-imsic-state.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-riscv-imsic-state.c
Extension
.c
Size
25500 bytes
Lines
969
Domain
Driver Families
Bucket
drivers/irqchip
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (mvec) {
			/*
			 * If the old vector has not been updated then
			 * try again in the next sync-up call.
			 */
			if (READ_ONCE(mvec->move_next)) {
				ret = false;
				continue;
			}

			WRITE_ONCE(vec->move_prev, NULL);
		}

		/*
		 * If a vector was being moved to a new vector on some other
		 * CPU then we can get a MSI during the movement so check the
		 * ID pending bit and re-trigger the new ID on other CPU using
		 * MMIO write.
		 */
		mvec = READ_ONCE(vec->move_next);
		if (mvec) {
			/*
			 * Devices having non-atomic MSI update might see
			 * an intermediate state so check both old ID and
			 * new ID for pending interrupts.
			 *
			 * For details, see imsic_irq_set_affinity().
			 */
			tvec = vec->local_id == mvec->local_id ?
				NULL : &lpriv->vectors[mvec->local_id];

			if (tvec && !irq_can_move_in_process_context(irq_get_irq_data(vec->irq)) &&
			    __imsic_id_read_clear_pending(tvec->local_id)) {
				/* Retrigger temporary vector if it was already in-use */
				if (READ_ONCE(tvec->enable)) {
					tlocal = per_cpu_ptr(imsic->global.local, tvec->cpu);
					writel_relaxed(tvec->local_id, tlocal->msi_va);
				}

				mlocal = per_cpu_ptr(imsic->global.local, mvec->cpu);
				writel_relaxed(mvec->local_id, mlocal->msi_va);
			}

			if (__imsic_id_read_clear_pending(vec->local_id)) {
				mlocal = per_cpu_ptr(imsic->global.local, mvec->cpu);
				writel_relaxed(mvec->local_id, mlocal->msi_va);
			}

			WRITE_ONCE(vec->move_next, NULL);
			imsic_vector_free(vec);
		}

skip:
		bitmap_clear(lpriv->dirty_bitmap, i, 1);
	}

	return ret;
}

#ifdef CONFIG_SMP
static void __imsic_local_timer_start(struct imsic_local_priv *lpriv, unsigned int cpu)
{
	lockdep_assert_held(&lpriv->lock);

	if (!timer_pending(&lpriv->timer)) {
		lpriv->timer.expires = jiffies + 1;
		add_timer_on(&lpriv->timer, cpu);
	}
}
#else
static inline void __imsic_local_timer_start(struct imsic_local_priv *lpriv, unsigned int cpu)
{
}
#endif

void imsic_local_sync_all(bool force_all)
{
	struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv);
	unsigned long flags;

	raw_spin_lock_irqsave(&lpriv->lock, flags);

	if (force_all)
		bitmap_fill(lpriv->dirty_bitmap, imsic->global.nr_ids + 1);
	if (!__imsic_local_sync(lpriv))
		__imsic_local_timer_start(lpriv, smp_processor_id());

	raw_spin_unlock_irqrestore(&lpriv->lock, flags);
}

Annotation

Implementation Notes