drivers/misc/vcpu_stall_detector.c

Source file repositories/reference/linux-study-clean/drivers/misc/vcpu_stall_detector.c

File Facts

System
Linux kernel
Corpus path
drivers/misc/vcpu_stall_detector.c
Extension
.c
Size
6725 bytes
Lines
247
Domain
Driver Families
Bucket
drivers/misc
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 vcpu_stall_detect_config {
	u32 clock_freq_hz;
	u32 stall_timeout_sec;
	int ppi_irq;

	void __iomem *membase;
	struct platform_device *dev;
	enum cpuhp_state hp_online;
};

struct vcpu_stall_priv {
	struct hrtimer vcpu_hrtimer;
	bool is_initialized;
};

/* The vcpu stall configuration structure which applies to all the CPUs */
static struct vcpu_stall_detect_config vcpu_stall_config;

#define vcpu_stall_reg_write(vcpu, reg, value)				\
	writel_relaxed((value),						\
		       (void __iomem *)(vcpu_stall_config.membase +	\
		       (vcpu) * VCPU_STALL_REG_LEN + (reg)))


static struct vcpu_stall_priv __percpu *vcpu_stall_detectors;

static enum hrtimer_restart
vcpu_stall_detect_timer_fn(struct hrtimer *hrtimer)
{
	u32 ticks, ping_timeout_ms;

	/* Reload the stall detector counter register every
	 * `ping_timeout_ms` to prevent the virtual device
	 * from decrementing it to 0. The virtual device decrements this
	 * register at 'clock_freq_hz' frequency.
	 */
	ticks = vcpu_stall_config.clock_freq_hz *
		vcpu_stall_config.stall_timeout_sec;
	vcpu_stall_reg_write(smp_processor_id(),
			     VCPU_STALL_REG_LOAD_CNT, ticks);

	ping_timeout_ms = vcpu_stall_config.stall_timeout_sec *
			  MSEC_PER_SEC / 2;
	hrtimer_forward_now(hrtimer,
			    ms_to_ktime(ping_timeout_ms));

	return HRTIMER_RESTART;
}

static irqreturn_t vcpu_stall_detector_irq(int irq, void *dev)
{
	panic("vCPU stall detector");
	return IRQ_HANDLED;
}

static int start_stall_detector_cpu(unsigned int cpu)
{
	u32 ticks, ping_timeout_ms;
	struct vcpu_stall_priv *vcpu_stall_detector =
		this_cpu_ptr(vcpu_stall_detectors);
	struct hrtimer *vcpu_hrtimer = &vcpu_stall_detector->vcpu_hrtimer;

	vcpu_stall_reg_write(cpu, VCPU_STALL_REG_CLOCK_FREQ_HZ,
			     vcpu_stall_config.clock_freq_hz);

	/* Compute the number of ticks required for the stall detector
	 * counter register based on the internal clock frequency and the
	 * timeout value given from the device tree.
	 */
	ticks = vcpu_stall_config.clock_freq_hz *
		vcpu_stall_config.stall_timeout_sec;
	vcpu_stall_reg_write(cpu, VCPU_STALL_REG_LOAD_CNT, ticks);

	/* Enable the internal clock and start the stall detector */
	vcpu_stall_reg_write(cpu, VCPU_STALL_REG_STATUS, 1);

	/* Pet the stall detector at half of its expiration timeout
	 * to prevent spurious resets.
	 */
	ping_timeout_ms = vcpu_stall_config.stall_timeout_sec *
			  MSEC_PER_SEC / 2;

	hrtimer_setup(vcpu_hrtimer, vcpu_stall_detect_timer_fn, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	vcpu_stall_detector->is_initialized = true;

	hrtimer_start(vcpu_hrtimer, ms_to_ktime(ping_timeout_ms),
		      HRTIMER_MODE_REL_PINNED);

	return 0;
}

Annotation

Implementation Notes