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

Commit 795434e6 authored by Asha Magadi Venkateshamurthy's avatar Asha Magadi Venkateshamurthy Committed by Swetha Chikkaboraiah
Browse files

msm: ipa: Add ipa rm support for ipa_v2



Ipa rm mechanism is added to support ipa_v2 for
kernel msm-4.19.

Change-Id: Ia537c9ccf26e7e304a31a6d9dd26834c194da9d3
Signed-off-by: default avatarAsha Magadi Venkateshamurthy <amagad@codeaurora.org>
Signed-off-by: default avatarSwetha Chikkaboraiah <schikk@codeaurora.org>
parent 602a398f
Loading
Loading
Loading
Loading
+24 −8
Original line number Diff line number Diff line
@@ -14,7 +14,6 @@
#include <linux/ipa_uc_offload.h>
#include <linux/pci.h>
#include "ipa_api.h"
#include "ipa_v3/ipa_i.h"

/*
 * The following for adding code (ie. for EMULATION) not found on x86.
@@ -2883,18 +2882,23 @@ enum ipa_client_type ipa_get_client_mapping(int pipe_idx)
EXPORT_SYMBOL(ipa_get_client_mapping);

/**
 * ipa_get_rm_resource_from_ep() - this function is part of the deprecated
 * RM mechanism but is still used by some drivers so we kept the definition.
 * ipa_get_rm_resource_from_ep() - get the IPA_RM resource which is related to
 * the supplied pipe index.
 *
 * @pipe_idx:
 *
 * Return value: IPA_RM resource related to the pipe, -1 if a resource was not
 * found.
 */

enum ipa_rm_resource_name ipa_get_rm_resource_from_ep(int pipe_idx)
{
	IPAERR("IPA RM is not supported idx=%d\n", pipe_idx);
	return -EFAULT;
}
EXPORT_SYMBOL(ipa_get_rm_resource_from_ep);
	int ret;

	IPA_API_DISPATCH_RETURN(ipa_get_rm_resource_from_ep, pipe_idx);

	return ret;
}
EXPORT_SYMBOL(ipa_get_rm_resource_from_ep);

/**
 * ipa_get_modem_cfg_emb_pipe_flt()- Return ipa_ctx->modem_cfg_emb_pipe_flt
@@ -3792,6 +3796,18 @@ int ipa_get_prot_id(enum ipa_client_type client)
}
EXPORT_SYMBOL(ipa_get_prot_id);

/**
 * ipa_pm_is_used() - Returns if IPA PM framework is used
 */
bool ipa_pm_is_used(void)
{
	bool ret;

	IPA_API_DISPATCH_RETURN(ipa_pm_is_used);

	return ret;
}

static const struct dev_pm_ops ipa_pm_ops = {
	.suspend_late = ipa_ap_suspend,
	.resume_early = ipa_ap_resume,
+284 −15
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#define DEBUGFS_DIR_NAME "rndis_ipa"
#define DEBUGFS_AGGR_DIR_NAME "rndis_ipa_aggregation"
#define NETDEV_NAME "rndis"
#define DRV_RESOURCE_ID IPA_RM_RESOURCE_RNDIS_PROD
#define IPV4_HDR_NAME "rndis_eth_ipv4"
#define IPV6_HDR_NAME "rndis_eth_ipv6"
#define IPA_TO_USB_CLIENT IPA_CLIENT_USB_CONS
@@ -159,6 +160,7 @@ enum rndis_ipa_operation {
 * @rx_dropped: number of filtered out Rx packets
 * @rx_dump_enable: dump all Rx packets
 * @icmp_filter: allow all ICMP packet to pass through the filters
 * @rm_enable: flag that enable/disable Resource manager request prior to Tx
 * @deaggregation_enable: enable/disable IPA HW deaggregation logic
 * @during_xmit_error: flags that indicate that the driver is in a middle
 *  of error handling in Tx path
@@ -194,6 +196,7 @@ struct rndis_ipa_dev {
	u32 rx_dropped;
	bool rx_dump_enable;
	bool icmp_filter;
	bool rm_enable;
	bool deaggregation_enable;
	bool during_xmit_error;
	struct dentry *directory;
@@ -255,10 +258,18 @@ static int rndis_ipa_hdrs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx);
static struct net_device_stats *rndis_ipa_get_stats(struct net_device *net);
static int rndis_ipa_register_properties(char *netdev_name, bool is_vlan_mode);
static int rndis_ipa_deregister_properties(char *netdev_name);
static void rndis_ipa_rm_notify
	(void *user_data, enum ipa_rm_event event,
	unsigned long data);
static int rndis_ipa_create_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx);
static int rndis_ipa_destroy_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx);
static int rndis_ipa_register_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx);
static int rndis_ipa_deregister_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx);
static bool rx_filter(struct sk_buff *skb);
static bool tx_filter(struct sk_buff *skb);
static bool rm_enabled(struct rndis_ipa_dev *rndis_ipa_ctx);
static int resource_request(struct rndis_ipa_dev *rndis_ipa_ctx);
static void resource_release(struct rndis_ipa_dev *rndis_ipa_ctx);
static netdev_tx_t rndis_ipa_start_xmit
	(struct sk_buff *skb, struct net_device *net);
