replace common qcom sources with samsung ones
This commit is contained in:
@@ -132,6 +132,13 @@
|
||||
#define DMA_FENCE_HASH_TABLE_BIT (12) /* size of table = (1 << 12) = 4096 */
|
||||
#define DMA_FENCE_HASH_TABLE_SIZE (1 << DMA_FENCE_HASH_TABLE_BIT)
|
||||
|
||||
enum hw_fence_lookup_ops {
|
||||
HW_FENCE_LOOKUP_OP_CREATE = 0x1,
|
||||
HW_FENCE_LOOKUP_OP_DESTROY,
|
||||
HW_FENCE_LOOKUP_OP_CREATE_JOIN,
|
||||
HW_FENCE_LOOKUP_OP_FIND_FENCE
|
||||
};
|
||||
|
||||
/**
|
||||
* enum hw_fence_client_data_id - Enum with the clients having client_data, an optional
|
||||
* parameter passed from the waiting client and returned
|
||||
@@ -251,7 +258,6 @@ struct msm_hw_fence_mem_data {
|
||||
* @entry_rd: flag to indicate if debugfs dumps a single line or table
|
||||
* @context_rd: debugfs setting to indicate which context id to dump
|
||||
* @seqno_rd: debugfs setting to indicate which seqno to dump
|
||||
* @client_id_rd: debugfs setting to indicate which client queue(s) to dump
|
||||
* @hw_fence_sim_release_delay: delay in micro seconds for the debugfs node that simulates the
|
||||
* hw-fences behavior, to release the hw-fences
|
||||
* @create_hw_fences: boolean to continuosly create hw-fences within debugfs
|
||||
@@ -265,7 +271,6 @@ struct msm_hw_fence_dbg_data {
|
||||
bool entry_rd;
|
||||
u64 context_rd;
|
||||
u64 seqno_rd;
|
||||
u32 client_id_rd;
|
||||
|
||||
u32 hw_fence_sim_release_delay;
|
||||
bool create_hw_fences;
|
||||
@@ -381,7 +386,6 @@ struct hw_fence_soccp {
|
||||
* @clients_num: number of supported hw fence clients (configured based on device-tree)
|
||||
* @hw_fences_tbl: pointer to the hw-fences table
|
||||
* @hw_fences_tbl_cnt: number of elements in the hw-fence table
|
||||
* @hlos_key_tbl: pointer to table of keys tracked by hlos only, same size as the hw-fences table
|
||||
* @events: start address of hw fence debug events
|
||||
* @total_events: total number of hw fence debug events supported
|
||||
* @client_lock_tbl: pointer to the per-client locks table
|
||||
@@ -448,7 +452,6 @@ struct hw_fence_driver_data {
|
||||
|
||||
/* HW Fences Table VA */
|
||||
struct msm_hw_fence *hw_fences_tbl;
|
||||
u64 *hlos_key_tbl;
|
||||
u32 hw_fences_tbl_cnt;
|
||||
|
||||
/* events */
|
||||
@@ -634,11 +637,11 @@ void hw_fence_cleanup_client(struct hw_fence_driver_data *drv_data,
|
||||
void hw_fence_utils_reset_queues(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence_client *hw_fence_client);
|
||||
int hw_fence_create(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence_client *hw_fence_client, u64 hlos_key,
|
||||
struct msm_hw_fence_client *hw_fence_client,
|
||||
u64 context, u64 seqno, u64 *hash);
|
||||
int hw_fence_add_callback(struct hw_fence_driver_data *drv_data, struct dma_fence *fence, u64 hash);
|
||||
int hw_fence_destroy(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence_client *hw_fence_client, u64 hlos_key,
|
||||
struct msm_hw_fence_client *hw_fence_client,
|
||||
u64 context, u64 seqno);
|
||||
int hw_fence_destroy_with_hash(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence_client *hw_fence_client, u64 hash);
|
||||
@@ -658,7 +661,6 @@ int hw_fence_update_queue_helper(struct hw_fence_driver_data *drv_data, u32 clie
|
||||
int hw_fence_update_existing_txq_payload(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence_client *hw_fence_client, u64 hash, u32 error);
|
||||
inline u64 hw_fence_get_qtime(struct hw_fence_driver_data *drv_data);
|
||||
char *_get_queue_type(int queue_type);
|
||||
int hw_fence_read_queue(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence_client *hw_fence_client, struct msm_hw_fence_queue_payload *payload,
|
||||
int queue_type);
|
||||
@@ -670,7 +672,7 @@ int hw_fence_register_wait_client(struct hw_fence_driver_data *drv_data,
|
||||
struct dma_fence *fence, struct msm_hw_fence_client *hw_fence_client, u64 context,
|
||||
u64 seqno, u64 *hash, u64 client_data);
|
||||
struct msm_hw_fence *msm_hw_fence_find(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence_client *hw_fence_client, u64 hlos_key,
|
||||
struct msm_hw_fence_client *hw_fence_client,
|
||||
u64 context, u64 seqno, u64 *hash);
|
||||
struct msm_hw_fence *hw_fence_find_with_dma_fence(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence_client *hw_fence_client, struct dma_fence *fence, u64 *hash,
|
||||
|
@@ -31,11 +31,6 @@
|
||||
|
||||
#define ktime_compare_safe(A, B) ktime_compare(ktime_sub((A), (B)), ktime_set(0, 0))
|
||||
|
||||
#define HFENCE_QHDR_MSG \
|
||||
"Client:%d %s q_sz_bytes:%u rd_idx:%u wr_idx:%u tx_wm:%u skips:%s start:%u factor:%u\n"
|
||||
#define HFENCE_QPAYLOAD_MSG \
|
||||
"%s[%d]: hash:%llu ctx:%llu seqno:%llu f:%llu d:%llu err:%u time:%llu type:%u\n"
|
||||
|
||||
u32 msm_hw_fence_debug_level = HW_FENCE_PRINTK;
|
||||
|
||||
/**
|
||||
@@ -106,9 +101,9 @@ void hw_fence_debug_dump_fence(enum hw_fence_drv_prio prio, struct msm_hw_fence
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DEBUG_FS)
|
||||
static int _get_debugfs_input_client_with_min(struct file *file,
|
||||
static int _get_debugfs_input_client(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos,
|
||||
struct hw_fence_driver_data **drv_data, int client_id_min)
|
||||
struct hw_fence_driver_data **drv_data)
|
||||
{
|
||||
char buf[10];
|
||||
int client_id;
|
||||
@@ -131,23 +126,15 @@ static int _get_debugfs_input_client_with_min(struct file *file,
|
||||
if (kstrtouint(buf, 0, &client_id))
|
||||
return -EFAULT;
|
||||
|
||||
if (client_id < client_id_min || client_id >= (*drv_data)->clients_num) {
|
||||
if (client_id < HW_FENCE_CLIENT_ID_CTX0 || client_id >= HW_FENCE_CLIENT_MAX) {
|
||||
HWFNC_ERR("invalid client_id:%d min:%d max:%d\n", client_id,
|
||||
client_id_min, (*drv_data)->clients_num);
|
||||
HW_FENCE_CLIENT_ID_CTX0, HW_FENCE_CLIENT_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return client_id;
|
||||
}
|
||||
|
||||
static int _get_debugfs_input_client(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos,
|
||||
struct hw_fence_driver_data **drv_data)
|
||||
{
|
||||
return _get_debugfs_input_client_with_min(file, user_buf, count, ppos, drv_data,
|
||||
HW_FENCE_CLIENT_ID_CTX0);
|
||||
}
|
||||
|
||||
static int _debugfs_ipcc_trigger(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos, u32 tx_client, u32 rx_client)
|
||||
{
|
||||
@@ -406,7 +393,7 @@ static ssize_t hw_fence_dbg_tx_and_signal_clients_wr(struct file *file,
|
||||
client_info_src->seqno_cnt++;
|
||||
|
||||
/* Create hw fence for src client */
|
||||
ret = hw_fence_create(drv_data, hw_fence_client, context, context, seqno, &hash);
|
||||
ret = hw_fence_create(drv_data, hw_fence_client, context, seqno, &hash);
|
||||
if (ret) {
|
||||
HWFNC_ERR("Error creating HW fence\n");
|
||||
goto exit;
|
||||
@@ -574,7 +561,7 @@ static int dump_single_entry(struct hw_fence_driver_data *drv_data, char *buf, u
|
||||
context = drv_data->debugfs_data.context_rd;
|
||||
seqno = drv_data->debugfs_data.seqno_rd;
|
||||
|
||||
hw_fence = msm_hw_fence_find(drv_data, NULL, context, context, seqno, &hash);
|
||||
hw_fence = msm_hw_fence_find(drv_data, NULL, context, seqno, &hash);
|
||||
if (!hw_fence) {
|
||||
HWFNC_ERR("no valid hfence found for context:%llu seqno:%llu hash:%llu",
|
||||
context, seqno, hash);
|
||||
@@ -693,7 +680,7 @@ static ssize_t hw_fence_dbg_dump_events_rd(struct file *file, char __user *user_
|
||||
size_t user_buf_size, loff_t *ppos)
|
||||
{
|
||||
struct hw_fence_driver_data *drv_data;
|
||||
u32 entry_size = sizeof(HFENCE_EVT_MSG), max_size = SZ_4K;
|
||||
u32 entry_size = sizeof(struct msm_hw_fence_event), max_size = SZ_4K;
|
||||
char *buf = NULL;
|
||||
int len = 0;
|
||||
static u64 start_time;
|
||||
@@ -780,69 +767,45 @@ exit:
|
||||
return len;
|
||||
}
|
||||
|
||||
static int _dump_queue_header(struct hw_fence_driver_data *drv_data, enum hw_fence_drv_prio prio,
|
||||
struct msm_hw_fence_queue *queue, int client_id, int queue_type, u32 **rd_idx_ptr,
|
||||
u32 **wr_idx_ptr, u32 **tx_wm_ptr)
|
||||
{
|
||||
if (!drv_data || !queue || !rd_idx_ptr || !wr_idx_ptr || !tx_wm_ptr) {
|
||||
HWFNC_ERR("invalid drv_data:0x%pK q:0x%pK rd_idx:0x%pK wr_idx:0x%pK tx_wm:0x%pK\n",
|
||||
drv_data, queue, rd_idx_ptr, wr_idx_ptr, tx_wm_ptr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hw_fence_get_queue_idx_ptrs(drv_data, queue->va_header, rd_idx_ptr, wr_idx_ptr,
|
||||
tx_wm_ptr);
|
||||
|
||||
HWFNC_DBG_DUMP(prio, HFENCE_QHDR_MSG, client_id, _get_queue_type(queue_type),
|
||||
queue->q_size_bytes, **rd_idx_ptr, **wr_idx_ptr, **tx_wm_ptr,
|
||||
queue->skip_wr_idx ? "true" : "false", queue->rd_wr_idx_start,
|
||||
queue->rd_wr_idx_factor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct msm_hw_fence_queue_payload *_dump_queue_payload(enum hw_fence_drv_prio prio,
|
||||
struct msm_hw_fence_queue *queue, int index, int queue_type)
|
||||
{
|
||||
struct msm_hw_fence_queue_payload *payload;
|
||||
u32 *read_ptr;
|
||||
u64 timestamp;
|
||||
|
||||
read_ptr = ((u32 *)queue->va_queue +
|
||||
(index * (sizeof(struct msm_hw_fence_queue_payload) / sizeof(u32))));
|
||||
payload = (struct msm_hw_fence_queue_payload *)read_ptr;
|
||||
timestamp = (u64)payload->timestamp_lo | ((u64)payload->timestamp_hi << 32);
|
||||
HWFNC_DBG_DUMP(prio, HFENCE_QPAYLOAD_MSG, _get_queue_type(queue_type),
|
||||
index, payload->hash, payload->ctxt_id, payload->seqno, payload->flags,
|
||||
payload->client_data, payload->error, timestamp, payload->type);
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
static void _dump_queue(struct hw_fence_driver_data *drv_data, enum hw_fence_drv_prio prio,
|
||||
struct msm_hw_fence_client *hw_fence_client, int queue_type)
|
||||
{
|
||||
struct msm_hw_fence_queue *queue;
|
||||
u32 queue_entries, *rd_idx_ptr, *wr_idx_ptr, *tx_wm_ptr;
|
||||
struct msm_hw_fence_queue_payload *payload;
|
||||
u64 timestamp;
|
||||
u32 *read_ptr, *rd_idx_ptr, *wr_idx_ptr, *tx_wm_ptr, queue_entries;
|
||||
int i;
|
||||
|
||||
queue = &hw_fence_client->queues[queue_type];
|
||||
queue = &hw_fence_client->queues[queue_type - 1];
|
||||
|
||||
if ((queue_type > hw_fence_client->queues_num) || !queue || !queue->va_header
|
||||
|| !queue->va_queue) {
|
||||
HWFNC_ERR("Cannot dump client:%d q_type:%s q_ptr:0x%pK q_header:0x%pK q_va:0x%pK\n",
|
||||
hw_fence_client->client_id, _get_queue_type(queue_type), queue,
|
||||
queue ? queue->va_header : NULL, queue ? queue->va_queue : NULL);
|
||||
hw_fence_client->client_id,
|
||||
(queue_type == HW_FENCE_TX_QUEUE) ? "TX QUEUE" : "RX QUEUE",
|
||||
queue, queue ? queue->va_header : NULL, queue ? queue->va_queue : NULL);
|
||||
return;
|
||||
}
|
||||
hw_fence_get_queue_idx_ptrs(drv_data, queue->va_header, &rd_idx_ptr, &wr_idx_ptr,
|
||||
&tx_wm_ptr);
|
||||
|
||||
mb(); /* make sure data is ready before read */
|
||||
_dump_queue_header(drv_data, prio, queue, hw_fence_client->client_id, queue_type,
|
||||
&rd_idx_ptr, &wr_idx_ptr, &tx_wm_ptr);
|
||||
HWFNC_DBG_DUMP(prio, "%s va:0x%pK rd_idx:%u wr_idx:%u tx_wm:%u q_size_bytes:%u\n",
|
||||
(queue_type == HW_FENCE_TX_QUEUE) ? "TX QUEUE" : "RX QUEUE", queue->va_queue,
|
||||
*rd_idx_ptr, *wr_idx_ptr, *tx_wm_ptr, queue->q_size_bytes);
|
||||
queue_entries = queue->q_size_bytes / HW_FENCE_CLIENT_QUEUE_PAYLOAD;
|
||||
|
||||
for (i = 0; i < queue_entries; i++) {
|
||||
_dump_queue_payload(prio, queue, i, queue_type);
|
||||
read_ptr = ((u32 *)queue->va_queue +
|
||||
(i * (sizeof(struct msm_hw_fence_queue_payload) / sizeof(u32))));
|
||||
payload = (struct msm_hw_fence_queue_payload *)read_ptr;
|
||||
timestamp = (u64)payload->timestamp_lo | ((u64)payload->timestamp_hi << 32);
|
||||
|
||||
HWFNC_DBG_DUMP(prio,
|
||||
"%s[%d]: hash:%llu ctx:%llu seqno:%llu f:%llu d:%llu err:%u time:%llu\n",
|
||||
(queue_type == HW_FENCE_TX_QUEUE) ? "tx" : "rx", i, payload->hash,
|
||||
payload->ctxt_id, payload->seqno, payload->flags, payload->client_data,
|
||||
payload->error, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -854,61 +817,28 @@ void hw_fence_debug_dump_queues(struct hw_fence_driver_data *drv_data, enum hw_f
|
||||
return;
|
||||
}
|
||||
|
||||
HWFNC_DBG_DUMP(prio, "Queues for client %d\n", hw_fence_client->client_id);
|
||||
if (hw_fence_client->queues_num == HW_FENCE_CLIENT_QUEUES)
|
||||
_dump_queue(drv_data, prio, hw_fence_client, HW_FENCE_RX_QUEUE - 1);
|
||||
_dump_queue(drv_data, prio, hw_fence_client, HW_FENCE_TX_QUEUE - 1);
|
||||
_dump_queue(drv_data, prio, hw_fence_client, HW_FENCE_RX_QUEUE);
|
||||
_dump_queue(drv_data, prio, hw_fence_client, HW_FENCE_TX_QUEUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* hw_fence_dbg_dump_queues_wr() - debugfs wr to control the dump of hw-fences queues.
|
||||
* hw_fence_dbg_dump_queues_wr() - debugfs wr to dump the hw-fences queues.
|
||||
* @file: file handler.
|
||||
* @user_buf: user buffer content for debugfs.
|
||||
* @count: size of the user buffer.
|
||||
* @ppos: position offset of the user buffer.
|
||||
*
|
||||
* This debugfs receives as parameter either zero to dump the ctrl queues or the client_id for
|
||||
* which to dump client queues in the next read of the same debugfs node.
|
||||
* This debugfs dumps the hw-fence queues. Takes as input the desired client to dump.
|
||||
* Dumps to debug msgs the contents of the TX and RX queues for that client, if they exist.
|
||||
*/
|
||||
static ssize_t hw_fence_dbg_dump_queues_wr(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
static ssize_t hw_fence_dbg_dump_queues_wr(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct hw_fence_driver_data *drv_data;
|
||||
int client_id;
|
||||
|
||||
client_id = _get_debugfs_input_client_with_min(file, user_buf, count, ppos, &drv_data, 0);
|
||||
if (client_id < 0)
|
||||
return -EINVAL;
|
||||
|
||||
drv_data->debugfs_data.client_id_rd = client_id;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* hw_fence_dbg_dump_queues_rd() - debugfs read to dump ctrl or client queues.
|
||||
* @file: file handler.
|
||||
* @user_buf: user buffer content for debugfs.
|
||||
* @user_buf_size: size of the user buffer.
|
||||
* @ppos: position offset of the user buffer.
|
||||
*
|
||||
* This debugfs dumps either hw-fence ctrl queues or the client queues of a given client. The user
|
||||
* can provide zero (to print the ctrl queues) or the client_id of interest by writing to this
|
||||
* debugfs node (see documentation for the write in 'hw_fence_dbg_dump_queues_wr'). By default,
|
||||
* dumps the ctrl queues.
|
||||
*/
|
||||
static ssize_t hw_fence_dbg_dump_queues_rd(struct file *file, char __user *user_buf,
|
||||
size_t user_buf_size, loff_t *ppos)
|
||||
{
|
||||
struct hw_fence_driver_data *drv_data;
|
||||
struct msm_hw_fence_client *hw_fence_client;
|
||||
struct msm_hw_fence_queue *queue;
|
||||
u32 entry_size = sizeof(HFENCE_QPAYLOAD_MSG), max_size = SZ_4K;
|
||||
u32 client_id, queue_entries, queues_num, *rd_idx_ptr, *wr_idx_ptr, *tx_wm_ptr;
|
||||
char *buf = NULL;
|
||||
int len = 0;
|
||||
static u32 index, queue_type;
|
||||
static bool qhdr_dumped;
|
||||
|
||||
if (!file || !file->private_data) {
|
||||
HWFNC_ERR("unexpected data file:0x%pK private_data:0x%pK\n", file,
|
||||
file ? file->private_data : NULL);
|
||||
@@ -916,95 +846,17 @@ static ssize_t hw_fence_dbg_dump_queues_rd(struct file *file, char __user *user_
|
||||
}
|
||||
drv_data = file->private_data;
|
||||
|
||||
client_id = drv_data->debugfs_data.client_id_rd;
|
||||
if (client_id == 0) {
|
||||
queue = &drv_data->ctrl_queues[queue_type];
|
||||
queues_num = HW_FENCE_CTRL_QUEUES;
|
||||
} else {
|
||||
if (!drv_data->clients[client_id]) {
|
||||
HWFNC_ERR("client %d not initialized\n", client_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
hw_fence_client = drv_data->clients[client_id];
|
||||
queue = &hw_fence_client->queues[queue_type];
|
||||
queues_num = hw_fence_client->queues_num;
|
||||
}
|
||||
queue_entries = queue->q_size_bytes / HW_FENCE_CLIENT_QUEUE_PAYLOAD;
|
||||
client_id = _get_debugfs_input_client(file, user_buf, count, ppos, &drv_data);
|
||||
if (client_id < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (queue_type >= queues_num) {
|
||||
HWFNC_DBG_H("no more data client_id:%d q_num:%u q_entries:%u\n", client_id,
|
||||
queues_num, queue_entries);
|
||||
queue_type = 0;
|
||||
index = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!queue || !queue->va_header || !queue->va_queue) {
|
||||
HWFNC_ERR("client:%d %s q_ptr:0x%pK qhdr_va:0x%pK q_va:0x%pK uninitialized\n",
|
||||
client_id, _get_queue_type(queue_type), queue,
|
||||
queue ? queue->va_header : NULL, queue ? queue->va_queue : NULL);
|
||||
if (!drv_data->clients[client_id]) {
|
||||
HWFNC_ERR("client %d not initialized\n", client_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
hw_fence_debug_dump_queues(drv_data, HW_FENCE_PRINTK, drv_data->clients[client_id]);
|
||||
|
||||
if (user_buf_size < entry_size) {
|
||||
HWFNC_ERR("Not enough buff size:%zu to dump entries:%d\n", user_buf_size,
|
||||
entry_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf = kvzalloc(max_size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!qhdr_dumped) {
|
||||
mb(); /* make sure data is ready before read */
|
||||
_dump_queue_header(drv_data, HW_FENCE_INFO, queue, client_id, queue_type,
|
||||
&rd_idx_ptr, &wr_idx_ptr, &tx_wm_ptr);
|
||||
len += scnprintf(buf + len, max_size - len, HFENCE_QHDR_MSG, client_id,
|
||||
_get_queue_type(queue_type), queue->q_size_bytes, *rd_idx_ptr, *wr_idx_ptr,
|
||||
*tx_wm_ptr, queue->skip_wr_idx ? "true" : "false", queue->rd_wr_idx_start,
|
||||
queue->rd_wr_idx_factor);
|
||||
qhdr_dumped = true;
|
||||
}
|
||||
|
||||
for (; index < queue_entries && len < (max_size - entry_size); index++) {
|
||||
struct msm_hw_fence_queue_payload *payload;
|
||||
u64 timestamp;
|
||||
|
||||
payload = _dump_queue_payload(HW_FENCE_INFO, queue, index, queue_type);
|
||||
|
||||
if (!(payload->hash || payload->ctxt_id || payload->seqno || payload->flags ||
|
||||
payload->client_data || payload->error || payload->timestamp_lo ||
|
||||
payload->timestamp_hi || payload->type))
|
||||
continue;
|
||||
|
||||
timestamp = (u64)payload->timestamp_lo | ((u64)payload->timestamp_hi << 32);
|
||||
len += scnprintf(buf + len, max_size - len, HFENCE_QPAYLOAD_MSG,
|
||||
_get_queue_type(queue_type), index, payload->hash, payload->ctxt_id,
|
||||
payload->seqno, payload->flags, payload->client_data, payload->error,
|
||||
timestamp, payload->type);
|
||||
}
|
||||
if (index >= queue_entries) {
|
||||
index = 0;
|
||||
queue_type++;
|
||||
qhdr_dumped = false;
|
||||
}
|
||||
|
||||
if (len <= 0 || len > user_buf_size) {
|
||||
HWFNC_ERR("len:%d invalid buff size:%zu\n", len, user_buf_size);
|
||||
len = 0;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (copy_to_user(user_buf, buf, len)) {
|
||||
HWFNC_ERR("failed to copy to user!\n");
|
||||
len = -EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
*ppos += len;
|
||||
exit:
|
||||
kvfree(buf);
|
||||
return len;
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1023,7 +875,7 @@ static ssize_t hw_fence_dbg_dump_table_rd(struct file *file, char __user *user_b
|
||||
size_t user_buf_size, loff_t *ppos)
|
||||
{
|
||||
struct hw_fence_driver_data *drv_data;
|
||||
int entry_size = sizeof(HFENCE_TBL_MSG);
|
||||
int entry_size = sizeof(struct msm_hw_fence);
|
||||
char *buf = NULL;
|
||||
int len = 0, max_size = SZ_4K;
|
||||
static u32 index, cnt;
|
||||
@@ -1345,8 +1197,7 @@ static long _process_val_signal(struct hw_fence_driver_data *drv_data,
|
||||
|
||||
context = fence ? fence->context : 0;
|
||||
seqno = fence ? fence->seqno : 0;
|
||||
HWFNC_DBG_L("Client_id:%u attempting to process signalled fence:%llu\n",
|
||||
hw_fence_client->client_id, hash);
|
||||
|
||||
while (read) {
|
||||
read = hw_fence_read_queue(drv_data, hw_fence_client, &payload, queue_type);
|
||||
if (read < 0) {
|
||||
@@ -1354,8 +1205,8 @@ static long _process_val_signal(struct hw_fence_driver_data *drv_data,
|
||||
hw_fence_client->client_id);
|
||||
break;
|
||||
}
|
||||
HWFNC_DBG_L("Client_id: %u rxq read: hash:%llu, flags:%llu, error:%u\n",
|
||||
hw_fence_client->client_id, payload.hash, payload.flags, payload.error);
|
||||
HWFNC_DBG_L("rxq read: hash:%llu, flags:%llu, error:%u\n",
|
||||
payload.hash, payload.flags, payload.error);
|
||||
if ((fence && payload.ctxt_id == context && payload.seqno == seqno) ||
|
||||
(mask && ((mask & hash) == (mask & payload.hash)))) {
|
||||
*error = payload.error;
|
||||
@@ -1370,10 +1221,9 @@ static long _process_val_signal(struct hw_fence_driver_data *drv_data,
|
||||
}
|
||||
}
|
||||
|
||||
HWFNC_ERR("fence received: hash:%llu ctx:%llu seq:%llu did not match expected fence\n",
|
||||
payload.hash, payload.ctxt_id, payload.seqno);
|
||||
HWFNC_ERR("Client_id:%u fence expected: hash:%llu ctx:%llu seq:%llu\n",
|
||||
hw_fence_client->client_id, hash, context, seqno);
|
||||
HWFNC_ERR("fence received did not match the fence expected\n");
|
||||
HWFNC_ERR("received: hash:%llu ctx:%llu seq:%llu expected: hash:%llu ctx:%llu seq:%llu\n",
|
||||
payload.hash, payload.ctxt_id, payload.seqno, hash, context, seqno);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1391,8 +1241,6 @@ int hw_fence_debug_wait_val(struct hw_fence_driver_data *drv_data,
|
||||
}
|
||||
|
||||
exp_ktime = ktime_add_ms(ktime_get(), timeout_ms);
|
||||
HWFNC_DBG_L("Client_id:%u attempting to wait on fence:%llu\n",
|
||||
hw_fence_client->client_id, hash);
|
||||
while (ret) {
|
||||
do {
|
||||
ret = wait_event_timeout(hw_fence_client->wait_queue,
|
||||
@@ -1403,8 +1251,7 @@ int hw_fence_debug_wait_val(struct hw_fence_driver_data *drv_data,
|
||||
ktime_compare_safe(exp_ktime, cur_ktime) > 0);
|
||||
|
||||
if (!ret) {
|
||||
HWFNC_ERR("Client_id: %u timed out waiting for the client signal %llu\n",
|
||||
hw_fence_client->client_id, timeout_ms);
|
||||
HWFNC_ERR("timed out waiting for the client signal %llu\n", timeout_ms);
|
||||
/* Decrement the refcount that hw_sync_get_fence increments */
|
||||
dma_fence_put(fence);
|
||||
return -ETIMEDOUT;
|
||||
@@ -1445,7 +1292,6 @@ static const struct file_operations hw_fence_dump_table_fops = {
|
||||
static const struct file_operations hw_fence_dump_queues_fops = {
|
||||
.open = simple_open,
|
||||
.write = hw_fence_dbg_dump_queues_wr,
|
||||
.read = hw_fence_dbg_dump_queues_rd,
|
||||
};
|
||||
|
||||
static const struct file_operations hw_fence_dump_events_fops = {
|
||||
|
@@ -190,7 +190,7 @@ int hw_fence_interop_create_fence_from_import(struct synx_import_indv_params *pa
|
||||
/* only synx clients can signal synx fences; no one can signal sw dma-fence from fw */
|
||||
dummy_client.client_id = is_synx ? HW_FENCE_SYNX_FENCE_CLIENT_ID :
|
||||
HW_FENCE_NATIVE_FENCE_CLIENT_ID;
|
||||
ret = hw_fence_create(hw_fence_drv_data, &dummy_client, (u64)fence, fence->context,
|
||||
ret = hw_fence_create(hw_fence_drv_data, &dummy_client, fence->context,
|
||||
fence->seqno, &handle);
|
||||
if (ret) {
|
||||
HWFNC_ERR("failed create fence client:%d ctx:%llu seq:%llu is_synx:%s ret:%d\n",
|
||||
|
@@ -36,17 +36,6 @@
|
||||
/* number of fences searched for HW Fence import */
|
||||
#define HW_FENCE_FIND_THRESHOLD 10
|
||||
|
||||
/*
|
||||
* Iterates through the hw-fence table populating hash and hw_fence pointers accordingly.
|
||||
* Note: This internally takes the hw-fence lock during iteration so this loop must be
|
||||
* exited by setting found = true.
|
||||
*/
|
||||
#define for_each_hw_fence(drv_data, hfence, hash, ctx, seqno, start, end, i, found) \
|
||||
for ((i) = _hw_fence_iterator_init((drv_data), (hfence), (hash), (ctx), (seqno), \
|
||||
(start), (end)); \
|
||||
((i) < (end)) && !(found); \
|
||||
(i) = _hw_fence_iterator_next((drv_data), (hfence), (hash), (i), (end), (found)))
|
||||
|
||||
inline u64 hw_fence_get_qtime(struct hw_fence_driver_data *drv_data)
|
||||
{
|
||||
#ifdef HWFENCE_USE_SLEEP_TIMER
|
||||
@@ -661,10 +650,6 @@ static int init_hw_fences_table(struct hw_fence_driver_data *drv_data)
|
||||
drv_data->hw_fences_tbl_cnt = drv_data->hw_fences_mem_desc.size /
|
||||
sizeof(struct msm_hw_fence);
|
||||
|
||||
drv_data->hlos_key_tbl = kcalloc(drv_data->hw_fences_tbl_cnt, sizeof(u64), GFP_KERNEL);
|
||||
if (!drv_data->hlos_key_tbl)
|
||||
return -ENOMEM;
|
||||
|
||||
HWFNC_DBG_INIT("hw_fences_table:0x%pK cnt:%u\n", drv_data->hw_fences_tbl,
|
||||
drv_data->hw_fences_tbl_cnt);
|
||||
|
||||
@@ -968,17 +953,45 @@ void hw_fence_cleanup_client(struct hw_fence_driver_data *drv_data,
|
||||
kfree(hw_fence_client);
|
||||
}
|
||||
|
||||
static inline int _calculate_hash(u64 context, u64 seqno, u64 m_size)
|
||||
static inline int _calculate_hash(u32 table_total_entries, u64 context, u64 seqno,
|
||||
u64 step, u64 *hash)
|
||||
{
|
||||
u64 a_multiplier = HW_FENCE_HASH_A_MULT;
|
||||
u64 c_multiplier = HW_FENCE_HASH_C_MULT;
|
||||
u64 b_multiplier = context + (context - 1); /* odd multiplier */
|
||||
u64 m_size = table_total_entries;
|
||||
int val = 0;
|
||||
|
||||
/*
|
||||
* if m, is power of 2, we can optimize with right shift,
|
||||
* for now we don't do it, to avoid assuming a power of two
|
||||
*/
|
||||
return (a_multiplier * seqno * b_multiplier + (c_multiplier * context)) % m_size;
|
||||
if (step == 0) {
|
||||
u64 a_multiplier = HW_FENCE_HASH_A_MULT;
|
||||
u64 c_multiplier = HW_FENCE_HASH_C_MULT;
|
||||
u64 b_multiplier = context + (context - 1); /* odd multiplier */
|
||||
|
||||
/*
|
||||
* if m, is power of 2, we can optimize with right shift,
|
||||
* for now we don't do it, to avoid assuming a power of two
|
||||
*/
|
||||
*hash = (a_multiplier * seqno * b_multiplier + (c_multiplier * context)) % m_size;
|
||||
} else {
|
||||
if (step >= m_size) {
|
||||
/*
|
||||
* If we already traversed the whole table, return failure since this means
|
||||
* there are not available spots, table is either full or full-enough
|
||||
* that we couldn't find an available spot after traverse the whole table.
|
||||
* Ideally table shouldn't be so full that we cannot find a value after some
|
||||
* iterations, so this maximum step size could be optimized to fail earlier.
|
||||
*/
|
||||
HWFNC_ERR("Fence Table tranversed and no available space!\n");
|
||||
val = -EINVAL;
|
||||
} else {
|
||||
/*
|
||||
* Linearly increment the hash value to find next element in the table
|
||||
* note that this relies in the 'scrambled' data from the original hash
|
||||
* Also, add a mod division to wrap-around in case that we reached the
|
||||
* end of the table
|
||||
*/
|
||||
*hash = (*hash + 1) % m_size;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline struct msm_hw_fence *_get_hw_fence(u32 table_total_entries,
|
||||
@@ -994,69 +1007,15 @@ static inline struct msm_hw_fence *_get_hw_fence(u32 table_total_entries,
|
||||
return &hw_fences_tbl[hash];
|
||||
}
|
||||
|
||||
static int _hw_fence_lookup_next(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence **hw_fence, u64 *hash, u32 init_step, u32 incr, u32 m_size)
|
||||
static bool _is_hw_fence_free(struct msm_hw_fence *hw_fence, u64 context, u64 seqno)
|
||||
{
|
||||
*hash = (*hash + incr) % m_size;
|
||||
*hw_fence = _get_hw_fence(m_size, drv_data->hw_fences_tbl, *hash);
|
||||
if (!*hw_fence) {
|
||||
HWFNC_ERR("failed to get hw-fence hash:%llu\n", *hash);
|
||||
return m_size;
|
||||
}
|
||||
GLOBAL_ATOMIC_STORE(drv_data, &(*hw_fence)->lock, 1);
|
||||
|
||||
return init_step + incr;
|
||||
/* If valid is set, the hw fence is not free */
|
||||
return hw_fence->valid ? false : true;
|
||||
}
|
||||
|
||||
/* returns initial step value and initializes hash and hw_fence */
|
||||
static int _hw_fence_iterator_init(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence **hw_fence, u64 *hash, u64 context, u64 seqno, u32 start_step,
|
||||
u32 end_step)
|
||||
static bool _hw_fence_match(struct msm_hw_fence *hw_fence, u64 context, u64 seqno)
|
||||
{
|
||||
u32 m_size;
|
||||
|
||||
if (!drv_data || !hw_fence || !hash || start_step >= end_step ||
|
||||
end_step > drv_data->hw_fences_tbl_cnt) {
|
||||
HWFNC_ERR("invalid drv_data:0x%pK hwf:0x%pK h:0x%pK start:%u end:%u tbl_size:%u\n",
|
||||
drv_data, hw_fence, hash, start_step, end_step,
|
||||
drv_data ? drv_data->hw_fences_tbl_cnt : -1);
|
||||
return end_step;
|
||||
}
|
||||
|
||||
m_size = drv_data->hw_fences_tbl_cnt;
|
||||
*hash = _calculate_hash(context, seqno, m_size);
|
||||
HWFNC_DBG_LUT("ctx:%llu seq:%llu tbl_size:%u start_step:%u initial_hash:%llu\n", context,
|
||||
seqno, m_size, start_step, *hash);
|
||||
|
||||
return _hw_fence_lookup_next(drv_data, hw_fence, hash, 0, start_step, m_size);
|
||||
}
|
||||
|
||||
/* returns new step value and populates hash and hw_fence */
|
||||
static int _hw_fence_iterator_next(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence **hw_fence, u64 *hash, u32 curr_step, u32 end_step, bool found)
|
||||
{
|
||||
u32 m_size = drv_data->hw_fences_tbl_cnt;
|
||||
|
||||
/* unlock previous entry */
|
||||
GLOBAL_ATOMIC_STORE(drv_data, &(*hw_fence)->lock, 0);
|
||||
if ((curr_step + 1) >= end_step || found) {
|
||||
HWFNC_DBG_LUT("found:%s step:%d max:%d h:%llu v:%u ctx:%llu seq:%llu flg:0x%llx\n",
|
||||
found ? "true" : "false", curr_step, end_step, *hash, (*hw_fence)->valid,
|
||||
(*hw_fence)->ctx_id, (*hw_fence)->seq_id, (*hw_fence)->flags);
|
||||
return found ? curr_step : curr_step + 1;
|
||||
}
|
||||
|
||||
HWFNC_DBG_LUT("cmp failed resolving collision step:%u max:%u hash:%llu\n", curr_step + 1,
|
||||
end_step, *hash);
|
||||
|
||||
return _hw_fence_lookup_next(drv_data, hw_fence, hash, curr_step, 1, m_size);
|
||||
}
|
||||
|
||||
static bool _hw_fence_match(struct hw_fence_driver_data *drv_data, struct msm_hw_fence *hw_fence,
|
||||
u64 hash, u64 context, u64 seqno, u64 hlos_key)
|
||||
{
|
||||
return (hw_fence->ctx_id == context) && (hw_fence->seq_id == seqno)
|
||||
&& (drv_data->hlos_key_tbl[hash] == hlos_key);
|
||||
return ((hw_fence->ctx_id == context && hw_fence->seq_id == seqno) ? true : false);
|
||||
}
|
||||
|
||||
/* clears everything but the 'valid' field */
|
||||
@@ -1088,9 +1047,34 @@ static void _cleanup_hw_fence(struct msm_hw_fence *hw_fence)
|
||||
memset(hw_fence->client_data, 0, sizeof(hw_fence->client_data));
|
||||
}
|
||||
|
||||
/* This function must be called with the hw fence lock */
|
||||
static int _reserve_hw_fence(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence *hw_fence, u32 client_id,
|
||||
u64 context, u64 seqno, u32 hash, u32 pending_child_cnt)
|
||||
{
|
||||
_cleanup_hw_fence(hw_fence);
|
||||
|
||||
/* reserve this HW fence */
|
||||
hw_fence->valid = 1;
|
||||
|
||||
hw_fence->ctx_id = context;
|
||||
hw_fence->seq_id = seqno;
|
||||
hw_fence->flags = 0; /* fence just reserved, there shouldn't be any flags set */
|
||||
hw_fence->fence_allocator = client_id;
|
||||
hw_fence->fence_create_time = hw_fence_get_qtime(drv_data);
|
||||
/* one released by creating client; one released by FCTL */
|
||||
hw_fence->refcount = HW_FENCE_FCTL_REFCOUNT + 1;
|
||||
|
||||
HWFNC_DBG_LUT("Reserved fence client:%d ctx:%llu seq:%llu hash:%u\n",
|
||||
client_id, context, seqno, hash);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function must be called with the hw fence lock */
|
||||
static int _unreserve_hw_fence(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence *hw_fence, u32 hash)
|
||||
struct msm_hw_fence *hw_fence, u32 client_id,
|
||||
u64 context, u64 seqno, u32 hash, u32 pending_child_cnt)
|
||||
{
|
||||
if (hw_fence->refcount & HW_FENCE_HLOS_REFCOUNT_MASK)
|
||||
hw_fence->refcount--;
|
||||
@@ -1103,18 +1087,10 @@ static int _unreserve_hw_fence(struct hw_fence_driver_data *drv_data,
|
||||
|
||||
/* unreserve this HW fence */
|
||||
hw_fence->valid = 0;
|
||||
|
||||
/**
|
||||
* Note: If last hwfence refcount is removed from fctl then this entry will not be
|
||||
* cleared. This is okay because the entry will be set to a new value at the time
|
||||
* of next fence creation.
|
||||
*/
|
||||
drv_data->hlos_key_tbl[hash] = 0;
|
||||
}
|
||||
|
||||
HWFNC_DBG_LUT("Removed ref on fence alloc:%d ctx:%llu seq:%llu refcount:0x%x hash:%u\n",
|
||||
hw_fence->fence_allocator, hw_fence->ctx_id, hw_fence->seq_id, hw_fence->refcount,
|
||||
hash);
|
||||
HWFNC_DBG_LUT("Unreserved fence client:%d ctx:%llu seq:%llu hash:%u refcount:%x\n",
|
||||
client_id, context, seqno, hash, hw_fence->refcount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1156,14 +1132,14 @@ int hw_fence_destroy_refcount(struct hw_fence_driver_data *drv_data, u64 hash, u
|
||||
}
|
||||
|
||||
/* This function must be called with the hw fence lock */
|
||||
static int _reserve_hw_fence(struct hw_fence_driver_data *drv_data,
|
||||
static int _reserve_join_fence(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence *hw_fence, u32 client_id, u64 context,
|
||||
u64 seqno, u32 hash, u32 pending_child_cnt, u64 hlos_key)
|
||||
u64 seqno, u32 hash, u32 pending_child_cnt)
|
||||
{
|
||||
_cleanup_hw_fence(hw_fence);
|
||||
|
||||
/* reserve this HW fence */
|
||||
hw_fence->valid = 1;
|
||||
hw_fence->valid = true;
|
||||
|
||||
hw_fence->ctx_id = context;
|
||||
hw_fence->seq_id = seqno;
|
||||
@@ -1174,17 +1150,16 @@ static int _reserve_hw_fence(struct hw_fence_driver_data *drv_data,
|
||||
|
||||
hw_fence->pending_child_cnt = pending_child_cnt;
|
||||
|
||||
drv_data->hlos_key_tbl[hash] = hlos_key;
|
||||
|
||||
HWFNC_DBG_LUT("Reserved fence client:%d ctx:%llu seq:%llu pending_child:%u hash:%u\n",
|
||||
client_id, context, seqno, pending_child_cnt, hash);
|
||||
HWFNC_DBG_LUT("Reserved join fence client:%d ctx:%llu seq:%llu hash:%u\n",
|
||||
client_id, context, seqno, hash);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function must be called with the hw fence lock */
|
||||
static int _fence_found(struct hw_fence_driver_data *drv_data, struct msm_hw_fence *hw_fence,
|
||||
u32 hash)
|
||||
static int _fence_found(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence *hw_fence, u32 client_id,
|
||||
u64 context, u64 seqno, u32 hash, u32 pending_child_cnt)
|
||||
{
|
||||
if ((hw_fence->refcount & HW_FENCE_HLOS_REFCOUNT_MASK) == HW_FENCE_HLOS_REFCOUNT_MASK)
|
||||
return -EINVAL;
|
||||
@@ -1194,125 +1169,176 @@ static int _fence_found(struct hw_fence_driver_data *drv_data, struct msm_hw_fen
|
||||
* is done, the refcount needs to be decremented either explicitly by the client or as part
|
||||
* of processing in HW Fence Driver.
|
||||
*/
|
||||
|
||||
hw_fence->refcount++;
|
||||
HWFNC_DBG_LUT("Found fence alloc:%d ctx:%llu seq:%llu refcount:0x%x hash:%u\n",
|
||||
hw_fence->fence_allocator, hw_fence->ctx_id, hw_fence->seq_id, hw_fence->refcount,
|
||||
hash);
|
||||
HWFNC_DBG_LUT("Found fence client:%d ctx:%llu seq:%llu hash:%u ref:0x%x\n",
|
||||
client_id, context, seqno, hash, hw_fence->refcount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct msm_hw_fence *_hw_fence_lookup_and_create_range(struct hw_fence_driver_data *drv_data,
|
||||
u32 client_id, u64 hlos_key, u64 context, u64 seqno, u32 pending_child_cnt, u64 *hash,
|
||||
u32 start_step, u32 end_step, u64 flags)
|
||||
char *_get_op_mode(enum hw_fence_lookup_ops op_code)
|
||||
{
|
||||
struct msm_hw_fence *hw_fence;
|
||||
bool hw_fence_found;
|
||||
int ret = 0;
|
||||
u32 step;
|
||||
|
||||
if (!drv_data || !hash) {
|
||||
HWFNC_ERR("Invalid input for hw_fence_lookup drv_data:0x%pK hash:0x%pK\n",
|
||||
drv_data, hash);
|
||||
return NULL;
|
||||
switch (op_code) {
|
||||
case HW_FENCE_LOOKUP_OP_CREATE:
|
||||
return "CREATE";
|
||||
case HW_FENCE_LOOKUP_OP_DESTROY:
|
||||
return "DESTROY";
|
||||
case HW_FENCE_LOOKUP_OP_CREATE_JOIN:
|
||||
return "CREATE_JOIN";
|
||||
case HW_FENCE_LOOKUP_OP_FIND_FENCE:
|
||||
return "FIND_FENCE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
for_each_hw_fence(drv_data, &hw_fence, hash, context, seqno, start_step, end_step,
|
||||
step, hw_fence_found) {
|
||||
if (!hw_fence->valid) {
|
||||
/* Process the hw fence found by the algorithm */
|
||||
ret = _reserve_hw_fence(drv_data, hw_fence, client_id, context, seqno,
|
||||
*hash, pending_child_cnt, hlos_key);
|
||||
|
||||
/* update memory table with processing */
|
||||
wmb();
|
||||
|
||||
HWFNC_DBG_L("client_id:%u ctx:%llu seqno:%llu hash:%llu step:%u\n",
|
||||
client_id, context, seqno, *hash, step);
|
||||
|
||||
hw_fence_found = true;
|
||||
} else if (_hw_fence_match(drv_data, hw_fence, *hash, context, seqno, hlos_key)) {
|
||||
hw_fence_found = true;
|
||||
if (flags & MSM_HW_FENCE_FLAG_CREATE_SIGNALED)
|
||||
ret = _fence_found(drv_data, hw_fence, *hash);
|
||||
else
|
||||
ret = -EALREADY;
|
||||
|
||||
HWFNC_DBG_L("client_id:%u ctx:%llu seqno:%llu hash:%llu step:%u\n",
|
||||
client_id, context, seqno, *hash, step);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == -EALREADY) {
|
||||
HWFNC_ERR("can't create hfence w/ same ctx:%llu seq:%llu hlos_key:0x%pK\n",
|
||||
context, seqno, (context == hlos_key) ? NULL : (void *)hlos_key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If we iterated through the whole list and didn't find available fences, return null */
|
||||
if (!hw_fence_found || ret) {
|
||||
HWFNC_DBG_LUT("fail to process create hw_fence ctx:%llu seq:%llu start:%u end:%u\n",
|
||||
context, seqno, start_step, end_step);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hw_fence;
|
||||
}
|
||||
|
||||
struct msm_hw_fence *_hw_fence_lookup_and_create(struct hw_fence_driver_data *drv_data,
|
||||
u32 client_id, u64 hlos_key, u64 context, u64 seqno, u32 pending_child_cnt, u64 *hash)
|
||||
{
|
||||
return _hw_fence_lookup_and_create_range(drv_data, client_id, hlos_key, context, seqno,
|
||||
pending_child_cnt, hash, 0, drv_data->hw_fences_tbl_cnt, 0);
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
struct msm_hw_fence *_hw_fence_lookup_and_process_range(struct hw_fence_driver_data *drv_data,
|
||||
u64 hlos_key, u64 context, u64 seqno, u64 *hash, u32 start_step, u32 end_step,
|
||||
int (*process_fn)(struct hw_fence_driver_data *drv_data, struct msm_hw_fence *hfence,
|
||||
u32 hash))
|
||||
struct msm_hw_fence *hw_fences_tbl, u64 context, u64 seqno, u32 client_id,
|
||||
u32 pending_child_cnt, enum hw_fence_lookup_ops op_code, u64 *hash, u64 flags,
|
||||
u64 start_step, u64 end_step)
|
||||
{
|
||||
struct msm_hw_fence *hw_fence;
|
||||
bool hw_fence_found;
|
||||
bool (*compare_fnc)(struct msm_hw_fence *hfence, u64 context, u64 seqno);
|
||||
int (*process_fnc)(struct hw_fence_driver_data *drv_data, struct msm_hw_fence *hfence,
|
||||
u32 client_id, u64 context, u64 seqno, u32 hash, u32 pending);
|
||||
struct msm_hw_fence *hw_fence = NULL;
|
||||
u64 step = start_step;
|
||||
int ret = 0;
|
||||
u32 step;
|
||||
bool hw_fence_found = false;
|
||||
|
||||
if (!drv_data || !hash || !process_fn) {
|
||||
HWFNC_ERR("Invalid input drv_data:0x%pK hash:0x%pK process_fn:0x%pK\n",
|
||||
drv_data, hash, process_fn);
|
||||
if (!hash | !drv_data | !hw_fences_tbl) {
|
||||
HWFNC_ERR("Invalid input for hw_fence_lookup\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for_each_hw_fence(drv_data, &hw_fence, hash, context, seqno, start_step, end_step, step,
|
||||
hw_fence_found) {
|
||||
if (_hw_fence_match(drv_data, hw_fence, *hash, context, seqno, hlos_key)) {
|
||||
/* Process the hw fence found by the algorithm */
|
||||
ret = process_fn(drv_data, hw_fence, *hash);
|
||||
HWFNC_DBG_L("ctx:%llu seqno:%llu hash:%llu step:%u\n", context, seqno,
|
||||
*hash, step);
|
||||
hw_fence_found = true;
|
||||
/*
|
||||
* When start_step != 0, the hash is already initialized at the correct value and should
|
||||
* not be reset.
|
||||
*/
|
||||
if (!step)
|
||||
*hash = ~0;
|
||||
|
||||
HWFNC_DBG_LUT("hw_fence_lookup: %d\n", op_code);
|
||||
|
||||
switch (op_code) {
|
||||
case HW_FENCE_LOOKUP_OP_CREATE:
|
||||
compare_fnc = &_is_hw_fence_free;
|
||||
process_fnc = &_reserve_hw_fence;
|
||||
break;
|
||||
case HW_FENCE_LOOKUP_OP_DESTROY:
|
||||
compare_fnc = &_hw_fence_match;
|
||||
process_fnc = &_unreserve_hw_fence;
|
||||
break;
|
||||
case HW_FENCE_LOOKUP_OP_CREATE_JOIN:
|
||||
compare_fnc = &_is_hw_fence_free;
|
||||
process_fnc = &_reserve_join_fence;
|
||||
break;
|
||||
case HW_FENCE_LOOKUP_OP_FIND_FENCE:
|
||||
compare_fnc = &_hw_fence_match;
|
||||
process_fnc = &_fence_found;
|
||||
break;
|
||||
default:
|
||||
HWFNC_ERR("Unknown op code:%d\n", op_code);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (!hw_fence_found && (step < end_step)) {
|
||||
|
||||
/* Calculate the Hash for the Fence */
|
||||
ret = _calculate_hash(drv_data->hw_fence_table_entries, context, seqno, step, hash);
|
||||
if (ret) {
|
||||
HWFNC_ERR("error calculating hash ctx:%llu seqno:%llu hash:%llu\n",
|
||||
context, seqno, *hash);
|
||||
break;
|
||||
}
|
||||
HWFNC_DBG_LUT("calculated hash:%llu [ctx:%llu seqno:%llu]\n", *hash, context,
|
||||
seqno);
|
||||
|
||||
/* Get element from the table using the hash */
|
||||
hw_fence = _get_hw_fence(drv_data->hw_fence_table_entries, hw_fences_tbl, *hash);
|
||||
HWFNC_DBG_LUT("hw_fence_tbl:0x%pK hw_fence:0x%pK, hash:%llu valid:0x%x\n",
|
||||
hw_fences_tbl, hw_fence, *hash, hw_fence ? hw_fence->valid : 0xbad);
|
||||
if (!hw_fence) {
|
||||
HWFNC_ERR("bad hw fence ctx:%llu seqno:%llu hash:%llu\n",
|
||||
context, seqno, *hash);
|
||||
break;
|
||||
}
|
||||
|
||||
GLOBAL_ATOMIC_STORE(drv_data, &hw_fence->lock, 1);
|
||||
|
||||
/* compare to either find a free fence or find an allocated fence */
|
||||
if (compare_fnc(hw_fence, context, seqno)) {
|
||||
|
||||
/* Process the hw fence found by the algorithm */
|
||||
if (process_fnc) {
|
||||
ret = process_fnc(drv_data, hw_fence, client_id, context, seqno,
|
||||
*hash, pending_child_cnt);
|
||||
|
||||
/* update memory table with processing */
|
||||
wmb();
|
||||
}
|
||||
|
||||
HWFNC_DBG_L("client_id:%u op:%s ctx:%llu seqno:%llu hash:%llu step:%llu\n",
|
||||
client_id, _get_op_mode(op_code), context, seqno, *hash, step);
|
||||
|
||||
hw_fence_found = true;
|
||||
} else {
|
||||
if ((op_code == HW_FENCE_LOOKUP_OP_CREATE ||
|
||||
op_code == HW_FENCE_LOOKUP_OP_CREATE_JOIN) &&
|
||||
seqno == hw_fence->seq_id && context == hw_fence->ctx_id) {
|
||||
if (flags & MSM_HW_FENCE_FLAG_CREATE_SIGNALED) {
|
||||
/* hw-fence created for importing client */
|
||||
ret = _fence_found(drv_data, hw_fence, client_id, context,
|
||||
seqno, *hash, pending_child_cnt);
|
||||
hw_fence_found = true;
|
||||
} else {
|
||||
ret = -EALREADY;
|
||||
}
|
||||
GLOBAL_ATOMIC_STORE(drv_data, &hw_fence->lock, 0);
|
||||
if (ret == -EALREADY)
|
||||
HWFNC_ERR("can't create hfence w/ same ctx:%llu seq:%llu\n",
|
||||
context, seqno);
|
||||
|
||||
break;
|
||||
}
|
||||
/* compare can fail if we have a collision, we will linearly resolve it */
|
||||
HWFNC_DBG_H("compare failed for hash:%llu [ctx:%llu seqno:%llu]\n", *hash,
|
||||
context, seqno);
|
||||
}
|
||||
|
||||
GLOBAL_ATOMIC_STORE(drv_data, &hw_fence->lock, 0);
|
||||
|
||||
if (hw_fence_found && ret)
|
||||
HWFNC_ERR("failed process_func client:%u op:%s ctx:%llu seq:%llu h:%llu\n",
|
||||
client_id, _get_op_mode(op_code), context, seqno, *hash);
|
||||
|
||||
/* Increment step for the next loop */
|
||||
step++;
|
||||
}
|
||||
|
||||
/* If we iterated through the whole list and didn't find available fences, return null */
|
||||
if (!hw_fence_found || ret) {
|
||||
HWFNC_DBG_LUT("fail to process create hw_fence ctx:%llu seq:%llu\n",
|
||||
context, seqno);
|
||||
return NULL;
|
||||
/* If we iterated through the whole list and didn't find the fence, return null */
|
||||
if (!hw_fence_found) {
|
||||
HWFNC_DBG_LUT("fail to process hw-fence op_code:%d step:%llu\n", op_code, step);
|
||||
hw_fence = NULL;
|
||||
}
|
||||
|
||||
HWFNC_DBG_LUT("lookup:%d hw_fence:%pK ctx:%llu seqno:%llu hash:%llu flags:0x%llx\n",
|
||||
op_code, hw_fence, context, seqno, *hash, hw_fence ? hw_fence->flags : -1);
|
||||
|
||||
return hw_fence;
|
||||
}
|
||||
|
||||
struct msm_hw_fence *_hw_fence_lookup_and_process(struct hw_fence_driver_data *drv_data,
|
||||
u64 hlos_key, u64 context, u64 seqno, u64 *hash,
|
||||
int (*process_fn)(struct hw_fence_driver_data *drv_data, struct msm_hw_fence *hfence,
|
||||
u32 hash))
|
||||
struct msm_hw_fence *hw_fences_tbl, u64 context, u64 seqno, u32 client_id,
|
||||
u32 pending_child_cnt, enum hw_fence_lookup_ops op_code, u64 *hash, u64 flags)
|
||||
{
|
||||
return _hw_fence_lookup_and_process_range(drv_data, hlos_key, context, seqno, hash, 0,
|
||||
drv_data->hw_fences_tbl_cnt, process_fn);
|
||||
return _hw_fence_lookup_and_process_range(drv_data, hw_fences_tbl, context, seqno,
|
||||
client_id, pending_child_cnt, op_code, hash, flags, 0,
|
||||
drv_data->hw_fence_table_entries);
|
||||
}
|
||||
|
||||
|
||||
struct dma_fence *hw_dma_fence_init(struct msm_hw_fence_client *hw_fence_client, u64 context,
|
||||
u64 seqno)
|
||||
{
|
||||
@@ -1414,7 +1440,7 @@ struct dma_fence *hw_fence_internal_dma_fence_create(struct hw_fence_driver_data
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
ret = hw_fence_create(drv_data, hw_fence_client, (u64)fence, context, seqno, hash);
|
||||
ret = hw_fence_create(drv_data, hw_fence_client, context, seqno, hash);
|
||||
if (ret) {
|
||||
HWFNC_ERR("failed to back internal dma-fence client:%d ctx:%llu seq:%llu\n",
|
||||
hw_fence_client->client_id, context, seqno);
|
||||
@@ -1539,14 +1565,16 @@ static int hw_fence_dma_fence_table_del(struct hw_fence_driver_data *drv_data, u
|
||||
}
|
||||
|
||||
int hw_fence_create(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence_client *hw_fence_client, u64 hlos_key, u64 context,
|
||||
u64 seqno, u64 *hash)
|
||||
struct msm_hw_fence_client *hw_fence_client,
|
||||
u64 context, u64 seqno, u64 *hash)
|
||||
{
|
||||
u32 client_id = hw_fence_client->client_id;
|
||||
struct msm_hw_fence *hw_fences_tbl = drv_data->hw_fences_tbl;
|
||||
int ret = 0;
|
||||
|
||||
/* allocate hw fence in table */
|
||||
if (!_hw_fence_lookup_and_create(drv_data, client_id, hlos_key, context, seqno, 0, hash)) {
|
||||
if (!_hw_fence_lookup_and_process(drv_data, hw_fences_tbl,
|
||||
context, seqno, client_id, 0, HW_FENCE_LOOKUP_OP_CREATE, hash, 0)) {
|
||||
HWFNC_ERR("Fail to create fence client:%u ctx:%llu seqno:%llu\n",
|
||||
client_id, context, seqno);
|
||||
ret = -EINVAL;
|
||||
@@ -1574,16 +1602,18 @@ int hw_fence_create(struct hw_fence_driver_data *drv_data,
|
||||
}
|
||||
|
||||
int hw_fence_destroy(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence_client *hw_fence_client, u64 hlos_key, u64 context, u64 seqno)
|
||||
struct msm_hw_fence_client *hw_fence_client,
|
||||
u64 context, u64 seqno)
|
||||
{
|
||||
u32 client_id = hw_fence_client->client_id;
|
||||
struct msm_hw_fence *hw_fences_tbl = drv_data->hw_fences_tbl;
|
||||
int ret = 0;
|
||||
u64 hash;
|
||||
|
||||
/* decrement refcount on hw-fence */
|
||||
if (!_hw_fence_lookup_and_process(drv_data, hlos_key, context, seqno, &hash,
|
||||
&_unreserve_hw_fence)) {
|
||||
HWFNC_ERR("Fail removing ref on fence client:%u ctx:%llu seqno:%llu\n",
|
||||
if (!_hw_fence_lookup_and_process(drv_data, hw_fences_tbl,
|
||||
context, seqno, client_id, 0, HW_FENCE_LOOKUP_OP_DESTROY, &hash, 0)) {
|
||||
HWFNC_ERR("Fail destroying fence client:%u ctx:%llu seqno:%llu\n",
|
||||
client_id, context, seqno);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
@@ -1689,8 +1719,9 @@ static struct msm_hw_fence *_hw_fence_process_join_fence(struct hw_fence_driver_
|
||||
|
||||
if (create) {
|
||||
/* allocate the fence */
|
||||
join_fence = _hw_fence_lookup_and_create(drv_data, client_id, (u64)array, context,
|
||||
seqno, pending_child_cnt, hash);
|
||||
join_fence = _hw_fence_lookup_and_process(drv_data, hw_fences_tbl, context,
|
||||
seqno, client_id, pending_child_cnt, HW_FENCE_LOOKUP_OP_CREATE_JOIN, hash,
|
||||
0);
|
||||
if (!join_fence)
|
||||
HWFNC_ERR("Fail to create join fence client:%u ctx:%llu seqno:%llu\n",
|
||||
client_id, context, seqno);
|
||||
@@ -1703,15 +1734,16 @@ static struct msm_hw_fence *_hw_fence_process_join_fence(struct hw_fence_driver_
|
||||
}
|
||||
|
||||
struct msm_hw_fence *msm_hw_fence_find(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence_client *hw_fence_client, u64 hlos_key, u64 context,
|
||||
u64 seqno, u64 *hash)
|
||||
struct msm_hw_fence_client *hw_fence_client,
|
||||
u64 context, u64 seqno, u64 *hash)
|
||||
{
|
||||
struct msm_hw_fence *hw_fences_tbl = drv_data->hw_fences_tbl;
|
||||
struct msm_hw_fence *hw_fence;
|
||||
u32 client_id = hw_fence_client ? hw_fence_client->client_id : ~0;
|
||||
|
||||
/* find the hw fence */
|
||||
hw_fence = _hw_fence_lookup_and_process(drv_data, hlos_key, context, seqno, hash,
|
||||
&_fence_found);
|
||||
hw_fence = _hw_fence_lookup_and_process(drv_data, hw_fences_tbl, context,
|
||||
seqno, client_id, 0, HW_FENCE_LOOKUP_OP_FIND_FENCE, hash, 0);
|
||||
if (!hw_fence)
|
||||
HWFNC_ERR("Fail to find hw fence client:%u ctx:%llu seqno:%llu\n",
|
||||
client_id, context, seqno);
|
||||
@@ -2040,8 +2072,7 @@ int hw_fence_register_wait_client(struct hw_fence_driver_data *drv_data,
|
||||
hw_fence = hw_fence_find_with_dma_fence(drv_data, hw_fence_client, fence, hash,
|
||||
&is_signaled, true);
|
||||
else
|
||||
hw_fence = msm_hw_fence_find(drv_data, hw_fence_client, context, context, seqno,
|
||||
hash);
|
||||
hw_fence = msm_hw_fence_find(drv_data, hw_fence_client, context, seqno, hash);
|
||||
if (!hw_fence) {
|
||||
HWFNC_ERR("Cannot find fence!\n");
|
||||
return -EINVAL;
|
||||
@@ -2214,11 +2245,12 @@ static void _signal_fence_if_unsignaled(struct hw_fence_driver_data *drv_data,
|
||||
struct msm_hw_fence *_create_signaled_hw_fence(struct hw_fence_driver_data *drv_data,
|
||||
u32 client_id, struct dma_fence *fence, u64 *hash)
|
||||
{
|
||||
struct msm_hw_fence *hw_fences_tbl = drv_data->hw_fences_tbl;
|
||||
struct msm_hw_fence *hw_fence;
|
||||
|
||||
/* create new hw-fence for signaled dma-fence */
|
||||
hw_fence = _hw_fence_lookup_and_create_range(drv_data, client_id, (u64)fence,
|
||||
fence->context, fence->seqno, 0, hash, 0, drv_data->hw_fences_tbl_cnt,
|
||||
hw_fence = _hw_fence_lookup_and_process(drv_data, hw_fences_tbl,
|
||||
fence->context, fence->seqno, client_id, 0, HW_FENCE_LOOKUP_OP_CREATE, hash,
|
||||
MSM_HW_FENCE_FLAG_CREATE_SIGNALED);
|
||||
if (hw_fence) {
|
||||
_signal_fence_if_unsignaled(drv_data, hw_fence, *hash, fence->error, true);
|
||||
@@ -2238,6 +2270,7 @@ struct msm_hw_fence *hw_fence_find_with_dma_fence(struct hw_fence_driver_data *d
|
||||
bool *is_signaled, bool create)
|
||||
{
|
||||
u32 step, end_step, client_id = hw_fence_client ? hw_fence_client->client_id : 0xff;
|
||||
struct msm_hw_fence *hw_fences_tbl = drv_data->hw_fences_tbl;
|
||||
struct msm_hw_fence *hw_fence = NULL;
|
||||
|
||||
if (!create && dma_fence_is_signaled(fence)) {
|
||||
@@ -2246,11 +2279,12 @@ struct msm_hw_fence *hw_fence_find_with_dma_fence(struct hw_fence_driver_data *d
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (step = 0; step < drv_data->hw_fences_tbl_cnt; step += HW_FENCE_FIND_THRESHOLD) {
|
||||
end_step = (step + HW_FENCE_FIND_THRESHOLD > drv_data->hw_fences_tbl_cnt) ?
|
||||
drv_data->hw_fences_tbl_cnt : step + HW_FENCE_FIND_THRESHOLD;
|
||||
hw_fence = _hw_fence_lookup_and_process_range(drv_data, (u64)fence, fence->context,
|
||||
fence->seqno, hash, step, end_step, _fence_found);
|
||||
for (step = 0; step < drv_data->hw_fence_table_entries; step += HW_FENCE_FIND_THRESHOLD) {
|
||||
end_step = (step + HW_FENCE_FIND_THRESHOLD > drv_data->hw_fence_table_entries) ?
|
||||
drv_data->hw_fence_table_entries : step + HW_FENCE_FIND_THRESHOLD;
|
||||
hw_fence = _hw_fence_lookup_and_process_range(drv_data, hw_fences_tbl,
|
||||
fence->context, fence->seqno, client_id, 0, HW_FENCE_LOOKUP_OP_FIND_FENCE,
|
||||
hash, 0, step, end_step);
|
||||
if (hw_fence) {
|
||||
/* successfully found backing hw-fence*/
|
||||
*is_signaled = false;
|
||||
|
@@ -411,7 +411,7 @@ static int _process_ctrl_rx_queue(struct hw_fence_driver_data *drv_data)
|
||||
&drv_data->ctrl_queues[HW_FENCE_RX_QUEUE - 1], &payload);
|
||||
if (read < 0) {
|
||||
HWFNC_DBG_Q("unable to read ctrl rxq\n");
|
||||
return 0;
|
||||
return read;
|
||||
}
|
||||
switch (payload.type) {
|
||||
case HW_FENCE_PAYLOAD_TYPE_2:
|
||||
|
@@ -291,7 +291,7 @@ int msm_hw_fence_create(void *client_handle,
|
||||
}
|
||||
|
||||
/* Create the HW Fence, i.e. add entry in the Global Table for this Fence */
|
||||
ret = hw_fence_create(hw_fence_drv_data, hw_fence_client, (u64)fence, fence->context,
|
||||
ret = hw_fence_create(hw_fence_drv_data, hw_fence_client, fence->context,
|
||||
fence->seqno, params->handle);
|
||||
if (ret) {
|
||||
HWFNC_ERR("Error creating HW fence\n");
|
||||
@@ -358,7 +358,7 @@ int msm_hw_fence_destroy(void *client_handle,
|
||||
}
|
||||
|
||||
/* Destroy the HW Fence, i.e. remove entry in the Global Table for the Fence */
|
||||
ret = hw_fence_destroy(hw_fence_drv_data, hw_fence_client, (u64)fence,
|
||||
ret = hw_fence_destroy(hw_fence_drv_data, hw_fence_client,
|
||||
fence->context, fence->seqno);
|
||||
if (ret) {
|
||||
HWFNC_ERR("Error destroying the HW fence\n");
|
||||
@@ -758,7 +758,7 @@ int msm_hw_fence_dump_fence(void *client_handle, struct dma_fence *fence)
|
||||
}
|
||||
hw_fence_client = (struct msm_hw_fence_client *)client_handle;
|
||||
|
||||
hw_fence = msm_hw_fence_find(hw_fence_drv_data, hw_fence_client, (u64)fence, fence->context,
|
||||
hw_fence = msm_hw_fence_find(hw_fence_drv_data, hw_fence_client, fence->context,
|
||||
fence->seqno, &hash);
|
||||
if (!hw_fence) {
|
||||
HWFNC_ERR("failed to find hw-fence client_id:%d fence:0x%pK ctx:%llu seqno:%llu\n",
|
||||
@@ -908,7 +908,6 @@ static int msm_hw_fence_remove(struct platform_device *pdev)
|
||||
/* free memory allocations as part of hw_fence_drv_data */
|
||||
kfree(hw_fence_drv_data->ipc_clients_table);
|
||||
kfree(hw_fence_drv_data->hw_fence_client_queue_size);
|
||||
kfree(hw_fence_drv_data->hlos_key_tbl);
|
||||
if (hw_fence_drv_data->cpu_addr_cookie)
|
||||
dma_free_attrs(hw_fence_drv_data->dev, hw_fence_drv_data->size,
|
||||
hw_fence_drv_data->cpu_addr_cookie, hw_fence_drv_data->res.start,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
@@ -407,13 +407,6 @@ static int spec_sync_bind_array(struct fence_bind_data *sync_bind_info)
|
||||
user_fds[i], sync_bind_info->out_bind_fd);
|
||||
ret = -EINVAL;
|
||||
goto bind_invalid;
|
||||
} else if (user_fence->context == fence_array->base.context &&
|
||||
user_fence->seqno == fence_array->base.seqno) {
|
||||
pr_err("invalid spec fence, ufd:%d o_b_fd:%d ctx:%lld seqno:%lld\n",
|
||||
user_fds[i], sync_bind_info->out_bind_fd,
|
||||
user_fence->context, user_fence->seqno);
|
||||
ret = -EINVAL;
|
||||
goto bind_invalid;
|
||||
}
|
||||
fence_array->fences[i] = user_fence;
|
||||
/*
|
||||
|
Reference in New Issue
Block a user