Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1101322b authored by jabashque's avatar jabashque
Browse files

qcacmn: lock reo_cmd_lock earlier in dp_reo_send_cmd to avoid race cond



In dp_reo_send_cmd(), when adding callback info to reo_cmd_list, we lock
and unlock reo_cmd_lock just before and just after adding the info to
the reo_cmd_list tailq.

The functions that dp_reo_send_cmd() call ends access to
reo_cmd_ring before dp_reo_send_cmd() adds the callback info to
reo_cmd_list. As such, there is a period of time where
dp_reo_status_ring_handler() can end up processing the REO device's
response from reo_status_ring and iterating through reo_cmd_list, all
before dp_reo_send_cmd() can get a chance to add the callback info to
reo_cmd_list.

Since dp_reo_status_ring_handler() also acquires a lock on reo_cmd_lock
before iterating through reo_cmd_list, we can instead have
dp_reo_send_cmd() lock reo_cmd_lock before even writing the cmd to
reo_cmd_ring. That way, if dp_reo_status_ring_handler() manages to
process the REO device's response before dp_reo_send_cmd() can add the
callback info, then dp_reo_status_ring_handler() will be blocked from
iterating through reo_cmd_list due to the lock on reo_cmd_lock.

Co-authored-by: default avatarAndrea <andrea@cpushare.com>
Change-Id: I955fd333631311e88ba701c0154c704def3d8ea9
parent a83a355d
Loading
Loading
Loading
Loading
+27 −13
Original line number Original line Diff line number Diff line
@@ -61,8 +61,20 @@ QDF_STATUS dp_reo_send_cmd(struct dp_soc *soc, enum hal_reo_cmd_type type,
		     struct hal_reo_cmd_params *params,
		     struct hal_reo_cmd_params *params,
		     void (*callback_fn), void *data)
		     void (*callback_fn), void *data)
{
{
	struct dp_reo_cmd_info *reo_cmd;
	struct dp_reo_cmd_info *reo_cmd = NULL;
	int num;
	int num;
	QDF_STATUS ret;

	if (callback_fn) {
		reo_cmd = qdf_mem_malloc(sizeof(*reo_cmd));
		if (!reo_cmd) {
			dp_err_log("alloc failed for REO cmd:%d!!",
				   type);
			ret = QDF_STATUS_E_NOMEM;
			goto fail;
		}
		qdf_spin_lock_bh(&soc->rx.reo_cmd_lock);
	}


	switch (type) {
	switch (type) {
	case CMD_GET_QUEUE_STATS:
	case CMD_GET_QUEUE_STATS:
@@ -91,34 +103,36 @@ QDF_STATUS dp_reo_send_cmd(struct dp_soc *soc, enum hal_reo_cmd_type type,
		break;
		break;
	default:
	default:
		dp_err_log("Invalid REO command type: %d", type);
		dp_err_log("Invalid REO command type: %d", type);
		return QDF_STATUS_E_INVAL;
		ret = QDF_STATUS_E_INVAL;
		goto fail_unlock;
	};
	};


	dp_reo_cmd_srng_event_record(soc, type, num);
	dp_reo_cmd_srng_event_record(soc, type, num);


	if (num < 0) {
	if (num < 0) {
		return QDF_STATUS_E_FAILURE;
		ret = QDF_STATUS_E_FAILURE;
		goto fail_unlock;
	}
	}


	if (callback_fn) {
	if (callback_fn) {
		reo_cmd = qdf_mem_malloc(sizeof(*reo_cmd));
		if (!reo_cmd) {
			dp_err_log("alloc failed for REO cmd:%d!!",
				   type);
			return QDF_STATUS_E_NOMEM;
		}

		reo_cmd->cmd = num;
		reo_cmd->cmd = num;
		reo_cmd->cmd_type = type;
		reo_cmd->cmd_type = type;
		reo_cmd->handler = callback_fn;
		reo_cmd->handler = callback_fn;
		reo_cmd->data = data;
		reo_cmd->data = data;
		qdf_spin_lock_bh(&soc->rx.reo_cmd_lock);
		TAILQ_INSERT_TAIL(&soc->rx.reo_cmd_list, reo_cmd,
		TAILQ_INSERT_TAIL(&soc->rx.reo_cmd_list, reo_cmd,
				  reo_cmd_list_elem);
				  reo_cmd_list_elem);
		qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock);
		reo_cmd = NULL;
	}
	}


	return QDF_STATUS_SUCCESS;
	ret = QDF_STATUS_SUCCESS;

fail_unlock:
	if (callback_fn)
		qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock);
fail:
	if (reo_cmd)
		qdf_mem_free(reo_cmd);
	return ret;
}
}


uint32_t dp_reo_status_ring_handler(struct dp_intr *int_ctx, struct dp_soc *soc)
uint32_t dp_reo_status_ring_handler(struct dp_intr *int_ctx, struct dp_soc *soc)