Browse Source

Merge "dsp: Fix out of bound memory access."

qctecmdr 4 years ago
parent
commit
8c500e2d43
4 changed files with 441 additions and 4 deletions
  1. 175 2
      dsp/q6afe.c
  2. 135 2
      dsp/q6core.c
  3. 10 0
      include/dsp/apr_audio-v2.h
  4. 121 0
      include/dsp/q6core.h

+ 175 - 2
dsp/q6afe.c

@@ -24,6 +24,21 @@
 
 #define WAKELOCK_TIMEOUT	5000
 #define AFE_CLK_TOKEN	1024
+
+struct afe_avcs_payload_port_mapping {
+	u16 port_id;
+	struct avcs_load_unload_modules_payload *payload;
+} __packed;
+
+enum {
+	ENCODER_CASE,
+	DECODER_CASE,
+	/* Add new use case here */
+	MAX_ALLOWED_USE_CASES
+};
+
+static struct afe_avcs_payload_port_mapping *pm[MAX_ALLOWED_USE_CASES];
+
 enum {
 	AFE_COMMON_RX_CAL = 0,
 	AFE_COMMON_TX_CAL,
@@ -240,6 +255,124 @@ static bool proxy_afe_started = false;
 #define SIZEOF_CFG_CMD(y) \
 		(sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
 
+static void q6afe_unload_avcs_modules(u16 port_id, int index)
+{
+	int ret = 0;
+
+	ret = q6core_avcs_load_unload_modules(pm[index]->payload,
+			AVCS_UNLOAD_MODULES);
+
+	if (ret < 0)
+		pr_err("%s: avcs module unload failed %d\n", __func__, ret);
+
+	kfree(pm[index]->payload);
+	pm[index]->payload = NULL;
+	kfree(pm[index]);
+	pm[index] = NULL;
+}
+
+static int q6afe_load_avcs_modules(int num_modules, u16 port_id,
+		 uint32_t use_case, u32 format_id)
+{
+	int i = 0;
+	int32_t ret = 0;
+	size_t payload_size = 0, port_struct_size = 0;
+	struct afe_avcs_payload_port_mapping payload_map;
+	struct avcs_load_unload_modules_sec_payload sec_payload;
+
+	if (num_modules <= 0) {
+		pr_err("%s: Invalid number of modules to load\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < MAX_ALLOWED_USE_CASES; i++) {
+		if (pm[i] == NULL) {
+			port_struct_size = sizeof(payload_map);
+			pm[i] = kzalloc(port_struct_size, GFP_KERNEL);
+			if (!pm[i])
+				return -ENOMEM;
+
+			pm[i]->port_id = port_id;
+			payload_size = sizeof(uint32_t) + (sizeof(sec_payload)
+					* num_modules);
+			pm[i]->payload = kzalloc(payload_size, GFP_KERNEL);
+			if (!pm[i]->payload) {
+				kfree(pm[i]);
+				pm[i] = NULL;
+				return -ENOMEM;
+			}
+
+			/*
+			 * index 0 : packetizer/de-packetizer
+			 * index 1 : encoder/decoder
+			 */
+
+			pm[i]->payload->num_modules = num_modules;
+
+			/*
+			 * Remaining fields of payload
+			 * are initialized to zero
+			 */
+
+			if (use_case == ENCODER_CASE) {
+				pm[i]->payload->load_unload_info[0].module_type =
+						AMDB_MODULE_TYPE_PACKETIZER;
+				pm[i]->payload->load_unload_info[0].id1 =
+						AVS_MODULE_ID_PACKETIZER_COP;
+				pm[i]->payload->load_unload_info[1].module_type =
+						AMDB_MODULE_TYPE_ENCODER;
+				pm[i]->payload->load_unload_info[1].id1 =
+						format_id;
+			} else if (use_case == DECODER_CASE) {
+				pm[i]->payload->load_unload_info[0].module_type =
+						AMDB_MODULE_TYPE_DEPACKETIZER;
+				pm[i]->payload->load_unload_info[0].id1 =
+					AVS_MODULE_ID_DEPACKETIZER_COP_V1;
+
+				if (format_id == ENC_CODEC_TYPE_LDAC) {
+					pm[i]->payload->load_unload_info[0].id1 =
+						AVS_MODULE_ID_DEPACKETIZER_COP;
+					goto load_unload;
+				}
+
+				pm[i]->payload->load_unload_info[1].module_type =
+						AMDB_MODULE_TYPE_DECODER;
+				pm[i]->payload->load_unload_info[1].id1 =
+						format_id;
+
+			} else {
+				pr_err("%s:load usecase %d not supported\n",
+					 __func__, use_case);
+				ret = -EINVAL;
+				goto fail;
+			}
+
+load_unload:
+			ret = q6core_avcs_load_unload_modules(pm[i]->payload,
+						 AVCS_LOAD_MODULES);
+
+			if (ret < 0) {
+				pr_err("%s: load failed %d\n", __func__, ret);
+				goto fail;
+			}
+			return 0;
+		}
+
+	}
+
+	ret = -EINVAL;
+	if (i == MAX_ALLOWED_USE_CASES) {
+		pr_err("%s: Not enough ports available\n", __func__);
+		return ret;
+	}
+fail:
+	kfree(pm[i]->payload);
+	pm[i]->payload = NULL;
+	kfree(pm[i]);
+	pm[i] = NULL;
+	return ret;
+}
+
 static int afe_get_cal_hw_delay(int32_t path,
 				struct audio_cal_hw_delay_entry *entry);
 static int remap_cal_data(struct cal_block_data *cal_block, int cal_index);
@@ -5514,8 +5647,21 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
 	if ((codec_format != ASM_MEDIA_FMT_NONE) &&
 	    (cfg_type == AFE_PARAM_ID_SLIMBUS_CONFIG)) {
 		if (enc_cfg != NULL) {
-			pr_debug("%s: Found AFE encoder support for SLIMBUS format = %d\n",
+			pr_debug("%s: Found AFE encoder support  for SLIMBUS format = %d\n",
 						__func__, codec_format);
+
+			if ((q6core_get_avcs_api_version_per_service(
+				APRV2_IDS_SERVICE_ID_ADSP_CORE_V) >=
+						AVCS_API_VERSION_V5)) {
+				ret = q6afe_load_avcs_modules(2, port_id,
+					ENCODER_CASE, codec_format);
+				if (ret < 0) {
+					pr_err("%s:encoder load for port 0x%x failed %d\n",
+						__func__, port_id, ret);
+					goto fail_cmd;
+				}
+			}
+
 			ret = q6afe_send_enc_config(port_id, enc_cfg,
 						    codec_format, *afe_config,
 						    afe_in_channels,
@@ -5529,7 +5675,24 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
 		}
 		if (dec_cfg != NULL) {
 			pr_debug("%s: Found AFE decoder support for SLIMBUS format = %d\n",
-				  __func__, codec_format);
+				__func__, codec_format);
+
+			if ((q6core_get_avcs_api_version_per_service(
+				APRV2_IDS_SERVICE_ID_ADSP_CORE_V) >=
+				AVCS_API_VERSION_V5)) {
+				/* LDAC doesn't require decoder */
+				if (codec_format == ENC_CODEC_TYPE_LDAC)
+					ret = q6afe_load_avcs_modules(1, port_id,
+						DECODER_CASE, codec_format);
+				else
+					ret = q6afe_load_avcs_modules(2, port_id,
+						DECODER_CASE, codec_format);
+				if (ret < 0) {
+					pr_err("%s:decoder load for port 0x%x failed %d\n",
+						__func__, port_id, ret);
+					goto fail_cmd;
+				}
+			}
 			ret = q6afe_send_dec_config(port_id, *afe_config,
 						    dec_cfg, codec_format,
 						    afe_in_channels,
@@ -8341,6 +8504,7 @@ int afe_close(int port_id)
 	struct afe_port_cmd_device_stop stop;
 	enum afe_mad_type mad_type;
 	int ret = 0;
+	u16 i;
 	int index = 0;
 	uint16_t port_index;
 
@@ -8463,6 +8627,15 @@ int afe_close(int port_id)
 		pr_err("%s: AFE close failed %d\n", __func__, ret);
 
 fail_cmd:
+	if ((q6core_get_avcs_api_version_per_service(
+		APRV2_IDS_SERVICE_ID_ADSP_CORE_V) >= AVCS_API_VERSION_V5)) {
+		for (i = 0; i < MAX_ALLOWED_USE_CASES; i++) {
+			if (pm[i] && pm[i]->port_id == port_id) {
+				q6afe_unload_avcs_modules(port_id, i);
+				break;
+			}
+		}
+	}
 	mutex_unlock(&this_afe.afe_cmd_lock);
 	return ret;
 }

+ 135 - 2
dsp/q6core.c

@@ -61,9 +61,11 @@ struct q6core_str {
 	wait_queue_head_t cmd_req_wait;
 	wait_queue_head_t avcs_fwk_ver_req_wait;
 	wait_queue_head_t lpass_npa_rsc_wait;
+	wait_queue_head_t avcs_module_load_unload_wait;
 	u32 lpass_npa_rsc_rsp_rcvd;
 	u32 bus_bw_resp_received;
 	u32 mdf_map_resp_received;
+	u32 avcs_module_resp_received;
 	enum cmd_flags {
 		FLAG_NONE,
 		FLAG_CMDRSP_LICENSE_RESULT
@@ -87,6 +89,9 @@ struct q6core_str {
 
 static struct q6core_str q6core_lcl;
 
+/* Global payload used for AVCS_CMD_RSP_MODULES command */
+static struct avcs_load_unload_modules_payload *rsp_payload;
+
 struct generic_get_data_ {
 	int valid;
 	int size_in_ints;
@@ -343,6 +348,29 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
 			q6core_lcl.lpass_npa_rsc_rsp_rcvd = 1;
 			wake_up(&q6core_lcl.lpass_npa_rsc_wait);
 			break;
+		case AVCS_CMD_LOAD_MODULES:
+			pr_err("%s: Cmd = %s failed status[%s]\n",
+				__func__, "AVCS_CMD_LOAD__MODULES",
+				adsp_err_get_err_str(payload1[1]));
+			q6core_lcl.avcs_module_resp_received = 1;
+			q6core_lcl.adsp_status = -payload1[1];
+			wake_up(&q6core_lcl.avcs_module_load_unload_wait);
+			break;
+		case AVCS_CMD_UNLOAD_MODULES:
+			if (payload1[1] == ADSP_EOK) {
+				pr_debug("%s: Cmd = %s success status[%s]\n",
+					__func__, "AVCS_CMD_UNLOAD_MODULES",
+					"ADSP_EOK");
+			} else {
+				pr_err("%s: Cmd = %s failed status[%s]\n",
+					__func__, "AVCS_CMD_UNLOAD_MODULES",
+				adsp_err_get_err_str(payload1[1]));
+				q6core_lcl.adsp_status = -payload1[1];
+			}
+			q6core_lcl.avcs_module_resp_received = 1;
+			wake_up(&q6core_lcl.avcs_module_load_unload_wait);
+			break;
+
 		default:
 			pr_err("%s: Invalid cmd rsp[0x%x][0x%x] opcode %d\n",
 					__func__,
@@ -441,6 +469,13 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
 		q6core_lcl.avcs_fwk_ver_resp_received = 1;
 		wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
 		break;
+	case AVCS_CMD_RSP_LOAD_MODULES:
+		pr_debug("%s: Received AVCS_CMD_RSP_LOAD_MODULES\n",
+			 __func__);
+		memcpy(rsp_payload, data->payload, data->payload_size);
+		q6core_lcl.avcs_module_resp_received = 1;
+		wake_up(&q6core_lcl.avcs_module_load_unload_wait);
+		break;
 	default:
 		pr_err("%s: Message id from adsp core svc: 0x%x\n",
 			__func__, data->opcode);
@@ -821,7 +856,6 @@ int32_t core_get_license_status(uint32_t module_id)
 	get_lvr_cmd.hdr.opcode = AVCS_CMD_GET_LICENSE_VALIDATION_RESULT;
 	get_lvr_cmd.id = module_id;
 
-
 	ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *) &get_lvr_cmd);
 	if (ret < 0) {
 		pr_err("%s: license_validation request failed, err %d\n",
@@ -894,6 +928,105 @@ uint32_t core_set_dolby_manufacturer_id(int manufacturer_id)
 }
 EXPORT_SYMBOL(core_set_dolby_manufacturer_id);
 
+int32_t q6core_avcs_load_unload_modules(struct avcs_load_unload_modules_payload
+				 *payload, uint32_t preload_type)
+{
+	int ret = 0;
+	size_t packet_size = 0,  payload_size = 0;
+	struct avcs_cmd_dynamic_modules *mod = NULL;
+	int num_modules;
+
+	if (payload == NULL) {
+		pr_err("%s: payload is null\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&(q6core_lcl.cmd_lock));
+	num_modules = payload->num_modules;
+	ocm_core_open();
+
+	if (q6core_lcl.core_handle_q == NULL) {
+		pr_err("%s: apr registration for CORE failed\n", __func__);
+		mutex_unlock(&(q6core_lcl.cmd_lock));
+		return -ENODEV;
+	}
+
+	payload_size = (sizeof(struct avcs_load_unload_modules_sec_payload)
+			* num_modules) + sizeof(uint32_t);
+	packet_size = sizeof(struct avcs_cmd_dynamic_modules) +
+			payload_size - sizeof(uint32_t);
+	mod = kzalloc(packet_size, GFP_KERNEL);
+
+	if (!mod) {
+		mutex_unlock(&(q6core_lcl.cmd_lock));
+		return -ENOMEM;
+	}
+
+	rsp_payload = kzalloc(payload_size, GFP_KERNEL);
+	if (!rsp_payload) {
+		kfree(mod);
+		mutex_unlock(&(q6core_lcl.cmd_lock));
+		return -ENOMEM;
+	}
+
+	memcpy((uint8_t *)mod + sizeof(struct apr_hdr) +
+		sizeof(struct avcs_load_unload_modules_meminfo),
+		payload, payload_size);
+
+	mod->hdr.hdr_field =
+			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mod->hdr.pkt_size = packet_size;
+	mod->hdr.src_port = 0;
+	mod->hdr.dest_port = 0;
+	mod->hdr.token = 0;
+	mod->meminfo.data_payload_addr_lsw = 0;
+	mod->meminfo.data_payload_addr_msw = 0;
+	mod->meminfo.mem_map_handle = 0;
+	mod->meminfo.buffer_size = payload_size;
+
+	if (preload_type == AVCS_LOAD_MODULES)
+		mod->hdr.opcode =  AVCS_CMD_LOAD_MODULES;
+	else
+		mod->hdr.opcode =  AVCS_CMD_UNLOAD_MODULES;
+
+	q6core_lcl.avcs_module_resp_received = 0;
+	ret = apr_send_pkt(q6core_lcl.core_handle_q,
+		(uint32_t *)mod);
+
+	if (ret < 0) {
+		pr_err("%s: modules load/unload failed ret = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	ret = wait_event_timeout(q6core_lcl.avcs_module_load_unload_wait,
+				(q6core_lcl.avcs_module_resp_received == 1),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s wait event timeout for avcs load/unload module\n",
+			__func__);
+		ret = -ETIMEDOUT;
+		goto done;
+	}
+
+	if (q6core_lcl.adsp_status < 0) {
+		pr_err("%s: modules load/unload failed %d\n", __func__,
+				q6core_lcl.adsp_status);
+		ret = q6core_lcl.adsp_status;
+		goto done;
+	} else {
+		if (mod->hdr.opcode == AVCS_CMD_LOAD_MODULES)
+			memcpy(payload, rsp_payload, payload_size);
+	}
+done:
+	kfree(mod);
+	kfree(rsp_payload);
+	mutex_unlock(&(q6core_lcl.cmd_lock));
+	return ret;
+}
+EXPORT_SYMBOL(q6core_avcs_load_unload_modules);
+
 int32_t q6core_load_unload_topo_modules(uint32_t topo_id,
 			bool preload_type)
 {
@@ -1871,7 +2004,6 @@ static int q6core_probe(struct platform_device *pdev)
 	if (rc < 0)
 		goto err;
 	q6core_lcl.avs_state = avs_state;
-
 	rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
 	if (rc) {
 		dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n",
@@ -1926,6 +2058,7 @@ int __init core_init(void)
 	init_waitqueue_head(&q6core_lcl.avcs_fwk_ver_req_wait);
 	init_waitqueue_head(&q6core_lcl.mdf_map_resp_wait);
 	init_waitqueue_head(&q6core_lcl.lpass_npa_rsc_wait);
+	init_waitqueue_head(&q6core_lcl.avcs_module_load_unload_wait);
 	q6core_lcl.cmd_resp_received_flag = FLAG_NONE;
 	mutex_init(&q6core_lcl.cmd_lock);
 	mutex_init(&q6core_lcl.ver_lock);

+ 10 - 0
include/dsp/apr_audio-v2.h

@@ -4143,6 +4143,16 @@ struct afe_id_aptx_adaptive_enc_init
 #define AFE_MODULE_ID_DEPACKETIZER_COP        0x00013233
 #define AFE_MODULE_ID_DEPACKETIZER_COP_V1     0x000132E9
 
+/* Macros for dynamic loading of modules by AVCS */
+
+#define AVS_MODULE_ID_PACKETIZER_COP        0x0001322A
+
+#define AVS_MODULE_ID_PACKETIZER_COP_V1     0x000132E8
+
+#define AVS_MODULE_ID_DEPACKETIZER_COP      0x00013233
+
+#define AVS_MODULE_ID_DEPACKETIZER_COP_V1   0x000132E9
+
 /*
  * Depacketizer type parameter for the #AVS_MODULE_ID_DECODER module.
  * This parameter cannot be set runtime.

+ 121 - 0
include/dsp/q6core.h

@@ -13,6 +13,7 @@
 #define AVCS_CMD_ADSP_EVENT_GET_STATE		0x0001290C
 #define AVCS_CMDRSP_ADSP_EVENT_GET_STATE	0x0001290D
 #define AVCS_API_VERSION_V4		4
+#define AVCS_API_VERSION_V5		5
 #define APRV2_IDS_SERVICE_ID_ADSP_CORE_V (0x3)
 
 bool q6core_is_adsp_ready(void);
@@ -198,6 +199,126 @@ struct avcs_cmd_load_unload_topo_modules {
 	uint32_t topology_id;
 } __packed;
 
+#define AVCS_LOAD_MODULES 1
+
+#define AVCS_UNLOAD_MODULES 0
+
+#define AVCS_CMD_LOAD_MODULES           0x00012989
+
+#define AVCS_CMD_UNLOAD_MODULES         0x0001298A
+
+#define AVCS_CMD_RSP_LOAD_MODULES       0x0001298B
+
+/*
+ * Module is generic, such as a preprocessor,
+ * postprocessor, or volume control
+ *  module.
+ */
+#define AMDB_MODULE_TYPE_GENERIC           0
+
+/** Module is a decoder. */
+#define AMDB_MODULE_TYPE_DECODER           1
+
+/** Module is an encoder. */
+#define AMDB_MODULE_TYPE_ENCODER           2
+
+/** Module is a converter. */
+#define AMDB_MODULE_TYPE_CONVERTER         3
+
+/** Module is a packetizer. */
+#define AMDB_MODULE_TYPE_PACKETIZER        4
+
+/** Module is a depacketizer. */
+#define AMDB_MODULE_TYPE_DEPACKETIZER      5
+
+
+struct avcs_load_unload_modules_sec_payload {
+	uint32_t       module_type;
+	/*
+	 * < Type of module.
+
+	 * @values
+	 * - #AMDB_MODULE_TYPE_GENERIC
+	 * - #AMDB_MODULE_TYPE_DECODER
+	 * - #AMDB_MODULE_TYPE_ENCODER
+	 * - #AMDB_MODULE_TYPE_CONVERTER
+	 * - #AMDB_MODULE_TYPE_PACKETIZER
+	 * - #AMDB_MODULE_TYPE_DEPACKETIZER
+	 */
+
+
+	uint32_t       id1;
+	/*
+	 * < One of the following types of IDs:
+	 * - Format ID for the encoder, decoder, and packetizer module types
+	 * - Module ID for the generic module type
+	 * - Source format ID for the converter module type
+	 */
+
+	uint32_t       id2;
+	/*
+	 * < Sink format ID for the converter module type.
+	 * Zero for other module types
+	 */
+
+	uint32_t handle_lsw;
+	/* < LSW of the Handle to the module loaded */
+
+	uint32_t handle_msw;
+	/* < MSW of the Handle to the module loaded. */
+} __packed;
+
+struct avcs_load_unload_modules_payload {
+	uint32_t num_modules;
+	/**< Number of modules being registered */
+
+	struct avcs_load_unload_modules_sec_payload load_unload_info[0];
+	/*
+	 * < Load/unload information for num_modules.
+	 * It will be of type avcs_load_unload_info_t[num_modules]
+	 */
+} __packed;
+
+struct avcs_load_unload_modules_meminfo {
+	uint32_t                  data_payload_addr_lsw;
+	/**< Lower 32 bits of the 64-bit data payload address. */
+
+	uint32_t                  data_payload_addr_msw;
+	/**< Upper 32 bits of the 64-bit data payload address. */
+
+	uint32_t                  mem_map_handle;
+	/*
+	 * < Unique identifier for an address. The aDSP returns this memory map
+	 * handle through the #AVCS_CMD_SHARED_MEM_MAP_REGIONS command.
+
+	 * @values @vertspace{-2}
+	 * - NULL -- Parameter data payloads are within the message payload
+	 * (in-band).
+	 * - Non-NULL -- Parameter data payloads begin at the address specified
+	 * in the data_payload_addr_lsw and data_payload_addr_msw fields
+	 * (out-of-band).
+
+	 * The client can choose in-band or out-of-band
+	 */
+
+	uint32_t                  buffer_size;
+	/*
+	 * < Actual size (in bytes) of the valid data
+	 * in the data payload address.
+	 */
+} __packed;
+
+struct avcs_cmd_dynamic_modules {
+	struct apr_hdr hdr;
+	struct avcs_load_unload_modules_meminfo meminfo;
+	struct avcs_load_unload_modules_payload payload;
+} __packed;
+
+
+int32_t q6core_avcs_load_unload_modules(struct avcs_load_unload_modules_payload *payload,
+				uint32_t preload_type);
+
+
 /* This command allows a remote client(HLOS) creates a client to LPASS NPA
  * resource node. Currently, this command supports only the NPA Sleep resource
  * "/island/core/drivers" node ID.