static int rndis_ipa_debugfs_atomic_open
@@ -541,6 +552,7 @@ int rndis_ipa_init(struct ipa_usb_init_params *params)
	rndis_ipa_ctx->tx_filter = false;
	rndis_ipa_ctx->rx_filter = false;
	rndis_ipa_ctx->icmp_filter = true;
	rndis_ipa_ctx->rm_enable = true;
	rndis_ipa_ctx->tx_dropped = 0;
	rndis_ipa_ctx->rx_dropped = 0;
	rndis_ipa_ctx->tx_dump_enable = false;
@@ -750,12 +762,15 @@ int rndis_ipa_pipe_connect_notify(
		return -EINVAL;
	}

	if (ipa_pm_is_used())
		result = rndis_ipa_register_pm_client(rndis_ipa_ctx);
	else
		result = rndis_ipa_create_rm_resource(rndis_ipa_ctx);
	if (result) {
		RNDIS_IPA_ERROR("fail on PM register\n");
		goto fail_register_pm;
		RNDIS_IPA_ERROR("fail on RM create\n");
		goto fail_create_rm;
	}
	RNDIS_IPA_DEBUG("PM client was registered\n");
	RNDIS_IPA_DEBUG("RM resource was created\n");

	rndis_ipa_ctx->ipa_to_usb_hdl = ipa_to_usb_hdl;
	rndis_ipa_ctx->usb_to_ipa_hdl = usb_to_ipa_hdl;
