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: Asha Magadi Venkateshamurthy <amagad@codeaurora.org>
Signed-off-by: Swetha Chikkaboraiah <schikk@codeaurora.org>
This commit is contained in:
Asha Magadi Venkateshamurthy authored and Swetha Chikkaboraiah committed 2020-10-24 15:03:40 +05:30
1 parent 602a398f32
commit 795434e607
3 files changed
+307 -20

No files matched your search

+24 -8
View File
@@ -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,19 +2882,24 @@ 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;
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,
+281 -12
View File
@@ -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
View File
@@ -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);