diff options
Diffstat (limited to 'drivers')
43 files changed, 982 insertions, 227 deletions
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index a84172106e0f..8017961783f7 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -291,6 +291,7 @@ struct fastrpc_file { int cid; int ssrcount; int pd; + int file_close; struct fastrpc_apps *apps; struct fastrpc_perf perf; struct dentry *debugfs_file; @@ -319,6 +320,7 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .channel = SMD_APPS_DSPS, .link.link_info.edge = "dsps", .link.link_info.transport = "smem", + .vmid = VMID_SSC_Q6, }, { .name = "cdsprpc-smd", @@ -699,7 +701,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, unsigned attr, if (vmid) { int srcVM[1] = {VMID_HLOS}; int destVM[2] = {VMID_HLOS, vmid}; - int destVMperm[2] = {PERM_READ | PERM_WRITE, + int destVMperm[2] = {PERM_READ | PERM_WRITE | PERM_EXEC, PERM_READ | PERM_WRITE | PERM_EXEC}; VERIFY(err, !hyp_assign_phys(map->phys, @@ -771,7 +773,7 @@ static int fastrpc_buf_alloc(struct fastrpc_file *fl, ssize_t size, if (vmid) { int srcVM[1] = {VMID_HLOS}; int destVM[2] = {VMID_HLOS, vmid}; - int destVMperm[2] = {PERM_READ | PERM_WRITE, + int destVMperm[2] = {PERM_READ | PERM_WRITE | PERM_EXEC, PERM_READ | PERM_WRITE | PERM_EXEC}; VERIFY(err, !hyp_assign_phys(buf->phys, buf_page_size(size), @@ -2195,6 +2197,9 @@ static int fastrpc_file_free(struct fastrpc_file *fl) return 0; } (void)fastrpc_release_current_dsp_process(fl); + spin_lock(&fl->hlock); + fl->file_close = 1; + spin_unlock(&fl->hlock); fastrpc_context_list_dtor(fl); fastrpc_buf_list_free(fl); hlist_for_each_entry_safe(map, n, &fl->maps, hn) { @@ -2583,6 +2588,14 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, p.inv.fds = 0; p.inv.attrs = 0; + spin_lock(&fl->hlock); + if (fl->file_close == 1) { + err = EBADF; + pr_warn("ADSPRPC: fastrpc_device_release is happening, So not sending any new requests to DSP"); + spin_unlock(&fl->hlock); + goto bail; + } + spin_unlock(&fl->hlock); switch (ioctl_num) { case FASTRPC_IOCTL_INVOKE: diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index cc56d68217b3..d81a39e2c637 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -642,6 +642,7 @@ struct diagchar_dev { #endif int time_sync_enabled; uint8_t uses_time_api; + struct platform_device *pdev; }; extern struct diagchar_dev *driver; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index afaedc99a4e7..eaed3b101095 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -22,6 +22,8 @@ #include <linux/sched.h> #include <linux/ratelimit.h> #include <linux/timer.h> +#include <linux/platform_device.h> +#include <linux/msm_mhi.h> #ifdef CONFIG_DIAG_OVER_USB #include <linux/usb/usbdiag.h> #endif @@ -701,6 +703,11 @@ static void diag_cmd_invalidate_polling(int change_flag) driver->polling_reg_flag = 0; list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); + if (&item->entry == NULL) { + pr_err("diag: In %s, unable to search command\n", + __func__); + return; + } polling = diag_cmd_chk_polling(&item->entry); if (polling == DIAG_CMD_POLLING) { driver->polling_reg_flag = 1; @@ -842,6 +849,12 @@ void diag_cmd_remove_reg_by_pid(int pid) mutex_lock(&driver->cmd_reg_mutex); list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); + if (&item->entry == NULL) { + pr_err("diag: In %s, unable to search command\n", + __func__); + mutex_unlock(&driver->cmd_reg_mutex); + return; + } if (item->pid == pid) { list_del(&item->link); kfree(item); @@ -860,6 +873,12 @@ void diag_cmd_remove_reg_by_proc(int proc) mutex_lock(&driver->cmd_reg_mutex); list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); + if (&item->entry == NULL) { + pr_err("diag: In %s, unable to search command\n", + __func__); + mutex_unlock(&driver->cmd_reg_mutex); + return; + } if (item->proc == proc) { list_del(&item->link); kfree(item); @@ -1836,14 +1855,18 @@ static int diag_ioctl_lsm_deinit(void) { int i; + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) break; - if (i == driver->num_clients) + if (i == driver->num_clients) { + mutex_unlock(&driver->diagchar_mutex); return -EINVAL; + } driver->data_ready[i] |= DEINIT_TYPE; + mutex_unlock(&driver->diagchar_mutex); wake_up_interruptible(&driver->wait_q); return 1; @@ -3585,6 +3608,41 @@ static int diagchar_cleanup(void) return 0; } +static int diag_mhi_probe(struct platform_device *pdev) +{ + int ret; + + if (!mhi_is_device_ready(&pdev->dev, "qcom,mhi")) + return -EPROBE_DEFER; + driver->pdev = pdev; + ret = diag_remote_init(); + if (ret) { + diag_remote_exit(); + return ret; + } + ret = diagfwd_bridge_init(); + if (ret) { + diagfwd_bridge_exit(); + return ret; + } + pr_debug("diag: mhi device is ready\n"); + return 0; +} + +static const struct of_device_id diag_mhi_table[] = { + {.compatible = "qcom,diag-mhi"}, + {}, +}; + +static struct platform_driver diag_mhi_driver = { + .probe = diag_mhi_probe, + .driver = { + .name = "DIAG MHI Platform", + .owner = THIS_MODULE, + .of_match_table = diag_mhi_table, + }, +}; + static int __init diagchar_init(void) { dev_t dev; @@ -3674,9 +3732,6 @@ static int __init diagchar_init(void) ret = diag_masks_init(); if (ret) goto fail; - ret = diag_remote_init(); - if (ret) - goto fail; ret = diag_mux_init(); if (ret) goto fail; @@ -3713,9 +3768,7 @@ static int __init diagchar_init(void) goto fail; pr_debug("diagchar initialized now"); - ret = diagfwd_bridge_init(); - if (ret) - diagfwd_bridge_exit(); + platform_driver_register(&diag_mhi_driver); return 0; fail: @@ -3729,9 +3782,7 @@ fail: diagfwd_cntl_exit(); diag_dci_exit(); diag_masks_exit(); - diag_remote_exit(); return -1; - } static void diagchar_exit(void) diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index 03133a5a89aa..edfba6bb09c9 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -197,7 +197,7 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) struct diag_mhi_buf_tbl_t *item = NULL; struct diag_mhi_ch_t *ch = NULL; - if (!mhi_info || !mhi_info->enabled) + if (!mhi_info) return; /* Clear all the pending reads */ @@ -678,7 +678,25 @@ static int diag_mhi_register_ch(int id, struct diag_mhi_ch_t *ch) atomic_set(&(ch->opened), 0); ctxt = SET_CH_CTXT(id, ch->type); ch->client_info.mhi_client_cb = mhi_notifier; - return mhi_register_channel(&ch->hdl, NULL); + ch->client_info.chan = ch->chan; + ch->client_info.dev = &driver->pdev->dev; + ch->client_info.node_name = "qcom,mhi"; + ch->client_info.user_data = (void *)(uintptr_t)ctxt; + return mhi_register_channel(&ch->hdl, &ch->client_info); +} + +static void diag_mhi_dev_exit(int dev) +{ + struct diag_mhi_info *mhi_info = NULL; + + mhi_info = &diag_mhi[dev]; + if (!mhi_info) + return; + if (mhi_info->mhi_wq) + destroy_workqueue(mhi_info->mhi_wq); + mhi_close(mhi_info->id); + if (mhi_info->mempool_init) + diagmem_exit(driver, mhi_info->mempool); } int diag_mhi_init() @@ -726,22 +744,16 @@ int diag_mhi_init() return 0; fail: - diag_mhi_exit(); + diag_mhi_dev_exit(i); return -ENOMEM; } void diag_mhi_exit() { int i; - struct diag_mhi_info *mhi_info = NULL; for (i = 0; i < NUM_MHI_DEV; i++) { - mhi_info = &diag_mhi[i]; - if (mhi_info->mhi_wq) - destroy_workqueue(mhi_info->mhi_wq); - mhi_close(mhi_info->id); - if (mhi_info->mempool_init) - diagmem_exit(driver, mhi_info->mempool); + diag_mhi_dev_exit(i); } } diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index 7dd8d3d3f6ad..49165daa807f 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -1432,7 +1432,7 @@ static int qcom_ice_config_start(struct platform_device *pdev, int ret = 0; bool is_pfe = false; - if (!pdev || !req || !setting) { + if (!pdev || !req) { pr_err("%s: Invalid params passed\n", __func__); return -EINVAL; } diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index 1b295949122b..e8b3e85603e4 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -1961,6 +1961,30 @@ enable_packet_control: hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); } +static void sde_hdmi_clear_hdr_infoframe(struct sde_hdmi *display) +{ + struct hdmi *hdmi; + struct drm_connector *connector; + u32 packet_control = 0; + + if (!display) { + SDE_ERROR("invalid input\n"); + return; + } + + hdmi = display->ctrl.ctrl; + connector = display->ctrl.ctrl->connector; + + if (!hdmi || !connector) { + SDE_ERROR("invalid input\n"); + return; + } + + packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL); + packet_control &= ~HDMI_GEN_PKT_CTRL_CLR_MASK; + hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); +} + int sde_hdmi_set_property(struct drm_connector *connector, struct drm_connector_state *state, int property_index, @@ -2305,15 +2329,28 @@ int sde_hdmi_pre_kickoff(struct drm_connector *connector, void *display, struct msm_display_kickoff_params *params) { + struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display; + struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl; + u8 hdr_op; if (!connector || !display || !params) { pr_err("Invalid params\n"); return -EINVAL; } - if (connector->hdr_supported) - sde_hdmi_panel_set_hdr_infoframe(display, - params->hdr_metadata); + hdr_ctrl = params->hdr_ctrl; + + hdr_op = sde_hdmi_hdr_get_ops(hdmi_display->curr_hdr_state, + hdr_ctrl->hdr_state); + + if (hdr_op == HDR_SEND_INFO) { + if (connector->hdr_supported) + sde_hdmi_panel_set_hdr_infoframe(display, + &hdr_ctrl->hdr_meta); + } else if (hdr_op == HDR_CLEAR_INFO) + sde_hdmi_clear_hdr_infoframe(display); + + hdmi_display->curr_hdr_state = hdr_ctrl->hdr_state; return 0; } diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h index 743d34d05e57..bafb2b949a6b 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -147,6 +147,7 @@ struct sde_hdmi { u32 hdcp22_present; u8 hdcp_status; u32 enc_lvl; + u8 curr_hdr_state; bool auth_state; bool sink_hdcp22_support; bool src_hdcp22_support; @@ -198,6 +199,8 @@ enum hdmi_tx_scdc_access_type { #define HDMI_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2 #define HDMI_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 +#define HDMI_GEN_PKT_CTRL_CLR_MASK 0x7 + /* Maximum pixel clock rates for hdmi tx */ #define HDMI_DEFAULT_MAX_PCLK_RATE 148500 #define HDMI_TX_3_MAX_PCLK_RATE 297000 diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c index a4c3c2e7ce46..62dd3aaf7078 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -518,12 +518,17 @@ static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; + struct sde_connector *c_conn = to_sde_connector(hdmi->connector); + struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; /* need to update hdcp info here to ensure right HDCP support*/ sde_hdmi_update_hdcp_info(hdmi->connector); /* start HDCP authentication */ sde_hdmi_start_hdcp(hdmi->connector); + + /* reset HDR state */ + display->curr_hdr_state = HDR_DISABLE; } static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c index ba47b7702efd..a291a1112aeb 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c @@ -68,6 +68,15 @@ static void sde_hdmi_hdcp2p2_ddc_clear_status(struct sde_hdmi *display) hdmi_write(hdmi, HDMI_HDCP2P2_DDC_STATUS, reg_val); } +static const char *sde_hdmi_hdr_sname(enum sde_hdmi_hdr_state hdr_state) +{ + switch (hdr_state) { + case HDR_DISABLE: return "HDR_DISABLE"; + case HDR_ENABLE: return "HDR_ENABLE"; + default: return "HDR_INVALID_STATE"; + } +} + /** * sde_hdmi_dump_regs - utility to dump HDMI regs * @hdmi_display: Pointer to private display handle @@ -898,3 +907,50 @@ int sde_hdmi_sink_dc_support(struct drm_connector *connector, return dc_format; } + +u8 sde_hdmi_hdr_get_ops(u8 curr_state, + u8 new_state) +{ + + /** There could be 3 valid state transitions: + * 1. HDR_DISABLE -> HDR_ENABLE + * + * In this transition, we shall start sending + * HDR metadata with metadata from the HDR clip + * + * 2. HDR_ENABLE -> HDR_ENABLE + * + * In this transition, we will keep sending + * HDR metadata but with EOTF and metadata as 0 + * + * 3. HDR_ENABLE -> HDR_DISABLE + * + * In this transition, we will stop sending + * metadata to the sink and clear PKT_CTRL register + * bits. + */ + + if ((curr_state == HDR_DISABLE) + && (new_state == HDR_ENABLE)) { + HDMI_UTIL_DEBUG("State changed %s ---> %s\n", + sde_hdmi_hdr_sname(curr_state), + sde_hdmi_hdr_sname(new_state)); + return HDR_SEND_INFO; + } else if ((curr_state == HDR_ENABLE) + && (new_state == HDR_ENABLE)) { + HDMI_UTIL_DEBUG("State changed %s ---> %s\n", + sde_hdmi_hdr_sname(curr_state), + sde_hdmi_hdr_sname(new_state)); + return HDR_SEND_INFO; + } else if ((curr_state == HDR_ENABLE) + && (new_state == HDR_DISABLE)) { + HDMI_UTIL_DEBUG("State changed %s ---> %s\n", + sde_hdmi_hdr_sname(curr_state), + sde_hdmi_hdr_sname(new_state)); + return HDR_CLEAR_INFO; + } + + HDMI_UTIL_DEBUG("Unsupported OR no state change\n"); + return HDR_UNSUPPORTED_OP; +} + diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h index 10effed54a14..1d89ae222a7b 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h @@ -125,6 +125,17 @@ enum sde_hdmi_tx_hdcp2p2_rxstatus_intr_mask { RXSTATUS_REAUTH_REQ = BIT(14), }; +enum sde_hdmi_hdr_state { + HDR_DISABLE, + HDR_ENABLE +}; + +enum sde_hdmi_hdr_op { + HDR_UNSUPPORTED_OP, + HDR_SEND_INFO, + HDR_CLEAR_INFO +}; + struct sde_hdmi_tx_hdcp2p2_ddc_data { enum sde_hdmi_tx_hdcp2p2_rxstatus_intr_mask intr_mask; u32 timeout_ms; @@ -170,4 +181,6 @@ bool sde_hdmi_validate_pixclk(struct drm_connector *connector, unsigned long pclk); int sde_hdmi_sink_dc_support(struct drm_connector *connector, struct drm_display_mode *mode); +u8 sde_hdmi_hdr_get_ops(u8 curr_state, + u8 new_state); #endif /* _SDE_HDMI_UTIL_H_ */ diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index ac15f399df7d..08868fce1cb0 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -144,7 +144,7 @@ enum msm_mdp_conn_property { /* blob properties, always put these first */ CONNECTOR_PROP_SDE_INFO, CONNECTOR_PROP_HDR_INFO, - CONNECTOR_PROP_HDR_METADATA, + CONNECTOR_PROP_HDR_CONTROL, /* # of blob properties */ CONNECTOR_PROP_BLOBCOUNT, @@ -237,10 +237,10 @@ struct msm_display_info { /** * struct - msm_display_kickoff_params - info for display features at kickoff - * @hdr_metadata: HDR metadata info passed from userspace + * @hdr_ctrl: HDR control info passed from userspace */ struct msm_display_kickoff_params { - struct drm_msm_ext_panel_hdr_metadata *hdr_metadata; + struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl; }; /** diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 76e6e4ef6e7d..875513d2840f 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -83,7 +83,7 @@ int sde_connector_pre_kickoff(struct drm_connector *connector) if (!c_conn->ops.pre_kickoff) return 0; - params.hdr_metadata = &c_state->hdr_meta; + params.hdr_ctrl = &c_state->hdr_ctrl; rc = c_conn->ops.pre_kickoff(connector, c_conn->display, ¶ms); @@ -247,6 +247,7 @@ static int _sde_connector_set_hdr_info( void *usr_ptr) { struct drm_connector *connector; + struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl; struct drm_msm_ext_panel_hdr_metadata *hdr_meta; int i; @@ -262,21 +263,26 @@ static int _sde_connector_set_hdr_info( return -ENOTSUPP; } - memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta)); + memset(&c_state->hdr_ctrl, 0, sizeof(c_state->hdr_ctrl)); if (!usr_ptr) { - SDE_DEBUG_CONN(c_conn, "hdr metadata cleared\n"); + SDE_DEBUG_CONN(c_conn, "hdr control cleared\n"); return 0; } - if (copy_from_user(&c_state->hdr_meta, + if (copy_from_user(&c_state->hdr_ctrl, (void __user *)usr_ptr, - sizeof(*hdr_meta))) { - SDE_ERROR_CONN(c_conn, "failed to copy hdr metadata\n"); + sizeof(*hdr_ctrl))) { + SDE_ERROR_CONN(c_conn, "failed to copy hdr control\n"); return -EFAULT; } - hdr_meta = &c_state->hdr_meta; + hdr_ctrl = &c_state->hdr_ctrl; + + SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n", + hdr_ctrl->hdr_state); + + hdr_meta = &hdr_ctrl->hdr_meta; SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n", hdr_meta->hdr_supported); @@ -362,7 +368,7 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, SDE_ERROR("invalid topology_control: 0x%llX\n", val); } - if (idx == CONNECTOR_PROP_HDR_METADATA) { + if (idx == CONNECTOR_PROP_HDR_CONTROL) { rc = _sde_connector_set_hdr_info(c_conn, c_state, (void *)val); if (rc) SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc); @@ -718,8 +724,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, } msm_property_install_volatile_range(&c_conn->property_info, - "hdr_metadata", 0x0, 0, ~0, 0, - CONNECTOR_PROP_HDR_METADATA); + "hdr_control", 0x0, 0, ~0, 0, + CONNECTOR_PROP_HDR_CONTROL); msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE", 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE); diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h index 19e2b8a3e41c..8257f29bd4b8 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.h +++ b/drivers/gpu/drm/msm/sde/sde_connector.h @@ -221,14 +221,14 @@ struct sde_connector { * @out_fb: Pointer to output frame buffer, if applicable * @aspace: Address space for accessing frame buffer objects, if applicable * @property_values: Local cache of current connector property values - * @hdr_meta: HDR metadata info passed from userspace + * @hdr_ctrl: HDR control info passed from userspace */ struct sde_connector_state { struct drm_connector_state base; struct drm_framebuffer *out_fb; struct msm_gem_address_space *aspace; uint64_t property_values[CONNECTOR_PROP_COUNT]; - struct drm_msm_ext_panel_hdr_metadata hdr_meta; + struct drm_msm_ext_panel_hdr_ctrl hdr_ctrl; }; /** diff --git a/drivers/hwtracing/coresight/coresight-remote-etm.c b/drivers/hwtracing/coresight/coresight-remote-etm.c index 30b13282f6c0..cc0b25b130d7 100644 --- a/drivers/hwtracing/coresight/coresight-remote-etm.c +++ b/drivers/hwtracing/coresight/coresight-remote-etm.c @@ -186,12 +186,9 @@ static void remote_etm_rcv_msg(struct work_struct *work) struct remote_etm_drvdata *drvdata = container_of(work, struct remote_etm_drvdata, work_rcv_msg); - mutex_lock(&drvdata->mutex); if (qmi_recv_msg(drvdata->handle) < 0) dev_err(drvdata->dev, "%s: Error receiving QMI message\n", __func__); - - mutex_unlock(&drvdata->mutex); } static void remote_etm_notify(struct qmi_handle *handle, diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c index 4f6086970131..43d566fd38ae 100644 --- a/drivers/md/dm-android-verity.c +++ b/drivers/md/dm-android-verity.c @@ -645,6 +645,8 @@ static int add_as_linear_device(struct dm_target *ti, char *dev) android_verity_target.iterate_devices = dm_linear_iterate_devices, android_verity_target.io_hints = NULL; + set_disk_ro(dm_disk(dm_table_get_md(ti->table)), 0); + err = dm_linear_ctr(ti, DM_LINEAR_ARGS, linear_table_args); if (!err) { diff --git a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c index 1adb380f335f..40806d5a164f 100644 --- a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c @@ -1722,6 +1722,10 @@ static long msm_actuator_subdev_do_ioctl( parg = &actuator_data; break; } + break; + case VIDIOC_MSM_ACTUATOR_CFG: + pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd); + return -EINVAL; } rc = msm_actuator_subdev_ioctl(sd, cmd, parg); diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c index e40869d41a5d..821833d53905 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -903,26 +903,45 @@ int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, void msm_jpeg_io_dump(void *base, int size) { - char line_str[128], *p_str; + char line_str[128]; void __iomem *addr = (void __iomem *)base; int i; u32 *p = (u32 *) addr; + size_t offset = 0; + size_t used = 0; + size_t min_range = 0; + size_t sizeof_line_str = sizeof(line_str); u32 data; JPEG_DBG_HIGH("%s:%d] %pK %d", __func__, __LINE__, addr, size); line_str[0] = '\0'; - p_str = line_str; for (i = 0; i < size/4; i++) { if (i % 4 == 0) { - snprintf(p_str, 12, "%08lx: ", (unsigned long)p); - p_str += 10; + used = snprintf(line_str + offset, + sizeof_line_str - offset, "%pK ", p); + if ((used < min_range) || + (offset + used >= sizeof_line_str)) { + JPEG_PR_ERR("%s\n", line_str); + offset = 0; + line_str[0] = '\0'; + } else { + offset += used; + } } data = msm_camera_io_r(p++); - snprintf(p_str, 12, "%08x ", data); - p_str += 9; + used = snprintf(line_str + offset, + sizeof_line_str - offset, "%08x ", data); + if ((used < min_range) || + (offset + used >= sizeof_line_str)) { + JPEG_PR_ERR("%s\n", line_str); + offset = 0; + line_str[0] = '\0'; + } else { + offset += used; + } if ((i + 1) % 4 == 0) { JPEG_DBG_HIGH("%s\n", line_str); line_str[0] = '\0'; - p_str = line_str; + offset = 0; } } if (line_str[0] != '\0') diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 28a4006b480c..0f6389370643 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -1491,6 +1491,7 @@ static int msm_vdec_queue_setup(struct vb2_queue *q, rc = -EINVAL; break; } + msm_dcvs_try_enable(inst); /* Pretend as if FW itself is asking for * additional buffers. @@ -1570,9 +1571,10 @@ exit: return rc; } -static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst) +static int set_max_internal_buffers_size(struct msm_vidc_inst *inst) { int rc = 0; + struct msm_vidc_list *buf_list = &inst->scratchbufs; struct { enum hal_buffer type; struct hal_buffer_requirements *req; @@ -1580,13 +1582,17 @@ static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst) } internal_buffers[] = { { HAL_BUFFER_INTERNAL_SCRATCH, NULL, 0}, { HAL_BUFFER_INTERNAL_SCRATCH_1, NULL, 0}, - { HAL_BUFFER_INTERNAL_SCRATCH_2, NULL, 0}, - { HAL_BUFFER_INTERNAL_PERSIST, NULL, 0}, - { HAL_BUFFER_INTERNAL_PERSIST_1, NULL, 0}, }; struct hal_frame_size frame_sz; int i; + mutex_lock(&buf_list->lock); + if (!list_empty(&buf_list->list)) { + dprintk(VIDC_DBG, "Scratch list already has allocated buf\n"); + mutex_unlock(&buf_list->lock); + return 0; + } + mutex_unlock(&buf_list->lock); frame_sz.buffer_type = HAL_BUFFER_INPUT; frame_sz.width = inst->capability.width.max; @@ -1612,6 +1618,15 @@ static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst) get_buff_req_buffer(inst, internal_buffers[i].type); internal_buffers[i].size = internal_buffers[i].req ? internal_buffers[i].req->buffer_size : 0; + + rc = allocate_and_set_internal_bufs(inst, + internal_buffers[i].req, + &inst->scratchbufs, false); + if (rc) + goto alloc_fail; + dprintk(VIDC_DBG, + "Allocated scratch type : %d size to : %zd\n", + internal_buffers[i].type, internal_buffers[i].size); } frame_sz.buffer_type = HAL_BUFFER_INPUT; @@ -1624,25 +1639,18 @@ static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst) dprintk(VIDC_ERR, "%s Failed to get back old buf req, %d\n", __func__, rc); - return rc; + goto alloc_fail; } - dprintk(VIDC_DBG, "Old buffer reqs, buffer type = %d width = %d, height = %d\n", frame_sz.buffer_type, frame_sz.width, frame_sz.height); - for (i = 0; i < ARRAY_SIZE(internal_buffers); i++) { - if (internal_buffers[i].req) { - internal_buffers[i].req->buffer_size = - internal_buffers[i].size; - dprintk(VIDC_DBG, - "Changing buffer type : %d size to : %zd\n", - internal_buffers[i].type, - internal_buffers[i].size); - } - } return 0; + +alloc_fail: + msm_comm_release_scratch_buffers(inst, false); + return rc; } static inline int start_streaming(struct msm_vidc_inst *inst) @@ -1653,6 +1661,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst) struct hal_buffer_size_minimum b; unsigned int buffer_size; struct msm_vidc_format *fmt = NULL; + bool max_internal_buf = false; fmt = &inst->fmts[CAPTURE_PORT]; buffer_size = fmt->get_frame_size(0, @@ -1676,8 +1685,9 @@ static inline int start_streaming(struct msm_vidc_inst *inst) dprintk(VIDC_ERR, "H/w scaling is not in valid range\n"); return -EINVAL; } - if ((inst->flags & VIDC_SECURE) && !inst->in_reconfig && - !slave_side_cp) { + max_internal_buf = (inst->flags & VIDC_SECURE) && !slave_side_cp + && (inst->session_type == MSM_VIDC_DECODER); + if (max_internal_buf) { rc = set_max_internal_buffers_size(inst); if (rc) { dprintk(VIDC_ERR, @@ -1686,7 +1696,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst) goto fail_start; } } - rc = msm_comm_set_scratch_buffers(inst); + rc = msm_comm_set_scratch_buffers(inst, max_internal_buf); if (rc) { dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc); diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index c5816511e056..e4698e0cdcd8 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1868,7 +1868,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst) "Failed to get Buffer Requirements : %d\n", rc); goto fail_start; } - rc = msm_comm_set_scratch_buffers(inst); + rc = msm_comm_set_scratch_buffers(inst, false); if (rc) { dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc); goto fail_start; diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 2b3070974df8..de4705c3d2eb 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -826,7 +826,8 @@ int output_buffer_cache_invalidate(struct msm_vidc_inst *inst, if (inst->session_type == MSM_VIDC_ENCODER && !i) - size = b->m.planes[i].bytesused; + size = b->m.planes[i].bytesused + + b->m.planes[i].data_offset; else size = -1; @@ -1060,7 +1061,8 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) if (binfo->handle[i] && (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) { if (inst->session_type == MSM_VIDC_DECODER && !i) - size = b->m.planes[i].bytesused; + size = b->m.planes[i].bytesused + + b->m.planes[i].data_offset; else size = -1; rc = msm_comm_smem_cache_operations(inst, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index f85fe6fd3867..1d910f4b235c 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -3342,9 +3342,9 @@ static bool reuse_internal_buffers(struct msm_vidc_inst *inst, return reused; } -static int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, +int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, struct hal_buffer_requirements *internal_bufreq, - struct msm_vidc_list *buf_list) + struct msm_vidc_list *buf_list, bool set_on_fw) { struct msm_smem *handle; struct internal_buf *binfo; @@ -3381,11 +3381,13 @@ static int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, binfo->handle = handle; binfo->buffer_type = internal_bufreq->buffer_type; - rc = set_internal_buf_on_fw(inst, internal_bufreq->buffer_type, - handle, false); - if (rc) - goto fail_set_buffers; - + if (set_on_fw) { + rc = set_internal_buf_on_fw(inst, + internal_bufreq->buffer_type, + handle, false); + if (rc) + goto fail_set_buffers; + } mutex_lock(&buf_list->lock); list_add_tail(&binfo->list, &buf_list->list); mutex_unlock(&buf_list->lock); @@ -3426,7 +3428,7 @@ static int set_internal_buffers(struct msm_vidc_inst *inst, return 0; return allocate_and_set_internal_bufs(inst, internal_buf, - buf_list); + buf_list, true); } int msm_comm_try_state(struct msm_vidc_inst *inst, int state) @@ -3587,39 +3589,6 @@ int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd) "Failed to flush buffers: %d\n", rc); } break; - case V4L2_DEC_QCOM_CMD_RECONFIG_HINT: - { - u32 *ptr = NULL; - struct hal_buffer_requirements *output_buf; - - rc = msm_comm_try_get_bufreqs(inst); - if (rc) { - dprintk(VIDC_ERR, - "Getting buffer requirements failed: %d\n", - rc); - break; - } - - output_buf = get_buff_req_buffer(inst, - msm_comm_get_hal_output_buffer(inst)); - if (output_buf) { - if (dec) { - ptr = (u32 *)dec->raw.data; - ptr[0] = output_buf->buffer_size; - ptr[1] = output_buf->buffer_count_actual; - dprintk(VIDC_DBG, - "Reconfig hint, size is %u, count is %u\n", - ptr[0], ptr[1]); - } else { - dprintk(VIDC_ERR, "Null decoder\n"); - } - } else { - dprintk(VIDC_DBG, - "This output buffer not required, buffer_type: %x\n", - HAL_BUFFER_OUTPUT); - } - break; - } default: dprintk(VIDC_ERR, "Unknown Command %d\n", which_cmd); rc = -ENOTSUPP; @@ -4453,15 +4422,15 @@ error: return rc; } -int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst) -{ +int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst, + bool max_int_buffer) { int rc = 0; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); return -EINVAL; } - if (msm_comm_release_scratch_buffers(inst, true)) + if (!max_int_buffer && msm_comm_release_scratch_buffers(inst, true)) dprintk(VIDC_WARN, "Failed to release scratch buffers\n"); rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index 7d28859c040c..5658df95db26 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -41,9 +41,13 @@ int msm_comm_try_set_prop(struct msm_vidc_inst *inst, enum hal_property ptype, void *pdata); int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype, union hal_get_property *hprop); -int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst); +int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst, + bool max_int_buffer); int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst); int msm_comm_set_output_buffers(struct msm_vidc_inst *inst); +int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, + struct hal_buffer_requirements *internal_bufreq, + struct msm_vidc_list *buf_list, bool set_on_fw); int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst); int msm_comm_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb); void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 8dc93900b16d..907763ddf234 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -4179,8 +4179,10 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host, /* keep track of the value in SDHCI_CAPABILITIES */ msm_host->caps_0 = caps; - if ((major == 1) && (minor >= 0x6b)) + if ((major == 1) && (minor >= 0x6b)) { msm_host->ice_hci_support = true; + host->cdr_support = true; + } } #ifdef CONFIG_MMC_CQ_HCI diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a5ff9f73dfbc..0033fea0a800 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3633,7 +3633,7 @@ static void sdhci_cmdq_set_transfer_params(struct mmc_host *mmc) ctrl |= SDHCI_CTRL_ADMA32; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } - if (host->ops->toggle_cdr) + if (host->ops->toggle_cdr && !host->cdr_support) host->ops->toggle_cdr(host, false); } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 93129b26dc5e..300be7fd0f24 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -564,6 +564,7 @@ struct sdhci_host { bool runtime_suspended; /* Host is runtime suspended */ bool bus_on; /* Bus power prevents runtime suspend */ bool preset_enabled; /* Preset is enabled */ + bool cdr_support; struct mmc_request *mrq; /* Current request */ struct mmc_command *cmd; /* Current command */ diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e430bab869a8..cce931e51d7e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -667,6 +667,36 @@ ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, *def = &conf->def; } +static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) +{ + int ret; + unsigned long time_left; + + lockdep_assert_held(&ar->conf_mutex); + + ret = ath10k_wmi_peer_delete(ar, vdev_id, addr); + if (ret) + return ret; + + ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr); + if (ret) + return ret; + + if (QCA_REV_WCN3990(ar)) { + time_left = wait_for_completion_timeout(&ar->peer_delete_done, + 50 * HZ); + + if (time_left == 0) { + ath10k_warn(ar, "Timeout in receiving peer delete response\n"); + return -ETIMEDOUT; + } + } + + ar->num_peers--; + + return 0; +} + static int ath10k_peer_create(struct ath10k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -711,7 +741,7 @@ static int ath10k_peer_create(struct ath10k *ar, spin_unlock_bh(&ar->data_lock); ath10k_warn(ar, "failed to find peer %pM on vdev %i after creation\n", addr, vdev_id); - ath10k_wmi_peer_delete(ar, vdev_id, addr); + ath10k_peer_delete(ar, vdev_id, addr); return -ENOENT; } @@ -779,36 +809,6 @@ static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value); } -static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) -{ - int ret; - unsigned long time_left; - - lockdep_assert_held(&ar->conf_mutex); - - ret = ath10k_wmi_peer_delete(ar, vdev_id, addr); - if (ret) - return ret; - - ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr); - if (ret) - return ret; - - if (QCA_REV_WCN3990(ar)) { - time_left = wait_for_completion_timeout(&ar->peer_delete_done, - 50 * HZ); - - if (time_left == 0) { - ath10k_warn(ar, "Timeout in receiving peer delete response\n"); - return -ETIMEDOUT; - } - } - - ar->num_peers--; - - return 0; -} - static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id) { struct ath10k_peer *peer, *tmp; @@ -5094,7 +5094,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, err_peer_delete: if (arvif->vdev_type == WMI_VDEV_TYPE_AP || arvif->vdev_type == WMI_VDEV_TYPE_IBSS) - ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr); + ath10k_peer_delete(ar, arvif->vdev_id, vif->addr); err_vdev_delete: ath10k_wmi_vdev_delete(ar, arvif->vdev_id); @@ -5150,8 +5150,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, if (arvif->vdev_type == WMI_VDEV_TYPE_AP || arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { - ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id, - vif->addr); + ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, + vif->addr); if (ret) ath10k_warn(ar, "failed to submit AP/IBSS self-peer removal on vdev %i: %d\n", arvif->vdev_id, ret); @@ -7168,12 +7168,25 @@ ath10k_mac_update_vif_chan(struct ath10k *ar, if (WARN_ON(!arvif->is_up)) continue; + if (QCA_REV_WCN3990(ar)) { + /* In the case of wcn3990 WLAN module we send + * vdev restart only, no need to send vdev down. + */ - ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); - if (ret) { - ath10k_warn(ar, "failed to down vdev %d: %d\n", - arvif->vdev_id, ret); - continue; + ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); + if (ret) { + ath10k_warn(ar, + "failed to restart vdev %d: %d\n", + arvif->vdev_id, ret); + continue; + } + } else { + ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); + if (ret) { + ath10k_warn(ar, "failed to down vdev %d: %d\n", + arvif->vdev_id, ret); + continue; + } } } @@ -7204,11 +7217,17 @@ ath10k_mac_update_vif_chan(struct ath10k *ar, ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", ret); - ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); - if (ret) { - ath10k_warn(ar, "failed to restart vdev %d: %d\n", - arvif->vdev_id, ret); - continue; + if (!QCA_REV_WCN3990(ar)) { + /* In case of other than wcn3990 WLAN module we + * send vdev down and vdev restart to the firmware. + */ + + ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); + if (ret) { + ath10k_warn(ar, "failed to restart vdev %d: %d\n", + arvif->vdev_id, ret); + continue; + } } ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 432960afe09a..e114d0c51a07 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -1100,7 +1100,8 @@ static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv) return -ENODEV; } - if (plat_priv->ramdump_info_v2.dump_data_valid) { + if (plat_priv->ramdump_info_v2.dump_data_valid || + test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) { cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT); cnss_pci_clear_dump_info(pci_priv); } diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index a17b72ce03ba..236654285db7 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -1392,8 +1392,12 @@ void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv) cnss_pci_set_mhi_state_bit(pci_priv, CNSS_MHI_RESUME); cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_OFF); - if (!plat_priv->ramdump_info_v2.dump_data_valid) - cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT); + + if (plat_priv->ramdump_info_v2.dump_data_valid || + test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) + return; + + cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT); } static int cnss_pci_probe(struct pci_dev *pci_dev, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 5fe425ea7655..034b7fc45d8d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -2093,6 +2093,8 @@ static void ipa3_cleanup_wlan_rx_common_cache(void) struct ipa3_rx_pkt_wrapper *rx_pkt; struct ipa3_rx_pkt_wrapper *tmp; + spin_lock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); + list_for_each_entry_safe(rx_pkt, tmp, &ipa3_ctx->wc_memb.wlan_comm_desc_list, link) { list_del(&rx_pkt->link); @@ -2113,6 +2115,8 @@ static void ipa3_cleanup_wlan_rx_common_cache(void) IPAERR("wlan comm buff total cnt: %d\n", ipa3_ctx->wc_memb.wlan_comm_total_cnt); + spin_unlock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); + } static void ipa3_alloc_wlan_rx_common_cache(u32 size) @@ -2150,11 +2154,13 @@ static void ipa3_alloc_wlan_rx_common_cache(u32 size) goto fail_dma_mapping; } + spin_lock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); list_add_tail(&rx_pkt->link, &ipa3_ctx->wc_memb.wlan_comm_desc_list); rx_len_cached = ++ipa3_ctx->wc_memb.wlan_comm_total_cnt; ipa3_ctx->wc_memb.wlan_comm_free_cnt++; + spin_unlock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index f8529faf159d..7c3b5838242e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -359,7 +359,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, entry->hdr = hdr_entry; if (add_ref_hdr) hdr_entry->ref_cnt++; - entry->cookie = IPA_HDR_COOKIE; + entry->cookie = IPA_PROC_HDR_COOKIE; needed_len = ipahal_get_proc_ctx_needed_len(proc_ctx->type); @@ -610,7 +610,7 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl, struct ipa3_hdr_proc_ctx_tbl *htbl = &ipa3_ctx->hdr_proc_ctx_tbl; entry = ipa3_id_find(proc_ctx_hdl); - if (!entry || (entry->cookie != IPA_HDR_COOKIE)) { + if (!entry || (entry->cookie != IPA_PROC_HDR_COOKIE)) { IPAERR_RL("bad parm\n"); return -EINVAL; } diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 7b7f991ecba9..240531948710 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -1946,6 +1946,7 @@ static int smb2_determine_initial_status(struct smb2 *chip) smblib_handle_icl_change(0, &irq_data); smblib_handle_step_chg_state_change(0, &irq_data); smblib_handle_step_chg_soc_update_request(0, &irq_data); + smblib_handle_batt_temp_changed(0, &irq_data); return 0; } @@ -2001,6 +2002,7 @@ static struct smb_irq_info smb2_irqs[] = { [BATT_TEMP_IRQ] = { .name = "bat-temp", .handler = smblib_handle_batt_temp_changed, + .wake = true, }, [BATT_OCP_IRQ] = { .name = "bat-ocp", diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 64d71727f7e6..6be8b1714cdb 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -2883,6 +2883,51 @@ int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg, return rc; } +static int smblib_recover_from_soft_jeita(struct smb_charger *chg) +{ + u8 stat_1, stat_2; + int rc; + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1); + if (rc < 0) { + smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", + rc); + return rc; + } + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2); + if (rc < 0) { + smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n", + rc); + return rc; + } + + if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) && + ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) { + /* + * We are moving from JEITA soft -> Normal and charging + * is terminated + */ + rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable charging rc=%d\n", + rc); + return rc; + } + rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, + CHARGING_ENABLE_CMD_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't enable charging rc=%d\n", + rc); + return rc; + } + } + + chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK; + + return 0; +} + /*********************** * USB MAIN PSY GETTERS * *************************/ @@ -3144,6 +3189,14 @@ irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; + int rc; + + rc = smblib_recover_from_soft_jeita(chg); + if (rc < 0) { + smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n", + rc); + return IRQ_HANDLED; + } rerun_election(chg->fcc_votable); power_supply_changed(chg->batt_psy); diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 18714827b8d2..d088167d4405 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -329,6 +329,7 @@ struct smb_charger { bool pr_swap_in_progress; int typec_mode; int usb_icl_change_irq_enabled; + u32 jeita_status; /* workaround flag */ u32 wa_flags; diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c new file mode 100644 index 000000000000..a2c08be960be --- /dev/null +++ b/drivers/power/supply/qcom/step-chg-jeita.c @@ -0,0 +1,272 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#define pr_fmt(fmt) "QCOM-STEPCHG: %s: " fmt, __func__ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/power_supply.h> +#include <linux/slab.h> +#include <linux/pmic-voter.h> +#include "step-chg-jeita.h" + +#define MAX_STEP_CHG_ENTRIES 8 +#define STEP_CHG_VOTER "STEP_CHG_VOTER" +#define STATUS_CHANGE_VOTER "STATUS_CHANGE_VOTER" + +#define is_between(left, right, value) \ + (((left) >= (right) && (left) >= (value) \ + && (value) >= (right)) \ + || ((left) <= (right) && (left) <= (value) \ + && (value) <= (right))) + +struct step_chg_data { + u32 vbatt_soc_low; + u32 vbatt_soc_high; + u32 fcc_ua; +}; + +struct step_chg_cfg { + u32 psy_prop; + char *prop_name; + struct step_chg_data cfg[MAX_STEP_CHG_ENTRIES]; +}; + +struct step_chg_info { + ktime_t last_update_time; + bool step_chg_enable; + + struct votable *fcc_votable; + struct wakeup_source *step_chg_ws; + struct power_supply *batt_psy; + struct delayed_work status_change_work; + struct notifier_block nb; +}; + +static struct step_chg_info *the_chip; + +/* + * Step Charging Configuration + * Update the table based on the battery profile + * Supports VBATT and SOC based source + */ +static struct step_chg_cfg step_chg_config = { + .psy_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW, + .prop_name = "VBATT", + .cfg = { + /* VBAT_LOW VBAT_HIGH FCC */ + {3600000, 4000000, 3000000}, + {4000000, 4200000, 2800000}, + {4200000, 4400000, 2000000}, + }, +/* + * SOC STEP-CHG configuration example. + * + * .psy_prop = POWER_SUPPLY_PROP_CAPACITY, + * .prop_name = "SOC", + * .cfg = { + * //SOC_LOW SOC_HIGH FCC + * {20, 70, 3000000}, + * {70, 90, 2750000}, + * {90, 100, 2500000}, + * }, + */ +}; + +static bool is_batt_available(struct step_chg_info *chip) +{ + if (!chip->batt_psy) + chip->batt_psy = power_supply_get_by_name("battery"); + + if (!chip->batt_psy) + return false; + + return true; +} + +static int get_fcc(int threshold) +{ + int i; + + for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++) + if (is_between(step_chg_config.cfg[i].vbatt_soc_low, + step_chg_config.cfg[i].vbatt_soc_high, threshold)) + return step_chg_config.cfg[i].fcc_ua; + + return -ENODATA; +} + +static int handle_step_chg_config(struct step_chg_info *chip) +{ + union power_supply_propval pval = {0, }; + int rc = 0, fcc_ua = 0; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED, &pval); + if (rc < 0) + chip->step_chg_enable = 0; + else + chip->step_chg_enable = pval.intval; + + if (!chip->step_chg_enable) { + if (chip->fcc_votable) + vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0); + return 0; + } + + rc = power_supply_get_property(chip->batt_psy, + step_chg_config.psy_prop, &pval); + if (rc < 0) { + pr_err("Couldn't read %s property rc=%d\n", + step_chg_config.prop_name, rc); + return rc; + } + + chip->fcc_votable = find_votable("FCC"); + if (!chip->fcc_votable) + return -EINVAL; + + fcc_ua = get_fcc(pval.intval); + if (fcc_ua < 0) { + /* remove the vote if no step-based fcc is found */ + vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0); + return 0; + } + + vote(chip->fcc_votable, STEP_CHG_VOTER, true, fcc_ua); + + pr_debug("%s = %d Step-FCC = %duA\n", + step_chg_config.prop_name, pval.intval, fcc_ua); + + return 0; +} + +#define STEP_CHG_HYSTERISIS_DELAY_US 5000000 /* 5 secs */ +static void status_change_work(struct work_struct *work) +{ + struct step_chg_info *chip = container_of(work, + struct step_chg_info, status_change_work.work); + int rc = 0; + u64 elapsed_us; + + elapsed_us = ktime_us_delta(ktime_get(), chip->last_update_time); + if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US) + goto release_ws; + + if (!is_batt_available(chip)) + goto release_ws; + + rc = handle_step_chg_config(chip); + if (rc < 0) + goto release_ws; + + chip->last_update_time = ktime_get(); + +release_ws: + __pm_relax(chip->step_chg_ws); +} + +static int step_chg_notifier_call(struct notifier_block *nb, + unsigned long ev, void *v) +{ + struct power_supply *psy = v; + struct step_chg_info *chip = container_of(nb, struct step_chg_info, nb); + + if (ev != PSY_EVENT_PROP_CHANGED) + return NOTIFY_OK; + + if ((strcmp(psy->desc->name, "battery") == 0)) { + __pm_stay_awake(chip->step_chg_ws); + schedule_delayed_work(&chip->status_change_work, 0); + } + + return NOTIFY_OK; +} + +static int step_chg_register_notifier(struct step_chg_info *chip) +{ + int rc; + + chip->nb.notifier_call = step_chg_notifier_call; + rc = power_supply_reg_notifier(&chip->nb); + if (rc < 0) { + pr_err("Couldn't register psy notifier rc = %d\n", rc); + return rc; + } + + return 0; +} + +int qcom_step_chg_init(bool step_chg_enable) +{ + int rc; + struct step_chg_info *chip; + + if (the_chip) { + pr_err("Already initialized\n"); + return -EINVAL; + } + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->step_chg_ws = wakeup_source_register("qcom-step-chg"); + if (!chip->step_chg_ws) { + rc = -EINVAL; + goto cleanup; + } + + chip->step_chg_enable = step_chg_enable; + + if (step_chg_enable && (!step_chg_config.psy_prop || + !step_chg_config.prop_name)) { + /* fail if step-chg configuration is invalid */ + pr_err("Step-chg configuration not defined - fail\n"); + return -ENODATA; + } + + INIT_DELAYED_WORK(&chip->status_change_work, status_change_work); + + rc = step_chg_register_notifier(chip); + if (rc < 0) { + pr_err("Couldn't register psy notifier rc = %d\n", rc); + goto release_wakeup_source; + } + + the_chip = chip; + + if (step_chg_enable) + pr_info("Step charging enabled. Using %s source\n", + step_chg_config.prop_name); + + return 0; + +release_wakeup_source: + wakeup_source_unregister(chip->step_chg_ws); +cleanup: + kfree(chip); + return rc; +} + +void qcom_step_chg_deinit(void) +{ + struct step_chg_info *chip = the_chip; + + if (!chip) + return; + + cancel_delayed_work_sync(&chip->status_change_work); + power_supply_unreg_notifier(&chip->nb); + wakeup_source_unregister(chip->step_chg_ws); + the_chip = NULL; + kfree(chip); +} diff --git a/drivers/power/supply/qcom/step-chg-jeita.h b/drivers/power/supply/qcom/step-chg-jeita.h new file mode 100644 index 000000000000..928eeb7a670b --- /dev/null +++ b/drivers/power/supply/qcom/step-chg-jeita.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __STEP_CHG_H__ +#define __STEP_CHG_H__ +int qcom_step_chg_init(bool); +void qcom_step_chg_deinit(void); +#endif /* __STEP_CHG_H__ */ diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index b1f4c3f27111..4b586f62cdc7 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -2858,7 +2858,7 @@ static void msm_thermal_bite(int zone_id, int temp) tsens_id, temp); } /* If it is a secure device ignore triggering the thermal bite. */ - if (scm_is_secure_device()) + if (!scm_is_secure_device()) return; if (!is_scm_armv8()) { scm_call_atomic1(SCM_SVC_BOOT, THERM_SECURE_BITE_CMD, 0); diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 8e8c1a349e6a..c3077ac11709 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -72,6 +72,8 @@ MODULE_PARM_DESC(cpu_to_affin, "affin usb irq to this cpu"); /* XHCI registers */ #define USB3_HCSPARAMS1 (0x4) +#define USB3_HCCPARAMS2 (0x1c) +#define HCC_CTC(p) ((p) & (1 << 3)) #define USB3_PORTSC (0x420) /** @@ -213,6 +215,7 @@ struct dwc3_msm { struct notifier_block dwc3_cpu_notifier; struct notifier_block usbdev_nb; bool hc_died; + bool xhci_ss_compliance_enable; struct extcon_dev *extcon_vbus; struct extcon_dev *extcon_id; @@ -2835,6 +2838,34 @@ static ssize_t speed_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(speed); static void msm_dwc3_perf_vote_work(struct work_struct *w); +static ssize_t xhci_link_compliance_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + + if (mdwc->xhci_ss_compliance_enable) + return snprintf(buf, PAGE_SIZE, "y\n"); + else + return snprintf(buf, PAGE_SIZE, "n\n"); +} + +static ssize_t xhci_link_compliance_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + bool value; + int ret; + + ret = strtobool(buf, &value); + if (!ret) { + mdwc->xhci_ss_compliance_enable = value; + return count; + } + + return ret; +} + +static DEVICE_ATTR_RW(xhci_link_compliance); static int dwc3_msm_probe(struct platform_device *pdev) { @@ -3179,6 +3210,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) device_create_file(&pdev->dev, &dev_attr_mode); device_create_file(&pdev->dev, &dev_attr_speed); + device_create_file(&pdev->dev, &dev_attr_xhci_link_compliance); host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST; if (host_mode || @@ -3210,6 +3242,7 @@ static int dwc3_msm_remove(struct platform_device *pdev) int ret_pm; device_remove_file(&pdev->dev, &dev_attr_mode); + device_remove_file(&pdev->dev, &dev_attr_xhci_link_compliance); if (cpu_to_affin) unregister_cpu_notifier(&mdwc->dwc3_cpu_notifier); @@ -3474,6 +3507,25 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) } /* + * If the Compliance Transition Capability(CTC) flag of + * HCCPARAMS2 register is set and xhci_link_compliance sysfs + * param has been enabled by the user for the SuperSpeed host + * controller, then write 10 (Link in Compliance Mode State) + * onto the Port Link State(PLS) field of the PORTSC register + * for 3.0 host controller which is at an offset of USB3_PORTSC + * + 0x10 from the DWC3 base address. Also, disable the runtime + * PM of 3.0 root hub (root hub of shared_hcd of xhci device) + */ + if (HCC_CTC(dwc3_msm_read_reg(mdwc->base, USB3_HCCPARAMS2)) + && mdwc->xhci_ss_compliance_enable + && dwc->maximum_speed == USB_SPEED_SUPER) { + dwc3_msm_write_reg(mdwc->base, USB3_PORTSC + 0x10, + 0x10340); + pm_runtime_disable(&hcd_to_xhci(platform_get_drvdata( + dwc->xhci))->shared_hcd->self.root_hub->dev); + } + + /* * In some cases it is observed that USB PHY is not going into * suspend with host mode suspend functionality. Hence disable * XHCI's runtime PM here if disable_host_mode_pm is set. diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c index 1ef3442cf618..7950f25136a5 100644 --- a/drivers/usb/gadget/function/f_accessory.c +++ b/drivers/usb/gadget/function/f_accessory.c @@ -346,6 +346,7 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) struct acc_dev *dev = ep->driver_data; char *string_dest = NULL; int length = req->actual; + unsigned long flags; if (req->status != 0) { pr_err("acc_complete_set_string, err %d\n", req->status); @@ -371,22 +372,26 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) case ACCESSORY_STRING_SERIAL: string_dest = dev->serial; break; + default: + pr_err("unknown accessory string index %d\n", + dev->string_index); + return; } - if (string_dest) { - unsigned long flags; - if (length >= ACC_STRING_SIZE) - length = ACC_STRING_SIZE - 1; - - spin_lock_irqsave(&dev->lock, flags); - memcpy(string_dest, req->buf, length); - /* ensure zero termination */ - string_dest[length] = 0; - spin_unlock_irqrestore(&dev->lock, flags); - } else { - pr_err("unknown accessory string index %d\n", - dev->string_index); + if (!length) { + pr_debug("zero length for accessory string index %d\n", + dev->string_index); + return; } + + if (length >= ACC_STRING_SIZE) + length = ACC_STRING_SIZE - 1; + + spin_lock_irqsave(&dev->lock, flags); + memcpy(string_dest, req->buf, length); + /* ensure zero termination */ + string_dest[length] = 0; + spin_unlock_irqrestore(&dev->lock, flags); } static void acc_complete_set_hid_report_desc(struct usb_ep *ep, diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 777acb489875..8536f10a2e35 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -183,15 +183,28 @@ static struct usb_qdss_opts *to_fi_usb_qdss_opts(struct usb_function_instance *f } /*----------------------------------------------------------------------*/ -static void qdss_ctrl_write_complete(struct usb_ep *ep, +static void qdss_write_complete(struct usb_ep *ep, struct usb_request *req) { struct f_qdss *qdss = ep->driver_data; struct qdss_request *d_req = req->context; + struct usb_ep *in; + struct list_head *list_pool; + enum qdss_state state; unsigned long flags; pr_debug("qdss_ctrl_write_complete\n"); + if (qdss->debug_inface_enabled) { + in = qdss->port.ctrl_in; + list_pool = &qdss->ctrl_write_pool; + state = USB_QDSS_CTRL_WRITE_DONE; + } else { + in = qdss->port.data; + list_pool = &qdss->data_write_pool; + state = USB_QDSS_DATA_WRITE_DONE; + } + if (!req->status) { /* send zlp */ if ((req->length >= ep->maxpacket) && @@ -199,13 +212,13 @@ static void qdss_ctrl_write_complete(struct usb_ep *ep, req->length = 0; d_req->actual = req->actual; d_req->status = req->status; - if (!usb_ep_queue(qdss->port.ctrl_in, req, GFP_ATOMIC)) + if (!usb_ep_queue(in, req, GFP_ATOMIC)) return; } } spin_lock_irqsave(&qdss->lock, flags); - list_add_tail(&req->list, &qdss->ctrl_write_pool); + list_add_tail(&req->list, list_pool); if (req->length != 0) { d_req->actual = req->actual; d_req->status = req->status; @@ -213,8 +226,7 @@ static void qdss_ctrl_write_complete(struct usb_ep *ep, spin_unlock_irqrestore(&qdss->lock, flags); if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, USB_QDSS_CTRL_WRITE_DONE, d_req, - NULL); + qdss->ch.notify(qdss->ch.priv, state, d_req, NULL); } static void qdss_ctrl_read_complete(struct usb_ep *ep, @@ -252,6 +264,12 @@ void usb_qdss_free_req(struct usb_qdss_ch *ch) return; } + list_for_each_safe(act, tmp, &qdss->data_write_pool) { + req = list_entry(act, struct usb_request, list); + list_del(&req->list); + usb_ep_free_request(qdss->port.data, req); + } + list_for_each_safe(act, tmp, &qdss->ctrl_write_pool) { req = list_entry(act, struct usb_request, list); list_del(&req->list); @@ -271,23 +289,41 @@ int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf, { struct f_qdss *qdss = ch->priv_usb; struct usb_request *req; + struct usb_ep *in; + struct list_head *list_pool; int i; pr_debug("usb_qdss_alloc_req\n"); - if (no_write_buf <= 0 || no_read_buf <= 0 || !qdss) { + if (!qdss) { + pr_err("usb_qdss_alloc_req: channel %s closed\n", ch->name); + return -ENODEV; + } + + if ((qdss->debug_inface_enabled && + (no_write_buf <= 0 || no_read_buf <= 0)) || + (!qdss->debug_inface_enabled && + (no_write_buf <= 0 || no_read_buf))) { pr_err("usb_qdss_alloc_req: missing params\n"); return -ENODEV; } + if (qdss->debug_inface_enabled) { + in = qdss->port.ctrl_in; + list_pool = &qdss->ctrl_write_pool; + } else { + in = qdss->port.data; + list_pool = &qdss->data_write_pool; + } + for (i = 0; i < no_write_buf; i++) { - req = usb_ep_alloc_request(qdss->port.ctrl_in, GFP_ATOMIC); + req = usb_ep_alloc_request(in, GFP_ATOMIC); if (!req) { pr_err("usb_qdss_alloc_req: ctrl_in allocation err\n"); goto fail; } - req->complete = qdss_ctrl_write_complete; - list_add_tail(&req->list, &qdss->ctrl_write_pool); + req->complete = qdss_write_complete; + list_add_tail(&req->list, list_pool); } for (i = 0; i < no_read_buf; i++) { @@ -479,21 +515,20 @@ static void usb_qdss_disconnect_work(struct work_struct *work) qdss = container_of(work, struct f_qdss, disconnect_w); pr_debug("usb_qdss_disconnect_work\n"); - /* - * Uninitialized init data i.e. ep specific operation. - * Notify qdss to cancel all active transfers. - */ - if (qdss->ch.app_conn) { + + /* Notify qdss to cancel all active transfers */ + if (qdss->ch.notify) + qdss->ch.notify(qdss->ch.priv, + USB_QDSS_DISCONNECT, + NULL, + NULL); + + /* Uninitialized init data i.e. ep specific operation */ + if (qdss->ch.app_conn && !strcmp(qdss->ch.name, USB_QDSS_CH_MSM)) { status = uninit_data(qdss->port.data); if (status) pr_err("%s: uninit_data error\n", __func__); - if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, - USB_QDSS_DISCONNECT, - NULL, - NULL); - status = set_qdss_data_connection(qdss, 0); if (status) pr_err("qdss_disconnect error"); @@ -550,15 +585,16 @@ static void usb_qdss_connect_work(struct work_struct *work) } pr_debug("usb_qdss_connect_work\n"); + + if (!strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) + goto notify; + status = set_qdss_data_connection(qdss, 1); if (status) { pr_err("set_qdss_data_connection error(%d)", status); return; } - if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT, - NULL, &qdss->ch); spin_lock_irqsave(&qdss->lock, flags); req = qdss->endless_req; spin_unlock_irqrestore(&qdss->lock, flags); @@ -566,8 +602,15 @@ static void usb_qdss_connect_work(struct work_struct *work) return; status = usb_ep_queue(qdss->port.data, req, GFP_ATOMIC); - if (status) + if (status) { pr_err("%s: usb_ep_queue error (%d)\n", __func__, status); + return; + } + +notify: + if (qdss->ch.notify) + qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT, + NULL, &qdss->ch); } static int qdss_set_alt(struct usb_function *f, unsigned intf, unsigned alt) @@ -706,6 +749,7 @@ static struct f_qdss *alloc_usb_qdss(char *channel_name) spin_lock_init(&qdss->lock); INIT_LIST_HEAD(&qdss->ctrl_read_pool); INIT_LIST_HEAD(&qdss->ctrl_write_pool); + INIT_LIST_HEAD(&qdss->data_write_pool); INIT_WORK(&qdss->connect_w, usb_qdss_connect_work); INIT_WORK(&qdss->disconnect_w, usb_qdss_disconnect_work); @@ -801,6 +845,50 @@ int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) } EXPORT_SYMBOL(usb_qdss_ctrl_write); +int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) +{ + struct f_qdss *qdss = ch->priv_usb; + unsigned long flags; + struct usb_request *req = NULL; + + pr_debug("usb_qdss_ctrl_write\n"); + + if (!qdss) + return -ENODEV; + + spin_lock_irqsave(&qdss->lock, flags); + + if (qdss->usb_connected == 0) { + spin_unlock_irqrestore(&qdss->lock, flags); + return -EIO; + } + + if (list_empty(&qdss->data_write_pool)) { + pr_err("error: usb_qdss_data_write list is empty\n"); + spin_unlock_irqrestore(&qdss->lock, flags); + return -EAGAIN; + } + + req = list_first_entry(&qdss->data_write_pool, struct usb_request, + list); + list_del(&req->list); + spin_unlock_irqrestore(&qdss->lock, flags); + + req->buf = d_req->buf; + req->length = d_req->length; + req->context = d_req; + if (usb_ep_queue(qdss->port.data, req, GFP_ATOMIC)) { + spin_lock_irqsave(&qdss->lock, flags); + list_add_tail(&req->list, &qdss->data_write_pool); + spin_unlock_irqrestore(&qdss->lock, flags); + pr_err("qdss usb_ep_queue failed\n"); + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL(usb_qdss_write); + struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv, void (*notify)(void *, unsigned, struct qdss_request *, struct usb_qdss_ch *)) @@ -859,7 +947,9 @@ void usb_qdss_close(struct usb_qdss_ch *ch) pr_debug("usb_qdss_close\n"); spin_lock_irqsave(&qdss_lock, flags); - if (!qdss || !qdss->usb_connected) { + ch->priv_usb = NULL; + if (!qdss || !qdss->usb_connected || + !strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) { ch->app_conn = 0; spin_unlock_irqrestore(&qdss_lock, flags); return; diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h index cad0f4cc06f9..fb7c01c0f939 100644 --- a/drivers/usb/gadget/function/f_qdss.h +++ b/drivers/usb/gadget/function/f_qdss.h @@ -53,6 +53,10 @@ struct f_qdss { struct usb_qdss_ch ch; struct list_head ctrl_read_pool; struct list_head ctrl_write_pool; + + /* for mdm channel SW path */ + struct list_head data_write_pool; + struct work_struct connect_w; struct work_struct disconnect_w; spinlock_t lock; diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 2f169074261a..89ec73c21630 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -3982,12 +3982,6 @@ static int mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp) { int ret = 0; - /* In case of HPD_IRQ events without DP link being turned on such as - * adb shell stop, skip handling hpd_irq event. - */ - if (!dp->dp_initialized) - goto exit; - pr_debug("start\n"); dp->hpd_irq_on = true; @@ -4103,6 +4097,15 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv) if (dp_drv->alt_mode.dp_status.hpd_irq) { pr_debug("Attention: hpd_irq high\n"); + /* In case of HPD_IRQ events without DP link being + * turned on such as adb shell stop, skip handling + * hpd_irq event. + */ + if (!dp_drv->dp_initialized) { + pr_err("DP not initialized yet\n"); + return; + } + if (dp_is_hdcp_enabled(dp_drv) && dp_drv->hdcp.ops->cp_irq) { if (!dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data)) return; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c index 71cab148e1c3..aabf7c507376 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -358,7 +358,8 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, int ret = 0, i = 0; char __iomem *hist_addr; u32 sz = 0, temp = 0, *data = NULL; - struct mdp_hist_lut_data_v1_7 *lut_data = NULL; + struct mdp_hist_lut_data_v1_7 lut_data_v1_7; + struct mdp_hist_lut_data_v1_7 *lut_data = &lut_data_v1_7; struct mdp_hist_lut_data *lut_cfg_data = NULL; if (!base_addr || !cfg_data) { @@ -378,7 +379,11 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, lut_cfg_data->version, lut_cfg_data->cfg_payload); return -EINVAL; } - lut_data = lut_cfg_data->cfg_payload; + if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload, + sizeof(*lut_data))) { + pr_err("copy from user failed for lut_data\n"); + return -EFAULT; + } if (lut_data->len != ENHIST_LUT_ENTRIES) { pr_err("invalid hist_lut len %d", lut_data->len); return -EINVAL; @@ -1786,7 +1791,8 @@ static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data, { int ret = 0, i = 0; struct mdp_igc_lut_data *lut_cfg_data = NULL; - struct mdp_igc_lut_data_v1_7 *lut_data = NULL; + struct mdp_igc_lut_data_v1_7 lut_data_v1_7; + struct mdp_igc_lut_data_v1_7 *lut_data = &lut_data_v1_7; char __iomem *c1 = NULL, *c2 = NULL; u32 *c0c1_data = NULL, *c2_data = NULL; u32 data = 0, sz = 0; @@ -1810,7 +1816,11 @@ static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data, ret = -EINVAL; goto exit; } - lut_data = lut_cfg_data->cfg_payload; + if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload, + sizeof(*lut_data))) { + pr_err("copy from user failed for lut_data\n"); + return -EFAULT; + } if (lut_data->len != IGC_LUT_ENTRIES) { pr_err("invalid lut len %d\n", lut_data->len); ret = -EINVAL; @@ -1954,20 +1964,24 @@ static int pp_pgc_get_config(char __iomem *base_addr, void *cfg_data, u32 *c0_data = NULL, *c1_data = NULL, *c2_data = NULL; u32 val = 0, i = 0, sz = 0; struct mdp_pgc_lut_data *pgc_data = NULL; - struct mdp_pgc_lut_data_v1_7 *pgc_data_v17 = NULL; + struct mdp_pgc_lut_data_v1_7 pgc_lut_data_v17; + struct mdp_pgc_lut_data_v1_7 *pgc_data_v17 = &pgc_lut_data_v17; if (!base_addr || !cfg_data) { pr_err("invalid params base_addr %pK cfg_data %pK block_type %d\n", base_addr, cfg_data, block_type); return -EINVAL; } pgc_data = (struct mdp_pgc_lut_data *) cfg_data; - pgc_data_v17 = (struct mdp_pgc_lut_data_v1_7 *) - pgc_data->cfg_payload; - if (pgc_data->version != mdp_pgc_v1_7 || !pgc_data_v17) { + if (pgc_data->version != mdp_pgc_v1_7 || !pgc_data->cfg_payload) { pr_err("invalid pgc version %d payload %pK\n", - pgc_data->version, pgc_data_v17); + pgc_data->version, pgc_data->cfg_payload); return -EINVAL; } + if (copy_from_user(pgc_data_v17, (void __user *) pgc_data->cfg_payload, + sizeof(*pgc_data_v17))) { + pr_err("copy from user failed for pgc lut data\n"); + return -EFAULT; + } if (!(pgc_data->flags & MDP_PP_OPS_READ)) { pr_info("read ops is not set %d", pgc_data->flags); return -EINVAL; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c index 25cb94f89dd5..b377f0921508 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -298,7 +298,8 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, int ret = 0, i = 0; char __iomem *hist_lut_addr; u32 sz = 0, temp = 0, *data = NULL; - struct mdp_hist_lut_data_v1_7 *lut_data = NULL; + struct mdp_hist_lut_data_v1_7 lut_data_v1_7; + struct mdp_hist_lut_data_v1_7 *lut_data = &lut_data_v1_7; struct mdp_hist_lut_data *lut_cfg_data = NULL; if (!base_addr || !cfg_data) { @@ -323,7 +324,11 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, lut_cfg_data->version, lut_cfg_data->cfg_payload); return -EINVAL; } - lut_data = lut_cfg_data->cfg_payload; + if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload, + sizeof(*lut_data))) { + pr_err("copy from user failed for lut_data\n"); + return -EFAULT; + } if (lut_data->len != ENHIST_LUT_ENTRIES) { pr_err("invalid hist_lut len %d", lut_data->len); return -EINVAL; |
