diff --git a/msm/dp/dp_altmode.c b/msm/dp/dp_altmode.c index 52d954f4a37a..0f09ddda36bf 100644 --- a/msm/dp/dp_altmode.c +++ b/msm/dp/dp_altmode.c @@ -40,7 +40,8 @@ enum dp_altmode_pin_assignment { DPAM_HPD_F, }; -static int dp_altmode_release_ss_lanes(struct dp_altmode_private *altmode) +static int dp_altmode_release_ss_lanes(struct dp_altmode_private *altmode, + bool multi_func) { int rc; struct device_node *np; @@ -69,7 +70,7 @@ static int dp_altmode_release_ss_lanes(struct dp_altmode_private *altmode) } while (timeout) { - rc = dwc3_msm_release_ss_lane(&usb_pdev->dev); + rc = dwc3_msm_release_ss_lane(&usb_pdev->dev, multi_func); if (rc != -EBUSY) break; @@ -178,11 +179,10 @@ static int dp_altmode_notify(void *priv, void *data, size_t len) altmode->dp_altmode.base.orientation = orientation; - if (!altmode->dp_altmode.base.multi_func) { - rc = dp_altmode_release_ss_lanes(altmode); - if (rc) - goto ack; - } + rc = dp_altmode_release_ss_lanes(altmode, + altmode->dp_altmode.base.multi_func); + if (rc) + goto ack; if (altmode->dp_cb && altmode->dp_cb->configure) altmode->dp_cb->configure(altmode->dev); diff --git a/msm/msm_atomic.c b/msm/msm_atomic.c index 6bddb33d9824..953fd3b174e1 100644 --- a/msm/msm_atomic.c +++ b/msm/msm_atomic.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2014 Red Hat * Author: Rob Clark * @@ -689,6 +689,16 @@ int msm_atomic_commit(struct drm_device *dev, c->plane_mask |= (1 << drm_plane_index(plane)); } + /* Protection for prepare_fence callback */ +retry: + ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex, + state->acquire_ctx); + + if (ret == -EDEADLK) { + drm_modeset_backoff(state->acquire_ctx); + goto retry; + } + /* * Wait for pending updates on any of the same crtc's and then * mark our set of crtc's as busy: diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 348bff1199ec..a54e222a81b8 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -6148,6 +6148,9 @@ static int _sde_debugfs_fence_status_show(struct seq_file *s, void *data) dev = crtc->dev; cstate = to_sde_crtc_state(crtc->state); + if (!sde_crtc->kickoff_in_progress) + goto skip_input_fence; + /* Dump input fence info */ seq_puts(s, "===Input fence===\n"); drm_atomic_crtc_for_each_plane(plane, crtc) { @@ -6175,6 +6178,7 @@ static int _sde_debugfs_fence_status_show(struct seq_file *s, void *data) } } +skip_input_fence: /* Dump release fence info */ seq_puts(s, "\n"); seq_puts(s, "===Release fence===\n"); diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index d8e062c5fc01..a6acf9f31a85 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -1509,20 +1509,27 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr( struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); struct sde_encoder_wait_info wait_info = {0}; - int ret; + struct sde_connector *c_conn; bool frame_pending = true; struct sde_hw_ctl *ctl; unsigned long lock_flags; + int ret, timeout_ms; - if (!phys_enc || !phys_enc->hw_ctl) { + if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->connector) { SDE_ERROR("invalid argument(s)\n"); return -EINVAL; } ctl = phys_enc->hw_ctl; + c_conn = to_sde_connector(phys_enc->connector); + timeout_ms = KICKOFF_TIMEOUT_MS; + + if (c_conn->lp_mode == SDE_MODE_DPMS_LP1 || + c_conn->lp_mode == SDE_MODE_DPMS_LP2) + timeout_ms = (KICKOFF_TIMEOUT_MS) * 2; wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_retire_fence_cnt; - wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; + wait_info.timeout_ms = timeout_ms; /* slave encoder doesn't enable for ppsplit */ if (_sde_encoder_phys_is_ppsplit_slave(phys_enc)) diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 0b36b0b2d0e7..78bcf7aed5be 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1589,7 +1589,7 @@ static void sde_kms_prepare_fence(struct msm_kms *kms, { struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; - int i, rc; + int i; if (!kms || !old_state || !old_state->dev || !old_state->acquire_ctx) { SDE_ERROR("invalid argument(s)\n"); @@ -1597,15 +1597,6 @@ static void sde_kms_prepare_fence(struct msm_kms *kms, } SDE_ATRACE_BEGIN("sde_kms_prepare_fence"); -retry: - /* attempt to acquire ww mutex for connection */ - rc = drm_modeset_lock(&old_state->dev->mode_config.connection_mutex, - old_state->acquire_ctx); - - if (rc == -EDEADLK) { - drm_modeset_backoff(old_state->acquire_ctx); - goto retry; - } /* old_state actually contains updated crtc pointers */ for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) { diff --git a/msm/sde/sde_rm.c b/msm/sde/sde_rm.c index fd76b4352576..cb3d589bd072 100644 --- a/msm/sde/sde_rm.c +++ b/msm/sde/sde_rm.c @@ -125,13 +125,15 @@ struct sde_rm_requirements { * @enc_id: Reservations are tracked by Encoder DRM object ID. * CRTCs may be connected to multiple Encoders. * An encoder or connector id identifies the display path. - * @topology DRM<->HW topology use case + * @topology: DRM<->HW topology use case + * @pending: True for pending rsvp-nxt, cleared when the rsvp is committed */ struct sde_rm_rsvp { struct list_head list; uint32_t seq; uint32_t enc_id; enum sde_rm_topology_name topology; + bool pending; }; /** @@ -274,9 +276,9 @@ static void _sde_rm_print_rsvps( SDE_DEBUG("%d\n", stage); list_for_each_entry(rsvp, &rm->rsvps, list) { - SDE_DEBUG("%d rsvp[s%ue%u] topology %d\n", stage, rsvp->seq, - rsvp->enc_id, rsvp->topology); - SDE_EVT32(stage, rsvp->seq, rsvp->enc_id, rsvp->topology); + SDE_DEBUG("%d rsvp%s[s%ue%u] topology %d\n", stage, rsvp->pending ? "_nxt" : "", + rsvp->seq, rsvp->enc_id, rsvp->topology); + SDE_EVT32(stage, rsvp->seq, rsvp->enc_id, rsvp->topology, rsvp->pending); } for (type = 0; type < SDE_HW_BLK_MAX; type++) { @@ -1825,6 +1827,7 @@ static int _sde_rm_make_next_rsvp(struct sde_rm *rm, struct drm_encoder *enc, rsvp->seq = ++rm->rsvp_next_seq; rsvp->enc_id = enc->base.id; rsvp->topology = reqs->topology->top_name; + rsvp->pending = true; list_add_tail(&rsvp->list, &rm->rsvps); ret = _sde_rm_make_lm_rsvp(rm, rsvp, reqs, splash_display); @@ -2076,9 +2079,8 @@ static int _sde_rm_populate_requirements( return 0; } -static struct sde_rm_rsvp *_sde_rm_get_rsvp( - struct sde_rm *rm, - struct drm_encoder *enc) +static struct sde_rm_rsvp *_sde_rm_get_rsvp(struct sde_rm *rm, + struct drm_encoder *enc, bool nxt) { struct sde_rm_rsvp *i; @@ -2091,30 +2093,22 @@ static struct sde_rm_rsvp *_sde_rm_get_rsvp( return NULL; list_for_each_entry(i, &rm->rsvps, list) - if (i->enc_id == enc->base.id) + if (i->pending == nxt && i->enc_id == enc->base.id) return i; return NULL; } -static struct sde_rm_rsvp *_sde_rm_get_rsvp_nxt( - struct sde_rm *rm, +static struct sde_rm_rsvp *_sde_rm_get_rsvp_nxt(struct sde_rm *rm, struct drm_encoder *enc) { - struct sde_rm_rsvp *i; + return _sde_rm_get_rsvp(rm, enc, true); +} - if (list_empty(&rm->rsvps)) - return NULL; - - list_for_each_entry(i, &rm->rsvps, list) - if (i->enc_id == enc->base.id) - break; - - list_for_each_entry_continue(i, &rm->rsvps, list) - if (i->enc_id == enc->base.id) - return i; - - return NULL; +static struct sde_rm_rsvp *_sde_rm_get_rsvp_cur(struct sde_rm *rm, + struct drm_encoder *enc) +{ + return _sde_rm_get_rsvp(rm, enc, false); } static struct drm_connector *_sde_rm_get_connector( @@ -2312,10 +2306,7 @@ void sde_rm_release(struct sde_rm *rm, struct drm_encoder *enc, bool nxt) mutex_lock(&rm->rm_lock); - if (nxt) - rsvp = _sde_rm_get_rsvp_nxt(rm, enc); - else - rsvp = _sde_rm_get_rsvp(rm, enc); + rsvp = _sde_rm_get_rsvp(rm, enc, nxt); if (!rsvp) { SDE_DEBUG("failed to find rsvp for enc %d, nxt %d", enc->base.id, nxt); @@ -2353,14 +2344,13 @@ end: mutex_unlock(&rm->rm_lock); } -static int _sde_rm_commit_rsvp( +static void _sde_rm_commit_rsvp( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, struct drm_connector_state *conn_state) { struct sde_rm_hw_blk *blk; enum sde_hw_blk_type type; - int ret = 0; /* Swap next rsvp to be the active */ for (type = 0; type < SDE_HW_BLK_MAX; type++) { @@ -2375,13 +2365,9 @@ static int _sde_rm_commit_rsvp( } } - if (!ret) { - SDE_DEBUG("rsrv enc %d topology %d\n", rsvp->enc_id, - rsvp->topology); - SDE_EVT32(rsvp->enc_id, rsvp->topology); - } - - return ret; + rsvp->pending = false; + SDE_DEBUG("rsrv enc %d topology %d\n", rsvp->enc_id, rsvp->topology); + SDE_EVT32(rsvp->enc_id, rsvp->topology); } /* call this only after rm_mutex held */ @@ -2420,7 +2406,7 @@ int sde_rm_reserve( struct msm_drm_private *priv; struct sde_kms *sde_kms; struct msm_compression_info *comp_info; - int ret; + int ret = 0; if (!rm || !enc || !crtc_state || !conn_state) { SDE_ERROR("invalid arguments\n"); @@ -2456,7 +2442,7 @@ int sde_rm_reserve( _sde_rm_print_rsvps(rm, SDE_RM_STAGE_BEGIN); - rsvp_cur = _sde_rm_get_rsvp(rm, enc); + rsvp_cur = _sde_rm_get_rsvp_cur(rm, enc); rsvp_nxt = _sde_rm_get_rsvp_nxt(rm, enc); /* @@ -2545,7 +2531,7 @@ int sde_rm_reserve( commit_rsvp: _sde_rm_release_rsvp(rm, rsvp_cur, conn_state->connector); - ret = _sde_rm_commit_rsvp(rm, rsvp_nxt, conn_state); + _sde_rm_commit_rsvp(rm, rsvp_nxt, conn_state); end: kfree(comp_info); @@ -2574,7 +2560,7 @@ int sde_rm_ext_blk_create_reserve(struct sde_rm *rm, mutex_lock(&rm->rm_lock); - rsvp = _sde_rm_get_rsvp(rm, enc); + rsvp = _sde_rm_get_rsvp_cur(rm, enc); if (!rsvp) { rsvp = kzalloc(sizeof(*rsvp), GFP_KERNEL); if (!rsvp) { @@ -2625,7 +2611,7 @@ int sde_rm_ext_blk_destroy(struct sde_rm *rm, mutex_lock(&rm->rm_lock); - rsvp = _sde_rm_get_rsvp(rm, enc); + rsvp = _sde_rm_get_rsvp_cur(rm, enc); if (!rsvp) { ret = -ENOENT; SDE_ERROR("failed to find rsvp for enc %d\n", enc->base.id); diff --git a/msm/sde_dbg.c b/msm/sde_dbg.c index eb85c0e37e7e..89715d376f24 100644 --- a/msm/sde_dbg.c +++ b/msm/sde_dbg.c @@ -300,6 +300,18 @@ struct sde_dbg_evtlog *sde_dbg_base_evtlog; /* sde_dbg_base_reglog - global pointer to main sde reg log for macro use */ struct sde_dbg_reglog *sde_dbg_base_reglog; +u32 sde_mini_dump_add_region(const char *name, u32 size, void *virt_addr) +{ + struct md_region md_entry; + + strlcpy(md_entry.name, name, sizeof(md_entry.name)); + md_entry.virt_addr = (uintptr_t)virt_addr; + md_entry.phys_addr = virt_to_phys(virt_addr); + md_entry.size = size; + + return msm_minidump_add_region(&md_entry); +} + static void _sde_debug_bus_xbar_dump(void __iomem *mem_base, struct sde_debug_bus_entry *entry, u32 val, u32 block_id_off, u32 test_id_off) @@ -856,6 +868,9 @@ static void _sde_dbg_dump_sde_dbg_bus(struct sde_dbg_sde_debug_bus *bus) dev_info(sde_dbg_base.dev, "%s: start_addr:0x%pK len:0x%x\n", __func__, dump_addr, list_size); + if (sde_mini_dump_add_region("sde_dbgbus", list_size, + *dump_mem) < 0) + pr_err("minidump add sde debug bus failed\n"); } else { in_mem = false; pr_err("dump_mem: allocation fails\n"); @@ -986,6 +1001,9 @@ static void _sde_dbg_dump_vbif_dbg_bus(struct sde_dbg_vbif_debug_bus *bus) dev_info(sde_dbg_base.dev, "%s: start_addr:0x%pK len:0x%x\n", __func__, dump_addr, list_size); + if (sde_mini_dump_add_region("vbif_dbgbus", list_size, + *dump_mem) < 0) + pr_err("minidump add vbif debug bus failed\n"); } else { in_mem = false; pr_err("dump_mem: allocation fails\n"); diff --git a/msm/sde_dbg.h b/msm/sde_dbg.h index 44ba3c145dc0..4e3dbdbb9b7b 100644 --- a/msm/sde_dbg.h +++ b/msm/sde_dbg.h @@ -9,6 +9,7 @@ #include #include #include +#include /* select an uncommon hex value for the limiter */ #define SDE_EVTLOG_DATA_LIMITER (0xC0DEBEEF) @@ -156,11 +157,10 @@ struct sde_dbg_reglog { u32 first; u32 last; u32 last_dump; - u32 curr; + atomic64_t curr; u32 next; u32 enable; u32 enable_mask; - spinlock_t spin_lock; }; extern struct sde_dbg_reglog *sde_dbg_base_reglog; @@ -249,6 +249,8 @@ extern struct sde_dbg_reglog *sde_dbg_base_reglog; #define SDE_DBG_CTRL(...) sde_dbg_ctrl(__func__, ##__VA_ARGS__, \ SDE_DBG_DUMP_DATA_LIMITER) +u32 sde_mini_dump_add_region(const char *name, u32 size, void *virt_addr); + /** * sde_evtlog_init - allocate a new event log object * Returns: evtlog or -ERROR diff --git a/msm/sde_dbg_evtlog.c b/msm/sde_dbg_evtlog.c index 484480b8eacd..21ae067957c5 100644 --- a/msm/sde_dbg_evtlog.c +++ b/msm/sde_dbg_evtlog.c @@ -103,27 +103,22 @@ exit: void sde_reglog_log(u8 blk_id, u32 val, u32 addr) { - unsigned long flags; struct sde_dbg_reglog_log *log; struct sde_dbg_reglog *reglog = sde_dbg_base_reglog; + int index; if (!reglog) return; - spin_lock_irqsave(®log->spin_lock, flags); - - log = ®log->logs[reglog->curr]; + index = abs(atomic64_inc_return(®log->curr) % SDE_REGLOG_ENTRY); + log = ®log->logs[index]; log->blk_id = blk_id; log->val = val; log->addr = addr; log->time = local_clock(); log->pid = current->pid; - - reglog->curr = (reglog->curr + 1) % SDE_REGLOG_ENTRY; reglog->last++; - - spin_unlock_irqrestore(®log->spin_lock, flags); } /* always dump the last entries which are not dumped yet */ @@ -228,6 +223,10 @@ struct sde_dbg_evtlog *sde_evtlog_init(void) if (!evtlog) return ERR_PTR(-ENOMEM); + if (sde_mini_dump_add_region("evt_log", sizeof(*evtlog), + evtlog) < 0) + pr_err("minidump add region failed for evtlog\n"); + spin_lock_init(&evtlog->spin_lock); evtlog->enable = SDE_EVTLOG_DEFAULT_ENABLE; @@ -244,7 +243,10 @@ struct sde_dbg_reglog *sde_reglog_init(void) if (!reglog) return ERR_PTR(-ENOMEM); - spin_lock_init(®log->spin_lock); + atomic64_set(®log->curr, 0); + if (sde_mini_dump_add_region("reg_log", sizeof(*reglog), + reglog) < 0) + pr_err("minidump add region failed for reglog\n"); return reglog; }