/* * Copyright 2022 HabanaLabs, Ltd. * All Rights Reserved.
*/
#include"habanalabs.h"
/** * hl_mmap_mem_buf_get - increase the buffer refcount and return a pointer to * the buffer descriptor. * * @mmg: parent unified memory manager * @handle: requested buffer handle * * Find the buffer in the store and return a pointer to its descriptor. * Increase buffer refcount. If not found - return NULL.
*/ struct hl_mmap_mem_buf *hl_mmap_mem_buf_get(struct hl_mem_mgr *mmg, u64 handle)
{ struct hl_mmap_mem_buf *buf;
spin_lock(&mmg->lock);
buf = idr_find(&mmg->handles, lower_32_bits(handle >> PAGE_SHIFT)); if (!buf) {
spin_unlock(&mmg->lock);
dev_dbg(mmg->dev, "Buff get failed, no match to handle %#llx\n", handle); return NULL;
}
kref_get(&buf->refcount);
spin_unlock(&mmg->lock); return buf;
}
/** * hl_mmap_mem_buf_destroy - destroy the unused buffer * * @buf: memory manager buffer descriptor * * Internal function, used as a final step of buffer release. Shall be invoked * only when the buffer is no longer in use (removed from idr). Will call the * release callback (if applicable), and free the memory.
*/ staticvoid hl_mmap_mem_buf_destroy(struct hl_mmap_mem_buf *buf)
{ if (buf->behavior->release)
buf->behavior->release(buf);
kfree(buf);
}
/** * hl_mmap_mem_buf_release - release buffer * * @kref: kref that reached 0. * * Internal function, used as a kref release callback, when the last user of * the buffer is released. Shall be called from an interrupt context.
*/ staticvoid hl_mmap_mem_buf_release(struct kref *kref)
{ struct hl_mmap_mem_buf *buf =
container_of(kref, struct hl_mmap_mem_buf, refcount);
/** * hl_mmap_mem_buf_remove_idr_locked - remove handle from idr * * @kref: kref that reached 0. * * Internal function, used for kref put by handle. Assumes mmg lock is taken. * Will remove the buffer from idr, without destroying it.
*/ staticvoid hl_mmap_mem_buf_remove_idr_locked(struct kref *kref)
{ struct hl_mmap_mem_buf *buf =
container_of(kref, struct hl_mmap_mem_buf, refcount);
/** * hl_mmap_mem_buf_put - decrease the reference to the buffer * * @buf: memory manager buffer descriptor * * Decrease the reference to the buffer, and release it if it was the last one. * Shall be called from an interrupt context.
*/ int hl_mmap_mem_buf_put(struct hl_mmap_mem_buf *buf)
{ return kref_put(&buf->refcount, hl_mmap_mem_buf_release);
}
/** * hl_mmap_mem_buf_put_handle - decrease the reference to the buffer with the * given handle. * * @mmg: parent unified memory manager * @handle: requested buffer handle * * Decrease the reference to the buffer, and release it if it was the last one. * Shall not be called from an interrupt context. Return -EINVAL if handle was * not found, else return the put outcome (0 or 1).
*/ int hl_mmap_mem_buf_put_handle(struct hl_mem_mgr *mmg, u64 handle)
{ struct hl_mmap_mem_buf *buf;
spin_lock(&mmg->lock);
buf = idr_find(&mmg->handles, lower_32_bits(handle >> PAGE_SHIFT)); if (!buf) {
spin_unlock(&mmg->lock);
dev_dbg(mmg->dev, "Buff put failed, no match to handle %#llx\n", handle); return -EINVAL;
}
if (kref_put(&buf->refcount, hl_mmap_mem_buf_remove_idr_locked)) {
spin_unlock(&mmg->lock);
hl_mmap_mem_buf_destroy(buf); return 1;
}
spin_unlock(&mmg->lock); return 0;
}
/** * hl_mmap_mem_buf_alloc - allocate a new mappable buffer * * @mmg: parent unified memory manager * @behavior: behavior object describing this buffer polymorphic behavior * @gfp: gfp flags to use for the memory allocations * @args: additional args passed to behavior->alloc * * Allocate and register a new memory buffer inside the give memory manager. * Return the pointer to the new buffer on success or NULL on failure.
*/ struct hl_mmap_mem_buf *
hl_mmap_mem_buf_alloc(struct hl_mem_mgr *mmg, struct hl_mmap_mem_buf_behavior *behavior, gfp_t gfp, void *args)
{ struct hl_mmap_mem_buf *buf; int rc;
buf = kzalloc(sizeof(*buf), gfp); if (!buf) return NULL;
spin_lock(&mmg->lock);
rc = idr_alloc(&mmg->handles, buf, 1, 0, GFP_ATOMIC);
spin_unlock(&mmg->lock); if (rc < 0) {
dev_err(mmg->dev, "%s: Failed to allocate IDR for a new buffer, rc=%d\n",
behavior->topic, rc); goto free_buf;
}
/** * hl_mmap_mem_buf_vm_close - handle mmap close * * @vma: the vma object for which mmap was closed. * * Put the memory buffer if it is no longer mapped.
*/ staticvoid hl_mmap_mem_buf_vm_close(struct vm_area_struct *vma)
{ struct hl_mmap_mem_buf *buf =
(struct hl_mmap_mem_buf *)vma->vm_private_data; long new_mmap_size;
/** * hl_mem_mgr_mmap - map the given buffer to the user * * @mmg: unified memory manager * @vma: the vma object for which mmap was closed. * @args: additional args passed to behavior->mmap * * Map the buffer specified by the vma->vm_pgoff to the given vma.
*/ int hl_mem_mgr_mmap(struct hl_mem_mgr *mmg, struct vm_area_struct *vma, void *args)
{ struct hl_mmap_mem_buf *buf;
u64 user_mem_size;
u64 handle; int rc;
/* We use the page offset to hold the idr and thus we need to clear * it before doing the mmap itself
*/
handle = vma->vm_pgoff << PAGE_SHIFT;
vma->vm_pgoff = 0;
/* Reference was taken here */
buf = hl_mmap_mem_buf_get(mmg, handle); if (!buf) {
dev_err(mmg->dev, "Memory mmap failed, no match to handle %#llx\n", handle); return -EINVAL;
}
staticvoid hl_mem_mgr_fini_stats_reset(struct hl_mem_mgr_fini_stats *stats)
{ if (!stats) return;
memset(stats, 0, sizeof(*stats));
}
staticvoid hl_mem_mgr_fini_stats_inc(u64 mem_id, struct hl_mem_mgr_fini_stats *stats)
{ if (!stats) return;
switch (mem_id) { case HL_MMAP_TYPE_CB:
++stats->n_busy_cb; break; case HL_MMAP_TYPE_TS_BUFF:
++stats->n_busy_ts; break; default: /* we currently store only CB/TS so this shouldn't happen */
++stats->n_busy_other;
}
}
/** * hl_mem_mgr_fini - release unified memory manager * * @mmg: parent unified memory manager * @stats: if non-NULL, will return some counters for handles that could not be removed. * * Release the unified memory manager. Shall be called from an interrupt context.
*/ void hl_mem_mgr_fini(struct hl_mem_mgr *mmg, struct hl_mem_mgr_fini_stats *stats)
{ struct hl_mmap_mem_buf *buf; struct idr *idp; constchar *topic;
u64 mem_id;
u32 id;
hl_mem_mgr_fini_stats_reset(stats);
idp = &mmg->handles;
idr_for_each_entry(idp, buf, id) {
topic = buf->behavior->topic;
mem_id = buf->behavior->mem_id; if (hl_mmap_mem_buf_put(buf) != 1) {
dev_err(mmg->dev, "%s: Buff handle %u for CTX is still alive\n",
topic, id);
hl_mem_mgr_fini_stats_inc(mem_id, stats);
}
}
}
/** * hl_mem_mgr_idr_destroy() - destroy memory manager IDR. * @mmg: parent unified memory manager * * Destroy the memory manager IDR. * Shall be called when IDR is empty and no memory buffers are in use.
*/ void hl_mem_mgr_idr_destroy(struct hl_mem_mgr *mmg)
{ if (!idr_is_empty(&mmg->handles))
dev_crit(mmg->dev, "memory manager IDR is destroyed while it is not empty!\n");
idr_destroy(&mmg->handles);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.29 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.