drivers/gpu/drm/i915/gvt/sched_policy.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/i915/gvt/sched_policy.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/i915/gvt/sched_policy.c
Extension
.c
Size
12925 bytes
Lines
482
Domain
Driver Families
Bucket
drivers/gpu
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 vgpu_sched_data {
	struct list_head lru_list;
	struct intel_vgpu *vgpu;
	bool active;
	bool pri_sched;
	ktime_t pri_time;
	ktime_t sched_in_time;
	ktime_t sched_time;
	ktime_t left_ts;
	ktime_t allocated_ts;

	struct vgpu_sched_ctl sched_ctl;
};

struct gvt_sched_data {
	struct intel_gvt *gvt;
	struct hrtimer timer;
	unsigned long period;
	struct list_head lru_runq_head;
	ktime_t expire_time;
};

static void vgpu_update_timeslice(struct intel_vgpu *vgpu, ktime_t cur_time)
{
	ktime_t delta_ts;
	struct vgpu_sched_data *vgpu_data;

	if (!vgpu || vgpu == vgpu->gvt->idle_vgpu)
		return;

	vgpu_data = vgpu->sched_data;
	delta_ts = ktime_sub(cur_time, vgpu_data->sched_in_time);
	vgpu_data->sched_time = ktime_add(vgpu_data->sched_time, delta_ts);
	vgpu_data->left_ts = ktime_sub(vgpu_data->left_ts, delta_ts);
	vgpu_data->sched_in_time = cur_time;
}

#define GVT_TS_BALANCE_PERIOD_MS 100
#define GVT_TS_BALANCE_STAGE_NUM 10

static void gvt_balance_timeslice(struct gvt_sched_data *sched_data)
{
	struct vgpu_sched_data *vgpu_data;
	struct list_head *pos;
	static u64 stage_check;
	int stage = stage_check++ % GVT_TS_BALANCE_STAGE_NUM;

	/* The timeslice accumulation reset at stage 0, which is
	 * allocated again without adding previous debt.
	 */
	if (stage == 0) {
		int total_weight = 0;
		ktime_t fair_timeslice;

		list_for_each(pos, &sched_data->lru_runq_head) {
			vgpu_data = container_of(pos, struct vgpu_sched_data, lru_list);
			total_weight += vgpu_data->sched_ctl.weight;
		}

		list_for_each(pos, &sched_data->lru_runq_head) {
			vgpu_data = container_of(pos, struct vgpu_sched_data, lru_list);
			fair_timeslice = ktime_divns(ms_to_ktime(GVT_TS_BALANCE_PERIOD_MS),
						     total_weight) * vgpu_data->sched_ctl.weight;

			vgpu_data->allocated_ts = fair_timeslice;
			vgpu_data->left_ts = vgpu_data->allocated_ts;
		}
	} else {
		list_for_each(pos, &sched_data->lru_runq_head) {
			vgpu_data = container_of(pos, struct vgpu_sched_data, lru_list);

			/* timeslice for next 100ms should add the left/debt
			 * slice of previous stages.
			 */
			vgpu_data->left_ts += vgpu_data->allocated_ts;
		}
	}
}

static void try_to_schedule_next_vgpu(struct intel_gvt *gvt)
{
	struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
	enum intel_engine_id i;
	struct intel_engine_cs *engine;
	struct vgpu_sched_data *vgpu_data;
	ktime_t cur_time;

	/* no need to schedule if next_vgpu is the same with current_vgpu,
	 * let scheduler chose next_vgpu again by setting it to NULL.
	 */

Annotation

Implementation Notes