cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

context.c (9339B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3/*
      4 * Copyright 2016-2021 HabanaLabs, Ltd.
      5 * All Rights Reserved.
      6 */
      7
      8#include "habanalabs.h"
      9
     10#include <linux/slab.h>
     11
     12void hl_encaps_handle_do_release(struct kref *ref)
     13{
     14	struct hl_cs_encaps_sig_handle *handle =
     15		container_of(ref, struct hl_cs_encaps_sig_handle, refcount);
     16	struct hl_encaps_signals_mgr *mgr = &handle->ctx->sig_mgr;
     17
     18	spin_lock(&mgr->lock);
     19	idr_remove(&mgr->handles, handle->id);
     20	spin_unlock(&mgr->lock);
     21
     22	hl_ctx_put(handle->ctx);
     23	kfree(handle);
     24}
     25
     26static void hl_encaps_handle_do_release_sob(struct kref *ref)
     27{
     28	struct hl_cs_encaps_sig_handle *handle =
     29		container_of(ref, struct hl_cs_encaps_sig_handle, refcount);
     30	struct hl_encaps_signals_mgr *mgr = &handle->ctx->sig_mgr;
     31
     32	/* if we're here, then there was a signals reservation but cs with
     33	 * encaps signals wasn't submitted, so need to put refcount
     34	 * to hw_sob taken at the reservation.
     35	 */
     36	hw_sob_put(handle->hw_sob);
     37
     38	spin_lock(&mgr->lock);
     39	idr_remove(&mgr->handles, handle->id);
     40	spin_unlock(&mgr->lock);
     41
     42	hl_ctx_put(handle->ctx);
     43	kfree(handle);
     44}
     45
     46static void hl_encaps_sig_mgr_init(struct hl_encaps_signals_mgr *mgr)
     47{
     48	spin_lock_init(&mgr->lock);
     49	idr_init(&mgr->handles);
     50}
     51
     52static void hl_encaps_sig_mgr_fini(struct hl_device *hdev,
     53			struct hl_encaps_signals_mgr *mgr)
     54{
     55	struct hl_cs_encaps_sig_handle *handle;
     56	struct idr *idp;
     57	u32 id;
     58
     59	idp = &mgr->handles;
     60
     61	if (!idr_is_empty(idp)) {
     62		dev_warn(hdev->dev, "device released while some encaps signals handles are still allocated\n");
     63		idr_for_each_entry(idp, handle, id)
     64			kref_put(&handle->refcount,
     65					hl_encaps_handle_do_release_sob);
     66	}
     67
     68	idr_destroy(&mgr->handles);
     69}
     70
     71static void hl_ctx_fini(struct hl_ctx *ctx)
     72{
     73	struct hl_device *hdev = ctx->hdev;
     74	int i;
     75
     76	/* Release all allocated HW block mapped list entries and destroy
     77	 * the mutex.
     78	 */
     79	hl_hw_block_mem_fini(ctx);
     80
     81	/*
     82	 * If we arrived here, there are no jobs waiting for this context
     83	 * on its queues so we can safely remove it.
     84	 * This is because for each CS, we increment the ref count and for
     85	 * every CS that was finished we decrement it and we won't arrive
     86	 * to this function unless the ref count is 0
     87	 */
     88
     89	for (i = 0 ; i < hdev->asic_prop.max_pending_cs ; i++)
     90		hl_fence_put(ctx->cs_pending[i]);
     91
     92	kfree(ctx->cs_pending);
     93
     94	if (ctx->asid != HL_KERNEL_ASID_ID) {
     95		dev_dbg(hdev->dev, "closing user context %d\n", ctx->asid);
     96
     97		/* The engines are stopped as there is no executing CS, but the
     98		 * Coresight might be still working by accessing addresses
     99		 * related to the stopped engines. Hence stop it explicitly.
    100		 */
    101		if (hdev->in_debug)
    102			hl_device_set_debug_mode(hdev, ctx, false);
    103
    104		hdev->asic_funcs->ctx_fini(ctx);
    105		hl_cb_va_pool_fini(ctx);
    106		hl_vm_ctx_fini(ctx);
    107		hl_asid_free(hdev, ctx->asid);
    108		hl_encaps_sig_mgr_fini(hdev, &ctx->sig_mgr);
    109
    110		/* Scrub both SRAM and DRAM */
    111		hdev->asic_funcs->scrub_device_mem(hdev, 0, 0);
    112	} else {
    113		dev_dbg(hdev->dev, "closing kernel context\n");
    114		hdev->asic_funcs->ctx_fini(ctx);
    115		hl_vm_ctx_fini(ctx);
    116		hl_mmu_ctx_fini(ctx);
    117	}
    118}
    119
    120void hl_ctx_do_release(struct kref *ref)
    121{
    122	struct hl_ctx *ctx;
    123
    124	ctx = container_of(ref, struct hl_ctx, refcount);
    125
    126	hl_ctx_fini(ctx);
    127
    128	if (ctx->hpriv)
    129		hl_hpriv_put(ctx->hpriv);
    130
    131	kfree(ctx);
    132}
    133
    134int hl_ctx_create(struct hl_device *hdev, struct hl_fpriv *hpriv)
    135{
    136	struct hl_ctx_mgr *mgr = &hpriv->ctx_mgr;
    137	struct hl_ctx *ctx;
    138	int rc;
    139
    140	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
    141	if (!ctx) {
    142		rc = -ENOMEM;
    143		goto out_err;
    144	}
    145
    146	mutex_lock(&mgr->ctx_lock);
    147	rc = idr_alloc(&mgr->ctx_handles, ctx, 1, 0, GFP_KERNEL);
    148	mutex_unlock(&mgr->ctx_lock);
    149
    150	if (rc < 0) {
    151		dev_err(hdev->dev, "Failed to allocate IDR for a new CTX\n");
    152		goto free_ctx;
    153	}
    154
    155	ctx->handle = rc;
    156
    157	rc = hl_ctx_init(hdev, ctx, false);
    158	if (rc)
    159		goto remove_from_idr;
    160
    161	hl_hpriv_get(hpriv);
    162	ctx->hpriv = hpriv;
    163
    164	/* TODO: remove for multiple contexts per process */
    165	hpriv->ctx = ctx;
    166
    167	/* TODO: remove the following line for multiple process support */
    168	hdev->is_compute_ctx_active = true;
    169
    170	return 0;
    171
    172remove_from_idr:
    173	mutex_lock(&mgr->ctx_lock);
    174	idr_remove(&mgr->ctx_handles, ctx->handle);
    175	mutex_unlock(&mgr->ctx_lock);
    176free_ctx:
    177	kfree(ctx);
    178out_err:
    179	return rc;
    180}
    181
    182int hl_ctx_init(struct hl_device *hdev, struct hl_ctx *ctx, bool is_kernel_ctx)
    183{
    184	int rc = 0;
    185
    186	ctx->hdev = hdev;
    187
    188	kref_init(&ctx->refcount);
    189
    190	ctx->cs_sequence = 1;
    191	spin_lock_init(&ctx->cs_lock);
    192	atomic_set(&ctx->thread_ctx_switch_token, 1);
    193	ctx->thread_ctx_switch_wait_token = 0;
    194	ctx->cs_pending = kcalloc(hdev->asic_prop.max_pending_cs,
    195				sizeof(struct hl_fence *),
    196				GFP_KERNEL);
    197	if (!ctx->cs_pending)
    198		return -ENOMEM;
    199
    200	hl_hw_block_mem_init(ctx);
    201
    202	if (is_kernel_ctx) {
    203		ctx->asid = HL_KERNEL_ASID_ID; /* Kernel driver gets ASID 0 */
    204		rc = hl_vm_ctx_init(ctx);
    205		if (rc) {
    206			dev_err(hdev->dev, "Failed to init mem ctx module\n");
    207			rc = -ENOMEM;
    208			goto err_hw_block_mem_fini;
    209		}
    210
    211		rc = hdev->asic_funcs->ctx_init(ctx);
    212		if (rc) {
    213			dev_err(hdev->dev, "ctx_init failed\n");
    214			goto err_vm_ctx_fini;
    215		}
    216	} else {
    217		ctx->asid = hl_asid_alloc(hdev);
    218		if (!ctx->asid) {
    219			dev_err(hdev->dev, "No free ASID, failed to create context\n");
    220			rc = -ENOMEM;
    221			goto err_hw_block_mem_fini;
    222		}
    223
    224		rc = hl_vm_ctx_init(ctx);
    225		if (rc) {
    226			dev_err(hdev->dev, "Failed to init mem ctx module\n");
    227			rc = -ENOMEM;
    228			goto err_asid_free;
    229		}
    230
    231		rc = hl_cb_va_pool_init(ctx);
    232		if (rc) {
    233			dev_err(hdev->dev,
    234				"Failed to init VA pool for mapped CB\n");
    235			goto err_vm_ctx_fini;
    236		}
    237
    238		rc = hdev->asic_funcs->ctx_init(ctx);
    239		if (rc) {
    240			dev_err(hdev->dev, "ctx_init failed\n");
    241			goto err_cb_va_pool_fini;
    242		}
    243
    244		hl_encaps_sig_mgr_init(&ctx->sig_mgr);
    245
    246		dev_dbg(hdev->dev, "create user context %d\n", ctx->asid);
    247	}
    248
    249	return 0;
    250
    251err_cb_va_pool_fini:
    252	hl_cb_va_pool_fini(ctx);
    253err_vm_ctx_fini:
    254	hl_vm_ctx_fini(ctx);
    255err_asid_free:
    256	if (ctx->asid != HL_KERNEL_ASID_ID)
    257		hl_asid_free(hdev, ctx->asid);
    258err_hw_block_mem_fini:
    259	hl_hw_block_mem_fini(ctx);
    260	kfree(ctx->cs_pending);
    261
    262	return rc;
    263}
    264
    265void hl_ctx_get(struct hl_ctx *ctx)
    266{
    267	kref_get(&ctx->refcount);
    268}
    269
    270int hl_ctx_put(struct hl_ctx *ctx)
    271{
    272	return kref_put(&ctx->refcount, hl_ctx_do_release);
    273}
    274
    275struct hl_ctx *hl_get_compute_ctx(struct hl_device *hdev)
    276{
    277	struct hl_ctx *ctx = NULL;
    278	struct hl_fpriv *hpriv;
    279
    280	mutex_lock(&hdev->fpriv_list_lock);
    281
    282	list_for_each_entry(hpriv, &hdev->fpriv_list, dev_node) {
    283		/* There can only be a single user which has opened the compute device, so exit
    284		 * immediately once we find him
    285		 */
    286		ctx = hpriv->ctx;
    287		hl_ctx_get(ctx);
    288		break;
    289	}
    290
    291	mutex_unlock(&hdev->fpriv_list_lock);
    292
    293	return ctx;
    294}
    295
    296/*
    297 * hl_ctx_get_fence_locked - get CS fence under CS lock
    298 *
    299 * @ctx: pointer to the context structure.
    300 * @seq: CS sequences number
    301 *
    302 * @return valid fence pointer on success, NULL if fence is gone, otherwise
    303 *         error pointer.
    304 *
    305 * NOTE: this function shall be called with cs_lock locked
    306 */
    307static struct hl_fence *hl_ctx_get_fence_locked(struct hl_ctx *ctx, u64 seq)
    308{
    309	struct asic_fixed_properties *asic_prop = &ctx->hdev->asic_prop;
    310	struct hl_fence *fence;
    311
    312	if (seq >= ctx->cs_sequence)
    313		return ERR_PTR(-EINVAL);
    314
    315	if (seq + asic_prop->max_pending_cs < ctx->cs_sequence)
    316		return NULL;
    317
    318	fence = ctx->cs_pending[seq & (asic_prop->max_pending_cs - 1)];
    319	hl_fence_get(fence);
    320	return fence;
    321}
    322
    323struct hl_fence *hl_ctx_get_fence(struct hl_ctx *ctx, u64 seq)
    324{
    325	struct hl_fence *fence;
    326
    327	spin_lock(&ctx->cs_lock);
    328
    329	fence = hl_ctx_get_fence_locked(ctx, seq);
    330
    331	spin_unlock(&ctx->cs_lock);
    332
    333	return fence;
    334}
    335
    336/*
    337 * hl_ctx_get_fences - get multiple CS fences under the same CS lock
    338 *
    339 * @ctx: pointer to the context structure.
    340 * @seq_arr: array of CS sequences to wait for
    341 * @fence: fence array to store the CS fences
    342 * @arr_len: length of seq_arr and fence_arr
    343 *
    344 * @return 0 on success, otherwise non 0 error code
    345 */
    346int hl_ctx_get_fences(struct hl_ctx *ctx, u64 *seq_arr,
    347				struct hl_fence **fence, u32 arr_len)
    348{
    349	struct hl_fence **fence_arr_base = fence;
    350	int i, rc = 0;
    351
    352	spin_lock(&ctx->cs_lock);
    353
    354	for (i = 0; i < arr_len; i++, fence++) {
    355		u64 seq = seq_arr[i];
    356
    357		*fence = hl_ctx_get_fence_locked(ctx, seq);
    358
    359		if (IS_ERR(*fence)) {
    360			dev_err(ctx->hdev->dev,
    361				"Failed to get fence for CS with seq 0x%llx\n",
    362					seq);
    363			rc = PTR_ERR(*fence);
    364			break;
    365		}
    366	}
    367
    368	spin_unlock(&ctx->cs_lock);
    369
    370	if (rc)
    371		hl_fences_put(fence_arr_base, i);
    372
    373	return rc;
    374}
    375
    376/*
    377 * hl_ctx_mgr_init - initialize the context manager
    378 *
    379 * @mgr: pointer to context manager structure
    380 *
    381 * This manager is an object inside the hpriv object of the user process.
    382 * The function is called when a user process opens the FD.
    383 */
    384void hl_ctx_mgr_init(struct hl_ctx_mgr *mgr)
    385{
    386	mutex_init(&mgr->ctx_lock);
    387	idr_init(&mgr->ctx_handles);
    388}
    389
    390/*
    391 * hl_ctx_mgr_fini - finalize the context manager
    392 *
    393 * @hdev: pointer to device structure
    394 * @mgr: pointer to context manager structure
    395 *
    396 * This function goes over all the contexts in the manager and frees them.
    397 * It is called when a process closes the FD.
    398 */
    399void hl_ctx_mgr_fini(struct hl_device *hdev, struct hl_ctx_mgr *mgr)
    400{
    401	struct hl_ctx *ctx;
    402	struct idr *idp;
    403	u32 id;
    404
    405	idp = &mgr->ctx_handles;
    406
    407	idr_for_each_entry(idp, ctx, id)
    408		kref_put(&ctx->refcount, hl_ctx_do_release);
    409
    410	idr_destroy(&mgr->ctx_handles);
    411	mutex_destroy(&mgr->ctx_lock);
    412}