977 lines
25 KiB
C
977 lines
25 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2020 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/list.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include "apusys_device.h"
|
|
#include "mdw_cmn.h"
|
|
#include "mdw_cmd.h"
|
|
#include "apu_cmd.h"
|
|
#include "mdw_mem.h"
|
|
#include "mdw_dbg.h"
|
|
#include "mdw_sched.h"
|
|
#include "mdw_rsc.h"
|
|
#include "mdw_trace.h"
|
|
#include "reviser_export.h"
|
|
#include "mdw_fence.h"
|
|
|
|
#define MDW_CMD_PSR_NUM_ERR 0xffffffff
|
|
#define MDW_CMD_SCR_BMP_ERR 0xffffffffffffffff
|
|
#define MDW_CMD_EMPTY_NUM 0xff
|
|
|
|
/* parse apu cmd related functions */
|
|
static void mdw_cmd_show_cmd(struct mdw_apu_cmd *c)
|
|
{
|
|
struct apu_cmd_hdr *h = c->hdr;
|
|
|
|
mdw_cmd_debug("-------------------------\n");
|
|
mdw_cmd_debug(" apusys cmd(0x%llx)\n", c->kid);
|
|
mdw_cmd_debug(" magic = 0x%llx\n", h->magic);
|
|
mdw_cmd_debug(" uid = 0x%llx\n", h->uid);
|
|
mdw_cmd_debug(" version = %u\n", h->version);
|
|
mdw_cmd_debug(" priority = %u\n", h->priority);
|
|
mdw_cmd_debug(" hard_limit = %u\n", h->hard_limit);
|
|
mdw_cmd_debug(" soft_limit = %u\n", h->soft_limit);
|
|
mdw_cmd_debug(" pid = %u\n", h->pid);
|
|
mdw_cmd_debug(" flags = 0x%llx\n", h->flags);
|
|
mdw_cmd_debug(" num_sc = %u\n", h->num_sc);
|
|
mdw_cmd_debug(" ofs_scr_list = %u\n", h->ofs_scr_list);
|
|
mdw_cmd_debug(" ofs_pdr_cnt_list = %u\n", h->ofs_pdr_cnt_list);
|
|
mdw_cmd_debug(" scofs_list_entry = %u\n", h->scofs_list_entry);
|
|
mdw_cmd_debug("-------------------------\n");
|
|
}
|
|
|
|
static void mdw_cmd_show_sc(struct mdw_apu_sc *sc)
|
|
{
|
|
struct apu_sc_hdr_cmn *h = sc->hdr;
|
|
|
|
mdw_cmd_debug("-------------------------\n");
|
|
mdw_cmd_debug(" apusys sc(0x%llx-#%d)\n", sc->parent->kid, sc->idx);
|
|
mdw_cmd_debug(" type = %u\n", h->type);
|
|
mdw_cmd_debug(" driver_time = %u\n", h->driver_time);
|
|
mdw_cmd_debug(" ip_time = %u\n", h->ip_time);
|
|
mdw_cmd_debug(" suggest_time = %u\n", h->suggest_time);
|
|
mdw_cmd_debug(" bandwidth = %u\n", h->bandwidth);
|
|
mdw_cmd_debug(" tcm_usage = %u\n", h->tcm_usage);
|
|
mdw_cmd_debug(" tcm_force = %d\n", h->tcm_force);
|
|
mdw_cmd_debug(" boost_val = %d\n", h->boost_val);
|
|
mdw_cmd_debug(" pack_id = %d\n", h->pack_id);
|
|
mdw_cmd_debug(" reserved = %d\n", h->reserved);
|
|
mdw_cmd_debug(" mem_ctx = %u\n", h->mem_ctx);
|
|
mdw_cmd_debug(" cb_info_size = %u\n", h->cb_info_size);
|
|
mdw_cmd_debug(" ofs_cb_info = %u\n", h->ofs_cb_info);
|
|
mdw_cmd_debug(" kva = 0x%llx\n", sc->kva);
|
|
mdw_cmd_debug(" size = %u\n", sc->size);
|
|
mdw_cmd_debug("-------------------------\n");
|
|
}
|
|
|
|
static void mdw_cmd_show_sc_perf(struct mdw_apu_sc *sc)
|
|
{
|
|
mdw_pef_debug("-------------------------\n");
|
|
mdw_pef_debug(" apusys sc(0x%llx-#%d)\n", sc->parent->kid, sc->idx);
|
|
mdw_pef_debug(" parsing time = %u\n",
|
|
mdw_cmn_get_time_diff(&sc->parent->ts_create, &sc->ts_create));
|
|
mdw_pef_debug(" wait dependency = %u\n",
|
|
mdw_cmn_get_time_diff(&sc->ts_create, &sc->ts_enque));
|
|
mdw_pef_debug(" sched time = %u\n",
|
|
mdw_cmn_get_time_diff(&sc->ts_enque, &sc->ts_deque));
|
|
mdw_pef_debug(" preset time = %u\n",
|
|
mdw_cmn_get_time_diff(&sc->ts_deque, &sc->ts_start));
|
|
mdw_pef_debug(" exec time = %u\n",
|
|
mdw_cmn_get_time_diff(&sc->ts_start, &sc->ts_end));
|
|
mdw_pef_debug(" post time = %u\n",
|
|
mdw_cmn_get_time_diff(&sc->ts_end, &sc->ts_delete));
|
|
mdw_pef_debug(" life time = %u\n",
|
|
mdw_cmn_get_time_diff(&sc->ts_create, &sc->ts_delete));
|
|
mdw_pef_debug("-------------------------\n");
|
|
}
|
|
|
|
static void mdw_cmd_show_cmd_perf(struct mdw_apu_cmd *c)
|
|
{
|
|
mdw_pef_debug("-------------------------\n");
|
|
mdw_pef_debug(" apusys cmd(0x%llx)\n", c->kid);
|
|
mdw_pef_debug(" life time = %u\n",
|
|
mdw_cmn_get_time_diff(&c->ts_create, &c->ts_delete));
|
|
mdw_pef_debug("-------------------------\n");
|
|
}
|
|
|
|
static void mdw_cmd_show_hnd(struct apusys_cmd_hnd *h)
|
|
{
|
|
mdw_cmd_debug("-------------------------\n");
|
|
mdw_cmd_debug(" kva = 0x%llx\n", h->kva);
|
|
mdw_cmd_debug(" iova = 0x%x\n", h->iova);
|
|
mdw_cmd_debug(" size = %u\n", h->size);
|
|
mdw_cmd_debug(" cmd_id = 0x%llx\n", h->cmd_id);
|
|
mdw_cmd_debug(" subcmd_idx = %u\n", h->subcmd_idx);
|
|
mdw_cmd_debug(" priority = %u\n", h->priority);
|
|
mdw_cmd_debug(" ip_time = %u\n", h->ip_time);
|
|
mdw_cmd_debug(" boost_val = %d\n", h->boost_val);
|
|
mdw_cmd_debug(" cluster_size = %d\n", h->cluster_size);
|
|
mdw_cmd_debug(" multicore_total = %u\n", h->multicore_total);
|
|
mdw_cmd_debug(" multicore_idx = %u\n", h->multicore_idx);
|
|
mdw_cmd_debug(" pmu_kva = 0x%llx\n", h->pmu_kva);
|
|
mdw_cmd_debug(" cmd_entry = 0x%llx\n", h->cmd_entry);
|
|
mdw_cmd_debug(" ctx_id = %d\n", h->ctx_id);
|
|
mdw_cmd_debug("-------------------------\n");
|
|
}
|
|
|
|
static uint32_t mdw_cmd_get_pdr_num(struct mdw_apu_sc *sc)
|
|
{
|
|
struct mdw_apu_cmd *cmd = sc->parent;
|
|
uint32_t pdr_cnt = 0;
|
|
uint32_t *pdr_cnt_list;
|
|
|
|
pdr_cnt_list = (uint32_t *)(
|
|
(uint64_t)cmd->u_hdr + cmd->hdr->ofs_pdr_cnt_list);
|
|
pdr_cnt = pdr_cnt_list[sc->idx];
|
|
mdw_cmd_debug("0x%llx/0x%llx/0x%x/%d -> %d\n", (uint64_t)pdr_cnt_list,
|
|
(uint64_t)cmd->u_hdr, cmd->hdr->ofs_pdr_cnt_list,
|
|
sc->idx, pdr_cnt_list[sc->idx]);
|
|
|
|
if (pdr_cnt > cmd->hdr->num_sc)
|
|
return MDW_CMD_PSR_NUM_ERR;
|
|
|
|
return pdr_cnt;
|
|
}
|
|
|
|
static struct apu_sc_hdr_cmn *mdw_cmd_get_sc_hdr(struct mdw_apu_cmd *cmd,
|
|
int idx)
|
|
{
|
|
uint32_t ofs = 0;
|
|
struct apu_cmd_hdr *cmd_hdr = cmd->u_hdr;
|
|
struct apu_sc_hdr_cmn *sh = NULL;
|
|
|
|
if ((uint32_t)idx >= cmd_hdr->num_sc)
|
|
return NULL;
|
|
|
|
ofs = *(uint32_t *)((uint64_t)&cmd_hdr->scofs_list_entry +
|
|
SIZE_SUBGRAPH_SCOFS_ELEMENT * idx);
|
|
if (ofs + sizeof(struct apu_sc_hdr_cmn) > cmd->size)
|
|
goto fail_size;
|
|
|
|
sh = (struct apu_sc_hdr_cmn *)((uint64_t)cmd_hdr + ofs);
|
|
if (sh->type == APUSYS_DEVICE_MDLA &&
|
|
ofs + sizeof(struct apu_sc_hdr_cmn) +
|
|
sizeof(struct apu_mdla_hdr) > cmd->size)
|
|
goto fail_size;
|
|
|
|
return (struct apu_sc_hdr_cmn *)((uint64_t)cmd_hdr + ofs);
|
|
|
|
fail_size:
|
|
mdw_drv_err("sc(0x%llx-#%d) ofs(%u) over size(%d)\n",
|
|
cmd_hdr->uid, idx, ofs, cmd->size);
|
|
return NULL;
|
|
}
|
|
|
|
static int mdw_cmd_parse_flags(struct mdw_apu_cmd *c)
|
|
{
|
|
c->multi = (uint8_t)((c->hdr->flags & HDR_FLAG_MASK_MULTI) >> 62);
|
|
if (c->multi > HDR_FLAG_MULTI_MULTI)
|
|
return -EINVAL;
|
|
|
|
/* Create Fence FD */
|
|
if (c->hdr->flags & HDR_FLAG_MASK_FENCE_EXEC) {
|
|
c->uf_hdr = (struct apu_fence_hdr *)(
|
|
(uint64_t)c->u_hdr + sizeof(struct apu_cmd_hdr) +
|
|
(c->hdr->num_sc - 1) * sizeof(uint32_t));
|
|
c->file = NULL;
|
|
if (apu_sync_file_create(c) < 0)
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static uint64_t mdw_cmd_get_scr(struct mdw_apu_sc *sc)
|
|
{
|
|
struct mdw_apu_cmd *cmd = sc->parent;
|
|
uint32_t *scr_list;
|
|
int i = 0, idx = 0, j = 0, num_scr = 0;
|
|
uint64_t scr_bmp = 0;
|
|
|
|
scr_list = (uint32_t *)((uint64_t)cmd->u_hdr + cmd->hdr->ofs_scr_list);
|
|
|
|
for (i = 0; i < (int)cmd->hdr->num_sc; i++) {
|
|
if (i != sc->idx) {
|
|
idx = idx + scr_list[idx] + 1;
|
|
continue;
|
|
}
|
|
|
|
num_scr = (int)scr_list[idx];
|
|
idx++;
|
|
/*
|
|
* idx start with 1, because 0=num
|
|
* refer to apusys cmd definition
|
|
*/
|
|
for (j = 0; j < num_scr; j++) {
|
|
mdw_cmd_debug("sc(0x%llx-#%d) add scr(%d/%p), num_scr = %d\n",
|
|
cmd->hdr->uid, sc->idx, scr_list[idx],
|
|
&scr_list[idx], num_scr);
|
|
if (scr_list[idx] >= cmd->hdr->num_sc) {
|
|
mdw_drv_err("sc(0x%llx-#%d) scr idx(%d/%d) invalid\n",
|
|
cmd->hdr->uid, sc->idx,
|
|
scr_list[idx], cmd->hdr->num_sc);
|
|
return MDW_CMD_SCR_BMP_ERR;
|
|
}
|
|
scr_bmp |= (1ULL << scr_list[idx]);
|
|
idx++;
|
|
}
|
|
mdw_cmd_debug("sc(#%d) scr_bmp = 0x%llx\n", sc->idx, scr_bmp);
|
|
break;
|
|
}
|
|
|
|
return scr_bmp;
|
|
}
|
|
|
|
static int mdw_cmd_hdr_get_status(struct mdw_apu_cmd *c)
|
|
{
|
|
return ((int)(c->u_hdr->flags & HDR_FlAG_MASK_STATUS_BMP)
|
|
>> HDR_FLAG_MASK_STATUS_OFS);
|
|
}
|
|
|
|
static void mdw_cmd_hdr_set_status(struct mdw_apu_cmd *c, int status)
|
|
{
|
|
c->u_hdr->flags = (c->u_hdr->flags & ~(HDR_FlAG_MASK_STATUS_BMP))
|
|
| status << HDR_FLAG_MASK_STATUS_OFS;
|
|
}
|
|
|
|
static void mdw_cmd_hdr_update_time(struct mdw_apu_cmd *c)
|
|
{
|
|
uint64_t us = 0;
|
|
|
|
if (c->uf_hdr) {
|
|
us = (c->end_ts.tv_sec - c->start_ts.tv_sec) * 1000000;
|
|
us += ((c->end_ts.tv_nsec - c->start_ts.tv_nsec) / 1000);
|
|
c->uf_hdr->total_time = us;
|
|
}
|
|
}
|
|
|
|
static void mdw_cmd_set_sc_hdr(struct mdw_apu_sc *sc)
|
|
{
|
|
/* execution time */
|
|
sc->u_hdr->driver_time = sc->driver_time;
|
|
/* ip time */
|
|
sc->u_hdr->ip_time = sc->ip_time;
|
|
/* bandwidth */
|
|
sc->u_hdr->bandwidth = sc->bw;
|
|
/* boost val */
|
|
sc->u_hdr->boost_val = sc->boost;
|
|
/* cmd status */
|
|
if (sc->status)
|
|
mdw_cmd_hdr_set_status(sc->parent,
|
|
HDR_FLAG_EXEC_STATUS_HWERROR);
|
|
}
|
|
|
|
static void *mdw_cmd_get_dev_hdr(struct mdw_apu_sc *sc)
|
|
{
|
|
return (void *)((uint64_t)sc->u_hdr + sizeof(struct apu_sc_hdr_cmn));
|
|
}
|
|
|
|
static inline int mdw_cmd_valid(struct mdw_apu_cmd *c)
|
|
{
|
|
struct apu_cmd_hdr *h = c->hdr;
|
|
|
|
if (h->magic != APUSYS_MAGIC_NUMBER ||
|
|
h->version != APUSYS_CMD_VERSION ||
|
|
h->num_sc == 0 ||
|
|
h->num_sc > MDW_CMD_SC_MAX ||
|
|
h->ofs_scr_list > c->size ||
|
|
h->ofs_pdr_cnt_list > c->size ||
|
|
h->priority >= MDW_CMD_PRIO_MAX)
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int mdw_cmd_sc_valid(struct mdw_apu_sc *sc)
|
|
{
|
|
struct mdw_apu_cmd *c = sc->parent;
|
|
|
|
/* check type max */
|
|
if (sc->hdr->type >= APUSYS_DEVICE_RT) {
|
|
mdw_drv_err("sc(0x%llx-#%d) invalid type(%u)\n",
|
|
c->kid, sc->idx, sc->hdr->type);
|
|
return -ENODEV;
|
|
}
|
|
/* check memory context range */
|
|
if (sc->hdr->mem_ctx >= MDW_CMD_SC_MAX) {
|
|
mdw_drv_err("sc(0x%llx-#%d) invalid ctx(%u)\n",
|
|
c->kid, sc->idx, sc->hdr->mem_ctx);
|
|
return -EINVAL;
|
|
}
|
|
/* check pack id */
|
|
if (sc->hdr->pack_id >= MDW_CMD_SC_MAX) {
|
|
mdw_drv_err("sc(0x%llx-#%d) invalid pack(%u)\n",
|
|
c->kid, sc->idx, sc->hdr->pack_id);
|
|
return -EINVAL;
|
|
}
|
|
/* check successor bitmap */
|
|
if (sc->scr_bmp == MDW_CMD_SCR_BMP_ERR) {
|
|
mdw_drv_err("sc(0x%llx-#%d) invalid scr bmp\n",
|
|
c->kid, sc->idx);
|
|
return -EINVAL;
|
|
}
|
|
/* check presuccessor number */
|
|
if (sc->pdr_num == MDW_CMD_PSR_NUM_ERR) {
|
|
mdw_drv_err("sc(0x%llx-#%d) invalid pdr num\n",
|
|
c->kid, sc->idx);
|
|
return -EINVAL;
|
|
}
|
|
/* limit boost value */
|
|
sc->boost = sc->hdr->boost_val < 100 ? sc->hdr->boost_val : 100;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mdw_cmd_check_sc_ready(struct mdw_apu_sc *sc)
|
|
{
|
|
if (sc->idx < 0 || sc->idx >= MDW_CMD_SC_MAX)
|
|
return -EINVAL;
|
|
|
|
mdw_cmd_debug("sc(0x%llx-#%d) pdr_num = %u/%u\n", sc->parent->kid,
|
|
sc->idx, sc->pdr_num, sc->parent->pdr_cnt[sc->idx]);
|
|
return sc->pdr_num - sc->parent->pdr_cnt[sc->idx] == 0 ? 0 : -EBADR;
|
|
}
|
|
|
|
static int mdw_cmd_get_pack_ctx(struct mdw_apu_cmd *c)
|
|
{
|
|
int i = 0;
|
|
struct apu_sc_hdr_cmn *h = NULL;
|
|
|
|
memset(c->ctx_repo, MDW_CMD_EMPTY_NUM, sizeof(c->ctx_repo));
|
|
|
|
for (i = 0; i < c->hdr->num_sc; i++) {
|
|
h = mdw_cmd_get_sc_hdr(c, i);
|
|
if (!h)
|
|
continue;
|
|
|
|
if (h->mem_ctx >= MDW_CMD_SC_MAX ||
|
|
h->pack_id >= MDW_CMD_SC_MAX) {
|
|
mdw_drv_err("sc(0x%llx-#%d) invalid pack(%u) ctx(%u)\n",
|
|
c->kid, i, h->pack_id, h->mem_ctx);
|
|
return -EINVAL;
|
|
}
|
|
c->ctx_cnt[h->mem_ctx]++;
|
|
c->pack_cnt[h->pack_id]++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool mdw_cmd_is_deadline(struct mdw_apu_sc *sc)
|
|
{
|
|
if (sc->period)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
static struct mdw_apu_cmd *mdw_cmd_create_cmd(int fd,
|
|
uint32_t size, uint32_t ofs, struct mdw_usr *u)
|
|
{
|
|
struct mdw_apu_cmd *c;
|
|
|
|
if (ofs + sizeof(struct apu_cmd_hdr) > size) {
|
|
mdw_drv_err("hdr ofs overflow(%u/%lu/%u)\n",
|
|
ofs, sizeof(struct apu_cmd_hdr), size);
|
|
goto out;
|
|
}
|
|
|
|
/* create cmd */
|
|
c = vzalloc(sizeof(struct mdw_apu_cmd));
|
|
if (!c)
|
|
goto fail_alloc_cmd;
|
|
|
|
/* mapping */
|
|
c->cmdbuf = vzalloc(sizeof(struct apusys_kmem));
|
|
if (!c->cmdbuf)
|
|
goto fail_alloc_km;
|
|
|
|
c->cmdbuf->fd = fd;
|
|
c->cmdbuf->size = size;
|
|
if (mdw_mem_map_kva(c->cmdbuf))
|
|
goto fail_map_kva;
|
|
|
|
/* setup hdr */
|
|
c->hdr = vzalloc(sizeof(struct apu_cmd_hdr));
|
|
if (!c->hdr)
|
|
goto fail_alloc_hdr;
|
|
|
|
c->u_hdr = (struct apu_cmd_hdr *)(c->cmdbuf->kva + ofs);
|
|
memcpy(c->hdr, c->u_hdr, sizeof(struct apu_cmd_hdr));
|
|
c->size = size;
|
|
c->kid = (uint64_t)c;
|
|
refcount_set(&c->ref.refcount, c->hdr->num_sc);
|
|
c->usr = u;
|
|
|
|
/* init cmd completion */
|
|
init_completion(&c->cmplt);
|
|
|
|
/* check basic information */
|
|
if (mdw_cmd_valid(c))
|
|
goto fail_cmd_invalid;
|
|
|
|
if (mdw_cmd_parse_flags(c))
|
|
goto fail_parse_flags;
|
|
|
|
if (mdw_cmd_get_pack_ctx(c))
|
|
goto fail_get_pack_ctx;
|
|
|
|
/* init sc list */
|
|
INIT_LIST_HEAD(&c->sc_list);
|
|
INIT_LIST_HEAD(&c->di_list);
|
|
|
|
/* init mutex*/
|
|
mutex_init(&c->mtx);
|
|
getnstimeofday(&c->ts_create);
|
|
|
|
ktime_get_ts64(&c->start_ts);
|
|
|
|
/* init sc state bmp */
|
|
c->sc_status_bmp = (1ULL << c->hdr->num_sc) - 1;
|
|
mdw_drv_debug("cmd(0x%llx/0x%llx) create\n", c->hdr->uid, c->kid);
|
|
mdw_cmd_debug("cmd sc status bitmap = 0x%llx\n", c->sc_status_bmp);
|
|
mdw_cmd_show_cmd(c);
|
|
|
|
return c;
|
|
|
|
fail_get_pack_ctx:
|
|
fail_parse_flags:
|
|
fail_cmd_invalid:
|
|
vfree(c->hdr);
|
|
fail_alloc_hdr:
|
|
mdw_mem_unmap_kva(c->cmdbuf);
|
|
fail_map_kva:
|
|
vfree(c->cmdbuf);
|
|
fail_alloc_km:
|
|
vfree(c);
|
|
fail_alloc_cmd:
|
|
out:
|
|
return NULL;
|
|
}
|
|
|
|
static int mdw_cmd_delete_cmd(struct mdw_apu_cmd *c)
|
|
{
|
|
if (kref_read(&c->ref) != 0) {
|
|
mdw_drv_err("cmd(0x%llx/0x%llx) can't destroy\n",
|
|
c->hdr->uid, c->kid);
|
|
return -EBUSY;
|
|
}
|
|
mdw_drv_debug("cmd(0x%llx/0x%llx) destroy\n", c->hdr->uid, c->kid);
|
|
|
|
getnstimeofday(&c->ts_delete);
|
|
|
|
ktime_get_ts64(&c->end_ts);
|
|
mdw_cmd_hdr_update_time(c);
|
|
mdw_cmd_show_cmd_perf(c);
|
|
|
|
mdw_mem_unmap_kva(c->cmdbuf);
|
|
vfree(c->cmdbuf);
|
|
vfree(c->hdr);
|
|
vfree(c);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mdw_cmd_get_codebuf_info(struct mdw_apu_sc *sc)
|
|
{
|
|
int fd = 0, ret = 0;
|
|
struct mdw_apu_cmd *c = sc->parent;
|
|
|
|
if (sc->hdr->ofs_cb_info & FLAG_SUBGRAPH_FD_MAP) {
|
|
fd = sc->hdr->ofs_cb_info & ~FLAG_SUBGRAPH_FD_MAP;
|
|
mdw_cmd_debug("sc(0x%llx-#%d) map from fd(%d)",
|
|
c->kid, sc->idx, fd);
|
|
sc->buf.fd = fd;
|
|
sc->buf.size = sc->hdr->cb_info_size;
|
|
|
|
ret = mdw_mem_map_kva(&sc->buf);
|
|
if (ret)
|
|
goto out;
|
|
|
|
sc->kva = sc->buf.kva;
|
|
} else {
|
|
sc->kva = (uint64_t)c->u_hdr + sc->hdr->ofs_cb_info;
|
|
mdw_cmd_debug("sc(0x%llx-#%d) form ofs(0x%x)",
|
|
c->kid, sc->idx, sc->hdr->ofs_cb_info);
|
|
|
|
/* check sc codebuf overflow */
|
|
if (sc->kva + sc->size > ((uint64_t)c->u_hdr + c->size)) {
|
|
mdw_drv_err("sc(0x%llx-#%d) codebuf overflow(0x%llx/%u/0x%llx/%u)\n",
|
|
c->kid, sc->idx, sc->kva, sc->size,
|
|
(uint64_t)c->u_hdr, c->size);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static void mdw_cmd_release_codebuf_info(struct mdw_apu_sc *sc)
|
|
{
|
|
if (sc->hdr->ofs_cb_info & FLAG_SUBGRAPH_FD_MAP)
|
|
mdw_mem_unmap_kva(&sc->buf);
|
|
}
|
|
|
|
static void mdw_cmd_done(struct kref *ref)
|
|
{
|
|
struct mdw_apu_cmd *c =
|
|
container_of(ref, struct mdw_apu_cmd, ref);
|
|
/* abort, delete cmd direct */
|
|
if (c->sc_status_bmp || c->state == MDW_CMD_STATE_ABORT) {
|
|
mdw_drv_warn("abort, delete c(0x%llx) directly\n", c->kid);
|
|
mdw_cmd_delete_cmd(c);
|
|
} else {
|
|
complete(&c->cmplt);
|
|
}
|
|
}
|
|
|
|
static void mdw_cmd_delete_sc(struct mdw_apu_sc *sc)
|
|
{
|
|
struct mdw_queue *mq = NULL;
|
|
|
|
mdw_drv_debug("sc(0x%llx-#%d) destroy\n",
|
|
sc->parent->kid, sc->idx);
|
|
|
|
mq = mdw_rsc_get_queue(sc->type);
|
|
if (!mq) {
|
|
mdw_drv_err("can't find mq(%d)\n", sc->type);
|
|
return;
|
|
}
|
|
|
|
mdw_queue_task_end(sc);
|
|
|
|
getnstimeofday(&sc->ts_delete);
|
|
mdw_cmd_show_sc_perf(sc);
|
|
|
|
mutex_lock(&sc->mtx);
|
|
mdw_cmd_set_sc_hdr(sc);
|
|
mdw_cmd_release_codebuf_info(sc);
|
|
mutex_unlock(&sc->mtx);
|
|
vfree(sc->hdr);
|
|
vfree(sc);
|
|
}
|
|
|
|
static struct mdw_apu_sc *mdw_cmd_create_sc(struct mdw_apu_cmd *c)
|
|
{
|
|
struct mdw_apu_sc *sc = NULL;
|
|
struct mdw_queue *mq = NULL;
|
|
|
|
sc = vzalloc(sizeof(struct mdw_apu_sc));
|
|
if (!sc)
|
|
return NULL;
|
|
|
|
/* init sc's list item and insert to cmd's list */
|
|
sc->u_hdr = mdw_cmd_get_sc_hdr(c, c->parsed_sc_num);
|
|
if (!sc->u_hdr)
|
|
goto fail_get_sc_hdr;
|
|
sc->hdr = vzalloc(sizeof(struct apu_sc_hdr_cmn));
|
|
if (!sc->hdr)
|
|
goto fail_alloc_hdr;
|
|
|
|
memcpy(sc->hdr, sc->u_hdr, sizeof(struct apu_sc_hdr_cmn));
|
|
mutex_init(&sc->mtx);
|
|
sc->parent = c;
|
|
sc->type = sc->hdr->type;
|
|
sc->size = sc->hdr->cb_info_size;
|
|
sc->idx = c->parsed_sc_num;
|
|
sc->pdr_num = mdw_cmd_get_pdr_num(sc);
|
|
sc->scr_bmp = mdw_cmd_get_scr(sc);
|
|
sc->runtime = sc->hdr->ip_time;
|
|
kref_init(&sc->multi_ref);
|
|
sc->d_hdr = (void *)((uint64_t)(sc->u_hdr) +
|
|
sizeof(struct apu_sc_hdr_cmn));
|
|
if (mdw_cmd_get_codebuf_info(sc))
|
|
goto fail_get_codebuf_info;
|
|
|
|
if (preemption_support &&
|
|
mdw_rsc_get_dev_num(sc->type + APUSYS_DEVICE_RT) &&
|
|
c->hdr->soft_limit) {
|
|
sc->type += APUSYS_DEVICE_RT;
|
|
sc->period = c->hdr->soft_limit * 1000;
|
|
sc->deadline = jiffies + usecs_to_jiffies(sc->period);
|
|
}
|
|
|
|
mdw_cmd_debug("sc(0x%llx-#%d) ctx(%d) pack(%d)\n",
|
|
c->kid, sc->idx, sc->hdr->mem_ctx, sc->hdr->pack_id);
|
|
|
|
/* check sc valid */
|
|
if (mdw_cmd_sc_valid(sc))
|
|
goto fail_sc_invalid;
|
|
|
|
/* task start */
|
|
mq = mdw_rsc_get_queue(sc->type);
|
|
if (!mq) {
|
|
mdw_drv_err("can't find mq(%d)\n", sc->type);
|
|
goto fail_get_mq;
|
|
}
|
|
|
|
mdw_queue_task_start(sc);
|
|
|
|
getnstimeofday(&sc->ts_create);
|
|
|
|
mdw_drv_debug("sc(0x%llx-#%d) create\n", c->kid, sc->idx);
|
|
mdw_cmd_show_sc(sc);
|
|
|
|
return sc;
|
|
|
|
fail_sc_invalid:
|
|
fail_get_mq:
|
|
fail_get_codebuf_info:
|
|
vfree(sc->hdr);
|
|
fail_alloc_hdr:
|
|
fail_get_sc_hdr:
|
|
mdw_flw_debug("\n");
|
|
vfree(sc);
|
|
return NULL;
|
|
}
|
|
|
|
static int mdw_cmd_abort_cmd(struct mdw_apu_cmd *c)
|
|
{
|
|
struct list_head *tmp = NULL, *list_ptr = NULL;
|
|
struct mdw_apu_sc *sc = NULL;
|
|
int i = 0, cnt = 0;
|
|
|
|
mutex_lock(&c->mtx);
|
|
c->state = MDW_CMD_STATE_ABORT;
|
|
if (!mdw_cmd_hdr_get_status(c))
|
|
mdw_cmd_hdr_set_status(c, HDR_FLAG_EXEC_STATUS_ABORT);
|
|
|
|
mdw_flw_debug("exec status in flag(%d)\n", mdw_cmd_hdr_get_status(c));
|
|
|
|
list_for_each_safe(list_ptr, tmp, &c->sc_list) {
|
|
sc = list_entry(list_ptr, struct mdw_apu_sc, cmd_item);
|
|
list_del(&sc->cmd_item);
|
|
mdw_cmd_delete_sc(sc);
|
|
cnt++;
|
|
}
|
|
mutex_unlock(&c->mtx);
|
|
|
|
for (i = 0; i < cnt; i++)
|
|
kref_put(&c->ref, mdw_cmd_done);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mdw_cmd_parse_cmd(struct mdw_apu_cmd *c, struct mdw_apu_sc **out)
|
|
{
|
|
int ret = 0;
|
|
struct mdw_apu_sc *sc;
|
|
|
|
*out = NULL;
|
|
|
|
if (c->parsed_sc_num >= c->hdr->num_sc)
|
|
return 0;
|
|
|
|
sc = mdw_cmd_create_sc(c);
|
|
if (!sc)
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&c->mtx);
|
|
if (mdw_cmd_check_sc_ready(sc))
|
|
list_add_tail(&sc->cmd_item, &c->sc_list);
|
|
else
|
|
*out = sc;
|
|
c->parsed_sc_num++;
|
|
ret = c->hdr->num_sc - c->parsed_sc_num;
|
|
mutex_unlock(&c->mtx);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void mdw_cmd_update_scr(struct mdw_apu_sc *sc)
|
|
{
|
|
struct mdw_apu_cmd *c = sc->parent;
|
|
int idx = 0;
|
|
|
|
while (sc->scr_bmp != 0) {
|
|
if (!(sc->scr_bmp & (1ULL << idx)))
|
|
goto next;
|
|
mdw_flw_debug("sc(0x%llx-#%d) update scr(%d)\n",
|
|
c->kid, sc->idx, idx);
|
|
c->pdr_cnt[idx]++;
|
|
sc->scr_bmp = sc->scr_bmp & ~(1ULL << idx);
|
|
next:
|
|
idx++;
|
|
if (idx >= MDW_CMD_SC_MAX)
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int mdw_cmd_end_sc(struct mdw_apu_sc *in, struct mdw_apu_sc **out)
|
|
{
|
|
int ret = 0;
|
|
struct mdw_apu_cmd *c;
|
|
struct mdw_apu_sc *sc = NULL;
|
|
struct list_head *tmp = NULL, *list_ptr = NULL;
|
|
|
|
*out = NULL;
|
|
|
|
c = in->parent;
|
|
mutex_lock(&c->mtx);
|
|
if (c->sc_status_bmp & (1ULL << in->idx)) {
|
|
c->sc_status_bmp &= ~(1ULL << in->idx);
|
|
mdw_cmd_update_scr(in);
|
|
|
|
/* update subcmd return value */
|
|
if (in->status)
|
|
c->sc_rets |= (1ULL << in->idx);
|
|
}
|
|
|
|
mdw_flw_debug("cmd status = 0x%llx after #%d sc done\n",
|
|
c->sc_status_bmp, in->idx);
|
|
|
|
/* check sc list */
|
|
if (list_empty(&c->sc_list)) {
|
|
mdw_flw_debug("cmd(0x%llx) empty\n", c->kid);
|
|
goto out;
|
|
}
|
|
|
|
list_for_each_safe(list_ptr, tmp, &c->sc_list) {
|
|
sc = list_entry(list_ptr, struct mdw_apu_sc, cmd_item);
|
|
mdw_flw_debug("sc(0x%llx-#%d) bmp(0x%llx/0x%llx)\n",
|
|
c->kid, sc->idx, sc->scr_bmp, c->sc_status_bmp);
|
|
|
|
if (!mdw_cmd_check_sc_ready(sc)) {
|
|
list_del(&sc->cmd_item);
|
|
*out = sc;
|
|
mdw_cmd_debug("sc(0x%llx-#%d) ready(%p)\n",
|
|
c->kid, sc->idx, sc);
|
|
break;
|
|
}
|
|
}
|
|
|
|
out:
|
|
mutex_unlock(&c->mtx);
|
|
/* if no out, delete sc */
|
|
if (*out == NULL) {
|
|
mdw_flw_debug("sc(0x%llx-#%d) done ref(%d)\n",
|
|
c->kid, in->idx, kref_read(&c->ref));
|
|
mdw_cmd_delete_sc(in);
|
|
kref_put(&c->ref, mdw_cmd_done);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mdw_cmd_get_ctx(struct mdw_apu_sc *sc)
|
|
{
|
|
int ret = 0;
|
|
uint32_t tcm_usage = 0;
|
|
struct mdw_apu_cmd *c = sc->parent;
|
|
|
|
mdw_trace_begin("get ctx|sc(0x%llx-%d)",
|
|
sc->parent->kid, sc->idx);
|
|
|
|
mutex_lock(&c->mtx);
|
|
// if tcm usage from user == 0, set by debug prop
|
|
tcm_usage = sc->hdr->tcm_usage == 0 ?
|
|
mdw_dbg_get_prop(MDW_DBG_PROP_TCM_DEFAULT) : sc->hdr->tcm_usage;
|
|
|
|
/* if indicated ctx == NONE, get vlm directly */
|
|
if (sc->hdr->mem_ctx == VALUE_SUBGRAPH_CTX_ID_NONE &&
|
|
sc->multi_total <= 1) {
|
|
ret = reviser_get_vlm(tcm_usage, sc->hdr->tcm_force,
|
|
&sc->ctx, &sc->real_tcm_usage);
|
|
mdw_flw_debug("sc(0x%llx-#%d) get ctx(%lu/%u/%u)\n",
|
|
c->kid, sc->idx, sc->ctx, sc->hdr->mem_ctx, tcm_usage);
|
|
goto out;
|
|
}
|
|
|
|
if (c->ctx_repo[sc->hdr->mem_ctx] != MDW_CMD_EMPTY_NUM) {
|
|
sc->ctx = (uint32_t)c->ctx_repo[sc->hdr->mem_ctx];
|
|
goto out;
|
|
}
|
|
|
|
ret = reviser_get_vlm(tcm_usage, sc->hdr->tcm_force,
|
|
&sc->ctx, &sc->real_tcm_usage);
|
|
c->ctx_repo[sc->hdr->mem_ctx] = sc->ctx;
|
|
mdw_flw_debug("sc(0x%llx-#%d) get ctx(%lu/%u/%u)\n",
|
|
c->kid, sc->idx, sc->ctx, sc->hdr->mem_ctx, tcm_usage);
|
|
|
|
out:
|
|
mutex_unlock(&c->mtx);
|
|
mdw_trace_end("get ctx|sc(0x%llx-%d) ctx(%lu)",
|
|
sc->parent->kid, sc->idx, sc->ctx);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void mdw_cmd_put_ctx(struct mdw_apu_sc *sc)
|
|
{
|
|
struct mdw_apu_cmd *c = sc->parent;
|
|
|
|
mdw_trace_begin("put ctx|sc(0x%llx-%d) ctx(%lu)",
|
|
sc->parent->kid, sc->idx, sc->ctx);
|
|
|
|
mutex_lock(&c->mtx);
|
|
if (sc->hdr->mem_ctx == VALUE_SUBGRAPH_CTX_ID_NONE &&
|
|
sc->multi_total <= 1) {
|
|
reviser_free_vlm(sc->ctx);
|
|
mdw_flw_debug("sc(0x%llx-#%d) put ctx(%lu/%u)\n",
|
|
c->kid, sc->idx, sc->ctx, sc->hdr->mem_ctx);
|
|
goto out;
|
|
}
|
|
|
|
c->ctx_cnt[sc->hdr->mem_ctx]--;
|
|
if (!c->ctx_cnt[sc->hdr->mem_ctx]) {
|
|
reviser_free_vlm(sc->ctx);
|
|
c->ctx_repo[sc->hdr->mem_ctx] = MDW_CMD_EMPTY_NUM;
|
|
mdw_flw_debug("sc(0x%llx-#%d) put ctx(%lu/%u)\n",
|
|
c->kid, sc->idx, sc->ctx, sc->hdr->mem_ctx);
|
|
}
|
|
out:
|
|
mutex_unlock(&c->mtx);
|
|
mdw_trace_end("put ctx|sc(0x%llx-%d) ctx(%lu)",
|
|
sc->parent->kid, sc->idx, sc->ctx);
|
|
}
|
|
|
|
static int mdw_cmd_sc_exec_num(struct mdw_apu_sc *sc)
|
|
{
|
|
struct apu_mdla_hdr *h = NULL;
|
|
int exec_num = 1;
|
|
int dbg_multi = 0;
|
|
|
|
dbg_multi = mdw_dbg_get_prop(MDW_DBG_PROP_MULTICORE);
|
|
if (dbg_multi == HDR_FLAG_MULTI_SINGLE ||
|
|
sc->parent->multi == HDR_FLAG_MULTI_SINGLE)
|
|
exec_num = 1;
|
|
else if (sc->type == APUSYS_DEVICE_MDLA ||
|
|
sc->type == APUSYS_DEVICE_MDLA_RT) {
|
|
h = (struct apu_mdla_hdr *)mdw_cmd_get_dev_hdr(sc);
|
|
if (h->ofs_codebuf_info_dual0 && h->ofs_codebuf_info_dual1)
|
|
exec_num = 2;
|
|
}
|
|
|
|
return exec_num;
|
|
}
|
|
|
|
static void mdw_cmd_sc_clr_hnd(struct mdw_apu_sc *sc, void *hnd)
|
|
{
|
|
struct apusys_cmd_hnd *h = (struct apusys_cmd_hnd *)hnd;
|
|
|
|
if (!h->kva)
|
|
return;
|
|
|
|
memcpy((void *)h->m_kva, (void *)h->kva, sc->size);
|
|
kfree((void *)h->kva);
|
|
h->kva = 0;
|
|
h->m_kva = 0;
|
|
}
|
|
|
|
static int mdw_cmd_sc_set_hnd(struct mdw_apu_sc *sc, int d_idx, void *hnd)
|
|
{
|
|
struct apusys_cmd_hnd *h = (struct apusys_cmd_hnd *)hnd;
|
|
struct apu_mdla_hdr *m_hdr = NULL;
|
|
struct mdw_apu_cmd *c = sc->parent;
|
|
int ret = 0;
|
|
|
|
/* contruct cmd hnd */
|
|
mutex_lock(&sc->mtx);
|
|
memset(h, 0, sizeof(struct apusys_cmd_hnd));
|
|
h->size = sc->size;
|
|
h->cmdbuf = c->cmdbuf;
|
|
h->cmd_id = c->kid;
|
|
h->subcmd_idx = sc->idx;
|
|
h->priority = c->hdr->priority;
|
|
h->ip_time = 0;
|
|
h->boost_val = sc->boost;
|
|
h->multicore_total = sc->multi_total;
|
|
h->multicore_idx = 0;
|
|
h->cmd_entry = c->cmdbuf->kva;
|
|
h->cmd_size = c->size;
|
|
h->ctx_id = sc->ctx;
|
|
h->context_callback = reviser_set_context;
|
|
h->cluster_size = sc->cluster_size;
|
|
|
|
switch (sc->type) {
|
|
case APUSYS_DEVICE_MDLA:
|
|
case APUSYS_DEVICE_MDLA_RT:
|
|
/* for mdla pmu */
|
|
m_hdr = (struct apu_mdla_hdr *)sc->d_hdr;
|
|
if (m_hdr->ofs_pmu_info > c->size)
|
|
h->pmu_kva = h->cmd_entry;
|
|
else
|
|
h->pmu_kva = c->cmdbuf->kva + m_hdr->ofs_pmu_info;
|
|
/* multicore */
|
|
if (sc->multi_total <= 1) {
|
|
h->m_kva = sc->kva;
|
|
} else {
|
|
m_hdr = mdw_cmd_get_dev_hdr(sc);
|
|
if (d_idx == 0) {
|
|
h->m_kva = c->cmdbuf->kva +
|
|
m_hdr->ofs_codebuf_info_dual0;
|
|
} else {
|
|
h->m_kva = c->cmdbuf->kva +
|
|
m_hdr->ofs_codebuf_info_dual1;
|
|
}
|
|
h->multicore_idx = d_idx;
|
|
|
|
if (h->m_kva + sc->size > c->cmdbuf->kva + c->size) {
|
|
mdw_drv_err("sc over size(0x%llx/%u)(0x%llx/%u)\n",
|
|
h->m_kva, sc->size,
|
|
c->cmdbuf->kva, c->size);
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
mdw_flw_debug("multi(%d/%d) kva(0x%llx), offset(%u/%u)\n",
|
|
d_idx, sc->multi_total, h->kva,
|
|
m_hdr->ofs_codebuf_info_dual0,
|
|
m_hdr->ofs_codebuf_info_dual1);
|
|
}
|
|
break;
|
|
default:
|
|
h->m_kva = sc->kva;
|
|
break;
|
|
}
|
|
|
|
/* duplicate cmdbuf */
|
|
h->kva = (uint64_t)kzalloc(sc->size, GFP_KERNEL);
|
|
if (!h->kva) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
memcpy((void *)h->kva, (void *)h->m_kva, sc->size);
|
|
mdw_cmd_debug("cmd(0x%llx-#%d) duplicate (0x%llx/%u)\n",
|
|
c->kid, sc->idx, h->kva, sc->size);
|
|
|
|
out:
|
|
mdw_cmd_show_hnd(h);
|
|
mutex_unlock(&sc->mtx);
|
|
return ret;
|
|
}
|
|
|
|
struct mdw_cmd_parser mdw_cmd_parser = {
|
|
.create_cmd = mdw_cmd_create_cmd,
|
|
.delete_cmd = mdw_cmd_delete_cmd,
|
|
.abort_cmd = mdw_cmd_abort_cmd,
|
|
.parse_cmd = mdw_cmd_parse_cmd,
|
|
.end_sc = mdw_cmd_end_sc,
|
|
.get_ctx = mdw_cmd_get_ctx,
|
|
.put_ctx = mdw_cmd_put_ctx,
|
|
.exec_core_num = mdw_cmd_sc_exec_num,
|
|
.set_hnd = mdw_cmd_sc_set_hnd,
|
|
.clr_hnd = mdw_cmd_sc_clr_hnd,
|
|
.is_deadline = mdw_cmd_is_deadline,
|
|
};
|
|
|
|
struct mdw_cmd_parser *mdw_cmd_get_parser(void)
|
|
{
|
|
return &mdw_cmd_parser;
|
|
}
|
|
|
|
uint64_t mdw_cmd_get_magic(void)
|
|
{
|
|
return APUSYS_MAGIC_NUMBER;
|
|
}
|
|
|
|
uint32_t mdw_cmd_get_ver(void)
|
|
{
|
|
return APUSYS_CMD_VERSION;
|
|
}
|