@@ -833,8 +848,11 @@ int rndis_ipa_pipe_connect_notify(
	return 0;

fail:
	if (ipa_pm_is_used())
		rndis_ipa_deregister_pm_client(rndis_ipa_ctx);
fail_register_pm:
	else
		rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
fail_create_rm:
	return result;
}
EXPORT_SYMBOL(rndis_ipa_pipe_connect_notify);
@@ -952,11 +970,11 @@ static netdev_tx_t rndis_ipa_start_xmit(struct sk_buff *skb,
		goto out;
	}

	ret = ipa_pm_activate(rndis_ipa_ctx->pm_hdl);
	if (unlikely(ret)) {
		RNDIS_IPA_DEBUG("Failed activate PM client\n");
	ret = resource_request(rndis_ipa_ctx);
	if (ret) {
		RNDIS_IPA_DEBUG("Waiting to resource\n");
		netif_stop_queue(net);
		goto fail_pm_activate;
		goto resource_busy;
	}

	if (atomic_read(&rndis_ipa_ctx->outstanding_pkts) >=
@@ -985,8 +1003,8 @@ static netdev_tx_t rndis_ipa_start_xmit(struct sk_buff *skb,
fail_tx_packet:
	rndis_ipa_xmit_error(skb);
out:
	ipa_pm_deferred_deactivate(rndis_ipa_ctx->pm_hdl);
fail_pm_activate:
	resource_release(rndis_ipa_ctx);
resource_busy:
	RNDIS_IPA_DEBUG
		("packet Tx done - %s\n",
		(status == NETDEV_TX_OK) ? "OK" : "FAIL");
@@ -1074,6 +1092,50 @@ static void rndis_ipa_tx_timeout(struct net_device *net)
	net->stats.tx_errors++;
}

/**
 * rndis_ipa_rm_notify() - callback supplied to IPA resource manager
 *   for grant/release events
 * user_data: the driver context supplied to IPA resource manager during call
 *  to ipa_rm_create_resource().
 * event: the event notified to us by IPA resource manager (Release/Grant)
 * data: reserved field supplied by IPA resource manager
 *
 * This callback shall be called based on resource request/release sent
 * to the IPA resource manager.
 * In case the queue was stopped during EINPROGRESS for Tx path and the
 * event received is Grant then the queue shall be restarted.
 * In case the event notified is a release notification the netdev discard it.
 */
static void rndis_ipa_rm_notify(
	void *user_data, enum ipa_rm_event event,
	unsigned long data)
{
	struct rndis_ipa_dev *rndis_ipa_ctx = user_data;

	RNDIS_IPA_LOG_ENTRY();

	if (event == IPA_RM_RESOURCE_RELEASED) {
		RNDIS_IPA_DEBUG("Resource Released\n");
		return;
	}

	if (event != IPA_RM_RESOURCE_GRANTED) {
		RNDIS_IPA_ERROR
			("Unexceoted event receieved from RM (%d\n)", event);
		return;
	}
	RNDIS_IPA_DEBUG("Resource Granted\n");

	if (netif_queue_stopped(rndis_ipa_ctx->net)) {
		RNDIS_IPA_DEBUG("starting queue\n");
		netif_start_queue(rndis_ipa_ctx->net);
	} else {
		RNDIS_IPA_DEBUG("queue already awake\n");
	}

	RNDIS_IPA_LOG_EXIT();
}

/**
 * rndis_ipa_packet_receive_notify() - Rx notify for packet sent from
 *  tethered PC (USB->IPA).
@@ -1293,12 +1355,15 @@ int rndis_ipa_pipe_disconnect_notify(void *private)
	rndis_ipa_ctx->net->stats.tx_dropped += outstanding_dropped_pkts;
	atomic_set(&rndis_ipa_ctx->outstanding_pkts, 0);

	if (ipa_pm_is_used())
		retval = rndis_ipa_deregister_pm_client(rndis_ipa_ctx);
	else
		retval = rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
	if (retval) {
		RNDIS_IPA_ERROR("Fail to deregister PM\n");
		RNDIS_IPA_ERROR("Fail to clean RM\n");
		return retval;
	}
	RNDIS_IPA_DEBUG("PM was successfully deregistered\n");
	RNDIS_IPA_DEBUG("RM was successfully destroyed\n");

	spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
	next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
@@ -1766,7 +1831,86 @@ static int rndis_ipa_deregister_properties(char *netdev_name)
	return 0;
}

/**
 * rndis_ipa_create_rm_resource() -creates the resource representing
 *  this Netdev and supply notification callback for resource event
 *  such as Grant/Release
 * @rndis_ipa_ctx: this driver context
 *
 * In order make sure all needed resources are available during packet
 * transmit this Netdev shall use Request/Release mechanism of
 * the IPA resource manager.
 * This mechanism shall iterate over a dependency graph and make sure
 * all dependent entities are ready to for packet Tx
 * transfer (Apps->IPA->USB).
 * In this function the resource representing the Netdev is created
 * in addition to the basic dependency between the Netdev and the USB client.
 * Hence, USB client, is a dependency for the Netdev and may be notified in
 * case of packet transmit from this Netdev to tethered Host.
 * As implied from the "may" in the above sentence there is a scenario where
 * the USB is not notified. This is done thanks to the IPA resource manager
 * inactivity timer.
 * The inactivity timer allow the Release requests to be delayed in order
 * prevent ping-pong with the USB and other dependencies.
 */
static int rndis_ipa_create_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx)
{
	struct ipa_rm_create_params create_params = {0};
	struct ipa_rm_perf_profile profile;
	int result;

	RNDIS_IPA_LOG_ENTRY();

	create_params.name = DRV_RESOURCE_ID;
	create_params.reg_params.user_data = rndis_ipa_ctx;
	create_params.reg_params.notify_cb = rndis_ipa_rm_notify;
	result = ipa_rm_create_resource(&create_params);
	if (result) {
		RNDIS_IPA_ERROR("Fail on ipa_rm_create_resource\n");
		goto fail_rm_create;
	}
	RNDIS_IPA_DEBUG("RM client was created\n");

	profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
	ipa_rm_set_perf_profile(DRV_RESOURCE_ID, &profile);

	result = ipa_rm_inactivity_timer_init
		(DRV_RESOURCE_ID,
		INACTIVITY_MSEC_DELAY);
	if (result) {
		RNDIS_IPA_ERROR("Fail on ipa_rm_inactivity_timer_init\n");
		goto fail_inactivity_timer;
	}

	RNDIS_IPA_DEBUG("rm_it client was created\n");

	result = ipa_rm_add_dependency_sync
		(DRV_RESOURCE_ID,
		IPA_RM_RESOURCE_USB_CONS);

	if (result && result != -EINPROGRESS)
		RNDIS_IPA_ERROR("unable to add RNDIS/USB dependency (%d)\n",
				result);
	else
		RNDIS_IPA_DEBUG("RNDIS/USB dependency was set\n");

	result = ipa_rm_add_dependency_sync
		(IPA_RM_RESOURCE_USB_PROD,
		IPA_RM_RESOURCE_APPS_CONS);
	if (result && result != -EINPROGRESS)
		RNDIS_IPA_ERROR("unable to add USB/APPS dependency (%d)\n",
				result);
	else
		RNDIS_IPA_DEBUG("USB/APPS dependency was set\n");

	RNDIS_IPA_LOG_EXIT();

	return 0;

fail_inactivity_timer:
fail_rm_create:
	return result;
}

static void rndis_ipa_pm_cb(void *p, enum ipa_pm_cb_event event)
{
@@ -1791,6 +1935,64 @@ static void rndis_ipa_pm_cb(void *p, enum ipa_pm_cb_event event)
	RNDIS_IPA_LOG_EXIT();
}

/**
 * rndis_ipa_destroy_rm_resource() - delete the dependency and destroy
 * the resource done on rndis_ipa_create_rm_resource()
 * @rndis_ipa_ctx: this driver context
 *
 * This function shall delete the dependency create between
 * the Netdev to the USB.
 * In addition the inactivity time shall be destroy and the resource shall
 * be deleted.
 */
static int rndis_ipa_destroy_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx)
{
	int result;

	RNDIS_IPA_LOG_ENTRY();

	result = ipa_rm_delete_dependency
		(DRV_RESOURCE_ID,
		IPA_RM_RESOURCE_USB_CONS);
	if (result && result != -EINPROGRESS) {
		RNDIS_IPA_ERROR("Fail to delete RNDIS/USB dependency\n");
		goto bail;
	}
	RNDIS_IPA_DEBUG("RNDIS/USB dependency was successfully deleted\n");

	result = ipa_rm_delete_dependency
		(IPA_RM_RESOURCE_USB_PROD,
		IPA_RM_RESOURCE_APPS_CONS);
	if (result == -EINPROGRESS) {
		RNDIS_IPA_DEBUG("RM dependency deletion is in progress");
	} else if (result) {
		RNDIS_IPA_ERROR("Fail to delete USB/APPS dependency\n");
		goto bail;
	} else {
		RNDIS_IPA_DEBUG("USB/APPS dependency was deleted\n");
	}

	result = ipa_rm_inactivity_timer_destroy(DRV_RESOURCE_ID);
	if (result) {
		RNDIS_IPA_ERROR("Fail to destroy inactivity timern");
		goto bail;
	}
	RNDIS_IPA_DEBUG("RM inactivity timer was successfully destroy\n");

	result = ipa_rm_delete_resource(DRV_RESOURCE_ID);
	if (result) {
		RNDIS_IPA_ERROR("resource deletion failed\n");
		goto bail;
	}
	RNDIS_IPA_DEBUG
		("Netdev RM resource was deleted (resid:%d)\n",
		DRV_RESOURCE_ID);

	RNDIS_IPA_LOG_EXIT();

bail:
	return result;
}

