drivers/misc/sgi-gru/grutlbpurge.c

Source file repositories/reference/linux-study-clean/drivers/misc/sgi-gru/grutlbpurge.c

File Facts

System
Linux kernel
Corpus path
drivers/misc/sgi-gru/grutlbpurge.c
Extension
.c
Size
10114 bytes
Lines
317
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

if (asids->mt_ctxbitmap && asid) {
			STAT(flush_tlb_gru_tgh);
			asid = GRUASID(asid, start);
			gru_dbg(grudev,
	"  FLUSH gruid %d, asid 0x%x, vaddr 0x%lx, vamask 0x%x, num %ld, cbmap 0x%x\n",
			      gid, asid, start, grupagesize, num, asids->mt_ctxbitmap);
			tgh = get_lock_tgh_handle(gru);
			tgh_invalidate(tgh, start, ~0, asid, grupagesize, 0,
				       num - 1, asids->mt_ctxbitmap);
			get_unlock_tgh_handle(tgh);
		} else {
			STAT(flush_tlb_gru_zero_asid);
			asids->mt_asid = 0;
			__clear_bit(gru->gs_gid, gms->ms_asidmap);
			gru_dbg(grudev,
	"  CLEARASID gruid %d, asid 0x%x, cbtmap 0x%x, asidmap 0x%lx\n",
				gid, asid, asids->mt_ctxbitmap,
				gms->ms_asidmap[0]);
		}
	}
	spin_unlock(&gms->ms_asid_lock);
}

/*
 * Flush the entire TLB on a chiplet.
 */
void gru_flush_all_tlb(struct gru_state *gru)
{
	struct gru_tlb_global_handle *tgh;

	gru_dbg(grudev, "gid %d\n", gru->gs_gid);
	tgh = get_lock_tgh_handle(gru);
	tgh_invalidate(tgh, 0, ~0, 0, 1, 1, GRUMAXINVAL - 1, 0xffff);
	get_unlock_tgh_handle(tgh);
}

/*
 * MMUOPS notifier callout functions
 */
static int gru_invalidate_range_start(struct mmu_notifier *mn,
			const struct mmu_notifier_range *range)
{
	struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct,
						 ms_notifier);

	STAT(mmu_invalidate_range);
	atomic_inc(&gms->ms_range_active);
	gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx, act %d\n", gms,
		range->start, range->end, atomic_read(&gms->ms_range_active));
	gru_flush_tlb_range(gms, range->start, range->end - range->start);

	return 0;
}

static void gru_invalidate_range_end(struct mmu_notifier *mn,
			const struct mmu_notifier_range *range)
{
	struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct,
						 ms_notifier);

	/* ..._and_test() provides needed barrier */
	(void)atomic_dec_and_test(&gms->ms_range_active);

	wake_up_all(&gms->ms_wait_queue);
	gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx\n",
		gms, range->start, range->end);
}

static struct mmu_notifier *gru_alloc_notifier(struct mm_struct *mm)
{
	struct gru_mm_struct *gms;

	gms = kzalloc_obj(*gms);
	if (!gms)
		return ERR_PTR(-ENOMEM);
	STAT(gms_alloc);
	spin_lock_init(&gms->ms_asid_lock);
	init_waitqueue_head(&gms->ms_wait_queue);

	return &gms->ms_notifier;
}

static void gru_free_notifier(struct mmu_notifier *mn)
{
	kfree(container_of(mn, struct gru_mm_struct, ms_notifier));
	STAT(gms_free);
}

static const struct mmu_notifier_ops gru_mmuops = {
	.invalidate_range_start	= gru_invalidate_range_start,

Annotation

Implementation Notes