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

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

Merge "msm: ipa3: ensure IPA registers are dumped by modem"

parents a5fe84a5 2204388f
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -97,6 +97,17 @@ Optional properties:
- clock-names: This property shall contain the clock input names used
    by driver in same order as the clocks property.This should be "iface_clk"

IPA SMP2P sub nodes

-compatible: "qcom,smp2pgpio-map-ipa-1-out" - represents the out gpio from
					      ipa driver to modem.

-compatible: "qcom,smp2pgpio-map-ipa-1-in" - represents the in gpio to
					     ipa driver from modem.

-gpios: Binding to the gpio defined in XXX-smp2p.dtsi


Example:

qcom,ipa@fd4c0000 {
@@ -147,4 +158,15 @@ qcom,ipa@fd4c0000 {
		qcom,descriptor-fifo-offset = <0xd00>;
		qcom,descriptor-fifo-size = <0x300>;
	};

	/* smp2p gpio information */
	qcom,smp2pgpio_map_ipa_1_out {
		compatible = "qcom,smp2pgpio-map-ipa-1-out";
		gpios = <&smp2pgpio_ipa_1_out 0 0>;
	};

	qcom,smp2pgpio_map_ipa_1_in {
		compatible = "qcom,smp2pgpio-map-ipa-1-in";
		gpios = <&smp2pgpio_ipa_1_in 0 0>;
	};
};
+28 −28
Original line number Diff line number Diff line
@@ -2648,6 +2648,8 @@ static struct of_device_id ipa_plat_drv_match[] = {
	{ .compatible = "qcom,ipa-smmu-ap-cb", },
	{ .compatible = "qcom,ipa-smmu-wlan-cb", },
	{ .compatible = "qcom,ipa-smmu-uc-cb", },
	{ .compatible = "qcom,smp2pgpio-map-ipa-1-in", },
	{ .compatible = "qcom,smp2pgpio-map-ipa-1-out", },
	{}
};

@@ -2655,21 +2657,29 @@ static int ipa_generic_plat_drv_probe(struct platform_device *pdev_p)
{
	int result;

	pr_debug("ipa: IPA driver probing started\n");
	/*
	* IPA probe function can be called for multiple times as the same probe
	* function handles multiple compatibilities
	*/
	pr_debug("ipa: IPA driver probing started for %s\n",
		pdev_p->dev.of_node->name);

	if (!ipa_api_ctrl) {
		ipa_api_ctrl = kzalloc(sizeof(*ipa_api_ctrl), GFP_KERNEL);
		if (!ipa_api_ctrl)
			return -ENOMEM;

		/* Get IPA HW Version */
	result = of_property_read_u32(pdev_p->dev.of_node, "qcom,ipa-hw-ver",
		&ipa_api_hw_type);
		result = of_property_read_u32(pdev_p->dev.of_node,
			"qcom,ipa-hw-ver", &ipa_api_hw_type);
		if ((result) || (ipa_api_hw_type == 0)) {
			pr_err("ipa: get resource failed for ipa-hw-ver!\n");
		result = -ENODEV;
		goto fail;
			kfree(ipa_api_ctrl);
			ipa_api_ctrl = 0;
			return -ENODEV;
		}
		pr_debug("ipa: ipa_api_hw_type = %d", ipa_api_hw_type);
	}

	/* call probe based on IPA HW version */
	switch (ipa_api_hw_type) {
@@ -2679,30 +2689,20 @@ static int ipa_generic_plat_drv_probe(struct platform_device *pdev_p)
	case IPA_HW_v2_6L:
		result = ipa_plat_drv_probe(pdev_p, ipa_api_ctrl,
			ipa_plat_drv_match);
		if (result) {
			pr_err("ipa: ipa_plat_drv_probe failed\n");
			goto fail;
		}
		break;
	case IPA_HW_v3_0:
	case IPA_HW_v3_1:
		result = ipa3_plat_drv_probe(pdev_p, ipa_api_ctrl,
			ipa_plat_drv_match);
		if (result) {
			pr_err("ipa: ipa3_plat_drv_probe failed\n");
			goto fail;
		}
		break;
	default:
		pr_err("ipa: unsupported version %d\n", ipa_api_hw_type);
		result = -EPERM;
		goto fail;
		return -EPERM;
	}

	return 0;
fail:
	kfree(ipa_api_ctrl);
	ipa_api_ctrl = 0;
	if (result && result != -EPROBE_DEFER)
		pr_err("ipa: ipa_plat_drv_probe failed\n");

	return result;
}

+145 −10
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/rbtree.h>
#include <linux/of_gpio.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/msm-bus.h>
@@ -41,6 +42,10 @@
#define CREATE_TRACE_POINTS
#include "ipa_trace.h"

