Loading drivers/platform/msm/ipa/ipa.c +80 −8 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ #include <linux/interrupt.h> #include <linux/msm-bus.h> #include <linux/msm-bus-board.h> #include <linux/netdevice.h> #include <linux/delay.h> #include "ipa_i.h" #include "ipa_rm_i.h" Loading Loading @@ -141,6 +143,9 @@ struct ipa_ioc_nat_alloc_mem32 { }; #endif static void ipa_start_tag_process(struct work_struct *work); static DECLARE_WORK(ipa_tag_work, ipa_start_tag_process); static struct ipa_plat_drv_res ipa_res = {0, }; static struct of_device_id ipa_plat_drv_match[] = { { Loading Loading @@ -1581,6 +1586,52 @@ void ipa_disable_clks(void) if (msm_bus_scale_client_update_request(ipa_ctx->ipa_bus_hdl, 0)) WARN_ON(1); } /** * ipa_start_tag_process() - Send TAG packet and wait for it to come back * * This function is called prior to clock gating when active client counter * is 1. TAG process ensures that there are no packets inside IPA HW that * were not submitted to peer's BAM. During TAG process all aggregation frames * are (force) closed. * * Return codes: * None */ static void ipa_start_tag_process(struct work_struct *work) { int res; IPADBG("starting TAG process\n"); mutex_lock(&ipa_ctx->ipa_active_clients_lock); ipa_ctx->start_tag_process_again = false; mutex_unlock(&ipa_ctx->ipa_active_clients_lock); /* close aggregation frames on all pipes */ res = ipa_tag_aggr_force_close(-1); if (res) { IPAERR("ipa_tag_aggr_force_close failed %d\n", res); return; } mutex_lock(&ipa_ctx->ipa_active_clients_lock); ipa_ctx->ipa_active_clients--; if (ipa_ctx->ipa_active_clients == 0) { /* check if during tag process a client used IPA */ if (ipa_ctx->start_tag_process_again) { IPADBG("Starting TAG process again\n"); ipa_ctx->ipa_active_clients = 1; mutex_unlock(&ipa_ctx->ipa_active_clients_lock); queue_work(ipa_ctx->power_mgmt_wq, &ipa_tag_work); return; } ipa_disable_clks(); } mutex_unlock(&ipa_ctx->ipa_active_clients_lock); IPADBG("TAG process done\n"); return; } /** * ipa_inc_client_enable_clks() - Increase active clients counter, and * enable ipa clocks if necessary Loading Loading @@ -1626,8 +1677,12 @@ bail: } /** * ipa_dec_client_disable_clks() - Decrease active clients counter, and * disable ipa clocks if necessary * ipa_dec_client_disable_clks() - Decrease active clients counter * * In case that there are no active clients this function also starts * TAG process. When TAG progress ends ipa clocks will be gated. * start_tag_process_again flag is set during this function to signal TAG * process to start again as there was another client that may send data to ipa * * Return codes: * None Loading @@ -1635,10 +1690,16 @@ bail: void ipa_dec_client_disable_clks(void) { mutex_lock(&ipa_ctx->ipa_active_clients_lock); ipa_ctx->start_tag_process_again = true; ipa_ctx->ipa_active_clients--; IPADBG("active clients = %d\n", ipa_ctx->ipa_active_clients); if (ipa_ctx->ipa_active_clients == 0) ipa_disable_clks(); if (ipa_ctx->ipa_active_clients == 0) { /* when TAG process ends, active clients will be decreased */ ipa_ctx->ipa_active_clients = 1; mutex_unlock(&ipa_ctx->ipa_active_clients_lock); queue_work(ipa_ctx->power_mgmt_wq, &ipa_tag_work); return; } mutex_unlock(&ipa_ctx->ipa_active_clients_lock); } Loading Loading @@ -2214,6 +2275,15 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, MAJOR(ipa_ctx->dev_num), MINOR(ipa_ctx->dev_num)); /* Create workqueue for power management */ ipa_ctx->power_mgmt_wq = create_singlethread_workqueue("ipa_power_mgmt"); if (!ipa_ctx->power_mgmt_wq) { IPAERR("failed to create wq\n"); result = -ENOMEM; goto fail_power_mgmt_wq; } /* Initialize IPA RM (resource manager) */ result = ipa_rm_initialize(); if (result) { Loading Loading @@ -2273,6 +2343,8 @@ fail_ipa_interrupts_init: fail_create_apps_resource: ipa_rm_exit(); fail_ipa_rm_init: destroy_workqueue(ipa_ctx->power_mgmt_wq); fail_power_mgmt_wq: cdev_del(&ipa_ctx->cdev); fail_cdev_add: device_destroy(ipa_ctx->class, ipa_ctx->dev_num); Loading drivers/platform/msm/ipa/ipa_client.c +7 −5 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ int ipa_disable_data_path(u32 clnt_hdl) struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl]; struct ipa_ep_cfg_holb holb_cfg; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; u32 aggr_init; int res = 0; IPADBG("Disabling data path\n"); Loading @@ -86,10 +87,11 @@ int ipa_disable_data_path(u32 clnt_hdl) } udelay(IPA_PKT_FLUSH_TO_US); if (IPA_CLIENT_IS_CONS(ep->client) && ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR && ep->cfg.aggr.aggr_time_limit) msleep(ep->cfg.aggr.aggr_time_limit); aggr_init = ipa_read_reg(ipa_ctx->mmio, IPA_ENDP_INIT_AGGR_N_OFST_v2_0(clnt_hdl)); if (((aggr_init & IPA_ENDP_INIT_AGGR_N_AGGR_EN_BMSK) >> IPA_ENDP_INIT_AGGR_N_AGGR_EN_SHFT) == IPA_ENABLE_AGGR) ipa_tag_aggr_force_close(clnt_hdl); return res; } Loading drivers/platform/msm/ipa/ipa_dp.c +19 −0 Original line number Diff line number Diff line Loading @@ -1641,6 +1641,25 @@ begin: } IPA_STATS_EXCP_CNT(status->exception, ipa_ctx->stats.rx_excp_pkts); if (status->status_mask & IPA_HW_PKT_STATUS_MASK_TAG_VALID) { struct completion *comp; IPADBG("TAG packet arrived\n"); if (status->tag_f_2 != IPA_COOKIE) { IPAERR("TAG arrived with wrong cookie\n"); skb_pull(skb, IPA_PKT_STATUS_SIZE); continue; } skb_pull(skb, IPA_PKT_STATUS_SIZE); if (skb->len < sizeof(comp)) { IPAERR("TAG arrived without packet\n"); return rc; } memcpy(&comp, skb->data, sizeof(comp)); skb_pull(skb, sizeof(comp)); complete(comp); continue; } if (status->endp_dest_idx >= IPA_NUM_PIPES || status->endp_src_idx >= IPA_NUM_PIPES || status->pkt_len > IPA_GENERIC_AGGR_BYTE_LIMIT * 1024) { Loading drivers/platform/msm/ipa/ipa_hw_defs.h +45 −17 Original line number Diff line number Diff line Loading @@ -28,12 +28,12 @@ #define IPA_HDR_INIT_LOCAL (9) #define IPA_HDR_INIT_SYSTEM (10) #define IPA_DECIPH_SETUP (11) #define IPA_INSERT_NAT_RULE (12) #define IPA_DELETE_NAT_RULE (13) #define IPA_REGISTER_WRITE (12) #define IPA_NAT_DMA (14) #define IPA_IP_PACKET_TAG (15) #define IPA_IP_PACKET_INIT (16) #define IPA_DMA_SHARED_MEM (19) #define IPA_IP_PACKET_TAG_STATUS (20) /** * struct ipa_flt_rule_hw_hdr - HW header of IPA filter rule Loading Loading @@ -187,6 +187,22 @@ struct ipa_a5_mux_hdr { u32 metadata; }; /** * struct ipa_register_write - IPA_REGISTER_WRITE command payload * @rsvd: reserved * @skip_pipeline_clear: 0 to wait until IPA pipeline is clear * @offset: offset from IPA base address * @value: value to write to register * @value_mask: mask specifying which value bits to write to the register */ struct ipa_register_write { u32 rsvd:15; u32 skip_pipeline_clear:1; u32 offset:16; u32 value:32; u32 value_mask:32; }; /** * struct ipa_nat_dma - IPA_NAT_DMA command payload * @table_index: NAT table index Loading Loading @@ -262,6 +278,18 @@ struct ipa_ip_packet_tag { u32 tag; }; /** * struct ipa_ip_packet_tag_status - IPA_IP_PACKET_TAG_STATUS command payload * @rsvd: reserved * @tag_f_1: tag value returned within status * @tag_f_2: tag value returned within status */ struct ipa_ip_packet_tag_status { u32 rsvd:16; u32 tag_f_1:16; u32 tag_f_2:32; }; /*! @brief Struct for the the IPA UL packet status header */ struct ipa_hw_pkt_status { u32 status_opcode:8; Loading drivers/platform/msm/ipa/ipa_i.h +7 −0 Original line number Diff line number Diff line Loading @@ -640,6 +640,8 @@ struct ipa_controller; * @ip4_flt_tbl_lcl: where ip4 flt tables reside 1-local; 0-system * @ip6_flt_tbl_lcl: where ip6 flt tables reside 1-local; 0-system * @empty_rt_tbl_mem: empty routing tables memory * @power_mgmt_wq: workqueue for power management * @start_tag_process_again: indicates whether to start tag process again * @pipe_mem_pool: pipe memory pool * @dma_pool: special purpose DMA pool * @ipa_hw_type: type of IPA HW type (e.g. IPA 1.0, IPA 1.1 etc') Loading Loading @@ -698,6 +700,8 @@ struct ipa_context { struct dma_pool *dma_pool; struct mutex ipa_active_clients_lock; int ipa_active_clients; struct workqueue_struct *power_mgmt_wq; bool start_tag_process_again; u32 clnt_hdl_cmd; u32 clnt_hdl_data_in; u32 clnt_hdl_data_out; Loading Loading @@ -942,5 +946,8 @@ int ipa_suspend_resource_no_block(enum ipa_rm_resource_name name); int ipa_suspend_resource_sync(enum ipa_rm_resource_name name); int ipa_resume_resource(enum ipa_rm_resource_name name); bool ipa_should_pipe_be_suspended(enum ipa_client_type client); int ipa_tag_aggr_force_close(int pipe_num); #endif /* _IPA_I_H_ */ Loading
drivers/platform/msm/ipa/ipa.c +80 −8 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ #include <linux/interrupt.h> #include <linux/msm-bus.h> #include <linux/msm-bus-board.h> #include <linux/netdevice.h> #include <linux/delay.h> #include "ipa_i.h" #include "ipa_rm_i.h" Loading Loading @@ -141,6 +143,9 @@ struct ipa_ioc_nat_alloc_mem32 { }; #endif static void ipa_start_tag_process(struct work_struct *work); static DECLARE_WORK(ipa_tag_work, ipa_start_tag_process); static struct ipa_plat_drv_res ipa_res = {0, }; static struct of_device_id ipa_plat_drv_match[] = { { Loading Loading @@ -1581,6 +1586,52 @@ void ipa_disable_clks(void) if (msm_bus_scale_client_update_request(ipa_ctx->ipa_bus_hdl, 0)) WARN_ON(1); } /** * ipa_start_tag_process() - Send TAG packet and wait for it to come back * * This function is called prior to clock gating when active client counter * is 1. TAG process ensures that there are no packets inside IPA HW that * were not submitted to peer's BAM. During TAG process all aggregation frames * are (force) closed. * * Return codes: * None */ static void ipa_start_tag_process(struct work_struct *work) { int res; IPADBG("starting TAG process\n"); mutex_lock(&ipa_ctx->ipa_active_clients_lock); ipa_ctx->start_tag_process_again = false; mutex_unlock(&ipa_ctx->ipa_active_clients_lock); /* close aggregation frames on all pipes */ res = ipa_tag_aggr_force_close(-1); if (res) { IPAERR("ipa_tag_aggr_force_close failed %d\n", res); return; } mutex_lock(&ipa_ctx->ipa_active_clients_lock); ipa_ctx->ipa_active_clients--; if (ipa_ctx->ipa_active_clients == 0) { /* check if during tag process a client used IPA */ if (ipa_ctx->start_tag_process_again) { IPADBG("Starting TAG process again\n"); ipa_ctx->ipa_active_clients = 1; mutex_unlock(&ipa_ctx->ipa_active_clients_lock); queue_work(ipa_ctx->power_mgmt_wq, &ipa_tag_work); return; } ipa_disable_clks(); } mutex_unlock(&ipa_ctx->ipa_active_clients_lock); IPADBG("TAG process done\n"); return; } /** * ipa_inc_client_enable_clks() - Increase active clients counter, and * enable ipa clocks if necessary Loading Loading @@ -1626,8 +1677,12 @@ bail: } /** * ipa_dec_client_disable_clks() - Decrease active clients counter, and * disable ipa clocks if necessary * ipa_dec_client_disable_clks() - Decrease active clients counter * * In case that there are no active clients this function also starts * TAG process. When TAG progress ends ipa clocks will be gated. * start_tag_process_again flag is set during this function to signal TAG * process to start again as there was another client that may send data to ipa * * Return codes: * None Loading @@ -1635,10 +1690,16 @@ bail: void ipa_dec_client_disable_clks(void) { mutex_lock(&ipa_ctx->ipa_active_clients_lock); ipa_ctx->start_tag_process_again = true; ipa_ctx->ipa_active_clients--; IPADBG("active clients = %d\n", ipa_ctx->ipa_active_clients); if (ipa_ctx->ipa_active_clients == 0) ipa_disable_clks(); if (ipa_ctx->ipa_active_clients == 0) { /* when TAG process ends, active clients will be decreased */ ipa_ctx->ipa_active_clients = 1; mutex_unlock(&ipa_ctx->ipa_active_clients_lock); queue_work(ipa_ctx->power_mgmt_wq, &ipa_tag_work); return; } mutex_unlock(&ipa_ctx->ipa_active_clients_lock); } Loading Loading @@ -2214,6 +2275,15 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, MAJOR(ipa_ctx->dev_num), MINOR(ipa_ctx->dev_num)); /* Create workqueue for power management */ ipa_ctx->power_mgmt_wq = create_singlethread_workqueue("ipa_power_mgmt"); if (!ipa_ctx->power_mgmt_wq) { IPAERR("failed to create wq\n"); result = -ENOMEM; goto fail_power_mgmt_wq; } /* Initialize IPA RM (resource manager) */ result = ipa_rm_initialize(); if (result) { Loading Loading @@ -2273,6 +2343,8 @@ fail_ipa_interrupts_init: fail_create_apps_resource: ipa_rm_exit(); fail_ipa_rm_init: destroy_workqueue(ipa_ctx->power_mgmt_wq); fail_power_mgmt_wq: cdev_del(&ipa_ctx->cdev); fail_cdev_add: device_destroy(ipa_ctx->class, ipa_ctx->dev_num); Loading
drivers/platform/msm/ipa/ipa_client.c +7 −5 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ int ipa_disable_data_path(u32 clnt_hdl) struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl]; struct ipa_ep_cfg_holb holb_cfg; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; u32 aggr_init; int res = 0; IPADBG("Disabling data path\n"); Loading @@ -86,10 +87,11 @@ int ipa_disable_data_path(u32 clnt_hdl) } udelay(IPA_PKT_FLUSH_TO_US); if (IPA_CLIENT_IS_CONS(ep->client) && ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR && ep->cfg.aggr.aggr_time_limit) msleep(ep->cfg.aggr.aggr_time_limit); aggr_init = ipa_read_reg(ipa_ctx->mmio, IPA_ENDP_INIT_AGGR_N_OFST_v2_0(clnt_hdl)); if (((aggr_init & IPA_ENDP_INIT_AGGR_N_AGGR_EN_BMSK) >> IPA_ENDP_INIT_AGGR_N_AGGR_EN_SHFT) == IPA_ENABLE_AGGR) ipa_tag_aggr_force_close(clnt_hdl); return res; } Loading
drivers/platform/msm/ipa/ipa_dp.c +19 −0 Original line number Diff line number Diff line Loading @@ -1641,6 +1641,25 @@ begin: } IPA_STATS_EXCP_CNT(status->exception, ipa_ctx->stats.rx_excp_pkts); if (status->status_mask & IPA_HW_PKT_STATUS_MASK_TAG_VALID) { struct completion *comp; IPADBG("TAG packet arrived\n"); if (status->tag_f_2 != IPA_COOKIE) { IPAERR("TAG arrived with wrong cookie\n"); skb_pull(skb, IPA_PKT_STATUS_SIZE); continue; } skb_pull(skb, IPA_PKT_STATUS_SIZE); if (skb->len < sizeof(comp)) { IPAERR("TAG arrived without packet\n"); return rc; } memcpy(&comp, skb->data, sizeof(comp)); skb_pull(skb, sizeof(comp)); complete(comp); continue; } if (status->endp_dest_idx >= IPA_NUM_PIPES || status->endp_src_idx >= IPA_NUM_PIPES || status->pkt_len > IPA_GENERIC_AGGR_BYTE_LIMIT * 1024) { Loading
drivers/platform/msm/ipa/ipa_hw_defs.h +45 −17 Original line number Diff line number Diff line Loading @@ -28,12 +28,12 @@ #define IPA_HDR_INIT_LOCAL (9) #define IPA_HDR_INIT_SYSTEM (10) #define IPA_DECIPH_SETUP (11) #define IPA_INSERT_NAT_RULE (12) #define IPA_DELETE_NAT_RULE (13) #define IPA_REGISTER_WRITE (12) #define IPA_NAT_DMA (14) #define IPA_IP_PACKET_TAG (15) #define IPA_IP_PACKET_INIT (16) #define IPA_DMA_SHARED_MEM (19) #define IPA_IP_PACKET_TAG_STATUS (20) /** * struct ipa_flt_rule_hw_hdr - HW header of IPA filter rule Loading Loading @@ -187,6 +187,22 @@ struct ipa_a5_mux_hdr { u32 metadata; }; /** * struct ipa_register_write - IPA_REGISTER_WRITE command payload * @rsvd: reserved * @skip_pipeline_clear: 0 to wait until IPA pipeline is clear * @offset: offset from IPA base address * @value: value to write to register * @value_mask: mask specifying which value bits to write to the register */ struct ipa_register_write { u32 rsvd:15; u32 skip_pipeline_clear:1; u32 offset:16; u32 value:32; u32 value_mask:32; }; /** * struct ipa_nat_dma - IPA_NAT_DMA command payload * @table_index: NAT table index Loading Loading @@ -262,6 +278,18 @@ struct ipa_ip_packet_tag { u32 tag; }; /** * struct ipa_ip_packet_tag_status - IPA_IP_PACKET_TAG_STATUS command payload * @rsvd: reserved * @tag_f_1: tag value returned within status * @tag_f_2: tag value returned within status */ struct ipa_ip_packet_tag_status { u32 rsvd:16; u32 tag_f_1:16; u32 tag_f_2:32; }; /*! @brief Struct for the the IPA UL packet status header */ struct ipa_hw_pkt_status { u32 status_opcode:8; Loading
drivers/platform/msm/ipa/ipa_i.h +7 −0 Original line number Diff line number Diff line Loading @@ -640,6 +640,8 @@ struct ipa_controller; * @ip4_flt_tbl_lcl: where ip4 flt tables reside 1-local; 0-system * @ip6_flt_tbl_lcl: where ip6 flt tables reside 1-local; 0-system * @empty_rt_tbl_mem: empty routing tables memory * @power_mgmt_wq: workqueue for power management * @start_tag_process_again: indicates whether to start tag process again * @pipe_mem_pool: pipe memory pool * @dma_pool: special purpose DMA pool * @ipa_hw_type: type of IPA HW type (e.g. IPA 1.0, IPA 1.1 etc') Loading Loading @@ -698,6 +700,8 @@ struct ipa_context { struct dma_pool *dma_pool; struct mutex ipa_active_clients_lock; int ipa_active_clients; struct workqueue_struct *power_mgmt_wq; bool start_tag_process_again; u32 clnt_hdl_cmd; u32 clnt_hdl_data_in; u32 clnt_hdl_data_out; Loading Loading @@ -942,5 +946,8 @@ int ipa_suspend_resource_no_block(enum ipa_rm_resource_name name); int ipa_suspend_resource_sync(enum ipa_rm_resource_name name); int ipa_resume_resource(enum ipa_rm_resource_name name); bool ipa_should_pipe_be_suspended(enum ipa_client_type client); int ipa_tag_aggr_force_close(int pipe_num); #endif /* _IPA_I_H_ */