drivers/net/ipa/ipa_smp2p.c

Source file repositories/reference/linux-study-clean/drivers/net/ipa/ipa_smp2p.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ipa/ipa_smp2p.c
Extension
.c
Size
9554 bytes
Lines
349
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source 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

struct ipa_smp2p {
	struct ipa *ipa;
	struct qcom_smem_state *valid_state;
	struct qcom_smem_state *enabled_state;
	u32 valid_bit;
	u32 enabled_bit;
	u32 clock_query_irq;
	u32 setup_ready_irq;
	bool power_on;
	bool notified;
	bool setup_disabled;
	struct mutex mutex;
	struct notifier_block panic_notifier;
};

/**
 * ipa_smp2p_notify() - use SMP2P to tell modem about IPA power state
 * @smp2p:	SMP2P information
 *
 * This is called either when the modem has requested it (by triggering
 * the modem power query IPA interrupt) or whenever the AP is shutting down
 * (via a panic notifier).  It sets the two SMP2P state bits--one saying
 * whether the IPA power is on, and the other indicating the first bit
 * is valid.
 */
static void ipa_smp2p_notify(struct ipa_smp2p *smp2p)
{
	u32 value;
	u32 mask;

	if (smp2p->notified)
		return;

	smp2p->power_on = pm_runtime_get_if_active(smp2p->ipa->dev) > 0;

	/* Signal whether the IPA power is enabled */
	mask = BIT(smp2p->enabled_bit);
	value = smp2p->power_on ? mask : 0;
	qcom_smem_state_update_bits(smp2p->enabled_state, mask, value);

	/* Now indicate that the enabled flag is valid */
	mask = BIT(smp2p->valid_bit);
	value = mask;
	qcom_smem_state_update_bits(smp2p->valid_state, mask, value);

	smp2p->notified = true;
}

/* Threaded IRQ handler for modem "ipa-clock-query" SMP2P interrupt */
static irqreturn_t ipa_smp2p_modem_clk_query_isr(int irq, void *dev_id)
{
	struct ipa_smp2p *smp2p = dev_id;

	ipa_smp2p_notify(smp2p);

	return IRQ_HANDLED;
}

static int ipa_smp2p_panic_notifier(struct notifier_block *nb,
				    unsigned long action, void *data)
{
	struct ipa_smp2p *smp2p;

	smp2p = container_of(nb, struct ipa_smp2p, panic_notifier);

	ipa_smp2p_notify(smp2p);

	if (smp2p->power_on)
		ipa_uc_panic_notifier(smp2p->ipa);

	return NOTIFY_DONE;
}

static int ipa_smp2p_panic_notifier_register(struct ipa_smp2p *smp2p)
{
	/* IPA panic handler needs to run before modem shuts down */
	smp2p->panic_notifier.notifier_call = ipa_smp2p_panic_notifier;
	smp2p->panic_notifier.priority = INT_MAX;	/* Do it early */

	return atomic_notifier_chain_register(&panic_notifier_list,
					      &smp2p->panic_notifier);
}

static void ipa_smp2p_panic_notifier_unregister(struct ipa_smp2p *smp2p)
{
	atomic_notifier_chain_unregister(&panic_notifier_list,
					 &smp2p->panic_notifier);
}

/* Threaded IRQ handler for modem "ipa-setup-ready" SMP2P interrupt */

Annotation

Implementation Notes