#define IPA_GPIO_IN_QUERY_CLK_IDX 0
#define IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX 0
#define IPA_GPIO_OUT_CLK_VOTE_IDX 1

#define IPA_SUMMING_THRESHOLD (0x10)
#define IPA_PIPE_MEM_START_OFST (0x0)
#define IPA_PIPE_MEM_SIZE (0x0)
@@ -3530,6 +3535,62 @@ static void ipa3_destroy_flt_tbl_idrs(void)
	}
}

static void ipa3_freeze_clock_vote_and_notify_modem(void)
{
	int res;
	u32 ipa_clk_state;
	struct ipa3_active_client_logging_info log_info;

	if (ipa3_ctx->smp2p_info.res_sent)
		return;

	IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "FREEZE_VOTE");
	res = ipa3_inc_client_enable_clks_no_block(&log_info);
	if (res)
		ipa_clk_state = 0;
	else
		ipa_clk_state = 1;

	if (ipa3_ctx->smp2p_info.out_base_id) {
		gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
			IPA_GPIO_OUT_CLK_VOTE_IDX, ipa_clk_state);
		gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
			IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 1);
		ipa3_ctx->smp2p_info.res_sent = true;
	} else {
		IPAERR("smp2p out gpio not assigned\n");
	}

	IPADBG("IPA clocks are %s\n", ipa_clk_state ? "ON" : "OFF");
}

static int ipa3_panic_notifier(struct notifier_block *this,
	unsigned long event, void *ptr)
{
	int res;

	ipa3_freeze_clock_vote_and_notify_modem();

	IPADBG("Calling uC panic handler\n");
	res = ipa3_uc_panic_notifier(this, event, ptr);
	if (res)
		IPAERR("uC panic handler failed %d\n" , res);

	return NOTIFY_DONE;
}

static struct notifier_block ipa3_panic_blk = {
	.notifier_call = ipa3_panic_notifier,
	/* IPA panic handler needs to run before modem shuts down */
	.priority = INT_MAX,
};

static void ipa3_register_panic_hdlr(void)
{
	atomic_notifier_chain_register(&panic_notifier_list,
		&ipa3_panic_blk);
}

static void ipa3_trigger_ipa_ready_cbs(void)
{
	struct ipa3_ready_cb_info *info;
@@ -4711,6 +4772,66 @@ static int ipa_smmu_ap_cb_probe(struct device *dev)
	return result;
}

static irqreturn_t ipa3_smp2p_modem_clk_query_isr(int irq, void *ctxt)
{
	ipa3_freeze_clock_vote_and_notify_modem();

	return IRQ_HANDLED;
}

static int ipa3_smp2p_probe(struct device *dev)
{
	struct device_node *node = dev->of_node;
	int res;

	IPADBG("node->name=%s\n", node->name);
	if (strcmp("qcom,smp2pgpio_map_ipa_1_out", node->name) == 0) {
		res = of_get_gpio(node, 0);
		if (res < 0) {
			IPADBG("of_get_gpio returned %d\n", res);
			return res;
		}

		ipa3_ctx->smp2p_info.out_base_id = res;
		IPADBG("smp2p out_base_id=%d\n",
			ipa3_ctx->smp2p_info.out_base_id);
	} else if (strcmp("qcom,smp2pgpio_map_ipa_1_in", node->name) == 0) {
		int irq;

		res = of_get_gpio(node, 0);
		if (res < 0) {
			IPADBG("of_get_gpio returned %d\n", res);
			return res;
		}

		ipa3_ctx->smp2p_info.in_base_id = res;
		IPADBG("smp2p in_base_id=%d\n",
			ipa3_ctx->smp2p_info.in_base_id);

		/* register for modem clk query */
		irq = gpio_to_irq(ipa3_ctx->smp2p_info.in_base_id +
			IPA_GPIO_IN_QUERY_CLK_IDX);
		if (irq < 0) {
			IPAERR("gpio_to_irq failed %d\n", irq);
			return -ENODEV;
		}
		IPADBG("smp2p irq#=%d\n", irq);
		res = request_irq(irq,
			(irq_handler_t)ipa3_smp2p_modem_clk_query_isr,
			IRQF_TRIGGER_RISING, "ipa_smp2p_clk_vote", dev);
		if (res) {
			IPAERR("fail to register smp2p irq=%d\n", irq);
			return -ENODEV;
		}
		res = enable_irq_wake(ipa3_ctx->smp2p_info.in_base_id +
			IPA_GPIO_IN_QUERY_CLK_IDX);
		if (res)
			IPAERR("failed to enable irq wake\n");
	}

	return 0;
}

