arch/x86/kvm/i8254.c

Source file repositories/reference/linux-study-clean/arch/x86/kvm/i8254.c

File Facts

System
Linux kernel
Corpus path
arch/x86/kvm/i8254.c
Extension
.c
Size
21033 bytes
Lines
817
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (ps->period < min_period) {
			pr_info_ratelimited(
			    "requested %lld ns "
			    "i8254 timer period limited to %lld ns\n",
			    ps->period, min_period);
			ps->period = min_period;
		}
	}

	hrtimer_start(&ps->timer, ktime_add_ns(ktime_get(), interval),
		      HRTIMER_MODE_ABS);
}

static void pit_load_count(struct kvm_pit *pit, int channel, u32 val)
{
	struct kvm_kpit_state *ps = &pit->pit_state;

	pr_debug("load_count val is %u, channel is %d\n", val, channel);

	/*
	 * The largest possible initial count is 0; this is equivalent
	 * to 216 for binary counting and 104 for BCD counting.
	 */
	if (val == 0)
		val = 0x10000;

	ps->channels[channel].count = val;

	if (channel != 0) {
		ps->channels[channel].count_load_time = ktime_get();
		return;
	}

	/* Two types of timer
	 * mode 1 is one shot, mode 2 is period, otherwise del timer */
	switch (ps->channels[0].mode) {
	case 0:
	case 1:
        /* FIXME: enhance mode 4 precision */
	case 4:
		create_pit_timer(pit, val, 0);
		break;
	case 2:
	case 3:
		create_pit_timer(pit, val, 1);
		break;
	default:
		destroy_pit_timer(pit);
	}
}

static void kvm_pit_load_count(struct kvm_pit *pit, int channel, u32 val,
			       int hpet_legacy_start)
{
	u8 saved_mode;

	WARN_ON_ONCE(!mutex_is_locked(&pit->pit_state.lock));

	if (hpet_legacy_start) {
		/* save existing mode for later reenablement */
		WARN_ON(channel != 0);
		saved_mode = pit->pit_state.channels[0].mode;
		pit->pit_state.channels[0].mode = 0xff; /* disable timer */
		pit_load_count(pit, channel, val);
		pit->pit_state.channels[0].mode = saved_mode;
	} else {
		pit_load_count(pit, channel, val);
	}
}

static inline struct kvm_pit *dev_to_pit(struct kvm_io_device *dev)
{
	return container_of(dev, struct kvm_pit, dev);
}

static inline struct kvm_pit *speaker_to_pit(struct kvm_io_device *dev)
{
	return container_of(dev, struct kvm_pit, speaker_dev);
}

static inline int pit_in_range(gpa_t addr)
{
	return ((addr >= KVM_PIT_BASE_ADDRESS) &&
		(addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH));
}

static int pit_ioport_write(struct kvm_vcpu *vcpu,
				struct kvm_io_device *this,
			    gpa_t addr, int len, const void *data)
{

Annotation

Implementation Notes