|
@@ -15,6 +15,73 @@
|
|
|
#include "hw_fence_drv_ipc.h"
|
|
|
#include "hw_fence_drv_debug.h"
|
|
|
|
|
|
+/**
|
|
|
+ * MAX_CLIENT_QUEUE_MEM_SIZE:
|
|
|
+ * Maximum memory size for client queues of a hw fence client.
|
|
|
+ */
|
|
|
+#define MAX_CLIENT_QUEUE_MEM_SIZE 0x100000
|
|
|
+
|
|
|
+/**
|
|
|
+ * HW_FENCE_MAX_CLIENT_TYPE:
|
|
|
+ * Total number of client types (GFX, DPU, VAL)
|
|
|
+ */
|
|
|
+#define HW_FENCE_MAX_CLIENT_TYPE 3
|
|
|
+
|
|
|
+/* Maximum number of clients for each client type */
|
|
|
+#define HW_FENCE_CLIENT_TYPE_MAX_GPU 1
|
|
|
+#define HW_FENCE_CLIENT_TYPE_MAX_DPU 6
|
|
|
+#define HW_FENCE_CLIENT_TYPE_MAX_VAL 7
|
|
|
+
|
|
|
+/**
|
|
|
+ * struct hw_fence_client_type_desc - Structure holding client type properties, including static
|
|
|
+ * properties and client queue properties read from device-tree.
|
|
|
+ *
|
|
|
+ * @name: name of client type, used to parse properties from device-tree
|
|
|
+ * @init_id: initial client_id for given client type within the 'hw_fence_client_id' enum, e.g.
|
|
|
+ * HW_FENCE_CLIENT_ID_CTL0 for DPU clients
|
|
|
+ * @max_clients_num: maximum number of clients of given client type
|
|
|
+ * @clients_num: number of clients of given client type
|
|
|
+ * @queues_num: number of queues per client of given client type; either one (for only Tx Queue) or
|
|
|
+ * two (for both Tx and Rx Queues)
|
|
|
+ * @queue_entries: number of entries per client queue of given client type
|
|
|
+ * @mem_size: size of memory allocated for client queue(s) per client
|
|
|
+ */
|
|
|
+struct hw_fence_client_type_desc {
|
|
|
+ char *name;
|
|
|
+ enum hw_fence_client_id init_id;
|
|
|
+ u32 max_clients_num;
|
|
|
+ u32 clients_num;
|
|
|
+ u32 queues_num;
|
|
|
+ u32 queue_entries;
|
|
|
+ u32 mem_size;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * struct hw_fence_client_types - Table describing all supported client types, used to parse
|
|
|
+ * device-tree properties related to client queue size.
|
|
|
+ *
|
|
|
+ * The fields name, init_id, and max_clients_num are constants. Default values for clients_num and
|
|
|
+ * queues_num are provided in this table, and clients_num, queues_num, and queue_entries can be read
|
|
|
+ * from device-tree.
|
|
|
+ *
|
|
|
+ * If a value for queue entries is not parsed for the client type, then the default number of client
|
|
|
+ * queue entries (parsed from device-tree) is used.
|
|
|
+ *
|
|
|
+ * Notes:
|
|
|
+ * 1. Client types must be in the same order as client_ids within the enum 'hw_fence_client_id'.
|
|
|
+ * 2. Each HW Fence client ID must be described by one of the client types in this table.
|
|
|
+ * 3. A new client type must set: name, init_id, max_clients_num, clients_num, and queues_num.
|
|
|
+ * 4. HW_FENCE_MAX_CLIENT_TYPE must be incremented for new client types.
|
|
|
+ */
|
|
|
+struct hw_fence_client_type_desc hw_fence_client_types[HW_FENCE_MAX_CLIENT_TYPE] = {
|
|
|
+ {"gpu", HW_FENCE_CLIENT_ID_CTX0, HW_FENCE_CLIENT_TYPE_MAX_GPU, HW_FENCE_CLIENT_TYPE_MAX_GPU,
|
|
|
+ HW_FENCE_CLIENT_QUEUES, 0, 0},
|
|
|
+ {"dpu", HW_FENCE_CLIENT_ID_CTL0, HW_FENCE_CLIENT_TYPE_MAX_DPU, HW_FENCE_CLIENT_TYPE_MAX_DPU,
|
|
|
+ HW_FENCE_CLIENT_QUEUES, 0, 0},
|
|
|
+ {"val", HW_FENCE_CLIENT_ID_VAL0, HW_FENCE_CLIENT_TYPE_MAX_VAL, HW_FENCE_CLIENT_TYPE_MAX_VAL,
|
|
|
+ HW_FENCE_CLIENT_QUEUES, 0, 0},
|
|
|
+};
|
|
|
+
|
|
|
static void _lock(uint64_t *wait)
|
|
|
{
|
|
|
#if defined(__aarch64__)
|
|
@@ -399,6 +466,11 @@ int hw_fence_utils_alloc_mem(struct hw_fence_driver_data *drv_data)
|
|
|
return -ENXIO;
|
|
|
}
|
|
|
drv_data->size = resource_size(&drv_data->res);
|
|
|
+ if (drv_data->size < drv_data->used_mem_size) {
|
|
|
+ HWFNC_ERR("0x%x size of carved-out memory region is less than required size:0x%x\n",
|
|
|
+ drv_data->size, drv_data->used_mem_size);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
|
|
|
HWFNC_DBG_INIT("io_mem_base:0x%x start:0x%x end:0x%x size:0x%x name:%s\n",
|
|
|
drv_data->io_mem_base, drv_data->res.start,
|
|
@@ -469,12 +541,17 @@ int hw_fence_utils_reserve_mem(struct hw_fence_driver_data *drv_data,
|
|
|
goto exit;
|
|
|
}
|
|
|
|
|
|
- start_offset = PAGE_ALIGN(drv_data->hw_fence_mem_ctrl_queues_size +
|
|
|
- HW_FENCE_MEM_LOCKS_SIZE +
|
|
|
- drv_data->hw_fence_mem_fences_table_size) +
|
|
|
- ((client_id - 1) * drv_data->hw_fence_mem_clients_queues_size);
|
|
|
- *size = drv_data->hw_fence_mem_clients_queues_size;
|
|
|
+ start_offset = drv_data->hw_fence_client_queue_size[client_id].start_offset;
|
|
|
+ *size = drv_data->hw_fence_client_queue_size[client_id].mem_size;
|
|
|
|
|
|
+ /*
|
|
|
+ * If this error occurs when client should be valid, check that support for this
|
|
|
+ * client has been configured in device-tree properties.
|
|
|
+ */
|
|
|
+ if (!*size) {
|
|
|
+ HWFNC_ERR("invalid client_id:%d not reserved client queue\n", client_id);
|
|
|
+ ret = -EINVAL;
|
|
|
+ }
|
|
|
break;
|
|
|
default:
|
|
|
HWFNC_ERR("Invalid mem reserve type:%d\n", type);
|
|
@@ -501,6 +578,95 @@ exit:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int _parse_client_queue_dt_props_indv(struct hw_fence_driver_data *drv_data,
|
|
|
+ struct hw_fence_client_type_desc *desc)
|
|
|
+{
|
|
|
+ char name[31];
|
|
|
+ u32 tmp[3];
|
|
|
+ u32 queue_size;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ /* parse client queue property from device-tree */
|
|
|
+ snprintf(name, sizeof(name), "qcom,hw-fence-client-type-%s", desc->name);
|
|
|
+ ret = of_property_read_u32_array(drv_data->dev->of_node, name, tmp, 3);
|
|
|
+ if (ret) {
|
|
|
+ HWFNC_DBG_INIT("missing %s client queue entry or invalid ret:%d\n", desc->name,
|
|
|
+ ret);
|
|
|
+ desc->queue_entries = drv_data->hw_fence_queue_entries;
|
|
|
+ } else {
|
|
|
+ desc->clients_num = tmp[0];
|
|
|
+ desc->queues_num = tmp[1];
|
|
|
+ desc->queue_entries = tmp[2];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (desc->clients_num > desc->max_clients_num || !desc->queues_num ||
|
|
|
+ desc->queues_num > HW_FENCE_CLIENT_QUEUES || !desc->queue_entries) {
|
|
|
+ HWFNC_ERR("%s invalid dt: clients_num:%lu queues_num:%lu, queue_entries:%lu\n",
|
|
|
+ desc->name, desc->clients_num, desc->queues_num, desc->queue_entries);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* compute mem_size */
|
|
|
+ if (desc->queue_entries >= U32_MAX / HW_FENCE_CLIENT_QUEUE_PAYLOAD) {
|
|
|
+ HWFNC_ERR("%s client queue entries:%lu will overflow client queue size\n",
|
|
|
+ desc->name, desc->queue_entries);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ queue_size = HW_FENCE_CLIENT_QUEUE_PAYLOAD * desc->queue_entries;
|
|
|
+ if (queue_size >= ((U32_MAX & PAGE_MASK) -
|
|
|
+ HW_FENCE_HFI_CLIENT_HEADERS_SIZE(desc->queues_num)) / desc->queues_num) {
|
|
|
+ HWFNC_ERR("%s client queue size:%lu will overflow client queue mem size\n",
|
|
|
+ desc->name, queue_size);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ desc->mem_size = PAGE_ALIGN(HW_FENCE_HFI_CLIENT_HEADERS_SIZE(desc->queues_num) +
|
|
|
+ (queue_size * desc->queues_num));
|
|
|
+
|
|
|
+ if (desc->mem_size > MAX_CLIENT_QUEUE_MEM_SIZE) {
|
|
|
+ HWFNC_ERR("%s client queue mem_size:%lu greater than max client queue size:%lu\n",
|
|
|
+ desc->name, desc->mem_size, MAX_CLIENT_QUEUE_MEM_SIZE);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ HWFNC_DBG_INIT("%s: clients=%lu q_num=%lu q_entries=%lu mem_sz=%lu\n", desc->name,
|
|
|
+ desc->clients_num, desc->queues_num, desc->queue_entries, desc->mem_size);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int _parse_client_queue_dt_props(struct hw_fence_driver_data *drv_data)
|
|
|
+{
|
|
|
+ struct hw_fence_client_type_desc *desc;
|
|
|
+ int i, j, ret;
|
|
|
+ u32 start_offset;
|
|
|
+
|
|
|
+ start_offset = PAGE_ALIGN(drv_data->hw_fence_mem_ctrl_queues_size +
|
|
|
+ HW_FENCE_MEM_LOCKS_SIZE + drv_data->hw_fence_mem_fences_table_size);
|
|
|
+ for (i = 0; i < HW_FENCE_MAX_CLIENT_TYPE; i++) {
|
|
|
+ desc = &hw_fence_client_types[i];
|
|
|
+ ret = _parse_client_queue_dt_props_indv(drv_data, desc);
|
|
|
+ if (ret) {
|
|
|
+ HWFNC_ERR("failed to initialize %s client queue size properties\n",
|
|
|
+ desc->name);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* initialize client queue size desc for each client */
|
|
|
+ for (j = 0; j < desc->clients_num; j++) {
|
|
|
+ drv_data->hw_fence_client_queue_size[desc->init_id + j] =
|
|
|
+ (struct hw_fence_client_queue_size_desc)
|
|
|
+ {desc->queues_num, desc->queue_entries, desc->mem_size,
|
|
|
+ start_offset};
|
|
|
+ start_offset += desc->mem_size;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ drv_data->used_mem_size = start_offset;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int hw_fence_utils_parse_dt_props(struct hw_fence_driver_data *drv_data)
|
|
|
{
|
|
|
int ret;
|
|
@@ -549,29 +715,17 @@ int hw_fence_utils_parse_dt_props(struct hw_fence_driver_data *drv_data)
|
|
|
|
|
|
/* clients queues init */
|
|
|
|
|
|
- if (drv_data->hw_fence_queue_entries >= U32_MAX / HW_FENCE_CLIENT_QUEUE_PAYLOAD) {
|
|
|
- HWFNC_ERR("queue entries:%lu will overflow client queue size\n",
|
|
|
- drv_data->hw_fence_queue_entries);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- drv_data->hw_fence_client_queue_size = HW_FENCE_CLIENT_QUEUE_PAYLOAD *
|
|
|
- drv_data->hw_fence_queue_entries;
|
|
|
-
|
|
|
- if (drv_data->hw_fence_client_queue_size >= ((U32_MAX & PAGE_MASK) -
|
|
|
- HW_FENCE_HFI_CLIENT_HEADERS_SIZE) / HW_FENCE_CLIENT_QUEUES) {
|
|
|
- HWFNC_ERR("queue size:%lu will overflow client queue mem size\n",
|
|
|
- drv_data->hw_fence_client_queue_size);
|
|
|
+ ret = _parse_client_queue_dt_props(drv_data);
|
|
|
+ if (ret) {
|
|
|
+ HWFNC_ERR("failed to parse client queue properties\n");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- drv_data->hw_fence_mem_clients_queues_size = PAGE_ALIGN(HW_FENCE_HFI_CLIENT_HEADERS_SIZE +
|
|
|
- (HW_FENCE_CLIENT_QUEUES * drv_data->hw_fence_client_queue_size));
|
|
|
|
|
|
HWFNC_DBG_INIT("table: entries=%lu mem_size=%lu queue: entries=%lu\b",
|
|
|
drv_data->hw_fence_table_entries, drv_data->hw_fence_mem_fences_table_size,
|
|
|
drv_data->hw_fence_queue_entries);
|
|
|
- HWFNC_DBG_INIT("ctrl queue: size=%lu mem_size=%lu clients queues: size=%lu mem_size=%lu\b",
|
|
|
- drv_data->hw_fence_ctrl_queue_size, drv_data->hw_fence_mem_ctrl_queues_size,
|
|
|
- drv_data->hw_fence_client_queue_size, drv_data->hw_fence_mem_clients_queues_size);
|
|
|
+ HWFNC_DBG_INIT("ctrl queue: size=%lu mem_size=%lu\b",
|
|
|
+ drv_data->hw_fence_ctrl_queue_size, drv_data->hw_fence_mem_ctrl_queues_size);
|
|
|
|
|
|
return 0;
|
|
|
}
|