static int rndis_ipa_register_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx)
{
@@ -1819,6 +2021,52 @@ static int rndis_ipa_deregister_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx)
	return 0;
}

/**
 * resource_request() - request for the Netdev resource
 * @rndis_ipa_ctx: main driver context
 *
 * This function shall send the IPA resource manager inactivity time a request
 * to Grant the Netdev producer.
 * In case the resource is already Granted the function shall return immediately
 * and "pet" the inactivity timer.
 * In case the resource was not already Granted this function shall
 * return EINPROGRESS and the Netdev shall stop the send queue until
 * the IPA resource manager notify it that the resource is
 * granted (done in a differ context)
 */
static int resource_request(struct rndis_ipa_dev *rndis_ipa_ctx)
{
	int result = 0;

	if (!rm_enabled(rndis_ipa_ctx))
		return result;

	if (ipa_pm_is_used())
		return ipa_pm_activate(rndis_ipa_ctx->pm_hdl);

	return ipa_rm_inactivity_timer_request_resource(
			DRV_RESOURCE_ID);

}

/**
 * resource_release() - release the Netdev resource
 * @rndis_ipa_ctx: main driver context
 *
 * start the inactivity timer count down.by using the IPA resource
 * manager inactivity time.
 * The actual resource release shall occur only if no request shall be done
 * during the INACTIVITY_MSEC_DELAY.
 */