int ipa3_plat_drv_probe(struct platform_device *pdev_p,
	struct ipa_api_controller *api_ctrl, struct of_device_id *pdrv_match)
{
@@ -4718,6 +4839,7 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p,
	struct device *dev = &pdev_p->dev;

	IPADBG("IPA driver probing started\n");
	IPADBG("dev->of_node->name = %s\n", dev->of_node->name);

	if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-ap-cb"))
		return ipa_smmu_ap_cb_probe(dev);
@@ -4728,6 +4850,14 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p,
	if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-uc-cb"))
		return ipa_smmu_uc_cb_probe(dev);

	if (of_device_is_compatible(dev->of_node,
	    "qcom,smp2pgpio-map-ipa-1-in"))
		return ipa3_smp2p_probe(dev);

	if (of_device_is_compatible(dev->of_node,
	    "qcom,smp2pgpio-map-ipa-1-out"))
		return ipa3_smp2p_probe(dev);

	master_dev = dev;
	if (!ipa3_pdev)
		ipa3_pdev = pdev_p;
@@ -4744,10 +4874,15 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p,
		return result;
	}

	if (of_property_read_bool(pdev_p->dev.of_node, "qcom,arm-smmu")) {
		arm_smmu = true;
	result = of_platform_populate(pdev_p->dev.of_node,
		pdrv_match, NULL, &pdev_p->dev);
	if (result) {
		IPAERR("failed to populate platform\n");
		return result;
	}

	if (of_property_read_bool(pdev_p->dev.of_node, "qcom,arm-smmu")) {
		arm_smmu = true;
	} else if (of_property_read_bool(pdev_p->dev.of_node,
				"qcom,msm-smmu")) {
		IPAERR("Legacy IOMMU not supported\n");
@@ -4759,6 +4894,7 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p,
			IPAERR("DMA set mask failed\n");
			return -EOPNOTSUPP;
		}
	}

	if (!ipa3_bus_scale_table)
		ipa3_bus_scale_table = msm_bus_cl_get_pdata(pdev_p);
@@ -4769,7 +4905,6 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p,
		IPAERR("ipa3_init failed\n");
		return result;
	}
	}

	return result;
}
+9 −1
Original line number Diff line number Diff line
@@ -1419,6 +1419,12 @@ struct ipa3_hash_tuple {
	bool meta_data;
};

struct ipa3_smp2p_info {
	u32 out_base_id;
	u32 in_base_id;
	bool res_sent;
};

/**
 * struct ipa3_ready_cb_info - A list of all the registrations
 *  for an indication of IPA driver readiness
@@ -1642,6 +1648,7 @@ struct ipa3_context {
	bool ipa_initialization_complete;
	struct list_head ipa_ready_cb_list;
	struct completion init_completion_obj;
	struct ipa3_smp2p_info smp2p_info;
};

/**
@@ -2418,7 +2425,6 @@ int ipa3_uc_loaded_check(void);
void ipa3_uc_load_notify(void);
int ipa3_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status,
		    bool polling_mode, unsigned long timeout_jiffies);
void ipa3_register_panic_hdlr(void);
void ipa3_uc_register_handlers(enum ipa3_hw_features feature,
			      struct ipa3_uc_hdlrs *hdlrs);
int ipa3_create_nat_device(void);
@@ -2480,6 +2486,8 @@ int ipa3_calc_extra_wrd_bytes(const struct ipa_ipfltri_rule_eq *attrib);
const char *ipa3_rm_resource_str(enum ipa_rm_resource_name resource_name);
int ipa3_restore_suspend_handler(void);
int ipa3_inject_dma_task_for_gsi(void);
int ipa3_uc_panic_notifier(struct notifier_block *this,
	unsigned long event, void *ptr);
void ipa3_inc_acquire_wakelock(void);
void ipa3_dec_release_wakelock(void);
int ipa3_load_fws(const struct firmware *firmware);
+2 −12
Original line number Diff line number Diff line
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2016, 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
@@ -397,7 +397,7 @@ static void ipa3_uc_event_handler(enum ipa_irq_type interrupt,

}

static int ipa3_uc_panic_notifier(struct notifier_block *this,
int ipa3_uc_panic_notifier(struct notifier_block *this,
		unsigned long event, void *ptr)
{
	int result = 0;
@@ -436,16 +436,6 @@ fail:
	return NOTIFY_DONE;
}

static struct notifier_block ipa3_uc_panic_blk = {
	.notifier_call  = ipa3_uc_panic_notifier,
};

void ipa3_register_panic_hdlr(void)
{
	atomic_notifier_chain_register(&panic_notifier_list,
			&ipa3_uc_panic_blk);
}

static void ipa3_uc_response_hdlr(enum ipa_irq_type interrupt,
				void *private_data,
				void *interrupt_data)