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

Commit 88e3b471 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "Merge commit '57c62991' msm-4.9_UPSTREAM_0130_PC91"

parents 177cafce 1245b0ca
Loading
Loading
Loading
Loading
+28 −5
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -196,6 +196,30 @@ int cam_context_handle_crm_flush_req(struct cam_context *ctx,
	return rc;
}

int cam_context_handle_crm_process_evt(struct cam_context *ctx,
	struct cam_req_mgr_link_evt_data *process_evt)
{
	int rc = 0;

	if (!ctx->state_machine) {
		CAM_ERR(CAM_CORE, "Context is not ready");
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].crm_ops.process_evt) {
		rc = ctx->state_machine[ctx->state].crm_ops.process_evt(ctx,
			process_evt);
	} else {
		/* handling of this message is optional */
		CAM_DBG(CAM_CORE, "No crm process evt in dev %d, state %d",
			ctx->dev_hdl, ctx->state);
	}
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_handle_acquire_dev(struct cam_context *ctx,
	struct cam_acquire_dev_cmd *cmd)
{
@@ -257,10 +281,10 @@ int cam_context_handle_release_dev(struct cam_context *ctx,
int cam_context_handle_flush_dev(struct cam_context *ctx,
	struct cam_flush_dev_cmd *cmd)
{
	int rc;
	int rc = 0;

	if (!ctx->state_machine) {
		CAM_ERR(CAM_CORE, "context is not ready");
		CAM_ERR(CAM_CORE, "Context is not ready");
		return -EINVAL;
	}

@@ -274,9 +298,8 @@ int cam_context_handle_flush_dev(struct cam_context *ctx,
		rc = ctx->state_machine[ctx->state].ioctl_ops.flush_dev(
			ctx, cmd);
	} else {
		CAM_ERR(CAM_CORE, "No flush device in dev %d, state %d",
		CAM_WARN(CAM_CORE, "No flush device in dev %d, state %d",
			ctx->dev_hdl, ctx->state);
		rc = -EPROTO;
	}
	mutex_unlock(&ctx->ctx_mutex);

+16 −1
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -110,6 +110,7 @@ struct cam_ctx_ioctl_ops {
 * @unlink:                Unlink the context
 * @apply_req:             Apply setting for the context
 * @flush_req:             Flush request to remove request ids
 * @process_evt:           Handle event notification from CRM.(optional)
 *
 */
struct cam_ctx_crm_ops {
@@ -123,6 +124,8 @@ struct cam_ctx_crm_ops {
			struct cam_req_mgr_apply_request *apply);
	int (*flush_req)(struct cam_context *ctx,
			struct cam_req_mgr_flush_request *flush);
	int (*process_evt)(struct cam_context *ctx,
			struct cam_req_mgr_link_evt_data *evt_data);
};


@@ -272,6 +275,18 @@ int cam_context_handle_crm_apply_req(struct cam_context *ctx,
int cam_context_handle_crm_flush_req(struct cam_context *ctx,
		struct cam_req_mgr_flush_request *apply);

/**
 * cam_context_handle_crm_process_evt()
 *
 * @brief:        Handle process event command
 *
 * @ctx:          Object pointer for cam_context
 * @process_evt:  process event command payload
 *
 */
int cam_context_handle_crm_process_evt(struct cam_context *ctx,
	struct cam_req_mgr_link_evt_data *process_evt);

/**
 * cam_context_handle_acquire_dev()
 *
+65 −18
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -430,6 +430,8 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx)
	uint32_t i;
	int rc = 0;

	CAM_DBG(CAM_CTXT, "E: NRT flush ctx");

	/*
	 * flush pending requests, take the sync lock to synchronize with the
	 * sync callback thread so that the sync cb thread does not try to
@@ -444,23 +446,33 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx)
	while (!list_empty(&temp_list)) {
		req = list_first_entry(&temp_list,
				struct cam_ctx_request, list);

		list_del_init(&req->list);
		req->flushed = 1;

		flush_args.flush_req_pending[flush_args.num_req_pending++] =
			req->req_priv;
		for (i = 0; i < req->num_out_map_entries; i++)
			if (req->out_map_entries[i].sync_id != -1)
				cam_sync_signal(req->out_map_entries[i].sync_id,
			if (req->out_map_entries[i].sync_id != -1) {
				rc = cam_sync_signal(
					req->out_map_entries[i].sync_id,
					CAM_SYNC_STATE_SIGNALED_ERROR);
				if (rc == -EALREADY) {
					CAM_ERR(CAM_CTXT,
						"Req: %llu already signalled, sync_id:%d",
						req->request_id,
						req->out_map_entries[i].
						sync_id);
					break;
				}
			}
	}
	mutex_unlock(&ctx->sync_mutex);

	if (ctx->hw_mgr_intf->hw_flush) {
		flush_args.num_req_active = 0;
		spin_lock(&ctx->lock);
		INIT_LIST_HEAD(&temp_list);
		list_splice_init(&ctx->active_req_list, &temp_list);
		list_for_each_entry(req, &temp_list, list) {
		list_for_each_entry(req, &ctx->active_req_list, list) {
			flush_args.flush_req_active[flush_args.num_req_active++]
				= req->req_priv;
		}
@@ -474,14 +486,31 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx)
		}
	}

	INIT_LIST_HEAD(&temp_list);
	spin_lock(&ctx->lock);
	list_splice_init(&ctx->active_req_list, &temp_list);
	INIT_LIST_HEAD(&ctx->active_req_list);
	spin_unlock(&ctx->lock);

	while (!list_empty(&temp_list)) {
		req = list_first_entry(&temp_list,
			struct cam_ctx_request, list);
		list_del_init(&req->list);
		for (i = 0; i < req->num_out_map_entries; i++)
		for (i = 0; i < req->num_out_map_entries; i++) {
			if (req->out_map_entries[i].sync_id != -1) {
				cam_sync_signal(req->out_map_entries[i].sync_id,
				rc = cam_sync_signal(
					req->out_map_entries[i].sync_id,
					CAM_SYNC_STATE_SIGNALED_ERROR);
				if (rc == -EALREADY) {
					CAM_ERR(CAM_CTXT,
						"Req: %llu already signalled ctx: %pK dev_name: %s dev_handle: %d ctx_state: %d",
						req->request_id, req->ctx,
						req->ctx->dev_name,
						req->ctx->dev_hdl,
						req->ctx->state);
					break;
				}
			}
		}

		spin_lock(&ctx->lock);
@@ -489,9 +518,10 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx)
		spin_unlock(&ctx->lock);
		req->ctx = NULL;
	}
	INIT_LIST_HEAD(&ctx->active_req_list);

	return rc;
	CAM_DBG(CAM_CTXT, "X: NRT flush ctx");

	return 0;
}

int32_t cam_context_flush_req_to_hw(struct cam_context *ctx,
@@ -502,6 +532,8 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx,
	uint32_t i;
	int rc = 0;

	CAM_DBG(CAM_CTXT, "E: NRT flush req");

	flush_args.num_req_pending = 0;
	flush_args.num_req_active = 0;
	mutex_lock(&ctx->sync_mutex);
@@ -510,7 +542,9 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx,
		if (req->request_id != cmd->req_id)
			continue;

		list_del_init(&req->list);
		req->flushed = 1;

		flush_args.flush_req_pending[flush_args.num_req_pending++] =
			req->req_priv;
		break;
@@ -525,6 +559,8 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx,
				if (req->request_id != cmd->req_id)
					continue;

				list_del_init(&req->list);

				flush_args.flush_req_active[
					flush_args.num_req_active++] =
					req->req_priv;
@@ -543,20 +579,31 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx,

	if (req) {
		if (flush_args.num_req_pending || flush_args.num_req_active) {
			list_del_init(&req->list);
			for (i = 0; i < req->num_out_map_entries; i++)
				if (req->out_map_entries[i].sync_id != -1)
					cam_sync_signal(
				if (req->out_map_entries[i].sync_id != -1) {
					rc = cam_sync_signal(
						req->out_map_entries[i].sync_id,
						CAM_SYNC_STATE_SIGNALED_ERROR);
					if (rc == -EALREADY) {
						CAM_ERR(CAM_CTXT,
							"Req: %llu already signalled, sync_id:%d",
							req->request_id,
							req->out_map_entries[i].
							sync_id);
						break;
					}
				}
			if (flush_args.num_req_active) {
				spin_lock(&ctx->lock);
				list_add_tail(&req->list, &ctx->free_req_list);
				spin_unlock(&ctx->lock);
				req->ctx = NULL;
			}
		}
	}
	CAM_DBG(CAM_CTXT, "X: NRT flush req");

	return rc;
	return 0;
}

int32_t cam_context_flush_dev_to_hw(struct cam_context *ctx,
+22 −2
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -220,7 +220,7 @@ static int __cam_node_handle_flush_dev(struct cam_node *node,

	rc = cam_context_handle_flush_dev(ctx, flush);
	if (rc)
		CAM_ERR(CAM_CORE, "FLush failure for node %s", node->name);
		CAM_ERR(CAM_CORE, "Flush failure for node %s", node->name);

	return rc;
}
@@ -342,6 +342,25 @@ static int __cam_node_crm_flush_req(struct cam_req_mgr_flush_request *flush)
	return cam_context_handle_crm_flush_req(ctx, flush);
}

static int __cam_node_crm_process_evt(
	struct cam_req_mgr_link_evt_data *evt_data)
{
	struct cam_context *ctx = NULL;

	if (!evt_data) {
		CAM_ERR(CAM_CORE, "Invalid process event request payload");
		return -EINVAL;
	}

	ctx = (struct cam_context *) cam_get_device_priv(evt_data->dev_hdl);
	if (!ctx) {
		CAM_ERR(CAM_CORE, "Can not get context for handle %d",
			evt_data->dev_hdl);
		return -EINVAL;
	}
	return cam_context_handle_crm_process_evt(ctx, evt_data);
}

int cam_node_deinit(struct cam_node *node)
{
	if (node)
@@ -394,6 +413,7 @@ int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf,
	node->crm_node_intf.get_dev_info = __cam_node_crm_get_dev_info;
	node->crm_node_intf.link_setup = __cam_node_crm_link_setup;
	node->crm_node_intf.flush_req = __cam_node_crm_flush_req;
	node->crm_node_intf.process_evt = __cam_node_crm_process_evt;

	mutex_init(&node->list_mutex);
	INIT_LIST_HEAD(&node->free_ctx_list);
+70 −17
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -16,12 +16,19 @@
#include <linux/msm-bus.h>
#include <linux/pm_opp.h>
#include <linux/slab.h>
#include <linux/module.h>

#include "cam_cpas_hw.h"
#include "cam_cpas_hw_intf.h"
#include "cam_cpas_soc.h"

#define CAM_CPAS_AXI_MIN_BW (2048 * 1024)
#define CAM_CPAS_AXI_MIN_MNOC_AB_BW   (2048 * 1024)
#define CAM_CPAS_AXI_MIN_MNOC_IB_BW   (2048 * 1024)
#define CAM_CPAS_AXI_MIN_CAMNOC_AB_BW (2048 * 1024)
#define CAM_CPAS_AXI_MIN_CAMNOC_IB_BW (3000000000L)

static uint cam_min_camnoc_ib_bw;
module_param(cam_min_camnoc_ib_bw, uint, 0644);

int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw,
	enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info)
@@ -84,11 +91,19 @@ static int cam_cpas_util_vote_bus_client_level(
}

static int cam_cpas_util_vote_bus_client_bw(
	struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib)
	struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib,
	bool camnoc_bw)
{
	struct msm_bus_paths *path;
	struct msm_bus_scale_pdata *pdata;
	int idx = 0;
	uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW;

	if (cam_min_camnoc_ib_bw > 0)
		min_camnoc_ib_bw = (uint64_t)cam_min_camnoc_ib_bw * 1000000L;

	CAM_DBG(CAM_CPAS, "cam_min_camnoc_ib_bw = %d, min_camnoc_ib_bw=%llu",
		cam_min_camnoc_ib_bw, min_camnoc_ib_bw);

	if (!bus_client->valid) {
		CAM_ERR(CAM_CPAS, "bus client not valid");
@@ -118,11 +133,19 @@ static int cam_cpas_util_vote_bus_client_bw(
	bus_client->curr_vote_level = idx;
	mutex_unlock(&bus_client->lock);

	if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_BW))
		ab = CAM_CPAS_AXI_MIN_BW;
	if (camnoc_bw == true) {
		if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_CAMNOC_AB_BW))
			ab = CAM_CPAS_AXI_MIN_CAMNOC_AB_BW;

	if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_BW))
		ib = CAM_CPAS_AXI_MIN_BW;
		if ((ib > 0) && (ib < min_camnoc_ib_bw))
			ib = min_camnoc_ib_bw;
	} else {
		if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_MNOC_AB_BW))
			ab = CAM_CPAS_AXI_MIN_MNOC_AB_BW;

		if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_MNOC_IB_BW))
			ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW;
	}

	pdata = bus_client->pdata;
	path = &(pdata->usecase[idx]);
@@ -205,7 +228,7 @@ static int cam_cpas_util_unregister_bus_client(
		return -EINVAL;

	if (bus_client->dyn_vote)
		cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0);
		cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false);
	else
		cam_cpas_util_vote_bus_client_level(bus_client, 0);

@@ -370,7 +393,7 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw,
	list_for_each_entry_safe(curr_port, temp_port,
		&cpas_core->axi_ports_list_head, sibling_port) {
		rc = cam_cpas_util_vote_bus_client_bw(&curr_port->mnoc_bus,
			mnoc_bw, mnoc_bw);
			mnoc_bw, mnoc_bw, false);
		if (rc) {
			CAM_ERR(CAM_CPAS,
				"Failed in mnoc vote, enable=%d, rc=%d",
@@ -380,13 +403,13 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw,

		if (soc_private->axi_camnoc_based) {
			cam_cpas_util_vote_bus_client_bw(
				&curr_port->camnoc_bus, 0, camnoc_bw);
				&curr_port->camnoc_bus, 0, camnoc_bw, true);
			if (rc) {
				CAM_ERR(CAM_CPAS,
					"Failed in mnoc vote, enable=%d, %d",
					enable, rc);
				cam_cpas_util_vote_bus_client_bw(
					&curr_port->mnoc_bus, 0, 0);
					&curr_port->mnoc_bus, 0, 0, false);
				goto remove_ahb_vote;
			}
		}
@@ -571,7 +594,7 @@ static int cam_cpas_util_apply_client_axi_vote(
		camnoc_bw, mnoc_bw);

	rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus,
		mnoc_bw, mnoc_bw);
		mnoc_bw, mnoc_bw, false);
	if (rc) {
		CAM_ERR(CAM_CPAS,
			"Failed in mnoc vote ab[%llu] ib[%llu] rc=%d",
@@ -581,7 +604,7 @@ static int cam_cpas_util_apply_client_axi_vote(

	if (soc_private->axi_camnoc_based) {
		rc = cam_cpas_util_vote_bus_client_bw(&axi_port->camnoc_bus,
			0, camnoc_bw);
			0, camnoc_bw, true);
		if (rc) {
			CAM_ERR(CAM_CPAS,
				"Failed camnoc vote ab[%llu] ib[%llu] rc=%d",
@@ -880,9 +903,11 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args,
		goto done;

	if (cpas_core->streamon_clients == 0) {
		atomic_set(&cpas_core->irq_count, 1);
		rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info,
			applied_level);
		if (rc) {
			atomic_set(&cpas_core->irq_count, 0);
			CAM_ERR(CAM_CPAS, "enable_resorce failed, rc=%d", rc);
			goto done;
		}
@@ -890,14 +915,17 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args,
		if (cpas_core->internal_ops.power_on) {
			rc = cpas_core->internal_ops.power_on(cpas_hw);
			if (rc) {
				atomic_set(&cpas_core->irq_count, 0);
				cam_cpas_soc_disable_resources(
					&cpas_hw->soc_info);
					&cpas_hw->soc_info, true, true);
				CAM_ERR(CAM_CPAS,
					"failed in power_on settings rc=%d",
					rc);
				goto done;
			}
		}
		CAM_DBG(CAM_CPAS, "irq_count=%d\n",
			atomic_read(&cpas_core->irq_count));
		cpas_hw->hw_state = CAM_HW_STATE_POWER_UP;
	}

@@ -912,6 +940,10 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args,
	return rc;
}

static int _check_irq_count(struct cam_cpas *cpas_core)
{
	return (atomic_read(&cpas_core->irq_count) > 0) ? 0 : 1;
}

static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
	uint32_t arg_size)
@@ -924,6 +956,7 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
	struct cam_ahb_vote ahb_vote;
	struct cam_axi_vote axi_vote;
	int rc = 0;
	long result;

	if (!hw_priv || !stop_args) {
		CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK",
@@ -972,11 +1005,29 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
			}
		}

		rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
		rc = cam_cpas_soc_disable_irq(&cpas_hw->soc_info);
		if (rc) {
			CAM_ERR(CAM_CPAS, "disable_irq failed, rc=%d", rc);
			goto done;
		}

		/* Wait for any IRQs still being handled */
		atomic_dec(&cpas_core->irq_count);
		result = wait_event_timeout(cpas_core->irq_count_wq,
			_check_irq_count(cpas_core), HZ);
		if (result == 0) {
			CAM_ERR(CAM_CPAS, "Wait failed: irq_count=%d",
				atomic_read(&cpas_core->irq_count));
		}

		rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info,
			true, false);
		if (rc) {
			CAM_ERR(CAM_CPAS, "disable_resorce failed, rc=%d", rc);
			goto done;
		}
		CAM_DBG(CAM_CPAS, "Disabled all the resources: irq_count=%d\n",
			atomic_read(&cpas_core->irq_count));
		cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
	}

@@ -1427,6 +1478,8 @@ int cam_cpas_hw_probe(struct platform_device *pdev,
	soc_private = (struct cam_cpas_private_soc *)
		cpas_hw->soc_info.soc_private;
	cpas_core->num_clients = soc_private->num_clients;
	atomic_set(&cpas_core->irq_count, 0);
	init_waitqueue_head(&cpas_core->irq_count_wq);

	if (internal_ops->setup_regbase) {
		rc = internal_ops->setup_regbase(&cpas_hw->soc_info,
@@ -1482,7 +1535,7 @@ int cam_cpas_hw_probe(struct platform_device *pdev,
	if (rc)
		goto disable_soc_res;

	rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
	rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true);
	if (rc) {
		CAM_ERR(CAM_CPAS, "failed in soc_disable_resources, rc=%d", rc);
		goto remove_default_vote;
@@ -1500,7 +1553,7 @@ int cam_cpas_hw_probe(struct platform_device *pdev,
	return 0;

disable_soc_res:
	cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
	cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true);
remove_default_vote:
	cam_cpas_util_vote_default_ahb_axi(cpas_hw, false);
axi_cleanup:
Loading