static void resource_release(struct rndis_ipa_dev *rndis_ipa_ctx)
{
	if (!rm_enabled(rndis_ipa_ctx))
		return;
	if (ipa_pm_is_used())
		ipa_pm_deferred_deactivate(rndis_ipa_ctx->pm_hdl);
	else
		ipa_rm_inactivity_timer_release_resource(DRV_RESOURCE_ID);
}

/**
 * rndis_encapsulate_skb() - encapsulate the given Ethernet skb with
@@ -1906,6 +2154,19 @@ static bool tx_filter(struct sk_buff *skb)
	return true;
}

/**
 * rm_enabled() - allow the use of resource manager Request/Release to
 *  be bypassed
 * @rndis_ipa_ctx: main driver context
 *
 * By disabling the resource manager flag the Request for the Netdev resource
 * shall be bypassed and the packet shall be sent.
 * accordingly, Release request shall be bypass as well.
 */
static bool rm_enabled(struct rndis_ipa_dev *rndis_ipa_ctx)
{
	return rndis_ipa_ctx->rm_enable;
}

/**
 * rndis_ipa_ep_registers_cfg() - configure the USB endpoints
@@ -2181,6 +2442,14 @@ static void rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx)
		goto fail_file;
	}

	file = debugfs_create_bool
		("rm_enable", flags_read_write,
		rndis_ipa_ctx->directory, &rndis_ipa_ctx->rm_enable);
	if (!file) {
		RNDIS_IPA_ERROR("could not create debugfs rm file\n");
		goto fail_file;
	}

	file = debugfs_create_u32
		("outstanding_high", flags_read_write,
		rndis_ipa_ctx->directory,
+2 −0
Original line number Diff line number Diff line
@@ -428,6 +428,8 @@ int ipa_disable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
const char *ipa_get_version_string(enum ipa_hw_type ver);
int ipa_start_gsi_channel(u32 clnt_hdl);

bool ipa_pm_is_used(void);

int ipa_smmu_store_sgt(struct sg_table **out_ch_ptr,
		struct sg_table *in_sgt_ptr);
int ipa_smmu_free_sgt(struct sg_table **out_sgt_ptr);