Loading drivers/platform/msm/gsi/gsi.c +3 −3 Original line number Diff line number Diff line Loading @@ -3719,7 +3719,7 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) curr = GSI_CHAN_MODE_CALLBACK; if (mode == curr) { GSIERR("already in requested mode %u chan_hdl=%lu\n", GSIDBG("already in requested mode %u chan_hdl=%lu\n", curr, chan_hdl); return -GSI_STATUS_UNSUPPORTED_OP; } Loading @@ -3730,7 +3730,7 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) gsi_writel(1 << ctx->evtr->id, gsi_ctx->base + GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(gsi_ctx->per.ee)); atomic_set(&ctx->poll_mode, mode); if (ctx->props.prot == GSI_CHAN_PROT_GCI) if ((ctx->props.prot == GSI_CHAN_PROT_GCI) && ctx->evtr->chan) atomic_set(&ctx->evtr->chan->poll_mode, mode); GSIDBG("set gsi_ctx evtr_id %d to %d mode\n", ctx->evtr->id, mode); Loading @@ -3740,7 +3740,7 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) if (curr == GSI_CHAN_MODE_POLL && mode == GSI_CHAN_MODE_CALLBACK) { atomic_set(&ctx->poll_mode, mode); if (ctx->props.prot == GSI_CHAN_PROT_GCI) if ((ctx->props.prot == GSI_CHAN_PROT_GCI) && ctx->evtr->chan) atomic_set(&ctx->evtr->chan->poll_mode, mode); __gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0); GSIDBG("set gsi_ctx evtr_id %d to %d mode\n", Loading drivers/platform/msm/ipa/ipa_v3/ipa.c +15 −5 Original line number Diff line number Diff line Loading @@ -54,6 +54,8 @@ #include "ipa_trace.h" #include "ipa_odl.h" #define IPA_SUSPEND_BUSY_TIMEOUT (msecs_to_jiffies(10)) /* * The following for adding code (ie. for EMULATION) not found on x86. */ Loading Loading @@ -117,7 +119,7 @@ static void ipa3_load_ipa_fw(struct work_struct *work); static DECLARE_WORK(ipa3_fw_loading_work, ipa3_load_ipa_fw); static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work); static DECLARE_WORK(ipa_dec_clients_disable_clks_on_wq_work, static DECLARE_DELAYED_WORK(ipa_dec_clients_disable_clks_on_wq_work, ipa_dec_clients_disable_clks_on_wq); static int ipa3_ioctl_add_rt_rule_v2(unsigned long arg); Loading Loading @@ -4815,8 +4817,16 @@ static void __ipa3_dec_client_disable_clks(void) ret = atomic_sub_return(1, &ipa3_ctx->ipa3_active_clients.cnt); if (ret > 0) goto unlock_mutex; ipa3_suspend_apps_pipes(true); ret = ipa3_suspend_apps_pipes(true); if (ret) { /* HW is busy, retry after some time */ atomic_inc(&ipa3_ctx->ipa3_active_clients.cnt); queue_delayed_work(ipa3_ctx->power_mgmt_wq, &ipa_dec_clients_disable_clks_on_wq_work, IPA_SUSPEND_BUSY_TIMEOUT); } else { ipa3_disable_clks(); } unlock_mutex: mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex); Loading Loading @@ -4869,8 +4879,8 @@ void ipa3_dec_client_disable_clks_no_block( } /* seems like this is the only client holding the clocks */ queue_work(ipa3_ctx->power_mgmt_wq, &ipa_dec_clients_disable_clks_on_wq_work); queue_delayed_work(ipa3_ctx->power_mgmt_wq, &ipa_dec_clients_disable_clks_on_wq_work, 0); } /** Loading drivers/platform/msm/ipa/ipa_v3/ipa_i.h +1 −1 Original line number Diff line number Diff line Loading @@ -2915,7 +2915,7 @@ int ipa3_create_wdi_mapping(u32 num_buffers, struct ipa_wdi_buffer_info *info); int ipa3_set_flt_tuple_mask(int pipe_idx, struct ipahal_reg_hash_tuple *tuple); int ipa3_set_rt_tuple_mask(int tbl_idx, struct ipahal_reg_hash_tuple *tuple); void ipa3_set_resorce_groups_min_max_limits(void); void ipa3_suspend_apps_pipes(bool suspend); int ipa3_suspend_apps_pipes(bool suspend); int ipa3_flt_read_tbl_from_hw(u32 pipe_idx, enum ipa_ip_type ip_type, bool hashable, Loading drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +142 −117 Original line number Diff line number Diff line Loading @@ -7484,12 +7484,10 @@ void ipa3_set_resorce_groups_min_max_limits(void) IPADBG("EXIT\n"); } static void ipa3_gsi_poll_after_suspend(struct ipa3_ep_context *ep) static bool ipa3_gsi_channel_is_quite(struct ipa3_ep_context *ep) { bool empty; IPADBG("switch ch %ld to poll\n", ep->gsi_chan_hdl); gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL); gsi_is_channel_empty(ep->gsi_chan_hdl, &empty); if (!empty) { IPADBG("ch %ld not empty\n", ep->gsi_chan_hdl); Loading @@ -7498,6 +7496,7 @@ static void ipa3_gsi_poll_after_suspend(struct ipa3_ep_context *ep) if (!atomic_read(&ep->sys->curr_polling_state)) __ipa_gsi_irq_rx_scedule_poll(ep->sys); } return empty; } static int __ipa3_stop_gsi_channel(u32 clnt_hdl) Loading Loading @@ -7623,36 +7622,38 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl) return res; } void ipa3_suspend_apps_pipes(bool suspend) static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend) { struct ipa_ep_cfg_ctrl cfg; int ipa_ep_idx; struct ipa3_ep_context *ep; int res; memset(&cfg, 0, sizeof(cfg)); cfg.ipa_ep_suspend = suspend; if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) { IPAERR("not supported\n"); return -EPERM; } ipa_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS); ipa_ep_idx = ipa3_get_ep_mapping(client); if (ipa_ep_idx < 0) { IPAERR("IPA client mapping failed\n"); ipa_assert(); return; IPADBG("client %d not configured\n", client); return 0; } ep = &ipa3_ctx->ep[ipa_ep_idx]; if (ep->valid) { IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend", ipa_ep_idx); if (!ep->valid) return 0; IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend", ipa_ep_idx); /* * move the channel to callback mode. * This needs to happen before starting the channel to make * sure we don't loose any interrupt */ if (!suspend && !atomic_read(&ep->sys->curr_polling_state)) if (!suspend && !atomic_read(&ep->sys->curr_polling_state) && !IPA_CLIENT_IS_APPS_PROD(client)) gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_CALLBACK); if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) { if (suspend) { res = __ipa3_stop_gsi_channel(ipa_ep_idx); if (res) { Loading @@ -7666,98 +7667,122 @@ void ipa3_suspend_apps_pipes(bool suspend) ipa_assert(); } } } else { ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg); /* Apps prod pipes use common event ring so cannot configure mode*/ if (IPA_CLIENT_IS_APPS_PROD(client)) return 0; if (suspend) { IPADBG("switch ch %ld to poll\n", ep->gsi_chan_hdl); gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL); if (!ipa3_gsi_channel_is_quite(ep)) return -EAGAIN; } else if (!atomic_read(&ep->sys->curr_polling_state)) { IPADBG("switch ch %ld to callback\n", ep->gsi_chan_hdl); gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_CALLBACK); } if (suspend) ipa3_gsi_poll_after_suspend(ep); return 0; } ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS); /* Considering the case for SSR. */ if (ipa_ep_idx == -1) { IPADBG("Invalid mapping for IPA_CLIENT_APPS_WAN_CONS\n"); void ipa3_force_close_coal(void) { struct ipahal_imm_cmd_pyld *cmd_pyld = NULL; struct ipahal_imm_cmd_register_write reg_write_cmd = { 0 }; struct ipahal_reg_valmask valmask; struct ipa3_desc desc; int ep_idx; ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS); if (ep_idx == IPA_EP_NOT_ALLOCATED || (!ipa3_ctx->ep[ep_idx].valid)) return; } ep = &ipa3_ctx->ep[ipa_ep_idx]; if (ep->valid) { IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend", ipa_ep_idx); /* * move the channel to callback mode. * This needs to happen before starting the channel to make * sure we don't loose any interrupt */ if (!suspend && !atomic_read(&ep->sys->curr_polling_state)) gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_CALLBACK); if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) { if (suspend) { res = __ipa3_stop_gsi_channel(ipa_ep_idx); if (res) { IPAERR("failed to stop WAN channel\n"); reg_write_cmd.skip_pipeline_clear = false; reg_write_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; reg_write_cmd.offset = ipahal_get_reg_ofst(IPA_AGGR_FORCE_CLOSE); ipahal_get_aggr_force_close_valmask(ep_idx, &valmask); reg_write_cmd.value = valmask.val; reg_write_cmd.value_mask = valmask.mask; cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE, ®_write_cmd, false); if (!cmd_pyld) { IPAERR("fail construct register_write imm cmd\n"); ipa_assert(); return; } } else if (!atomic_read(&ipa3_ctx->is_ssr)) { /* If SSR was alreday started not required to * start WAN channel,Because in SSR will stop * channel and reset the channel. */ res = gsi_start_channel(ep->gsi_chan_hdl); if (res) { IPAERR("failed to start WAN channel\n"); ipa3_init_imm_cmd_desc(&desc, cmd_pyld); IPADBG("Sending 1 descriptor for coal force close\n"); if (ipa3_send_cmd_timeout(1, &desc, IPA_DMA_TASK_FOR_GSI_TIMEOUT_MSEC)) { IPAERR("ipa3_send_cmd failed\n"); ipa_assert(); } ipahal_destroy_imm_cmd(cmd_pyld); } } else { ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg); } int ipa3_suspend_apps_pipes(bool suspend) { int res; enum ipa_client_type client; if (suspend) ipa3_gsi_poll_after_suspend(ep); } ipa3_force_close_coal(); ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_ODL_DPL_CONS); /* Considering the case for SSR. */ if (ipa_ep_idx == -1) { IPADBG("Invalid mapping for IPA_CLIENT_ODL_DPL_CONS\n"); return; for (client = 0; client < IPA_CLIENT_MAX; client++) { if (IPA_CLIENT_IS_APPS_CONS(client)) { res = _ipa_suspend_resume_pipe(client, suspend); if (res) goto undo_cons; } ep = &ipa3_ctx->ep[ipa_ep_idx]; if (ep->valid) { IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend", ipa_ep_idx); /* * move the channel to callback mode. * This needs to happen before starting the channel to make * sure we don't loose any interrupt */ if (!suspend && !atomic_read(&ep->sys->curr_polling_state)) gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_CALLBACK); if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) { } if (suspend) { res = __ipa3_stop_gsi_channel(ipa_ep_idx); if (res) { IPAERR("failed to stop ODL channel\n"); ipa_assert(); struct ipahal_reg_tx_wrapper tx; int ep_idx; ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS); if (ep_idx == IPA_EP_NOT_ALLOCATED || (!ipa3_ctx->ep[ep_idx].valid)) goto do_prod; ipahal_read_reg_fields(IPA_STATE_TX_WRAPPER, &tx); if (tx.coal_slave_open_frame != 0) { IPADBG("COAL frame is open 0x%x\n", tx.coal_slave_open_frame); goto undo_cons; } } else if (!atomic_read(&ipa3_ctx->is_ssr)) { /* If SSR was alreday started not required to * start WAN channel,Because in SSR will stop * channel and reset the channel. */ res = gsi_start_channel(ep->gsi_chan_hdl); usleep_range(IPA_TAG_SLEEP_MIN_USEC, IPA_TAG_SLEEP_MAX_USEC); res = ipahal_read_reg_n(IPA_SUSPEND_IRQ_INFO_EE_n, ipa3_ctx->ee); if (res) { IPAERR("failed to start ODL channel\n"); ipa_assert(); IPADBG("suspend irq is pending 0x%x\n", res); goto undo_cons; } } } else { ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg); do_prod: for (client = 0; client < IPA_CLIENT_MAX; client++) { if (IPA_CLIENT_IS_APPS_PROD(client)) { res = _ipa_suspend_resume_pipe(client, suspend); if (res) goto undo_prod; } if (suspend) ipa3_gsi_poll_after_suspend(ep); } return 0; undo_prod: for (client--; client < IPA_CLIENT_MAX && client >= 0; client--) if (IPA_CLIENT_IS_APPS_PROD(client)) _ipa_suspend_resume_pipe(client, !suspend); client = IPA_CLIENT_MAX; undo_cons: for (client--; client < IPA_CLIENT_MAX && client >= 0; client--) if (IPA_CLIENT_IS_APPS_CONS(client)) _ipa_suspend_resume_pipe(client, !suspend); return res; } int ipa3_allocate_dma_task_for_gsi(void) Loading drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +112 −0 Original line number Diff line number Diff line Loading @@ -1180,6 +1180,112 @@ static void ipareg_parse_comp_cfg_v4_5( IPA_COMP_CFG_IPA_FULL_FLUSH_WAIT_RSC_CLOSURE_EN_BMSK_v4_5); } static void ipareg_parse_state_tx_wrapper_v4_5( enum ipahal_reg_name reg, void *fields, u32 val) { struct ipahal_reg_tx_wrapper *tx = (struct ipahal_reg_tx_wrapper *)fields; tx->tx0_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_TX0_IDLE_SHFT, IPA_STATE_TX_WRAPPER_TX0_IDLE_BMSK); tx->tx1_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_TX1_IDLE_SHFT, IPA_STATE_TX_WRAPPER_TX1_IDLE_BMSK); tx->ipa_prod_ackmngr_db_empty = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_DB_EMPTY_SHFT, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_DB_EMPTY_BMSK); tx->ipa_prod_ackmngr_state_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_STATE_IDLE_SHFT, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_STATE_IDLE_BMSK); tx->ipa_prod_prod_bresp_empty = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_SHFT, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_BMSK); tx->ipa_prod_prod_bresp_toggle_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_SHFT, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_BMSK); tx->ipa_mbim_pkt_fms_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_MBIM_PKT_FMS_IDLE_SHFT, IPA_STATE_TX_WRAPPER_IPA_MBIM_PKT_FMS_IDLE_BMSK); tx->mbim_direct_dma = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_MBIM_DIRECT_DMA_SHFT, IPA_STATE_TX_WRAPPER_MBIM_DIRECT_DMA_BMSK); tx->trnseq_force_valid = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_TRNSEQ_FORCE_VALID_SHFT, IPA_STATE_TX_WRAPPER_TRNSEQ_FORCE_VALID_BMSK); tx->pkt_drop_cnt_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_PKT_DROP_CNT_IDLE_SHFT, IPA_STATE_TX_WRAPPER_PKT_DROP_CNT_IDLE_BMSK); tx->nlo_direct_dma = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_NLO_DIRECT_DMA_SHFT, IPA_STATE_TX_WRAPPER_NLO_DIRECT_DMA_BMSK); tx->coal_direct_dma = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_DIRECT_DMA_SHFT, IPA_STATE_TX_WRAPPER_COAL_DIRECT_DMA_BMSK); tx->coal_slave_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_IDLE_SHFT, IPA_STATE_TX_WRAPPER_COAL_SLAVE_IDLE_BMSK); tx->coal_slave_ctx_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_CTX_IDLE_SHFT, IPA_STATE_TX_WRAPPER_COAL_SLAVE_CTX_IDLE_BMSK); tx->coal_slave_open_frame = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_OPEN_FRAME_SHFT, IPA_STATE_TX_WRAPPER_COAL_SLAVE_OPEN_FRAME_BMSK); } static void ipareg_parse_state_tx_wrapper_v4_7( enum ipahal_reg_name reg, void *fields, u32 val) { struct ipahal_reg_tx_wrapper *tx = (struct ipahal_reg_tx_wrapper *)fields; tx->tx0_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_TX0_IDLE_SHFT_v4_7, IPA_STATE_TX_WRAPPER_TX0_IDLE_BMSK_v4_7); tx->tx1_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_TX1_IDLE_SHFT_v4_7, IPA_STATE_TX_WRAPPER_TX1_IDLE_BMSK_v4_7); tx->ipa_prod_ackmngr_db_empty = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_DB_EMPTY_SHFT_v4_7, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_DB_EMPTY_BMSK_v4_7); tx->ipa_prod_ackmngr_state_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_STATE_IDLE_SHFT_v4_7, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_STATE_IDLE_BMSK_v4_7); tx->ipa_prod_prod_bresp_empty = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_SHFT_v4_7, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_BMSK_v4_7); tx->coal_slave_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_IDLE_SHFT_v4_7, IPA_STATE_TX_WRAPPER_COAL_SLAVE_IDLE_BMSK_v4_7); tx->coal_slave_ctx_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_CTX_IDLE_SHFT_v4_7, IPA_STATE_TX_WRAPPER_COAL_SLAVE_CTX_IDLE_BMSK_v4_7); tx->coal_slave_open_frame = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_OPEN_FRAME_SHFT_v4_7, IPA_STATE_TX_WRAPPER_COAL_SLAVE_OPEN_FRAME_BMSK_v4_7); } static void ipareg_construct_qcncm( enum ipahal_reg_name reg, const void *fields, u32 *val) { Loading Loading @@ -2968,6 +3074,9 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { [IPA_HW_v4_5][IPA_COMP_CFG] = { ipareg_construct_comp_cfg_v4_5, ipareg_parse_comp_cfg_v4_5, 0x0000003C, 0, 0, 0, 0}, [IPA_HW_v4_5][IPA_STATE_TX_WRAPPER] = { ipareg_construct_dummy, ipareg_parse_state_tx_wrapper_v4_5, 0x00000090, 0, 0, 0, 1 }, [IPA_HW_v4_5][IPA_STATE_FETCHER_MASK] = { ipareg_construct_dummy, ipareg_parse_dummy, -1, 0, 0, 0, 0}, Loading Loading @@ -3167,6 +3276,9 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { [IPA_HW_v4_5][IPA_COAL_QMAP_CFG] = { ipareg_construct_coal_qmap_cfg, ipareg_parse_coal_qmap_cfg, 0x00001810, 0, 0, 0, 0}, [IPA_HW_v4_7][IPA_STATE_TX_WRAPPER] = { ipareg_construct_dummy, ipareg_parse_state_tx_wrapper_v4_7, 0x00000090, 0, 0, 0, 1 }, }; /* Loading Loading
drivers/platform/msm/gsi/gsi.c +3 −3 Original line number Diff line number Diff line Loading @@ -3719,7 +3719,7 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) curr = GSI_CHAN_MODE_CALLBACK; if (mode == curr) { GSIERR("already in requested mode %u chan_hdl=%lu\n", GSIDBG("already in requested mode %u chan_hdl=%lu\n", curr, chan_hdl); return -GSI_STATUS_UNSUPPORTED_OP; } Loading @@ -3730,7 +3730,7 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) gsi_writel(1 << ctx->evtr->id, gsi_ctx->base + GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(gsi_ctx->per.ee)); atomic_set(&ctx->poll_mode, mode); if (ctx->props.prot == GSI_CHAN_PROT_GCI) if ((ctx->props.prot == GSI_CHAN_PROT_GCI) && ctx->evtr->chan) atomic_set(&ctx->evtr->chan->poll_mode, mode); GSIDBG("set gsi_ctx evtr_id %d to %d mode\n", ctx->evtr->id, mode); Loading @@ -3740,7 +3740,7 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) if (curr == GSI_CHAN_MODE_POLL && mode == GSI_CHAN_MODE_CALLBACK) { atomic_set(&ctx->poll_mode, mode); if (ctx->props.prot == GSI_CHAN_PROT_GCI) if ((ctx->props.prot == GSI_CHAN_PROT_GCI) && ctx->evtr->chan) atomic_set(&ctx->evtr->chan->poll_mode, mode); __gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0); GSIDBG("set gsi_ctx evtr_id %d to %d mode\n", Loading
drivers/platform/msm/ipa/ipa_v3/ipa.c +15 −5 Original line number Diff line number Diff line Loading @@ -54,6 +54,8 @@ #include "ipa_trace.h" #include "ipa_odl.h" #define IPA_SUSPEND_BUSY_TIMEOUT (msecs_to_jiffies(10)) /* * The following for adding code (ie. for EMULATION) not found on x86. */ Loading Loading @@ -117,7 +119,7 @@ static void ipa3_load_ipa_fw(struct work_struct *work); static DECLARE_WORK(ipa3_fw_loading_work, ipa3_load_ipa_fw); static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work); static DECLARE_WORK(ipa_dec_clients_disable_clks_on_wq_work, static DECLARE_DELAYED_WORK(ipa_dec_clients_disable_clks_on_wq_work, ipa_dec_clients_disable_clks_on_wq); static int ipa3_ioctl_add_rt_rule_v2(unsigned long arg); Loading Loading @@ -4815,8 +4817,16 @@ static void __ipa3_dec_client_disable_clks(void) ret = atomic_sub_return(1, &ipa3_ctx->ipa3_active_clients.cnt); if (ret > 0) goto unlock_mutex; ipa3_suspend_apps_pipes(true); ret = ipa3_suspend_apps_pipes(true); if (ret) { /* HW is busy, retry after some time */ atomic_inc(&ipa3_ctx->ipa3_active_clients.cnt); queue_delayed_work(ipa3_ctx->power_mgmt_wq, &ipa_dec_clients_disable_clks_on_wq_work, IPA_SUSPEND_BUSY_TIMEOUT); } else { ipa3_disable_clks(); } unlock_mutex: mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex); Loading Loading @@ -4869,8 +4879,8 @@ void ipa3_dec_client_disable_clks_no_block( } /* seems like this is the only client holding the clocks */ queue_work(ipa3_ctx->power_mgmt_wq, &ipa_dec_clients_disable_clks_on_wq_work); queue_delayed_work(ipa3_ctx->power_mgmt_wq, &ipa_dec_clients_disable_clks_on_wq_work, 0); } /** Loading
drivers/platform/msm/ipa/ipa_v3/ipa_i.h +1 −1 Original line number Diff line number Diff line Loading @@ -2915,7 +2915,7 @@ int ipa3_create_wdi_mapping(u32 num_buffers, struct ipa_wdi_buffer_info *info); int ipa3_set_flt_tuple_mask(int pipe_idx, struct ipahal_reg_hash_tuple *tuple); int ipa3_set_rt_tuple_mask(int tbl_idx, struct ipahal_reg_hash_tuple *tuple); void ipa3_set_resorce_groups_min_max_limits(void); void ipa3_suspend_apps_pipes(bool suspend); int ipa3_suspend_apps_pipes(bool suspend); int ipa3_flt_read_tbl_from_hw(u32 pipe_idx, enum ipa_ip_type ip_type, bool hashable, Loading
drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +142 −117 Original line number Diff line number Diff line Loading @@ -7484,12 +7484,10 @@ void ipa3_set_resorce_groups_min_max_limits(void) IPADBG("EXIT\n"); } static void ipa3_gsi_poll_after_suspend(struct ipa3_ep_context *ep) static bool ipa3_gsi_channel_is_quite(struct ipa3_ep_context *ep) { bool empty; IPADBG("switch ch %ld to poll\n", ep->gsi_chan_hdl); gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL); gsi_is_channel_empty(ep->gsi_chan_hdl, &empty); if (!empty) { IPADBG("ch %ld not empty\n", ep->gsi_chan_hdl); Loading @@ -7498,6 +7496,7 @@ static void ipa3_gsi_poll_after_suspend(struct ipa3_ep_context *ep) if (!atomic_read(&ep->sys->curr_polling_state)) __ipa_gsi_irq_rx_scedule_poll(ep->sys); } return empty; } static int __ipa3_stop_gsi_channel(u32 clnt_hdl) Loading Loading @@ -7623,36 +7622,38 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl) return res; } void ipa3_suspend_apps_pipes(bool suspend) static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend) { struct ipa_ep_cfg_ctrl cfg; int ipa_ep_idx; struct ipa3_ep_context *ep; int res; memset(&cfg, 0, sizeof(cfg)); cfg.ipa_ep_suspend = suspend; if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) { IPAERR("not supported\n"); return -EPERM; } ipa_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS); ipa_ep_idx = ipa3_get_ep_mapping(client); if (ipa_ep_idx < 0) { IPAERR("IPA client mapping failed\n"); ipa_assert(); return; IPADBG("client %d not configured\n", client); return 0; } ep = &ipa3_ctx->ep[ipa_ep_idx]; if (ep->valid) { IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend", ipa_ep_idx); if (!ep->valid) return 0; IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend", ipa_ep_idx); /* * move the channel to callback mode. * This needs to happen before starting the channel to make * sure we don't loose any interrupt */ if (!suspend && !atomic_read(&ep->sys->curr_polling_state)) if (!suspend && !atomic_read(&ep->sys->curr_polling_state) && !IPA_CLIENT_IS_APPS_PROD(client)) gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_CALLBACK); if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) { if (suspend) { res = __ipa3_stop_gsi_channel(ipa_ep_idx); if (res) { Loading @@ -7666,98 +7667,122 @@ void ipa3_suspend_apps_pipes(bool suspend) ipa_assert(); } } } else { ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg); /* Apps prod pipes use common event ring so cannot configure mode*/ if (IPA_CLIENT_IS_APPS_PROD(client)) return 0; if (suspend) { IPADBG("switch ch %ld to poll\n", ep->gsi_chan_hdl); gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL); if (!ipa3_gsi_channel_is_quite(ep)) return -EAGAIN; } else if (!atomic_read(&ep->sys->curr_polling_state)) { IPADBG("switch ch %ld to callback\n", ep->gsi_chan_hdl); gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_CALLBACK); } if (suspend) ipa3_gsi_poll_after_suspend(ep); return 0; } ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS); /* Considering the case for SSR. */ if (ipa_ep_idx == -1) { IPADBG("Invalid mapping for IPA_CLIENT_APPS_WAN_CONS\n"); void ipa3_force_close_coal(void) { struct ipahal_imm_cmd_pyld *cmd_pyld = NULL; struct ipahal_imm_cmd_register_write reg_write_cmd = { 0 }; struct ipahal_reg_valmask valmask; struct ipa3_desc desc; int ep_idx; ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS); if (ep_idx == IPA_EP_NOT_ALLOCATED || (!ipa3_ctx->ep[ep_idx].valid)) return; } ep = &ipa3_ctx->ep[ipa_ep_idx]; if (ep->valid) { IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend", ipa_ep_idx); /* * move the channel to callback mode. * This needs to happen before starting the channel to make * sure we don't loose any interrupt */ if (!suspend && !atomic_read(&ep->sys->curr_polling_state)) gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_CALLBACK); if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) { if (suspend) { res = __ipa3_stop_gsi_channel(ipa_ep_idx); if (res) { IPAERR("failed to stop WAN channel\n"); reg_write_cmd.skip_pipeline_clear = false; reg_write_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; reg_write_cmd.offset = ipahal_get_reg_ofst(IPA_AGGR_FORCE_CLOSE); ipahal_get_aggr_force_close_valmask(ep_idx, &valmask); reg_write_cmd.value = valmask.val; reg_write_cmd.value_mask = valmask.mask; cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE, ®_write_cmd, false); if (!cmd_pyld) { IPAERR("fail construct register_write imm cmd\n"); ipa_assert(); return; } } else if (!atomic_read(&ipa3_ctx->is_ssr)) { /* If SSR was alreday started not required to * start WAN channel,Because in SSR will stop * channel and reset the channel. */ res = gsi_start_channel(ep->gsi_chan_hdl); if (res) { IPAERR("failed to start WAN channel\n"); ipa3_init_imm_cmd_desc(&desc, cmd_pyld); IPADBG("Sending 1 descriptor for coal force close\n"); if (ipa3_send_cmd_timeout(1, &desc, IPA_DMA_TASK_FOR_GSI_TIMEOUT_MSEC)) { IPAERR("ipa3_send_cmd failed\n"); ipa_assert(); } ipahal_destroy_imm_cmd(cmd_pyld); } } else { ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg); } int ipa3_suspend_apps_pipes(bool suspend) { int res; enum ipa_client_type client; if (suspend) ipa3_gsi_poll_after_suspend(ep); } ipa3_force_close_coal(); ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_ODL_DPL_CONS); /* Considering the case for SSR. */ if (ipa_ep_idx == -1) { IPADBG("Invalid mapping for IPA_CLIENT_ODL_DPL_CONS\n"); return; for (client = 0; client < IPA_CLIENT_MAX; client++) { if (IPA_CLIENT_IS_APPS_CONS(client)) { res = _ipa_suspend_resume_pipe(client, suspend); if (res) goto undo_cons; } ep = &ipa3_ctx->ep[ipa_ep_idx]; if (ep->valid) { IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend", ipa_ep_idx); /* * move the channel to callback mode. * This needs to happen before starting the channel to make * sure we don't loose any interrupt */ if (!suspend && !atomic_read(&ep->sys->curr_polling_state)) gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_CALLBACK); if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) { } if (suspend) { res = __ipa3_stop_gsi_channel(ipa_ep_idx); if (res) { IPAERR("failed to stop ODL channel\n"); ipa_assert(); struct ipahal_reg_tx_wrapper tx; int ep_idx; ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS); if (ep_idx == IPA_EP_NOT_ALLOCATED || (!ipa3_ctx->ep[ep_idx].valid)) goto do_prod; ipahal_read_reg_fields(IPA_STATE_TX_WRAPPER, &tx); if (tx.coal_slave_open_frame != 0) { IPADBG("COAL frame is open 0x%x\n", tx.coal_slave_open_frame); goto undo_cons; } } else if (!atomic_read(&ipa3_ctx->is_ssr)) { /* If SSR was alreday started not required to * start WAN channel,Because in SSR will stop * channel and reset the channel. */ res = gsi_start_channel(ep->gsi_chan_hdl); usleep_range(IPA_TAG_SLEEP_MIN_USEC, IPA_TAG_SLEEP_MAX_USEC); res = ipahal_read_reg_n(IPA_SUSPEND_IRQ_INFO_EE_n, ipa3_ctx->ee); if (res) { IPAERR("failed to start ODL channel\n"); ipa_assert(); IPADBG("suspend irq is pending 0x%x\n", res); goto undo_cons; } } } else { ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg); do_prod: for (client = 0; client < IPA_CLIENT_MAX; client++) { if (IPA_CLIENT_IS_APPS_PROD(client)) { res = _ipa_suspend_resume_pipe(client, suspend); if (res) goto undo_prod; } if (suspend) ipa3_gsi_poll_after_suspend(ep); } return 0; undo_prod: for (client--; client < IPA_CLIENT_MAX && client >= 0; client--) if (IPA_CLIENT_IS_APPS_PROD(client)) _ipa_suspend_resume_pipe(client, !suspend); client = IPA_CLIENT_MAX; undo_cons: for (client--; client < IPA_CLIENT_MAX && client >= 0; client--) if (IPA_CLIENT_IS_APPS_CONS(client)) _ipa_suspend_resume_pipe(client, !suspend); return res; } int ipa3_allocate_dma_task_for_gsi(void) Loading
drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +112 −0 Original line number Diff line number Diff line Loading @@ -1180,6 +1180,112 @@ static void ipareg_parse_comp_cfg_v4_5( IPA_COMP_CFG_IPA_FULL_FLUSH_WAIT_RSC_CLOSURE_EN_BMSK_v4_5); } static void ipareg_parse_state_tx_wrapper_v4_5( enum ipahal_reg_name reg, void *fields, u32 val) { struct ipahal_reg_tx_wrapper *tx = (struct ipahal_reg_tx_wrapper *)fields; tx->tx0_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_TX0_IDLE_SHFT, IPA_STATE_TX_WRAPPER_TX0_IDLE_BMSK); tx->tx1_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_TX1_IDLE_SHFT, IPA_STATE_TX_WRAPPER_TX1_IDLE_BMSK); tx->ipa_prod_ackmngr_db_empty = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_DB_EMPTY_SHFT, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_DB_EMPTY_BMSK); tx->ipa_prod_ackmngr_state_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_STATE_IDLE_SHFT, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_STATE_IDLE_BMSK); tx->ipa_prod_prod_bresp_empty = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_SHFT, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_BMSK); tx->ipa_prod_prod_bresp_toggle_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_SHFT, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_BMSK); tx->ipa_mbim_pkt_fms_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_MBIM_PKT_FMS_IDLE_SHFT, IPA_STATE_TX_WRAPPER_IPA_MBIM_PKT_FMS_IDLE_BMSK); tx->mbim_direct_dma = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_MBIM_DIRECT_DMA_SHFT, IPA_STATE_TX_WRAPPER_MBIM_DIRECT_DMA_BMSK); tx->trnseq_force_valid = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_TRNSEQ_FORCE_VALID_SHFT, IPA_STATE_TX_WRAPPER_TRNSEQ_FORCE_VALID_BMSK); tx->pkt_drop_cnt_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_PKT_DROP_CNT_IDLE_SHFT, IPA_STATE_TX_WRAPPER_PKT_DROP_CNT_IDLE_BMSK); tx->nlo_direct_dma = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_NLO_DIRECT_DMA_SHFT, IPA_STATE_TX_WRAPPER_NLO_DIRECT_DMA_BMSK); tx->coal_direct_dma = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_DIRECT_DMA_SHFT, IPA_STATE_TX_WRAPPER_COAL_DIRECT_DMA_BMSK); tx->coal_slave_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_IDLE_SHFT, IPA_STATE_TX_WRAPPER_COAL_SLAVE_IDLE_BMSK); tx->coal_slave_ctx_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_CTX_IDLE_SHFT, IPA_STATE_TX_WRAPPER_COAL_SLAVE_CTX_IDLE_BMSK); tx->coal_slave_open_frame = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_OPEN_FRAME_SHFT, IPA_STATE_TX_WRAPPER_COAL_SLAVE_OPEN_FRAME_BMSK); } static void ipareg_parse_state_tx_wrapper_v4_7( enum ipahal_reg_name reg, void *fields, u32 val) { struct ipahal_reg_tx_wrapper *tx = (struct ipahal_reg_tx_wrapper *)fields; tx->tx0_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_TX0_IDLE_SHFT_v4_7, IPA_STATE_TX_WRAPPER_TX0_IDLE_BMSK_v4_7); tx->tx1_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_TX1_IDLE_SHFT_v4_7, IPA_STATE_TX_WRAPPER_TX1_IDLE_BMSK_v4_7); tx->ipa_prod_ackmngr_db_empty = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_DB_EMPTY_SHFT_v4_7, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_DB_EMPTY_BMSK_v4_7); tx->ipa_prod_ackmngr_state_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_STATE_IDLE_SHFT_v4_7, IPA_STATE_TX_WRAPPER_IPA_PROD_ACKMNGR_STATE_IDLE_BMSK_v4_7); tx->ipa_prod_prod_bresp_empty = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_SHFT_v4_7, IPA_STATE_TX_WRAPPER_IPA_PROD_BRESP_EMPTY_BMSK_v4_7); tx->coal_slave_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_IDLE_SHFT_v4_7, IPA_STATE_TX_WRAPPER_COAL_SLAVE_IDLE_BMSK_v4_7); tx->coal_slave_ctx_idle = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_CTX_IDLE_SHFT_v4_7, IPA_STATE_TX_WRAPPER_COAL_SLAVE_CTX_IDLE_BMSK_v4_7); tx->coal_slave_open_frame = IPA_GETFIELD_FROM_REG(val, IPA_STATE_TX_WRAPPER_COAL_SLAVE_OPEN_FRAME_SHFT_v4_7, IPA_STATE_TX_WRAPPER_COAL_SLAVE_OPEN_FRAME_BMSK_v4_7); } static void ipareg_construct_qcncm( enum ipahal_reg_name reg, const void *fields, u32 *val) { Loading Loading @@ -2968,6 +3074,9 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { [IPA_HW_v4_5][IPA_COMP_CFG] = { ipareg_construct_comp_cfg_v4_5, ipareg_parse_comp_cfg_v4_5, 0x0000003C, 0, 0, 0, 0}, [IPA_HW_v4_5][IPA_STATE_TX_WRAPPER] = { ipareg_construct_dummy, ipareg_parse_state_tx_wrapper_v4_5, 0x00000090, 0, 0, 0, 1 }, [IPA_HW_v4_5][IPA_STATE_FETCHER_MASK] = { ipareg_construct_dummy, ipareg_parse_dummy, -1, 0, 0, 0, 0}, Loading Loading @@ -3167,6 +3276,9 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { [IPA_HW_v4_5][IPA_COAL_QMAP_CFG] = { ipareg_construct_coal_qmap_cfg, ipareg_parse_coal_qmap_cfg, 0x00001810, 0, 0, 0, 0}, [IPA_HW_v4_7][IPA_STATE_TX_WRAPPER] = { ipareg_construct_dummy, ipareg_parse_state_tx_wrapper_v4_7, 0x00000090, 0, 0, 0, 1 }, }; /* Loading