Loading drivers/platform/msm/ipa/ipa_api.c +24 −8 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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, Loading drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c +284 −15 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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) >= Loading Loading @@ -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"); Loading Loading @@ -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). Loading Loading @@ -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, Loading Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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, Loading drivers/platform/msm/ipa/ipa_common_i.h +2 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading
drivers/platform/msm/ipa/ipa_api.c +24 −8 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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, Loading
drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c +284 −15 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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) >= Loading Loading @@ -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"); Loading Loading @@ -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). Loading Loading @@ -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, Loading Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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, Loading
drivers/platform/msm/ipa/ipa_common_i.h +2 −0 Original line number Diff line number Diff line Loading @@ -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); Loading