From: Sasha Levin Date: Fri, 4 Mar 2022 17:28:53 +0000 (-0500) Subject: Fixes for 5.15 X-Git-Tag: v4.9.305~92 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=edcf1e2fafe46950519fd3aa31bba24266b52f37;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.15 Signed-off-by: Sasha Levin --- diff --git a/queue-5.15/bnxt_en-fix-occasional-ethtool-t-loopback-test-failu.patch b/queue-5.15/bnxt_en-fix-occasional-ethtool-t-loopback-test-failu.patch new file mode 100644 index 00000000000..9252f522e05 --- /dev/null +++ b/queue-5.15/bnxt_en-fix-occasional-ethtool-t-loopback-test-failu.patch @@ -0,0 +1,102 @@ +From c2bbc85ba720286c3caf92054a5600a91377b2cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 20 Feb 2022 04:05:49 -0500 +Subject: bnxt_en: Fix occasional ethtool -t loopback test failures + +From: Michael Chan + +[ Upstream commit cfcab3b3b61584a02bb523ffa99564eafa761dfe ] + +In the current code, we setup the port to PHY or MAC loopback mode +and then transmit a test broadcast packet for the loopback test. This +scheme fails sometime if the port is shared with management firmware +that can also send packets. The driver may receive the management +firmware's packet and the test will fail when the contents don't +match the test packet. + +Change the test packet to use it's own MAC address as the destination +and setup the port to only receive it's own MAC address. This should +filter out other packets sent by management firmware. + +Fixes: 91725d89b97a ("bnxt_en: Add PHY loopback to ethtool self-test.") +Reviewed-by: Pavan Chebbi +Reviewed-by: Edwin Peer +Reviewed-by: Andy Gospodarek +Signed-off-by: Michael Chan +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/bnxt/bnxt.c | 7 +++++++ + drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + + drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +- + 3 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +index f92bea4faa019..ce36ee5a250fb 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +@@ -8617,6 +8617,9 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) + vnic->uc_filter_count = 1; + + vnic->rx_mask = 0; ++ if (test_bit(BNXT_STATE_HALF_OPEN, &bp->state)) ++ goto skip_rx_mask; ++ + if (bp->dev->flags & IFF_BROADCAST) + vnic->rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_BCAST; + +@@ -8637,6 +8640,7 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) + if (rc) + goto err_out; + ++skip_rx_mask: + rc = bnxt_hwrm_set_coal(bp); + if (rc) + netdev_warn(bp->dev, "HWRM set coalescing failure rc: %x\n", +@@ -10302,8 +10306,10 @@ int bnxt_half_open_nic(struct bnxt *bp) + netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc); + goto half_open_err; + } ++ set_bit(BNXT_STATE_HALF_OPEN, &bp->state); + rc = bnxt_init_nic(bp, true); + if (rc) { ++ clear_bit(BNXT_STATE_HALF_OPEN, &bp->state); + netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc); + goto half_open_err; + } +@@ -10324,6 +10330,7 @@ void bnxt_half_close_nic(struct bnxt *bp) + bnxt_hwrm_resource_free(bp, false, true); + bnxt_free_skbs(bp); + bnxt_free_mem(bp, true); ++ clear_bit(BNXT_STATE_HALF_OPEN, &bp->state); + } + + static void bnxt_reenable_sriov(struct bnxt *bp) +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h +index 0a5137c1f6d4e..ca6fdf03e5865 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h +@@ -1840,6 +1840,7 @@ struct bnxt { + #define BNXT_STATE_DRV_REGISTERED 7 + #define BNXT_STATE_PCI_CHANNEL_IO_FROZEN 8 + #define BNXT_STATE_NAPI_DISABLED 9 ++#define BNXT_STATE_HALF_OPEN 15 /* For offline ethtool tests */ + + #define BNXT_NO_FW_ACCESS(bp) \ + (test_bit(BNXT_STATE_FW_FATAL_COND, &(bp)->state) || \ +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +index da3ee22e8a16f..af7de9ee66cf2 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +@@ -3409,7 +3409,7 @@ static int bnxt_run_loopback(struct bnxt *bp) + if (!skb) + return -ENOMEM; + data = skb_put(skb, pkt_size); +- eth_broadcast_addr(data); ++ ether_addr_copy(&data[i], bp->dev->dev_addr); + i += ETH_ALEN; + ether_addr_copy(&data[i], bp->dev->dev_addr); + i += ETH_ALEN; +-- +2.34.1 + diff --git a/queue-5.15/bpf-arm64-use-emit_addr_mov_i64-for-bpf_pseudo_func.patch b/queue-5.15/bpf-arm64-use-emit_addr_mov_i64-for-bpf_pseudo_func.patch new file mode 100644 index 00000000000..bf002988a21 --- /dev/null +++ b/queue-5.15/bpf-arm64-use-emit_addr_mov_i64-for-bpf_pseudo_func.patch @@ -0,0 +1,59 @@ +From 53a9337e96db2364cceb9f409f78256373b83800 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Dec 2021 23:10:18 +0800 +Subject: bpf, arm64: Use emit_addr_mov_i64() for BPF_PSEUDO_FUNC + +From: Hou Tao + +[ Upstream commit e4a41c2c1fa916547e63440c73a51a5eb06247af ] + +The following error is reported when running "./test_progs -t for_each" +under arm64: + + bpf_jit: multi-func JIT bug 58 != 56 + [...] + JIT doesn't support bpf-to-bpf calls + +The root cause is the size of BPF_PSEUDO_FUNC instruction increases +from 2 to 3 after the address of called bpf-function is settled and +there are two bpf-to-bpf calls in test_pkt_access. The generated +instructions are shown below: + + 0x48: 21 00 C0 D2 movz x1, #0x1, lsl #32 + 0x4c: 21 00 80 F2 movk x1, #0x1 + + 0x48: E1 3F C0 92 movn x1, #0x1ff, lsl #32 + 0x4c: 41 FE A2 F2 movk x1, #0x17f2, lsl #16 + 0x50: 81 70 9F F2 movk x1, #0xfb84 + +Fixing it by using emit_addr_mov_i64() for BPF_PSEUDO_FUNC, so +the size of jited image will not change. + +Fixes: 69c087ba6225 ("bpf: Add bpf_for_each_map_elem() helper") +Signed-off-by: Hou Tao +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/bpf/20211231151018.3781550-1-houtao1@huawei.com +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 465c44d0c72fc..3d7381ffc1712 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -788,7 +788,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, + u64 imm64; + + imm64 = (u64)insn1.imm << 32 | (u32)imm; +- emit_a64_mov_i64(dst, imm64, ctx); ++ if (bpf_pseudo_func(insn)) ++ emit_addr_mov_i64(dst, imm64, ctx); ++ else ++ emit_a64_mov_i64(dst, imm64, ctx); + + return 1; + } +-- +2.34.1 + diff --git a/queue-5.15/bpf-fix-possible-race-in-inc_misses_counter.patch b/queue-5.15/bpf-fix-possible-race-in-inc_misses_counter.patch new file mode 100644 index 00000000000..3a02ffd1355 --- /dev/null +++ b/queue-5.15/bpf-fix-possible-race-in-inc_misses_counter.patch @@ -0,0 +1,47 @@ +From 9a45c44573ba9428f978d99230092ae474f16045 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 22 Jan 2022 10:29:36 +0000 +Subject: bpf: Fix possible race in inc_misses_counter + +From: He Fengqing + +[ Upstream commit 0e3135d3bfa5dfb658145238d2bc723a8e30c3a3 ] + +It seems inc_misses_counter() suffers from same issue fixed in +the commit d979617aa84d ("bpf: Fixes possible race in update_prog_stats() +for 32bit arches"): +As it can run while interrupts are enabled, it could +be re-entered and the u64_stats syncp could be mangled. + +Fixes: 9ed9e9ba2337 ("bpf: Count the number of times recursion was prevented") +Signed-off-by: He Fengqing +Acked-by: John Fastabend +Link: https://lore.kernel.org/r/20220122102936.1219518-1-hefengqing@huawei.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/trampoline.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c +index 6933a9bfee637..2660fbced9ad4 100644 +--- a/kernel/bpf/trampoline.c ++++ b/kernel/bpf/trampoline.c +@@ -541,11 +541,12 @@ static u64 notrace bpf_prog_start_time(void) + static void notrace inc_misses_counter(struct bpf_prog *prog) + { + struct bpf_prog_stats *stats; ++ unsigned int flags; + + stats = this_cpu_ptr(prog->stats); +- u64_stats_update_begin(&stats->syncp); ++ flags = u64_stats_update_begin_irqsave(&stats->syncp); + u64_stats_inc(&stats->misses); +- u64_stats_update_end(&stats->syncp); ++ u64_stats_update_end_irqrestore(&stats->syncp, flags); + } + + /* The logic is similar to bpf_prog_run(), but with an explicit +-- +2.34.1 + diff --git a/queue-5.15/bpf-use-u64_stats_t-in-struct-bpf_prog_stats.patch b/queue-5.15/bpf-use-u64_stats_t-in-struct-bpf_prog_stats.patch new file mode 100644 index 00000000000..be75c5137e9 --- /dev/null +++ b/queue-5.15/bpf-use-u64_stats_t-in-struct-bpf_prog_stats.patch @@ -0,0 +1,139 @@ +From f3c6b4d11bc60342817719fa79759c3512196d38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Oct 2021 14:41:33 -0700 +Subject: bpf: Use u64_stats_t in struct bpf_prog_stats + +From: Eric Dumazet + +[ Upstream commit 61a0abaee2092eee69e44fe60336aa2f5b578938 ] + +Commit 316580b69d0a ("u64_stats: provide u64_stats_t type") +fixed possible load/store tearing on 64bit arches. + +For instance the following C code + +stats->nsecs += sched_clock() - start; + +Could be rightfully implemented like this by a compiler, +confusing concurrent readers a lot: + +stats->nsecs += sched_clock(); +// arbitrary delay +stats->nsecs -= start; + +Signed-off-by: Eric Dumazet +Signed-off-by: Alexei Starovoitov +Link: https://lore.kernel.org/bpf/20211026214133.3114279-4-eric.dumazet@gmail.com +Signed-off-by: Sasha Levin +--- + include/linux/filter.h | 10 +++++----- + kernel/bpf/syscall.c | 18 ++++++++++++------ + kernel/bpf/trampoline.c | 6 +++--- + 3 files changed, 20 insertions(+), 14 deletions(-) + +diff --git a/include/linux/filter.h b/include/linux/filter.h +index 1611dc9d44207..a9956b681f090 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -554,9 +554,9 @@ struct bpf_binary_header { + }; + + struct bpf_prog_stats { +- u64 cnt; +- u64 nsecs; +- u64 misses; ++ u64_stats_t cnt; ++ u64_stats_t nsecs; ++ u64_stats_t misses; + struct u64_stats_sync syncp; + } __aligned(2 * sizeof(u64)); + +@@ -618,8 +618,8 @@ static __always_inline u32 __bpf_prog_run(const struct bpf_prog *prog, + ret = dfunc(ctx, prog->insnsi, prog->bpf_func); + stats = this_cpu_ptr(prog->stats); + flags = u64_stats_update_begin_irqsave(&stats->syncp); +- stats->cnt++; +- stats->nsecs += sched_clock() - start; ++ u64_stats_inc(&stats->cnt); ++ u64_stats_add(&stats->nsecs, sched_clock() - start); + u64_stats_update_end_irqrestore(&stats->syncp, flags); + } else { + ret = dfunc(ctx, prog->insnsi, prog->bpf_func); +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index 53384622e8dac..42490c39dfbf5 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -1824,8 +1824,14 @@ static int bpf_prog_release(struct inode *inode, struct file *filp) + return 0; + } + ++struct bpf_prog_kstats { ++ u64 nsecs; ++ u64 cnt; ++ u64 misses; ++}; ++ + static void bpf_prog_get_stats(const struct bpf_prog *prog, +- struct bpf_prog_stats *stats) ++ struct bpf_prog_kstats *stats) + { + u64 nsecs = 0, cnt = 0, misses = 0; + int cpu; +@@ -1838,9 +1844,9 @@ static void bpf_prog_get_stats(const struct bpf_prog *prog, + st = per_cpu_ptr(prog->stats, cpu); + do { + start = u64_stats_fetch_begin_irq(&st->syncp); +- tnsecs = st->nsecs; +- tcnt = st->cnt; +- tmisses = st->misses; ++ tnsecs = u64_stats_read(&st->nsecs); ++ tcnt = u64_stats_read(&st->cnt); ++ tmisses = u64_stats_read(&st->misses); + } while (u64_stats_fetch_retry_irq(&st->syncp, start)); + nsecs += tnsecs; + cnt += tcnt; +@@ -1856,7 +1862,7 @@ static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp) + { + const struct bpf_prog *prog = filp->private_data; + char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; +- struct bpf_prog_stats stats; ++ struct bpf_prog_kstats stats; + + bpf_prog_get_stats(prog, &stats); + bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); +@@ -3595,7 +3601,7 @@ static int bpf_prog_get_info_by_fd(struct file *file, + struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info); + struct bpf_prog_info info; + u32 info_len = attr->info.info_len; +- struct bpf_prog_stats stats; ++ struct bpf_prog_kstats stats; + char __user *uinsns; + u32 ulen; + int err; +diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c +index d3a307a8c42b9..6933a9bfee637 100644 +--- a/kernel/bpf/trampoline.c ++++ b/kernel/bpf/trampoline.c +@@ -544,7 +544,7 @@ static void notrace inc_misses_counter(struct bpf_prog *prog) + + stats = this_cpu_ptr(prog->stats); + u64_stats_update_begin(&stats->syncp); +- stats->misses++; ++ u64_stats_inc(&stats->misses); + u64_stats_update_end(&stats->syncp); + } + +@@ -589,8 +589,8 @@ static void notrace update_prog_stats(struct bpf_prog *prog, + + stats = this_cpu_ptr(prog->stats); + flags = u64_stats_update_begin_irqsave(&stats->syncp); +- stats->cnt++; +- stats->nsecs += sched_clock() - start; ++ u64_stats_inc(&stats->cnt); ++ u64_stats_add(&stats->nsecs, sched_clock() - start); + u64_stats_update_end_irqrestore(&stats->syncp, flags); + } + } +-- +2.34.1 + diff --git a/queue-5.15/cifs-fix-confusing-unneeded-warning-message-on-smb2..patch b/queue-5.15/cifs-fix-confusing-unneeded-warning-message-on-smb2..patch new file mode 100644 index 00000000000..e981cce4273 --- /dev/null +++ b/queue-5.15/cifs-fix-confusing-unneeded-warning-message-on-smb2..patch @@ -0,0 +1,58 @@ +From d448d6efbea220fbff7b81afa09ba55e8dc7ec51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Feb 2022 13:23:53 -0600 +Subject: cifs: fix confusing unneeded warning message on smb2.1 and earlier + +From: Steve French + +[ Upstream commit 53923e0fe2098f90f339510aeaa0e1413ae99a16 ] + +When mounting with SMB2.1 or earlier, even with nomultichannel, we +log the confusing warning message: + "CIFS: VFS: multichannel is not supported on this protocol version, use 3.0 or above" + +Fix this so that we don't log this unless they really are trying +to mount with multichannel. + +BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=215608 +Reported-by: Kim Scarborough +Cc: stable@vger.kernel.org # 5.11+ +Reviewed-by: Paulo Alcantara (SUSE) +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/cifs/sess.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c +index a1e688113645f..5500ea7837845 100644 +--- a/fs/cifs/sess.c ++++ b/fs/cifs/sess.c +@@ -76,11 +76,6 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) + struct cifs_server_iface *ifaces = NULL; + size_t iface_count; + +- if (ses->server->dialect < SMB30_PROT_ID) { +- cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n"); +- return 0; +- } +- + spin_lock(&ses->chan_lock); + + new_chan_count = old_chan_count = ses->chan_count; +@@ -94,6 +89,12 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) + return 0; + } + ++ if (ses->server->dialect < SMB30_PROT_ID) { ++ spin_unlock(&ses->chan_lock); ++ cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n"); ++ return 0; ++ } ++ + if (!(ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) { + cifs_dbg(VFS, "server %s does not support multichannel\n", ses->server->hostname); + ses->chan_max = 1; +-- +2.34.1 + diff --git a/queue-5.15/cifs-protect-session-channel-fields-with-chan_lock.patch b/queue-5.15/cifs-protect-session-channel-fields-with-chan_lock.patch new file mode 100644 index 00000000000..4e81f3b0569 --- /dev/null +++ b/queue-5.15/cifs-protect-session-channel-fields-with-chan_lock.patch @@ -0,0 +1,317 @@ +From 9a8cb59074661248bac0c9c34b676b3263808952 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jul 2021 10:54:46 +0000 +Subject: cifs: protect session channel fields with chan_lock + +From: Shyam Prasad N + +[ Upstream commit 724244cdb3828522109c88e56a0242537aefabe9 ] + +Introducing a new spin lock to protect all the channel related +fields in a cifs_ses struct. This lock should be taken +whenever dealing with the channel fields, and should be held +only for very short intervals which will not sleep. + +Currently, all channel related fields in cifs_ses structure +are protected by session_mutex. However, this mutex is held for +long periods (sometimes while waiting for a reply from server). +This makes the codepath quite tricky to change. + +Signed-off-by: Shyam Prasad N +Reviewed-by: Paulo Alcantara (SUSE) +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/cifs/cifs_debug.c | 2 ++ + fs/cifs/cifsglob.h | 5 +++++ + fs/cifs/connect.c | 25 +++++++++++++++++++--- + fs/cifs/misc.c | 1 + + fs/cifs/sess.c | 50 +++++++++++++++++++++++++++++++++----------- + fs/cifs/transport.c | 3 +++ + 6 files changed, 71 insertions(+), 15 deletions(-) + +diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c +index 905a901f7f80b..248a8f973cf9c 100644 +--- a/fs/cifs/cifs_debug.c ++++ b/fs/cifs/cifs_debug.c +@@ -414,12 +414,14 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) + from_kuid(&init_user_ns, ses->linux_uid), + from_kuid(&init_user_ns, ses->cred_uid)); + ++ spin_lock(&ses->chan_lock); + if (ses->chan_count > 1) { + seq_printf(m, "\n\n\tExtra Channels: %zu ", + ses->chan_count-1); + for (j = 1; j < ses->chan_count; j++) + cifs_dump_channel(m, j, &ses->chans[j]); + } ++ spin_unlock(&ses->chan_lock); + + seq_puts(m, "\n\n\tShares: "); + j = 0; +diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h +index 3e5b8e177cfa7..b33835b2943e9 100644 +--- a/fs/cifs/cifsglob.h ++++ b/fs/cifs/cifsglob.h +@@ -934,16 +934,21 @@ struct cifs_ses { + * iface_lock should be taken when accessing any of these fields + */ + spinlock_t iface_lock; ++ /* ========= begin: protected by iface_lock ======== */ + struct cifs_server_iface *iface_list; + size_t iface_count; + unsigned long iface_last_update; /* jiffies */ ++ /* ========= end: protected by iface_lock ======== */ + ++ spinlock_t chan_lock; ++ /* ========= begin: protected by chan_lock ======== */ + #define CIFS_MAX_CHANNELS 16 + struct cifs_chan chans[CIFS_MAX_CHANNELS]; + struct cifs_chan *binding_chan; + size_t chan_count; + size_t chan_max; + atomic_t chan_seq; /* round robin state */ ++ /* ========= end: protected by chan_lock ======== */ + }; + + /* +diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c +index 439f02f1886c1..70da1d27be3db 100644 +--- a/fs/cifs/connect.c ++++ b/fs/cifs/connect.c +@@ -1526,8 +1526,12 @@ static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx) + * If an existing session is limited to less channels than + * requested, it should not be reused + */ +- if (ses->chan_max < ctx->max_channels) ++ spin_lock(&ses->chan_lock); ++ if (ses->chan_max < ctx->max_channels) { ++ spin_unlock(&ses->chan_lock); + return 0; ++ } ++ spin_unlock(&ses->chan_lock); + + switch (ses->sectype) { + case Kerberos: +@@ -1662,6 +1666,7 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) + void cifs_put_smb_ses(struct cifs_ses *ses) + { + unsigned int rc, xid; ++ unsigned int chan_count; + struct TCP_Server_Info *server = ses->server; + cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count); + +@@ -1703,12 +1708,24 @@ void cifs_put_smb_ses(struct cifs_ses *ses) + list_del_init(&ses->smb_ses_list); + spin_unlock(&cifs_tcp_ses_lock); + ++ spin_lock(&ses->chan_lock); ++ chan_count = ses->chan_count; ++ spin_unlock(&ses->chan_lock); ++ + /* close any extra channels */ +- if (ses->chan_count > 1) { ++ if (chan_count > 1) { + int i; + +- for (i = 1; i < ses->chan_count; i++) ++ for (i = 1; i < chan_count; i++) { ++ /* ++ * note: for now, we're okay accessing ses->chans ++ * without chan_lock. But when chans can go away, we'll ++ * need to introduce ref counting to make sure that chan ++ * is not freed from under us. ++ */ + cifs_put_tcp_session(ses->chans[i].server, 0); ++ ses->chans[i].server = NULL; ++ } + } + + sesInfoFree(ses); +@@ -1959,9 +1976,11 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) + mutex_lock(&ses->session_mutex); + + /* add server as first channel */ ++ spin_lock(&ses->chan_lock); + ses->chans[0].server = server; + ses->chan_count = 1; + ses->chan_max = ctx->multichannel ? ctx->max_channels:1; ++ spin_unlock(&ses->chan_lock); + + rc = cifs_negotiate_protocol(xid, ses); + if (!rc) +diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c +index bb1185fff8cc4..0a0d0724c4294 100644 +--- a/fs/cifs/misc.c ++++ b/fs/cifs/misc.c +@@ -75,6 +75,7 @@ sesInfoAlloc(void) + INIT_LIST_HEAD(&ret_buf->tcon_list); + mutex_init(&ret_buf->session_mutex); + spin_lock_init(&ret_buf->iface_lock); ++ spin_lock_init(&ret_buf->chan_lock); + } + return ret_buf; + } +diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c +index 23e02db7923f6..a1e688113645f 100644 +--- a/fs/cifs/sess.c ++++ b/fs/cifs/sess.c +@@ -54,41 +54,53 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface) + { + int i; + ++ spin_lock(&ses->chan_lock); + for (i = 0; i < ses->chan_count; i++) { +- if (is_server_using_iface(ses->chans[i].server, iface)) ++ if (is_server_using_iface(ses->chans[i].server, iface)) { ++ spin_unlock(&ses->chan_lock); + return true; ++ } + } ++ spin_unlock(&ses->chan_lock); + return false; + } + + /* returns number of channels added */ + int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) + { +- int old_chan_count = ses->chan_count; +- int left = ses->chan_max - ses->chan_count; ++ int old_chan_count, new_chan_count; ++ int left; + int i = 0; + int rc = 0; + int tries = 0; + struct cifs_server_iface *ifaces = NULL; + size_t iface_count; + ++ if (ses->server->dialect < SMB30_PROT_ID) { ++ cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n"); ++ return 0; ++ } ++ ++ spin_lock(&ses->chan_lock); ++ ++ new_chan_count = old_chan_count = ses->chan_count; ++ left = ses->chan_max - ses->chan_count; ++ + if (left <= 0) { + cifs_dbg(FYI, + "ses already at max_channels (%zu), nothing to open\n", + ses->chan_max); +- return 0; +- } +- +- if (ses->server->dialect < SMB30_PROT_ID) { +- cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n"); ++ spin_unlock(&ses->chan_lock); + return 0; + } + + if (!(ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) { + cifs_dbg(VFS, "server %s does not support multichannel\n", ses->server->hostname); + ses->chan_max = 1; ++ spin_unlock(&ses->chan_lock); + return 0; + } ++ spin_unlock(&ses->chan_lock); + + /* + * Make a copy of the iface list at the time and use that +@@ -142,10 +154,11 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) + cifs_dbg(FYI, "successfully opened new channel on iface#%d\n", + i); + left--; ++ new_chan_count++; + } + + kfree(ifaces); +- return ses->chan_count - old_chan_count; ++ return new_chan_count - old_chan_count; + } + + /* +@@ -157,10 +170,14 @@ cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server) + { + int i; + ++ spin_lock(&ses->chan_lock); + for (i = 0; i < ses->chan_count; i++) { +- if (ses->chans[i].server == server) ++ if (ses->chans[i].server == server) { ++ spin_unlock(&ses->chan_lock); + return &ses->chans[i]; ++ } + } ++ spin_unlock(&ses->chan_lock); + return NULL; + } + +@@ -168,6 +185,7 @@ static int + cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, + struct cifs_server_iface *iface) + { ++ struct TCP_Server_Info *chan_server; + struct cifs_chan *chan; + struct smb3_fs_context ctx = {NULL}; + static const char unc_fmt[] = "\\%s\\foo"; +@@ -240,15 +258,20 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, + SMB2_CLIENT_GUID_SIZE); + ctx.use_client_guid = true; + +- mutex_lock(&ses->session_mutex); ++ chan_server = cifs_get_tcp_session(&ctx); + ++ mutex_lock(&ses->session_mutex); ++ spin_lock(&ses->chan_lock); + chan = ses->binding_chan = &ses->chans[ses->chan_count]; +- chan->server = cifs_get_tcp_session(&ctx); ++ chan->server = chan_server; + if (IS_ERR(chan->server)) { + rc = PTR_ERR(chan->server); + chan->server = NULL; ++ spin_unlock(&ses->chan_lock); + goto out; + } ++ spin_unlock(&ses->chan_lock); ++ + spin_lock(&cifs_tcp_ses_lock); + chan->server->is_channel = true; + spin_unlock(&cifs_tcp_ses_lock); +@@ -283,8 +306,11 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, + * ses to the new server. + */ + ++ spin_lock(&ses->chan_lock); + ses->chan_count++; + atomic_set(&ses->chan_seq, 0); ++ spin_unlock(&ses->chan_lock); ++ + out: + ses->binding = false; + ses->binding_chan = NULL; +diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c +index b7379329b741c..61ea3d3f95b4a 100644 +--- a/fs/cifs/transport.c ++++ b/fs/cifs/transport.c +@@ -1044,14 +1044,17 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) + if (!ses) + return NULL; + ++ spin_lock(&ses->chan_lock); + if (!ses->binding) { + /* round robin */ + if (ses->chan_count > 1) { + index = (uint)atomic_inc_return(&ses->chan_seq); + index %= ses->chan_count; + } ++ spin_unlock(&ses->chan_lock); + return ses->chans[index].server; + } else { ++ spin_unlock(&ses->chan_lock); + return cifs_ses_server(ses); + } + } +-- +2.34.1 + diff --git a/queue-5.15/dma-buf-cma_heap-fix-mutex-locking-section.patch b/queue-5.15/dma-buf-cma_heap-fix-mutex-locking-section.patch new file mode 100644 index 00000000000..1bb84d1b0b6 --- /dev/null +++ b/queue-5.15/dma-buf-cma_heap-fix-mutex-locking-section.patch @@ -0,0 +1,55 @@ +From 2b557880b5c68916a65eb9f2c908842782dd6c0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jan 2022 15:35:45 +0800 +Subject: dma-buf: cma_heap: Fix mutex locking section + +From: Weizhao Ouyang + +[ Upstream commit 54329e6f7beea6af56c1230da293acc97d6a6ee7 ] + +Fix cma_heap_buffer mutex locking critical section to protect vmap_cnt +and vaddr. + +Fixes: a5d2d29e24be ("dma-buf: heaps: Move heap-helper logic into the cma_heap implementation") +Signed-off-by: Weizhao Ouyang +Acked-by: John Stultz +Signed-off-by: Sumit Semwal +Link: https://patchwork.freedesktop.org/patch/msgid/20220104073545.124244-1-o451686892@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/dma-buf/heaps/cma_heap.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c +index 0c05b79870f96..83f02bd51dda6 100644 +--- a/drivers/dma-buf/heaps/cma_heap.c ++++ b/drivers/dma-buf/heaps/cma_heap.c +@@ -124,10 +124,11 @@ static int cma_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, + struct cma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + ++ mutex_lock(&buffer->lock); ++ + if (buffer->vmap_cnt) + invalidate_kernel_vmap_range(buffer->vaddr, buffer->len); + +- mutex_lock(&buffer->lock); + list_for_each_entry(a, &buffer->attachments, list) { + if (!a->mapped) + continue; +@@ -144,10 +145,11 @@ static int cma_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, + struct cma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + ++ mutex_lock(&buffer->lock); ++ + if (buffer->vmap_cnt) + flush_kernel_vmap_range(buffer->vaddr, buffer->len); + +- mutex_lock(&buffer->lock); + list_for_each_entry(a, &buffer->attachments, list) { + if (!a->mapped) + continue; +-- +2.34.1 + diff --git a/queue-5.15/drm-amd-display-fix-stream-link_enc-unassigned-durin.patch b/queue-5.15/drm-amd-display-fix-stream-link_enc-unassigned-durin.patch new file mode 100644 index 00000000000..3e8b36cf88e --- /dev/null +++ b/queue-5.15/drm-amd-display-fix-stream-link_enc-unassigned-durin.patch @@ -0,0 +1,53 @@ +From 6a6f972d42808d8883ea363e57aa4fd60bbd92a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Jan 2022 12:04:34 -0500 +Subject: drm/amd/display: Fix stream->link_enc unassigned during stream + removal + +From: Nicholas Kazlauskas + +[ Upstream commit 3743e7f6fcb938b7d8b7967e6a9442805e269b3d ] + +[Why] +Found when running igt@kms_atomic. + +Userspace attempts to do a TEST_COMMIT when 0 streams which calls +dc_remove_stream_from_ctx. This in turn calls link_enc_unassign +which ends up modifying stream->link = NULL directly, causing the +global link_enc to be removed preventing further link activity +and future link validation from passing. + +[How] +We take care of link_enc unassignment at the start of +link_enc_cfg_link_encs_assign so this call is no longer necessary. + +Fixes global state from being modified while unlocked. + +Reviewed-by: Jimmy Kizito +Acked-by: Jasdeep Dhillon +Signed-off-by: Nicholas Kazlauskas +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Cc: stable@vger.kernel.org +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index e94546187cf15..7ae409f7dcf8d 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -1799,9 +1799,6 @@ enum dc_status dc_remove_stream_from_ctx( + dc->res_pool, + del_pipe->stream_res.stream_enc, + false); +- /* Release link encoder from stream in new dc_state. */ +- if (dc->res_pool->funcs->link_enc_unassign) +- dc->res_pool->funcs->link_enc_unassign(new_ctx, del_pipe->stream); + + if (del_pipe->stream_res.audio) + update_audio_usage( +-- +2.34.1 + diff --git a/queue-5.15/drm-amd-display-for-vblank_disable_immediate-check-p.patch b/queue-5.15/drm-amd-display-for-vblank_disable_immediate-check-p.patch new file mode 100644 index 00000000000..cb323d651af --- /dev/null +++ b/queue-5.15/drm-amd-display-for-vblank_disable_immediate-check-p.patch @@ -0,0 +1,68 @@ +From c2d45bade27051c302ce27c37a2b42f1aba9ab83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Feb 2022 19:53:37 +0100 +Subject: drm/amd/display: For vblank_disable_immediate, check PSR is really + used +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michel Dänzer + +[ Upstream commit 4d22336f903930eb94588b939c310743a3640276 ] + +Even if PSR is allowed for a present GPU, there might be no eDP link +which supports PSR. + +Fixes: 708978487304 ("drm/amdgpu/display: Only set vblank_disable_immediate when PSR is not enabled") +Reviewed-by: Harry Wentland +Signed-off-by: Michel Dänzer +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 76967adc51606..cd611444ad177 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -3812,6 +3812,9 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) + } + #endif + ++ /* Disable vblank IRQs aggressively for power-saving. */ ++ adev_to_drm(adev)->vblank_disable_immediate = true; ++ + /* loops over all connectors on the board */ + for (i = 0; i < link_cnt; i++) { + struct dc_link *link = NULL; +@@ -3858,19 +3861,17 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) + update_connector_ext_caps(aconnector); + if (amdgpu_dc_feature_mask & DC_PSR_MASK) + amdgpu_dm_set_psr_caps(link); ++ ++ /* TODO: Fix vblank control helpers to delay PSR entry to allow this when ++ * PSR is also supported. ++ */ ++ if (link->psr_settings.psr_feature_enabled) ++ adev_to_drm(adev)->vblank_disable_immediate = false; + } + + + } + +- /* +- * Disable vblank IRQs aggressively for power-saving. +- * +- * TODO: Fix vblank control helpers to delay PSR entry to allow this when PSR +- * is also supported. +- */ +- adev_to_drm(adev)->vblank_disable_immediate = !psr_feature_enabled; +- + /* Software is initialized. Now we can register interrupt handlers. */ + switch (adev->asic_type) { + #if defined(CONFIG_DRM_AMD_DC_SI) +-- +2.34.1 + diff --git a/queue-5.15/drm-amd-display-move-fpu-associated-dcn301-code-to-d.patch b/queue-5.15/drm-amd-display-move-fpu-associated-dcn301-code-to-d.patch new file mode 100644 index 00000000000..6ae93a1f6af --- /dev/null +++ b/queue-5.15/drm-amd-display-move-fpu-associated-dcn301-code-to-d.patch @@ -0,0 +1,986 @@ +From 3c4a40ea8abaa5a00b4fd3006835c6f10e98dc13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Oct 2021 17:56:55 +0800 +Subject: drm/amd/display: move FPU associated DCN301 code to DML folder +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Qingqing Zhuo + +[ Upstream commit 31484207feb23e6cdb12827560442ab294855923 ] + +[Why & How] +As part of the FPU isolation work documented in +https://patchwork.freedesktop.org/series/93042/, isolate +code that uses FPU in DCN301 to DML, where all FPU code +should locate. + +Cc: Christian König +Cc: Harry Wentland +Cc: Rodrigo Siqueira +Tested-by: Zhan Liu +Tested-by: Daniel Wheeler +Signed-off-by: Qingqing Zhuo +Reviewed-by: Rodrigo Siqueira +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/display/dc/dcn30/dcn30_resource.c | 2 + + .../gpu/drm/amd/display/dc/dcn301/Makefile | 26 -- + .../amd/display/dc/dcn301/dcn301_resource.c | 349 +--------------- + .../amd/display/dc/dcn301/dcn301_resource.h | 3 + + drivers/gpu/drm/amd/display/dc/dml/Makefile | 3 + + .../amd/display/dc/dml/dcn301/dcn301_fpu.c | 390 ++++++++++++++++++ + .../amd/display/dc/dml/dcn301/dcn301_fpu.h | 42 ++ + 7 files changed, 450 insertions(+), 365 deletions(-) + create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c + create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +index 0294d0cc47595..db4a9d2760cd1 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +@@ -2319,7 +2319,9 @@ bool dcn30_validate_bandwidth(struct dc *dc, + goto validate_out; + } + ++ DC_FP_START(); + dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel); ++ DC_FP_END(); + + BW_VAL_TRACE_END_WATERMARKS(); + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile +index 09264716d1dc9..7aa628c219734 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile +@@ -13,32 +13,6 @@ + DCN301 = dcn301_init.o dcn301_resource.o dcn301_dccg.o \ + dcn301_dio_link_encoder.o dcn301_hwseq.o dcn301_panel_cntl.o dcn301_hubbub.o + +-ifdef CONFIG_X86 +-CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o := -msse +-endif +- +-ifdef CONFIG_PPC64 +-CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o := -mhard-float -maltivec +-endif +- +-ifdef CONFIG_CC_IS_GCC +-ifeq ($(call cc-ifversion, -lt, 0701, y), y) +-IS_OLD_GCC = 1 +-endif +-CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o += -mhard-float +-endif +- +-ifdef CONFIG_X86 +-ifdef IS_OLD_GCC +-# Stack alignment mismatch, proceed with caution. +-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3 +-# (8B stack alignment). +-CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o += -mpreferred-stack-boundary=4 +-else +-CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o += -msse2 +-endif +-endif +- + AMD_DAL_DCN301 = $(addprefix $(AMDDALPATH)/dc/dcn301/,$(DCN301)) + + AMD_DISPLAY_FILES += $(AMD_DAL_DCN301) +diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +index dea358b01791c..d17994bb318f7 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +@@ -82,6 +82,7 @@ + #include "dce/dce_i2c.h" + + #include "dml/dcn30/display_mode_vba_30.h" ++#include "dml/dcn301/dcn301_fpu.h" + #include "vm_helper.h" + #include "dcn20/dcn20_vmid.h" + #include "amdgpu_socbb.h" +@@ -91,184 +92,6 @@ + + #define DC_LOGGER_INIT(logger) + +-struct _vcs_dpi_ip_params_st dcn3_01_ip = { +- .odm_capable = 1, +- .gpuvm_enable = 1, +- .hostvm_enable = 1, +- .gpuvm_max_page_table_levels = 1, +- .hostvm_max_page_table_levels = 2, +- .hostvm_cached_page_table_levels = 0, +- .pte_group_size_bytes = 2048, +- .num_dsc = 3, +- .rob_buffer_size_kbytes = 184, +- .det_buffer_size_kbytes = 184, +- .dpte_buffer_size_in_pte_reqs_luma = 64, +- .dpte_buffer_size_in_pte_reqs_chroma = 32, +- .pde_proc_buffer_size_64k_reqs = 48, +- .dpp_output_buffer_pixels = 2560, +- .opp_output_buffer_lines = 1, +- .pixel_chunk_size_kbytes = 8, +- .meta_chunk_size_kbytes = 2, +- .writeback_chunk_size_kbytes = 8, +- .line_buffer_size_bits = 789504, +- .is_line_buffer_bpp_fixed = 0, // ? +- .line_buffer_fixed_bpp = 48, // ? +- .dcc_supported = true, +- .writeback_interface_buffer_size_kbytes = 90, +- .writeback_line_buffer_buffer_size = 656640, +- .max_line_buffer_lines = 12, +- .writeback_luma_buffer_size_kbytes = 12, // writeback_line_buffer_buffer_size = 656640 +- .writeback_chroma_buffer_size_kbytes = 8, +- .writeback_chroma_line_buffer_width_pixels = 4, +- .writeback_max_hscl_ratio = 1, +- .writeback_max_vscl_ratio = 1, +- .writeback_min_hscl_ratio = 1, +- .writeback_min_vscl_ratio = 1, +- .writeback_max_hscl_taps = 1, +- .writeback_max_vscl_taps = 1, +- .writeback_line_buffer_luma_buffer_size = 0, +- .writeback_line_buffer_chroma_buffer_size = 14643, +- .cursor_buffer_size = 8, +- .cursor_chunk_size = 2, +- .max_num_otg = 4, +- .max_num_dpp = 4, +- .max_num_wb = 1, +- .max_dchub_pscl_bw_pix_per_clk = 4, +- .max_pscl_lb_bw_pix_per_clk = 2, +- .max_lb_vscl_bw_pix_per_clk = 4, +- .max_vscl_hscl_bw_pix_per_clk = 4, +- .max_hscl_ratio = 6, +- .max_vscl_ratio = 6, +- .hscl_mults = 4, +- .vscl_mults = 4, +- .max_hscl_taps = 8, +- .max_vscl_taps = 8, +- .dispclk_ramp_margin_percent = 1, +- .underscan_factor = 1.11, +- .min_vblank_lines = 32, +- .dppclk_delay_subtotal = 46, +- .dynamic_metadata_vm_enabled = true, +- .dppclk_delay_scl_lb_only = 16, +- .dppclk_delay_scl = 50, +- .dppclk_delay_cnvc_formatter = 27, +- .dppclk_delay_cnvc_cursor = 6, +- .dispclk_delay_subtotal = 119, +- .dcfclk_cstate_latency = 5.2, // SRExitTime +- .max_inter_dcn_tile_repeaters = 8, +- .max_num_hdmi_frl_outputs = 0, +- .odm_combine_4to1_supported = true, +- +- .xfc_supported = false, +- .xfc_fill_bw_overhead_percent = 10.0, +- .xfc_fill_constant_bytes = 0, +- .gfx7_compat_tiling_supported = 0, +- .number_of_cursors = 1, +-}; +- +-struct _vcs_dpi_soc_bounding_box_st dcn3_01_soc = { +- .clock_limits = { +- { +- .state = 0, +- .dram_speed_mts = 2400.0, +- .fabricclk_mhz = 600, +- .socclk_mhz = 278.0, +- .dcfclk_mhz = 400.0, +- .dscclk_mhz = 206.0, +- .dppclk_mhz = 1015.0, +- .dispclk_mhz = 1015.0, +- .phyclk_mhz = 600.0, +- }, +- { +- .state = 1, +- .dram_speed_mts = 2400.0, +- .fabricclk_mhz = 688, +- .socclk_mhz = 278.0, +- .dcfclk_mhz = 400.0, +- .dscclk_mhz = 206.0, +- .dppclk_mhz = 1015.0, +- .dispclk_mhz = 1015.0, +- .phyclk_mhz = 600.0, +- }, +- { +- .state = 2, +- .dram_speed_mts = 4267.0, +- .fabricclk_mhz = 1067, +- .socclk_mhz = 278.0, +- .dcfclk_mhz = 608.0, +- .dscclk_mhz = 296.0, +- .dppclk_mhz = 1015.0, +- .dispclk_mhz = 1015.0, +- .phyclk_mhz = 810.0, +- }, +- +- { +- .state = 3, +- .dram_speed_mts = 4267.0, +- .fabricclk_mhz = 1067, +- .socclk_mhz = 715.0, +- .dcfclk_mhz = 676.0, +- .dscclk_mhz = 338.0, +- .dppclk_mhz = 1015.0, +- .dispclk_mhz = 1015.0, +- .phyclk_mhz = 810.0, +- }, +- +- { +- .state = 4, +- .dram_speed_mts = 4267.0, +- .fabricclk_mhz = 1067, +- .socclk_mhz = 953.0, +- .dcfclk_mhz = 810.0, +- .dscclk_mhz = 338.0, +- .dppclk_mhz = 1015.0, +- .dispclk_mhz = 1015.0, +- .phyclk_mhz = 810.0, +- }, +- }, +- +- .sr_exit_time_us = 9.0, +- .sr_enter_plus_exit_time_us = 11.0, +- .urgent_latency_us = 4.0, +- .urgent_latency_pixel_data_only_us = 4.0, +- .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, +- .urgent_latency_vm_data_only_us = 4.0, +- .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, +- .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, +- .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, +- .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0, +- .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 75.0, +- .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0, +- .max_avg_sdp_bw_use_normal_percent = 60.0, +- .max_avg_dram_bw_use_normal_percent = 60.0, +- .writeback_latency_us = 12.0, +- .max_request_size_bytes = 256, +- .dram_channel_width_bytes = 4, +- .fabric_datapath_to_dcn_data_return_bytes = 32, +- .dcn_downspread_percent = 0.5, +- .downspread_percent = 0.38, +- .dram_page_open_time_ns = 50.0, +- .dram_rw_turnaround_time_ns = 17.5, +- .dram_return_buffer_per_channel_bytes = 8192, +- .round_trip_ping_latency_dcfclk_cycles = 191, +- .urgent_out_of_order_return_per_channel_bytes = 4096, +- .channel_interleave_bytes = 256, +- .num_banks = 8, +- .num_chans = 4, +- .gpuvm_min_page_size_bytes = 4096, +- .hostvm_min_page_size_bytes = 4096, +- .dram_clock_change_latency_us = 23.84, +- .writeback_dram_clock_change_latency_us = 23.0, +- .return_bus_width_bytes = 64, +- .dispclk_dppclk_vco_speed_mhz = 3550, +- .xfc_bus_transport_time_us = 20, // ? +- .xfc_xbuf_latency_tolerance_us = 4, // ? +- .use_urgent_burst_bw = 1, // ? +- .num_states = 5, +- .do_urgent_latency_adjustment = false, +- .urgent_latency_adjustment_fabric_clock_component_us = 0, +- .urgent_latency_adjustment_fabric_clock_reference_mhz = 0, +-}; +- + enum dcn301_clk_src_array_id { + DCN301_CLK_SRC_PLL0, + DCN301_CLK_SRC_PLL1, +@@ -1476,8 +1299,6 @@ static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap + }; + +-#define fixed16_to_double(x) (((double) x) / ((double) (1 << 16))) +-#define fixed16_to_double_to_cpu(x) fixed16_to_double(le32_to_cpu(x)) + + static bool is_soc_bounding_box_valid(struct dc *dc) + { +@@ -1504,26 +1325,24 @@ static bool init_soc_bounding_box(struct dc *dc, + + loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator; + loaded_ip->max_num_dpp = pool->base.pipe_count; ++ DC_FP_START(); + dcn20_patch_bounding_box(dc, loaded_bb); ++ DC_FP_END(); + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info) { + struct bp_soc_bb_info bb_info = {0}; + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info(dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) { +- if (bb_info.dram_clock_change_latency_100ns > 0) +- dcn3_01_soc.dram_clock_change_latency_us = bb_info.dram_clock_change_latency_100ns * 10; +- +- if (bb_info.dram_sr_enter_exit_latency_100ns > 0) +- dcn3_01_soc.sr_enter_plus_exit_time_us = bb_info.dram_sr_enter_exit_latency_100ns * 10; +- +- if (bb_info.dram_sr_exit_latency_100ns > 0) +- dcn3_01_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10; ++ DC_FP_START(); ++ dcn301_fpu_init_soc_bounding_box(bb_info); ++ DC_FP_END(); + } + } + + return true; + } + ++ + static void set_wm_ranges( + struct pp_smu_funcs *pp_smu, + struct _vcs_dpi_soc_bounding_box_st *loaded_bb) +@@ -1546,9 +1365,9 @@ static void set_wm_ranges( + ranges.reader_wm_sets[i].wm_inst = i; + ranges.reader_wm_sets[i].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[i].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; +- ranges.reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; +- ranges.reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16; +- ++ DC_FP_START(); ++ dcn301_fpu_set_wm_ranges(i, &ranges, loaded_bb); ++ DC_FP_END(); + ranges.num_reader_wm_sets = i + 1; + } + +@@ -1568,154 +1387,6 @@ static void set_wm_ranges( + pp_smu->nv_funcs.set_wm_ranges(&pp_smu->nv_funcs.pp_smu, &ranges); + } + +-static void dcn301_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +-{ +- struct dcn301_resource_pool *pool = TO_DCN301_RES_POOL(dc->res_pool); +- struct clk_limit_table *clk_table = &bw_params->clk_table; +- struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES]; +- unsigned int i, closest_clk_lvl; +- int j; +- +- // Default clock levels are used for diags, which may lead to overclocking. +- if (!IS_DIAG_DC(dc->ctx->dce_environment)) { +- dcn3_01_ip.max_num_otg = pool->base.res_cap->num_timing_generator; +- dcn3_01_ip.max_num_dpp = pool->base.pipe_count; +- dcn3_01_soc.num_chans = bw_params->num_channels; +- +- ASSERT(clk_table->num_entries); +- for (i = 0; i < clk_table->num_entries; i++) { +- /* loop backwards*/ +- for (closest_clk_lvl = 0, j = dcn3_01_soc.num_states - 1; j >= 0; j--) { +- if ((unsigned int) dcn3_01_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) { +- closest_clk_lvl = j; +- break; +- } +- } +- +- clock_limits[i].state = i; +- clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz; +- clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz; +- clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz; +- clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2; +- +- clock_limits[i].dispclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dispclk_mhz; +- clock_limits[i].dppclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dppclk_mhz; +- clock_limits[i].dram_bw_per_chan_gbps = dcn3_01_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps; +- clock_limits[i].dscclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dscclk_mhz; +- clock_limits[i].dtbclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dtbclk_mhz; +- clock_limits[i].phyclk_d18_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz; +- clock_limits[i].phyclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].phyclk_mhz; +- } +- for (i = 0; i < clk_table->num_entries; i++) +- dcn3_01_soc.clock_limits[i] = clock_limits[i]; +- if (clk_table->num_entries) { +- dcn3_01_soc.num_states = clk_table->num_entries; +- /* duplicate last level */ +- dcn3_01_soc.clock_limits[dcn3_01_soc.num_states] = dcn3_01_soc.clock_limits[dcn3_01_soc.num_states - 1]; +- dcn3_01_soc.clock_limits[dcn3_01_soc.num_states].state = dcn3_01_soc.num_states; +- } +- } +- +- dcn3_01_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; +- dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; +- +- dml_init_instance(&dc->dml, &dcn3_01_soc, &dcn3_01_ip, DML_PROJECT_DCN30); +-} +- +-static void calculate_wm_set_for_vlevel( +- int vlevel, +- struct wm_range_table_entry *table_entry, +- struct dcn_watermarks *wm_set, +- struct display_mode_lib *dml, +- display_e2e_pipe_params_st *pipes, +- int pipe_cnt) +-{ +- double dram_clock_change_latency_cached = dml->soc.dram_clock_change_latency_us; +- +- ASSERT(vlevel < dml->soc.num_states); +- /* only pipe 0 is read for voltage and dcf/soc clocks */ +- pipes[0].clks_cfg.voltage = vlevel; +- pipes[0].clks_cfg.dcfclk_mhz = dml->soc.clock_limits[vlevel].dcfclk_mhz; +- pipes[0].clks_cfg.socclk_mhz = dml->soc.clock_limits[vlevel].socclk_mhz; +- +- dml->soc.dram_clock_change_latency_us = table_entry->pstate_latency_us; +- dml->soc.sr_exit_time_us = table_entry->sr_exit_time_us; +- dml->soc.sr_enter_plus_exit_time_us = table_entry->sr_enter_plus_exit_time_us; +- +- wm_set->urgent_ns = get_wm_urgent(dml, pipes, pipe_cnt) * 1000; +- wm_set->cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(dml, pipes, pipe_cnt) * 1000; +- wm_set->cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(dml, pipes, pipe_cnt) * 1000; +- wm_set->cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(dml, pipes, pipe_cnt) * 1000; +- wm_set->pte_meta_urgent_ns = get_wm_memory_trip(dml, pipes, pipe_cnt) * 1000; +- wm_set->frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(dml, pipes, pipe_cnt) * 1000; +- wm_set->frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(dml, pipes, pipe_cnt) * 1000; +- wm_set->urgent_latency_ns = get_urgent_latency(dml, pipes, pipe_cnt) * 1000; +- dml->soc.dram_clock_change_latency_us = dram_clock_change_latency_cached; +- +-} +- +-static void dcn301_calculate_wm_and_dlg( +- struct dc *dc, struct dc_state *context, +- display_e2e_pipe_params_st *pipes, +- int pipe_cnt, +- int vlevel_req) +-{ +- int i, pipe_idx; +- int vlevel, vlevel_max; +- struct wm_range_table_entry *table_entry; +- struct clk_bw_params *bw_params = dc->clk_mgr->bw_params; +- +- ASSERT(bw_params); +- +- vlevel_max = bw_params->clk_table.num_entries - 1; +- +- /* WM Set D */ +- table_entry = &bw_params->wm_table.entries[WM_D]; +- if (table_entry->wm_type == WM_TYPE_RETRAINING) +- vlevel = 0; +- else +- vlevel = vlevel_max; +- calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.d, +- &context->bw_ctx.dml, pipes, pipe_cnt); +- /* WM Set C */ +- table_entry = &bw_params->wm_table.entries[WM_C]; +- vlevel = min(max(vlevel_req, 2), vlevel_max); +- calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.c, +- &context->bw_ctx.dml, pipes, pipe_cnt); +- /* WM Set B */ +- table_entry = &bw_params->wm_table.entries[WM_B]; +- vlevel = min(max(vlevel_req, 1), vlevel_max); +- calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.b, +- &context->bw_ctx.dml, pipes, pipe_cnt); +- +- /* WM Set A */ +- table_entry = &bw_params->wm_table.entries[WM_A]; +- vlevel = min(vlevel_req, vlevel_max); +- calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.a, +- &context->bw_ctx.dml, pipes, pipe_cnt); +- +- for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { +- if (!context->res_ctx.pipe_ctx[i].stream) +- continue; +- +- pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt); +- pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); +- +- if (dc->config.forced_clocks) { +- pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz; +- pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; +- } +- if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000) +- pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0; +- if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) +- pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0; +- +- pipe_idx++; +- } +- +- dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); +-} +- + static struct resource_funcs dcn301_res_pool_funcs = { + .destroy = dcn301_destroy_resource_pool, + .link_enc_create = dcn301_link_encoder_create, +diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h +index 17e4e91ff4b8e..ae8672680cdd1 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h ++++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h +@@ -32,6 +32,9 @@ struct dc; + struct resource_pool; + struct _vcs_dpi_display_pipe_params_st; + ++extern struct _vcs_dpi_ip_params_st dcn3_01_ip; ++extern struct _vcs_dpi_soc_bounding_box_st dcn3_01_soc; ++ + struct dcn301_resource_pool { + struct resource_pool base; + }; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile +index 9009b92490f34..069f0cf113f30 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile +@@ -70,6 +70,7 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) $(fram + CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) $(frame_warn_flag) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_ccflags) ++CFLAGS_$(AMDDALPATH)/dc/dml/dcn301/dcn301_fpu.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/dsc/rc_calc_fpu.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) + CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_rcflags) +@@ -84,6 +85,7 @@ CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_rcflags) + CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_rcflags) + CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_rcflags) + CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_rcflags) ++CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn301/dcn301_fpu.o := $(dml_rcflags) + CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_rcflags) + CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dsc/rc_calc_fpu.o := $(dml_rcflags) + endif +@@ -101,6 +103,7 @@ DML += dcn20/display_rq_dlg_calc_20v2.o dcn20/display_mode_vba_20v2.o + DML += dcn21/display_rq_dlg_calc_21.o dcn21/display_mode_vba_21.o + DML += dcn30/display_mode_vba_30.o dcn30/display_rq_dlg_calc_30.o + DML += dcn31/display_mode_vba_31.o dcn31/display_rq_dlg_calc_31.o ++DML += dcn301/dcn301_fpu.o + DML += dsc/rc_calc_fpu.o + endif + +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c +new file mode 100644 +index 0000000000000..94c32832a0e7b +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c +@@ -0,0 +1,390 @@ ++/* ++ * Copyright 2019-2021 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++#include "resource.h" ++#include "clk_mgr.h" ++#include "dcn20/dcn20_resource.h" ++#include "dcn301/dcn301_resource.h" ++ ++#include "dml/dcn20/dcn20_fpu.h" ++#include "dcn301_fpu.h" ++ ++#define TO_DCN301_RES_POOL(pool)\ ++ container_of(pool, struct dcn301_resource_pool, base) ++ ++/* Based on: //vidip/dc/dcn3/doc/architecture/DCN3x_Display_Mode.xlsm#83 */ ++struct _vcs_dpi_ip_params_st dcn3_01_ip = { ++ .odm_capable = 1, ++ .gpuvm_enable = 1, ++ .hostvm_enable = 1, ++ .gpuvm_max_page_table_levels = 1, ++ .hostvm_max_page_table_levels = 2, ++ .hostvm_cached_page_table_levels = 0, ++ .pte_group_size_bytes = 2048, ++ .num_dsc = 3, ++ .rob_buffer_size_kbytes = 184, ++ .det_buffer_size_kbytes = 184, ++ .dpte_buffer_size_in_pte_reqs_luma = 64, ++ .dpte_buffer_size_in_pte_reqs_chroma = 32, ++ .pde_proc_buffer_size_64k_reqs = 48, ++ .dpp_output_buffer_pixels = 2560, ++ .opp_output_buffer_lines = 1, ++ .pixel_chunk_size_kbytes = 8, ++ .meta_chunk_size_kbytes = 2, ++ .writeback_chunk_size_kbytes = 8, ++ .line_buffer_size_bits = 789504, ++ .is_line_buffer_bpp_fixed = 0, // ? ++ .line_buffer_fixed_bpp = 48, // ? ++ .dcc_supported = true, ++ .writeback_interface_buffer_size_kbytes = 90, ++ .writeback_line_buffer_buffer_size = 656640, ++ .max_line_buffer_lines = 12, ++ .writeback_luma_buffer_size_kbytes = 12, // writeback_line_buffer_buffer_size = 656640 ++ .writeback_chroma_buffer_size_kbytes = 8, ++ .writeback_chroma_line_buffer_width_pixels = 4, ++ .writeback_max_hscl_ratio = 1, ++ .writeback_max_vscl_ratio = 1, ++ .writeback_min_hscl_ratio = 1, ++ .writeback_min_vscl_ratio = 1, ++ .writeback_max_hscl_taps = 1, ++ .writeback_max_vscl_taps = 1, ++ .writeback_line_buffer_luma_buffer_size = 0, ++ .writeback_line_buffer_chroma_buffer_size = 14643, ++ .cursor_buffer_size = 8, ++ .cursor_chunk_size = 2, ++ .max_num_otg = 4, ++ .max_num_dpp = 4, ++ .max_num_wb = 1, ++ .max_dchub_pscl_bw_pix_per_clk = 4, ++ .max_pscl_lb_bw_pix_per_clk = 2, ++ .max_lb_vscl_bw_pix_per_clk = 4, ++ .max_vscl_hscl_bw_pix_per_clk = 4, ++ .max_hscl_ratio = 6, ++ .max_vscl_ratio = 6, ++ .hscl_mults = 4, ++ .vscl_mults = 4, ++ .max_hscl_taps = 8, ++ .max_vscl_taps = 8, ++ .dispclk_ramp_margin_percent = 1, ++ .underscan_factor = 1.11, ++ .min_vblank_lines = 32, ++ .dppclk_delay_subtotal = 46, ++ .dynamic_metadata_vm_enabled = true, ++ .dppclk_delay_scl_lb_only = 16, ++ .dppclk_delay_scl = 50, ++ .dppclk_delay_cnvc_formatter = 27, ++ .dppclk_delay_cnvc_cursor = 6, ++ .dispclk_delay_subtotal = 119, ++ .dcfclk_cstate_latency = 5.2, // SRExitTime ++ .max_inter_dcn_tile_repeaters = 8, ++ .max_num_hdmi_frl_outputs = 0, ++ .odm_combine_4to1_supported = true, ++ ++ .xfc_supported = false, ++ .xfc_fill_bw_overhead_percent = 10.0, ++ .xfc_fill_constant_bytes = 0, ++ .gfx7_compat_tiling_supported = 0, ++ .number_of_cursors = 1, ++}; ++ ++struct _vcs_dpi_soc_bounding_box_st dcn3_01_soc = { ++ .clock_limits = { ++ { ++ .state = 0, ++ .dram_speed_mts = 2400.0, ++ .fabricclk_mhz = 600, ++ .socclk_mhz = 278.0, ++ .dcfclk_mhz = 400.0, ++ .dscclk_mhz = 206.0, ++ .dppclk_mhz = 1015.0, ++ .dispclk_mhz = 1015.0, ++ .phyclk_mhz = 600.0, ++ }, ++ ++ { ++ .state = 1, ++ .dram_speed_mts = 2400.0, ++ .fabricclk_mhz = 688, ++ .socclk_mhz = 278.0, ++ .dcfclk_mhz = 400.0, ++ .dscclk_mhz = 206.0, ++ .dppclk_mhz = 1015.0, ++ .dispclk_mhz = 1015.0, ++ .phyclk_mhz = 600.0, ++ }, ++ ++ { ++ .state = 2, ++ .dram_speed_mts = 4267.0, ++ .fabricclk_mhz = 1067, ++ .socclk_mhz = 278.0, ++ .dcfclk_mhz = 608.0, ++ .dscclk_mhz = 296.0, ++ .dppclk_mhz = 1015.0, ++ .dispclk_mhz = 1015.0, ++ .phyclk_mhz = 810.0, ++ }, ++ ++ { ++ .state = 3, ++ .dram_speed_mts = 4267.0, ++ .fabricclk_mhz = 1067, ++ .socclk_mhz = 715.0, ++ .dcfclk_mhz = 676.0, ++ .dscclk_mhz = 338.0, ++ .dppclk_mhz = 1015.0, ++ .dispclk_mhz = 1015.0, ++ .phyclk_mhz = 810.0, ++ }, ++ ++ { ++ .state = 4, ++ .dram_speed_mts = 4267.0, ++ .fabricclk_mhz = 1067, ++ .socclk_mhz = 953.0, ++ .dcfclk_mhz = 810.0, ++ .dscclk_mhz = 338.0, ++ .dppclk_mhz = 1015.0, ++ .dispclk_mhz = 1015.0, ++ .phyclk_mhz = 810.0, ++ }, ++ }, ++ ++ .sr_exit_time_us = 9.0, ++ .sr_enter_plus_exit_time_us = 11.0, ++ .urgent_latency_us = 4.0, ++ .urgent_latency_pixel_data_only_us = 4.0, ++ .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, ++ .urgent_latency_vm_data_only_us = 4.0, ++ .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, ++ .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, ++ .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, ++ .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0, ++ .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 75.0, ++ .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0, ++ .max_avg_sdp_bw_use_normal_percent = 60.0, ++ .max_avg_dram_bw_use_normal_percent = 60.0, ++ .writeback_latency_us = 12.0, ++ .max_request_size_bytes = 256, ++ .dram_channel_width_bytes = 4, ++ .fabric_datapath_to_dcn_data_return_bytes = 32, ++ .dcn_downspread_percent = 0.5, ++ .downspread_percent = 0.38, ++ .dram_page_open_time_ns = 50.0, ++ .dram_rw_turnaround_time_ns = 17.5, ++ .dram_return_buffer_per_channel_bytes = 8192, ++ .round_trip_ping_latency_dcfclk_cycles = 191, ++ .urgent_out_of_order_return_per_channel_bytes = 4096, ++ .channel_interleave_bytes = 256, ++ .num_banks = 8, ++ .num_chans = 4, ++ .gpuvm_min_page_size_bytes = 4096, ++ .hostvm_min_page_size_bytes = 4096, ++ .dram_clock_change_latency_us = 23.84, ++ .writeback_dram_clock_change_latency_us = 23.0, ++ .return_bus_width_bytes = 64, ++ .dispclk_dppclk_vco_speed_mhz = 3550, ++ .xfc_bus_transport_time_us = 20, // ? ++ .xfc_xbuf_latency_tolerance_us = 4, // ? ++ .use_urgent_burst_bw = 1, // ? ++ .num_states = 5, ++ .do_urgent_latency_adjustment = false, ++ .urgent_latency_adjustment_fabric_clock_component_us = 0, ++ .urgent_latency_adjustment_fabric_clock_reference_mhz = 0, ++}; ++ ++static void calculate_wm_set_for_vlevel(int vlevel, ++ struct wm_range_table_entry *table_entry, ++ struct dcn_watermarks *wm_set, ++ struct display_mode_lib *dml, ++ display_e2e_pipe_params_st *pipes, ++ int pipe_cnt) ++{ ++ double dram_clock_change_latency_cached = dml->soc.dram_clock_change_latency_us; ++ ++ ASSERT(vlevel < dml->soc.num_states); ++ /* only pipe 0 is read for voltage and dcf/soc clocks */ ++ pipes[0].clks_cfg.voltage = vlevel; ++ pipes[0].clks_cfg.dcfclk_mhz = dml->soc.clock_limits[vlevel].dcfclk_mhz; ++ pipes[0].clks_cfg.socclk_mhz = dml->soc.clock_limits[vlevel].socclk_mhz; ++ ++ dml->soc.dram_clock_change_latency_us = table_entry->pstate_latency_us; ++ dml->soc.sr_exit_time_us = table_entry->sr_exit_time_us; ++ dml->soc.sr_enter_plus_exit_time_us = table_entry->sr_enter_plus_exit_time_us; ++ ++ wm_set->urgent_ns = get_wm_urgent(dml, pipes, pipe_cnt) * 1000; ++ wm_set->cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(dml, pipes, pipe_cnt) * 1000; ++ wm_set->cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(dml, pipes, pipe_cnt) * 1000; ++ wm_set->cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(dml, pipes, pipe_cnt) * 1000; ++ wm_set->pte_meta_urgent_ns = get_wm_memory_trip(dml, pipes, pipe_cnt) * 1000; ++ wm_set->frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(dml, pipes, pipe_cnt) * 1000; ++ wm_set->frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(dml, pipes, pipe_cnt) * 1000; ++ wm_set->urgent_latency_ns = get_urgent_latency(dml, pipes, pipe_cnt) * 1000; ++ dml->soc.dram_clock_change_latency_us = dram_clock_change_latency_cached; ++ ++} ++ ++void dcn301_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) ++{ ++ struct dcn301_resource_pool *pool = TO_DCN301_RES_POOL(dc->res_pool); ++ struct clk_limit_table *clk_table = &bw_params->clk_table; ++ struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES]; ++ unsigned int i, closest_clk_lvl; ++ int j; ++ ++ dc_assert_fp_enabled(); ++ ++ /* Default clock levels are used for diags, which may lead to overclocking. */ ++ if (!IS_DIAG_DC(dc->ctx->dce_environment)) { ++ dcn3_01_ip.max_num_otg = pool->base.res_cap->num_timing_generator; ++ dcn3_01_ip.max_num_dpp = pool->base.pipe_count; ++ dcn3_01_soc.num_chans = bw_params->num_channels; ++ ++ ASSERT(clk_table->num_entries); ++ for (i = 0; i < clk_table->num_entries; i++) { ++ /* loop backwards*/ ++ for (closest_clk_lvl = 0, j = dcn3_01_soc.num_states - 1; j >= 0; j--) { ++ if ((unsigned int) dcn3_01_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) { ++ closest_clk_lvl = j; ++ break; ++ } ++ } ++ ++ clock_limits[i].state = i; ++ clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz; ++ clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz; ++ clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz; ++ clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2; ++ ++ clock_limits[i].dispclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dispclk_mhz; ++ clock_limits[i].dppclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dppclk_mhz; ++ clock_limits[i].dram_bw_per_chan_gbps = dcn3_01_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps; ++ clock_limits[i].dscclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dscclk_mhz; ++ clock_limits[i].dtbclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dtbclk_mhz; ++ clock_limits[i].phyclk_d18_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz; ++ clock_limits[i].phyclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].phyclk_mhz; ++ } ++ ++ for (i = 0; i < clk_table->num_entries; i++) ++ dcn3_01_soc.clock_limits[i] = clock_limits[i]; ++ ++ if (clk_table->num_entries) { ++ dcn3_01_soc.num_states = clk_table->num_entries; ++ /* duplicate last level */ ++ dcn3_01_soc.clock_limits[dcn3_01_soc.num_states] = dcn3_01_soc.clock_limits[dcn3_01_soc.num_states - 1]; ++ dcn3_01_soc.clock_limits[dcn3_01_soc.num_states].state = dcn3_01_soc.num_states; ++ } ++ } ++ ++ dcn3_01_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; ++ dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; ++ ++ dml_init_instance(&dc->dml, &dcn3_01_soc, &dcn3_01_ip, DML_PROJECT_DCN30); ++} ++ ++void dcn301_fpu_set_wm_ranges(int i, ++ struct pp_smu_wm_range_sets *ranges, ++ struct _vcs_dpi_soc_bounding_box_st *loaded_bb) ++{ ++ dc_assert_fp_enabled(); ++ ++ ranges->reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; ++ ranges->reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16; ++} ++ ++void dcn301_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info) ++{ ++ dc_assert_fp_enabled(); ++ ++ if (bb_info.dram_clock_change_latency_100ns > 0) ++ dcn3_01_soc.dram_clock_change_latency_us = bb_info.dram_clock_change_latency_100ns * 10; ++ ++ if (bb_info.dram_sr_enter_exit_latency_100ns > 0) ++ dcn3_01_soc.sr_enter_plus_exit_time_us = bb_info.dram_sr_enter_exit_latency_100ns * 10; ++ ++ if (bb_info.dram_sr_exit_latency_100ns > 0) ++ dcn3_01_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10; ++} ++ ++void dcn301_calculate_wm_and_dlg(struct dc *dc, ++ struct dc_state *context, ++ display_e2e_pipe_params_st *pipes, ++ int pipe_cnt, ++ int vlevel_req) ++{ ++ int i, pipe_idx; ++ int vlevel, vlevel_max; ++ struct wm_range_table_entry *table_entry; ++ struct clk_bw_params *bw_params = dc->clk_mgr->bw_params; ++ ++ ASSERT(bw_params); ++ dc_assert_fp_enabled(); ++ ++ vlevel_max = bw_params->clk_table.num_entries - 1; ++ ++ /* WM Set D */ ++ table_entry = &bw_params->wm_table.entries[WM_D]; ++ if (table_entry->wm_type == WM_TYPE_RETRAINING) ++ vlevel = 0; ++ else ++ vlevel = vlevel_max; ++ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.d, ++ &context->bw_ctx.dml, pipes, pipe_cnt); ++ /* WM Set C */ ++ table_entry = &bw_params->wm_table.entries[WM_C]; ++ vlevel = min(max(vlevel_req, 2), vlevel_max); ++ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.c, ++ &context->bw_ctx.dml, pipes, pipe_cnt); ++ /* WM Set B */ ++ table_entry = &bw_params->wm_table.entries[WM_B]; ++ vlevel = min(max(vlevel_req, 1), vlevel_max); ++ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.b, ++ &context->bw_ctx.dml, pipes, pipe_cnt); ++ ++ /* WM Set A */ ++ table_entry = &bw_params->wm_table.entries[WM_A]; ++ vlevel = min(vlevel_req, vlevel_max); ++ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.a, ++ &context->bw_ctx.dml, pipes, pipe_cnt); ++ ++ for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { ++ if (!context->res_ctx.pipe_ctx[i].stream) ++ continue; ++ ++ pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt); ++ pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); ++ ++ if (dc->config.forced_clocks) { ++ pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz; ++ pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; ++ } ++ if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000) ++ pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0; ++ if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) ++ pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0; ++ pipe_idx++; ++ } ++ ++ dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); ++} +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h +new file mode 100644 +index 0000000000000..fc7065d178422 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h +@@ -0,0 +1,42 @@ ++/* ++ * Copyright 2019-2021 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#ifndef __DCN301_FPU_H__ ++#define __DCN301_FPU_H__ ++ ++void dcn301_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); ++ ++void dcn301_fpu_set_wm_ranges(int i, ++ struct pp_smu_wm_range_sets *ranges, ++ struct _vcs_dpi_soc_bounding_box_st *loaded_bb); ++ ++void dcn301_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info); ++ ++void dcn301_calculate_wm_and_dlg(struct dc *dc, ++ struct dc_state *context, ++ display_e2e_pipe_params_st *pipes, ++ int pipe_cnt, ++ int vlevel_req); ++#endif /* __DCN301_FPU_H__*/ +-- +2.34.1 + diff --git a/queue-5.15/drm-amd-display-move-fpu-associated-dsc-code-to-dml-.patch b/queue-5.15/drm-amd-display-move-fpu-associated-dsc-code-to-dml-.patch new file mode 100644 index 00000000000..98e013c160b --- /dev/null +++ b/queue-5.15/drm-amd-display-move-fpu-associated-dsc-code-to-dml-.patch @@ -0,0 +1,861 @@ +From 1c628a8f04ea79bfa944cc534be3215c8cde902e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Aug 2021 07:52:24 -0400 +Subject: drm/amd/display: move FPU associated DSC code to DML folder +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Qingqing Zhuo + +[ Upstream commit d738db6883df3e3c513f9e777c842262693f951b ] + +[Why & How] +As part of the FPU isolation work documented in +https://patchwork.freedesktop.org/series/93042/, isolate code that uses +FPU in DSC to DML, where all FPU code should locate. + +This change does not refactor any functions but move code around. + +Cc: Christian König +Cc: Hersen Wu +Cc: Anson Jacob +Cc: Harry Wentland +Reviewed-by: Rodrigo Siqueira +Acked-by: Agustin Gutierrez +Tested-by: Anson Jacob +Tested-by: Daniel Wheeler +Signed-off-by: Qingqing Zhuo +Acked-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dml/Makefile | 3 + + .../amd/display/dc/{ => dml}/dsc/qp_tables.h | 0 + .../drm/amd/display/dc/dml/dsc/rc_calc_fpu.c | 291 ++++++++++++++++++ + .../drm/amd/display/dc/dml/dsc/rc_calc_fpu.h | 94 ++++++ + drivers/gpu/drm/amd/display/dc/dsc/Makefile | 29 -- + drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c | 259 ---------------- + drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h | 50 +-- + .../gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c | 1 - + 8 files changed, 389 insertions(+), 338 deletions(-) + rename drivers/gpu/drm/amd/display/dc/{ => dml}/dsc/qp_tables.h (100%) + create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c + create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h + +diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile +index 56055df2e8d2e..9009b92490f34 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile +@@ -70,6 +70,7 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) $(fram + CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) $(frame_warn_flag) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_ccflags) ++CFLAGS_$(AMDDALPATH)/dc/dml/dsc/rc_calc_fpu.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) + CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_rcflags) + CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn2x/dcn2x.o := $(dml_rcflags) +@@ -84,6 +85,7 @@ CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_rcfla + CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_rcflags) + CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_rcflags) + CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_rcflags) ++CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dsc/rc_calc_fpu.o := $(dml_rcflags) + endif + CFLAGS_$(AMDDALPATH)/dc/dml/dml1_display_rq_dlg_calc.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/display_rq_dlg_helpers.o := $(dml_ccflags) +@@ -99,6 +101,7 @@ DML += dcn20/display_rq_dlg_calc_20v2.o dcn20/display_mode_vba_20v2.o + DML += dcn21/display_rq_dlg_calc_21.o dcn21/display_mode_vba_21.o + DML += dcn30/display_mode_vba_30.o dcn30/display_rq_dlg_calc_30.o + DML += dcn31/display_mode_vba_31.o dcn31/display_rq_dlg_calc_31.o ++DML += dsc/rc_calc_fpu.o + endif + + AMD_DAL_DML = $(addprefix $(AMDDALPATH)/dc/dml/,$(DML)) +diff --git a/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h b/drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h +similarity index 100% +rename from drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h +rename to drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c +new file mode 100644 +index 0000000000000..3ee858f311d12 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c +@@ -0,0 +1,291 @@ ++/* ++ * Copyright 2021 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#include "rc_calc_fpu.h" ++ ++#include "qp_tables.h" ++#include "amdgpu_dm/dc_fpu.h" ++ ++#define table_hash(mode, bpc, max_min) ((mode << 16) | (bpc << 8) | max_min) ++ ++#define MODE_SELECT(val444, val422, val420) \ ++ (cm == CM_444 || cm == CM_RGB) ? (val444) : (cm == CM_422 ? (val422) : (val420)) ++ ++ ++#define TABLE_CASE(mode, bpc, max) case (table_hash(mode, BPC_##bpc, max)): \ ++ table = qp_table_##mode##_##bpc##bpc_##max; \ ++ table_size = sizeof(qp_table_##mode##_##bpc##bpc_##max)/sizeof(*qp_table_##mode##_##bpc##bpc_##max); \ ++ break ++ ++static int median3(int a, int b, int c) ++{ ++ if (a > b) ++ swap(a, b); ++ if (b > c) ++ swap(b, c); ++ if (a > b) ++ swap(b, c); ++ ++ return b; ++} ++ ++static double dsc_roundf(double num) ++{ ++ if (num < 0.0) ++ num = num - 0.5; ++ else ++ num = num + 0.5; ++ ++ return (int)(num); ++} ++ ++static double dsc_ceil(double num) ++{ ++ double retval = (int)num; ++ ++ if (retval != num && num > 0) ++ retval = num + 1; ++ ++ return (int)retval; ++} ++ ++static void get_qp_set(qp_set qps, enum colour_mode cm, enum bits_per_comp bpc, ++ enum max_min max_min, float bpp) ++{ ++ int mode = MODE_SELECT(444, 422, 420); ++ int sel = table_hash(mode, bpc, max_min); ++ int table_size = 0; ++ int index; ++ const struct qp_entry *table = 0L; ++ ++ // alias enum ++ enum { min = DAL_MM_MIN, max = DAL_MM_MAX }; ++ switch (sel) { ++ TABLE_CASE(444, 8, max); ++ TABLE_CASE(444, 8, min); ++ TABLE_CASE(444, 10, max); ++ TABLE_CASE(444, 10, min); ++ TABLE_CASE(444, 12, max); ++ TABLE_CASE(444, 12, min); ++ TABLE_CASE(422, 8, max); ++ TABLE_CASE(422, 8, min); ++ TABLE_CASE(422, 10, max); ++ TABLE_CASE(422, 10, min); ++ TABLE_CASE(422, 12, max); ++ TABLE_CASE(422, 12, min); ++ TABLE_CASE(420, 8, max); ++ TABLE_CASE(420, 8, min); ++ TABLE_CASE(420, 10, max); ++ TABLE_CASE(420, 10, min); ++ TABLE_CASE(420, 12, max); ++ TABLE_CASE(420, 12, min); ++ } ++ ++ if (table == 0) ++ return; ++ ++ index = (bpp - table[0].bpp) * 2; ++ ++ /* requested size is bigger than the table */ ++ if (index >= table_size) { ++ dm_error("ERROR: Requested rc_calc to find a bpp entry that exceeds the table size\n"); ++ return; ++ } ++ ++ memcpy(qps, table[index].qps, sizeof(qp_set)); ++} ++ ++static void get_ofs_set(qp_set ofs, enum colour_mode mode, float bpp) ++{ ++ int *p = ofs; ++ ++ if (mode == CM_444 || mode == CM_RGB) { ++ *p++ = (bpp <= 6) ? (0) : ((((bpp >= 8) && (bpp <= 12))) ? (2) : ((bpp >= 15) ? (10) : ((((bpp > 6) && (bpp < 8))) ? (0 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (2 + dsc_roundf((bpp - 12) * (8 / 3.0)))))); ++ *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (8) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (8 / 3.0)))))); ++ *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (6) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); ++ *p++ = (bpp <= 6) ? (-4) : ((((bpp >= 8) && (bpp <= 12))) ? (-2) : ((bpp >= 15) ? (4) : ((((bpp > 6) && (bpp < 8))) ? (-4 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-2 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); ++ *p++ = (bpp <= 6) ? (-6) : ((((bpp >= 8) && (bpp <= 12))) ? (-4) : ((bpp >= 15) ? (2) : ((((bpp > 6) && (bpp < 8))) ? (-6 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-4 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); ++ *p++ = (bpp <= 12) ? (-6) : ((bpp >= 15) ? (0) : (-6 + dsc_roundf((bpp - 12) * (6 / 3.0)))); ++ *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-2) : (-8 + dsc_roundf((bpp - 12) * (6 / 3.0)))); ++ *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-4) : (-8 + dsc_roundf((bpp - 12) * (4 / 3.0)))); ++ *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-6) : (-8 + dsc_roundf((bpp - 12) * (2 / 3.0)))); ++ *p++ = (bpp <= 12) ? (-10) : ((bpp >= 15) ? (-8) : (-10 + dsc_roundf((bpp - 12) * (2 / 3.0)))); ++ *p++ = -10; ++ *p++ = (bpp <= 6) ? (-12) : ((bpp >= 8) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2 / 2.0)))); ++ *p++ = -12; ++ *p++ = -12; ++ *p++ = -12; ++ } else if (mode == CM_422) { ++ *p++ = (bpp <= 8) ? (2) : ((bpp >= 10) ? (10) : (2 + dsc_roundf((bpp - 8) * (8 / 2.0)))); ++ *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (8) : (0 + dsc_roundf((bpp - 8) * (8 / 2.0)))); ++ *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (6) : (0 + dsc_roundf((bpp - 8) * (6 / 2.0)))); ++ *p++ = (bpp <= 8) ? (-2) : ((bpp >= 10) ? (4) : (-2 + dsc_roundf((bpp - 8) * (6 / 2.0)))); ++ *p++ = (bpp <= 8) ? (-4) : ((bpp >= 10) ? (2) : (-4 + dsc_roundf((bpp - 8) * (6 / 2.0)))); ++ *p++ = (bpp <= 8) ? (-6) : ((bpp >= 10) ? (0) : (-6 + dsc_roundf((bpp - 8) * (6 / 2.0)))); ++ *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-2) : (-8 + dsc_roundf((bpp - 8) * (6 / 2.0)))); ++ *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-4) : (-8 + dsc_roundf((bpp - 8) * (4 / 2.0)))); ++ *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-6) : (-8 + dsc_roundf((bpp - 8) * (2 / 2.0)))); ++ *p++ = (bpp <= 8) ? (-10) : ((bpp >= 10) ? (-8) : (-10 + dsc_roundf((bpp - 8) * (2 / 2.0)))); ++ *p++ = -10; ++ *p++ = (bpp <= 6) ? (-12) : ((bpp >= 7) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2.0 / 1)))); ++ *p++ = -12; ++ *p++ = -12; ++ *p++ = -12; ++ } else { ++ *p++ = (bpp <= 6) ? (2) : ((bpp >= 8) ? (10) : (2 + dsc_roundf((bpp - 6) * (8 / 2.0)))); ++ *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (8) : (0 + dsc_roundf((bpp - 6) * (8 / 2.0)))); ++ *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (6) : (0 + dsc_roundf((bpp - 6) * (6 / 2.0)))); ++ *p++ = (bpp <= 6) ? (-2) : ((bpp >= 8) ? (4) : (-2 + dsc_roundf((bpp - 6) * (6 / 2.0)))); ++ *p++ = (bpp <= 6) ? (-4) : ((bpp >= 8) ? (2) : (-4 + dsc_roundf((bpp - 6) * (6 / 2.0)))); ++ *p++ = (bpp <= 6) ? (-6) : ((bpp >= 8) ? (0) : (-6 + dsc_roundf((bpp - 6) * (6 / 2.0)))); ++ *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-2) : (-8 + dsc_roundf((bpp - 6) * (6 / 2.0)))); ++ *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-4) : (-8 + dsc_roundf((bpp - 6) * (4 / 2.0)))); ++ *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-6) : (-8 + dsc_roundf((bpp - 6) * (2 / 2.0)))); ++ *p++ = (bpp <= 6) ? (-10) : ((bpp >= 8) ? (-8) : (-10 + dsc_roundf((bpp - 6) * (2 / 2.0)))); ++ *p++ = -10; ++ *p++ = (bpp <= 4) ? (-12) : ((bpp >= 5) ? (-10) : (-12 + dsc_roundf((bpp - 4) * (2 / 1.0)))); ++ *p++ = -12; ++ *p++ = -12; ++ *p++ = -12; ++ } ++} ++ ++void _do_calc_rc_params(struct rc_params *rc, ++ enum colour_mode cm, ++ enum bits_per_comp bpc, ++ u16 drm_bpp, ++ bool is_navite_422_or_420, ++ int slice_width, ++ int slice_height, ++ int minor_version) ++{ ++ float bpp; ++ float bpp_group; ++ float initial_xmit_delay_factor; ++ int padding_pixels; ++ int i; ++ ++ dc_assert_fp_enabled(); ++ ++ bpp = ((float)drm_bpp / 16.0); ++ /* in native_422 or native_420 modes, the bits_per_pixel is double the ++ * target bpp (the latter is what calc_rc_params expects) ++ */ ++ if (is_navite_422_or_420) ++ bpp /= 2.0; ++ ++ rc->rc_quant_incr_limit0 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); ++ rc->rc_quant_incr_limit1 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); ++ ++ bpp_group = MODE_SELECT(bpp, bpp * 2.0, bpp * 2.0); ++ ++ switch (cm) { ++ case CM_420: ++ rc->initial_fullness_offset = (bpp >= 6) ? (2048) : ((bpp <= 4) ? (6144) : ((((bpp > 4) && (bpp <= 5))) ? (6144 - dsc_roundf((bpp - 4) * (512))) : (5632 - dsc_roundf((bpp - 5) * (3584))))); ++ rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 3) - (3 * bpp_group))); ++ rc->second_line_bpg_offset = median3(0, 12, (int)((3 * bpc * 3) - (3 * bpp_group))); ++ break; ++ case CM_422: ++ rc->initial_fullness_offset = (bpp >= 8) ? (2048) : ((bpp <= 7) ? (5632) : (5632 - dsc_roundf((bpp - 7) * (3584)))); ++ rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 4) - (3 * bpp_group))); ++ rc->second_line_bpg_offset = 0; ++ break; ++ case CM_444: ++ case CM_RGB: ++ rc->initial_fullness_offset = (bpp >= 12) ? (2048) : ((bpp <= 8) ? (6144) : ((((bpp > 8) && (bpp <= 10))) ? (6144 - dsc_roundf((bpp - 8) * (512 / 2))) : (5632 - dsc_roundf((bpp - 10) * (3584 / 2))))); ++ rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)(((3 * bpc + (cm == CM_444 ? 0 : 2)) * 3) - (3 * bpp_group))); ++ rc->second_line_bpg_offset = 0; ++ break; ++ } ++ ++ initial_xmit_delay_factor = (cm == CM_444 || cm == CM_RGB) ? 1.0 : 2.0; ++ rc->initial_xmit_delay = dsc_roundf(8192.0/2.0/bpp/initial_xmit_delay_factor); ++ ++ if (cm == CM_422 || cm == CM_420) ++ slice_width /= 2; ++ ++ padding_pixels = ((slice_width % 3) != 0) ? (3 - (slice_width % 3)) * (rc->initial_xmit_delay / slice_width) : 0; ++ if (3 * bpp_group >= (((rc->initial_xmit_delay + 2) / 3) * (3 + (cm == CM_422)))) { ++ if ((rc->initial_xmit_delay + padding_pixels) % 3 == 1) ++ rc->initial_xmit_delay++; ++ } ++ ++ rc->flatness_min_qp = ((bpc == BPC_8) ? (3) : ((bpc == BPC_10) ? (7) : (11))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); ++ rc->flatness_max_qp = ((bpc == BPC_8) ? (12) : ((bpc == BPC_10) ? (16) : (20))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); ++ rc->flatness_det_thresh = 2 << (bpc - 8); ++ ++ get_qp_set(rc->qp_min, cm, bpc, DAL_MM_MIN, bpp); ++ get_qp_set(rc->qp_max, cm, bpc, DAL_MM_MAX, bpp); ++ if (cm == CM_444 && minor_version == 1) { ++ for (i = 0; i < QP_SET_SIZE; ++i) { ++ rc->qp_min[i] = rc->qp_min[i] > 0 ? rc->qp_min[i] - 1 : 0; ++ rc->qp_max[i] = rc->qp_max[i] > 0 ? rc->qp_max[i] - 1 : 0; ++ } ++ } ++ get_ofs_set(rc->ofs, cm, bpp); ++ ++ /* fixed parameters */ ++ rc->rc_model_size = 8192; ++ rc->rc_edge_factor = 6; ++ rc->rc_tgt_offset_hi = 3; ++ rc->rc_tgt_offset_lo = 3; ++ ++ rc->rc_buf_thresh[0] = 896; ++ rc->rc_buf_thresh[1] = 1792; ++ rc->rc_buf_thresh[2] = 2688; ++ rc->rc_buf_thresh[3] = 3584; ++ rc->rc_buf_thresh[4] = 4480; ++ rc->rc_buf_thresh[5] = 5376; ++ rc->rc_buf_thresh[6] = 6272; ++ rc->rc_buf_thresh[7] = 6720; ++ rc->rc_buf_thresh[8] = 7168; ++ rc->rc_buf_thresh[9] = 7616; ++ rc->rc_buf_thresh[10] = 7744; ++ rc->rc_buf_thresh[11] = 7872; ++ rc->rc_buf_thresh[12] = 8000; ++ rc->rc_buf_thresh[13] = 8064; ++} ++ ++u32 _do_bytes_per_pixel_calc(int slice_width, ++ u16 drm_bpp, ++ bool is_navite_422_or_420) ++{ ++ float bpp; ++ u32 bytes_per_pixel; ++ double d_bytes_per_pixel; ++ ++ dc_assert_fp_enabled(); ++ ++ bpp = ((float)drm_bpp / 16.0); ++ d_bytes_per_pixel = dsc_ceil(bpp * slice_width / 8.0) / slice_width; ++ // TODO: Make sure the formula for calculating this is precise (ceiling ++ // vs. floor, and at what point they should be applied) ++ if (is_navite_422_or_420) ++ d_bytes_per_pixel /= 2; ++ ++ bytes_per_pixel = (u32)dsc_ceil(d_bytes_per_pixel * 0x10000000); ++ ++ return bytes_per_pixel; ++} +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h +new file mode 100644 +index 0000000000000..b93b95409fbe2 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h +@@ -0,0 +1,94 @@ ++/* ++ * Copyright 2021 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#ifndef __RC_CALC_FPU_H__ ++#define __RC_CALC_FPU_H__ ++ ++#include "os_types.h" ++#include ++ ++#define QP_SET_SIZE 15 ++ ++typedef int qp_set[QP_SET_SIZE]; ++ ++struct rc_params { ++ int rc_quant_incr_limit0; ++ int rc_quant_incr_limit1; ++ int initial_fullness_offset; ++ int initial_xmit_delay; ++ int first_line_bpg_offset; ++ int second_line_bpg_offset; ++ int flatness_min_qp; ++ int flatness_max_qp; ++ int flatness_det_thresh; ++ qp_set qp_min; ++ qp_set qp_max; ++ qp_set ofs; ++ int rc_model_size; ++ int rc_edge_factor; ++ int rc_tgt_offset_hi; ++ int rc_tgt_offset_lo; ++ int rc_buf_thresh[QP_SET_SIZE - 1]; ++}; ++ ++enum colour_mode { ++ CM_RGB, /* 444 RGB */ ++ CM_444, /* 444 YUV or simple 422 */ ++ CM_422, /* native 422 */ ++ CM_420 /* native 420 */ ++}; ++ ++enum bits_per_comp { ++ BPC_8 = 8, ++ BPC_10 = 10, ++ BPC_12 = 12 ++}; ++ ++enum max_min { ++ DAL_MM_MIN = 0, ++ DAL_MM_MAX = 1 ++}; ++ ++struct qp_entry { ++ float bpp; ++ const qp_set qps; ++}; ++ ++typedef struct qp_entry qp_table[]; ++ ++u32 _do_bytes_per_pixel_calc(int slice_width, ++ u16 drm_bpp, ++ bool is_navite_422_or_420); ++ ++void _do_calc_rc_params(struct rc_params *rc, ++ enum colour_mode cm, ++ enum bits_per_comp bpc, ++ u16 drm_bpp, ++ bool is_navite_422_or_420, ++ int slice_width, ++ int slice_height, ++ int minor_version); ++ ++#endif +diff --git a/drivers/gpu/drm/amd/display/dc/dsc/Makefile b/drivers/gpu/drm/amd/display/dc/dsc/Makefile +index 8d31eb75c6a6e..a2537229ee88b 100644 +--- a/drivers/gpu/drm/amd/display/dc/dsc/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/dsc/Makefile +@@ -1,35 +1,6 @@ + # SPDX-License-Identifier: MIT + # + # Makefile for the 'dsc' sub-component of DAL. +- +-ifdef CONFIG_X86 +-dsc_ccflags := -mhard-float -msse +-endif +- +-ifdef CONFIG_PPC64 +-dsc_ccflags := -mhard-float -maltivec +-endif +- +-ifdef CONFIG_CC_IS_GCC +-ifeq ($(call cc-ifversion, -lt, 0701, y), y) +-IS_OLD_GCC = 1 +-endif +-endif +- +-ifdef CONFIG_X86 +-ifdef IS_OLD_GCC +-# Stack alignment mismatch, proceed with caution. +-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3 +-# (8B stack alignment). +-dsc_ccflags += -mpreferred-stack-boundary=4 +-else +-dsc_ccflags += -msse2 +-endif +-endif +- +-CFLAGS_$(AMDDALPATH)/dc/dsc/rc_calc.o := $(dsc_ccflags) +-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dsc/rc_calc.o := $(dsc_rcflags) +- + DSC = dc_dsc.o rc_calc.o rc_calc_dpi.o + + AMD_DAL_DSC = $(addprefix $(AMDDALPATH)/dc/dsc/,$(DSC)) +diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c +index 7b294f637881a..b19d3aeb5962c 100644 +--- a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c ++++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c +@@ -23,266 +23,7 @@ + * Authors: AMD + * + */ +-#include +- +-#include "os_types.h" + #include "rc_calc.h" +-#include "qp_tables.h" +- +-#define table_hash(mode, bpc, max_min) ((mode << 16) | (bpc << 8) | max_min) +- +-#define MODE_SELECT(val444, val422, val420) \ +- (cm == CM_444 || cm == CM_RGB) ? (val444) : (cm == CM_422 ? (val422) : (val420)) +- +- +-#define TABLE_CASE(mode, bpc, max) case (table_hash(mode, BPC_##bpc, max)): \ +- table = qp_table_##mode##_##bpc##bpc_##max; \ +- table_size = sizeof(qp_table_##mode##_##bpc##bpc_##max)/sizeof(*qp_table_##mode##_##bpc##bpc_##max); \ +- break +- +- +-static void get_qp_set(qp_set qps, enum colour_mode cm, enum bits_per_comp bpc, +- enum max_min max_min, float bpp) +-{ +- int mode = MODE_SELECT(444, 422, 420); +- int sel = table_hash(mode, bpc, max_min); +- int table_size = 0; +- int index; +- const struct qp_entry *table = 0L; +- +- // alias enum +- enum { min = DAL_MM_MIN, max = DAL_MM_MAX }; +- switch (sel) { +- TABLE_CASE(444, 8, max); +- TABLE_CASE(444, 8, min); +- TABLE_CASE(444, 10, max); +- TABLE_CASE(444, 10, min); +- TABLE_CASE(444, 12, max); +- TABLE_CASE(444, 12, min); +- TABLE_CASE(422, 8, max); +- TABLE_CASE(422, 8, min); +- TABLE_CASE(422, 10, max); +- TABLE_CASE(422, 10, min); +- TABLE_CASE(422, 12, max); +- TABLE_CASE(422, 12, min); +- TABLE_CASE(420, 8, max); +- TABLE_CASE(420, 8, min); +- TABLE_CASE(420, 10, max); +- TABLE_CASE(420, 10, min); +- TABLE_CASE(420, 12, max); +- TABLE_CASE(420, 12, min); +- } +- +- if (table == 0) +- return; +- +- index = (bpp - table[0].bpp) * 2; +- +- /* requested size is bigger than the table */ +- if (index >= table_size) { +- dm_error("ERROR: Requested rc_calc to find a bpp entry that exceeds the table size\n"); +- return; +- } +- +- memcpy(qps, table[index].qps, sizeof(qp_set)); +-} +- +-static double dsc_roundf(double num) +-{ +- if (num < 0.0) +- num = num - 0.5; +- else +- num = num + 0.5; +- +- return (int)(num); +-} +- +-static double dsc_ceil(double num) +-{ +- double retval = (int)num; +- +- if (retval != num && num > 0) +- retval = num + 1; +- +- return (int)retval; +-} +- +-static void get_ofs_set(qp_set ofs, enum colour_mode mode, float bpp) +-{ +- int *p = ofs; +- +- if (mode == CM_444 || mode == CM_RGB) { +- *p++ = (bpp <= 6) ? (0) : ((((bpp >= 8) && (bpp <= 12))) ? (2) : ((bpp >= 15) ? (10) : ((((bpp > 6) && (bpp < 8))) ? (0 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (2 + dsc_roundf((bpp - 12) * (8 / 3.0)))))); +- *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (8) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (8 / 3.0)))))); +- *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (6) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); +- *p++ = (bpp <= 6) ? (-4) : ((((bpp >= 8) && (bpp <= 12))) ? (-2) : ((bpp >= 15) ? (4) : ((((bpp > 6) && (bpp < 8))) ? (-4 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-2 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); +- *p++ = (bpp <= 6) ? (-6) : ((((bpp >= 8) && (bpp <= 12))) ? (-4) : ((bpp >= 15) ? (2) : ((((bpp > 6) && (bpp < 8))) ? (-6 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-4 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); +- *p++ = (bpp <= 12) ? (-6) : ((bpp >= 15) ? (0) : (-6 + dsc_roundf((bpp - 12) * (6 / 3.0)))); +- *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-2) : (-8 + dsc_roundf((bpp - 12) * (6 / 3.0)))); +- *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-4) : (-8 + dsc_roundf((bpp - 12) * (4 / 3.0)))); +- *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-6) : (-8 + dsc_roundf((bpp - 12) * (2 / 3.0)))); +- *p++ = (bpp <= 12) ? (-10) : ((bpp >= 15) ? (-8) : (-10 + dsc_roundf((bpp - 12) * (2 / 3.0)))); +- *p++ = -10; +- *p++ = (bpp <= 6) ? (-12) : ((bpp >= 8) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2 / 2.0)))); +- *p++ = -12; +- *p++ = -12; +- *p++ = -12; +- } else if (mode == CM_422) { +- *p++ = (bpp <= 8) ? (2) : ((bpp >= 10) ? (10) : (2 + dsc_roundf((bpp - 8) * (8 / 2.0)))); +- *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (8) : (0 + dsc_roundf((bpp - 8) * (8 / 2.0)))); +- *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (6) : (0 + dsc_roundf((bpp - 8) * (6 / 2.0)))); +- *p++ = (bpp <= 8) ? (-2) : ((bpp >= 10) ? (4) : (-2 + dsc_roundf((bpp - 8) * (6 / 2.0)))); +- *p++ = (bpp <= 8) ? (-4) : ((bpp >= 10) ? (2) : (-4 + dsc_roundf((bpp - 8) * (6 / 2.0)))); +- *p++ = (bpp <= 8) ? (-6) : ((bpp >= 10) ? (0) : (-6 + dsc_roundf((bpp - 8) * (6 / 2.0)))); +- *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-2) : (-8 + dsc_roundf((bpp - 8) * (6 / 2.0)))); +- *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-4) : (-8 + dsc_roundf((bpp - 8) * (4 / 2.0)))); +- *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-6) : (-8 + dsc_roundf((bpp - 8) * (2 / 2.0)))); +- *p++ = (bpp <= 8) ? (-10) : ((bpp >= 10) ? (-8) : (-10 + dsc_roundf((bpp - 8) * (2 / 2.0)))); +- *p++ = -10; +- *p++ = (bpp <= 6) ? (-12) : ((bpp >= 7) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2.0 / 1)))); +- *p++ = -12; +- *p++ = -12; +- *p++ = -12; +- } else { +- *p++ = (bpp <= 6) ? (2) : ((bpp >= 8) ? (10) : (2 + dsc_roundf((bpp - 6) * (8 / 2.0)))); +- *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (8) : (0 + dsc_roundf((bpp - 6) * (8 / 2.0)))); +- *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (6) : (0 + dsc_roundf((bpp - 6) * (6 / 2.0)))); +- *p++ = (bpp <= 6) ? (-2) : ((bpp >= 8) ? (4) : (-2 + dsc_roundf((bpp - 6) * (6 / 2.0)))); +- *p++ = (bpp <= 6) ? (-4) : ((bpp >= 8) ? (2) : (-4 + dsc_roundf((bpp - 6) * (6 / 2.0)))); +- *p++ = (bpp <= 6) ? (-6) : ((bpp >= 8) ? (0) : (-6 + dsc_roundf((bpp - 6) * (6 / 2.0)))); +- *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-2) : (-8 + dsc_roundf((bpp - 6) * (6 / 2.0)))); +- *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-4) : (-8 + dsc_roundf((bpp - 6) * (4 / 2.0)))); +- *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-6) : (-8 + dsc_roundf((bpp - 6) * (2 / 2.0)))); +- *p++ = (bpp <= 6) ? (-10) : ((bpp >= 8) ? (-8) : (-10 + dsc_roundf((bpp - 6) * (2 / 2.0)))); +- *p++ = -10; +- *p++ = (bpp <= 4) ? (-12) : ((bpp >= 5) ? (-10) : (-12 + dsc_roundf((bpp - 4) * (2 / 1.0)))); +- *p++ = -12; +- *p++ = -12; +- *p++ = -12; +- } +-} +- +-static int median3(int a, int b, int c) +-{ +- if (a > b) +- swap(a, b); +- if (b > c) +- swap(b, c); +- if (a > b) +- swap(b, c); +- +- return b; +-} +- +-static void _do_calc_rc_params(struct rc_params *rc, enum colour_mode cm, +- enum bits_per_comp bpc, u16 drm_bpp, +- bool is_navite_422_or_420, +- int slice_width, int slice_height, +- int minor_version) +-{ +- float bpp; +- float bpp_group; +- float initial_xmit_delay_factor; +- int padding_pixels; +- int i; +- +- bpp = ((float)drm_bpp / 16.0); +- /* in native_422 or native_420 modes, the bits_per_pixel is double the +- * target bpp (the latter is what calc_rc_params expects) +- */ +- if (is_navite_422_or_420) +- bpp /= 2.0; +- +- rc->rc_quant_incr_limit0 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); +- rc->rc_quant_incr_limit1 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); +- +- bpp_group = MODE_SELECT(bpp, bpp * 2.0, bpp * 2.0); +- +- switch (cm) { +- case CM_420: +- rc->initial_fullness_offset = (bpp >= 6) ? (2048) : ((bpp <= 4) ? (6144) : ((((bpp > 4) && (bpp <= 5))) ? (6144 - dsc_roundf((bpp - 4) * (512))) : (5632 - dsc_roundf((bpp - 5) * (3584))))); +- rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 3) - (3 * bpp_group))); +- rc->second_line_bpg_offset = median3(0, 12, (int)((3 * bpc * 3) - (3 * bpp_group))); +- break; +- case CM_422: +- rc->initial_fullness_offset = (bpp >= 8) ? (2048) : ((bpp <= 7) ? (5632) : (5632 - dsc_roundf((bpp - 7) * (3584)))); +- rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 4) - (3 * bpp_group))); +- rc->second_line_bpg_offset = 0; +- break; +- case CM_444: +- case CM_RGB: +- rc->initial_fullness_offset = (bpp >= 12) ? (2048) : ((bpp <= 8) ? (6144) : ((((bpp > 8) && (bpp <= 10))) ? (6144 - dsc_roundf((bpp - 8) * (512 / 2))) : (5632 - dsc_roundf((bpp - 10) * (3584 / 2))))); +- rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)(((3 * bpc + (cm == CM_444 ? 0 : 2)) * 3) - (3 * bpp_group))); +- rc->second_line_bpg_offset = 0; +- break; +- } +- +- initial_xmit_delay_factor = (cm == CM_444 || cm == CM_RGB) ? 1.0 : 2.0; +- rc->initial_xmit_delay = dsc_roundf(8192.0/2.0/bpp/initial_xmit_delay_factor); +- +- if (cm == CM_422 || cm == CM_420) +- slice_width /= 2; +- +- padding_pixels = ((slice_width % 3) != 0) ? (3 - (slice_width % 3)) * (rc->initial_xmit_delay / slice_width) : 0; +- if (3 * bpp_group >= (((rc->initial_xmit_delay + 2) / 3) * (3 + (cm == CM_422)))) { +- if ((rc->initial_xmit_delay + padding_pixels) % 3 == 1) +- rc->initial_xmit_delay++; +- } +- +- rc->flatness_min_qp = ((bpc == BPC_8) ? (3) : ((bpc == BPC_10) ? (7) : (11))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); +- rc->flatness_max_qp = ((bpc == BPC_8) ? (12) : ((bpc == BPC_10) ? (16) : (20))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); +- rc->flatness_det_thresh = 2 << (bpc - 8); +- +- get_qp_set(rc->qp_min, cm, bpc, DAL_MM_MIN, bpp); +- get_qp_set(rc->qp_max, cm, bpc, DAL_MM_MAX, bpp); +- if (cm == CM_444 && minor_version == 1) { +- for (i = 0; i < QP_SET_SIZE; ++i) { +- rc->qp_min[i] = rc->qp_min[i] > 0 ? rc->qp_min[i] - 1 : 0; +- rc->qp_max[i] = rc->qp_max[i] > 0 ? rc->qp_max[i] - 1 : 0; +- } +- } +- get_ofs_set(rc->ofs, cm, bpp); +- +- /* fixed parameters */ +- rc->rc_model_size = 8192; +- rc->rc_edge_factor = 6; +- rc->rc_tgt_offset_hi = 3; +- rc->rc_tgt_offset_lo = 3; +- +- rc->rc_buf_thresh[0] = 896; +- rc->rc_buf_thresh[1] = 1792; +- rc->rc_buf_thresh[2] = 2688; +- rc->rc_buf_thresh[3] = 3584; +- rc->rc_buf_thresh[4] = 4480; +- rc->rc_buf_thresh[5] = 5376; +- rc->rc_buf_thresh[6] = 6272; +- rc->rc_buf_thresh[7] = 6720; +- rc->rc_buf_thresh[8] = 7168; +- rc->rc_buf_thresh[9] = 7616; +- rc->rc_buf_thresh[10] = 7744; +- rc->rc_buf_thresh[11] = 7872; +- rc->rc_buf_thresh[12] = 8000; +- rc->rc_buf_thresh[13] = 8064; +-} +- +-static u32 _do_bytes_per_pixel_calc(int slice_width, u16 drm_bpp, +- bool is_navite_422_or_420) +-{ +- float bpp; +- u32 bytes_per_pixel; +- double d_bytes_per_pixel; +- +- bpp = ((float)drm_bpp / 16.0); +- d_bytes_per_pixel = dsc_ceil(bpp * slice_width / 8.0) / slice_width; +- // TODO: Make sure the formula for calculating this is precise (ceiling +- // vs. floor, and at what point they should be applied) +- if (is_navite_422_or_420) +- d_bytes_per_pixel /= 2; +- +- bytes_per_pixel = (u32)dsc_ceil(d_bytes_per_pixel * 0x10000000); +- +- return bytes_per_pixel; +-} + + /** + * calc_rc_params - reads the user's cmdline mode +diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h +index 262f06afcbf95..c2340e001b578 100644 +--- a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h ++++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h +@@ -27,55 +27,7 @@ + #ifndef __RC_CALC_H__ + #define __RC_CALC_H__ + +- +-#define QP_SET_SIZE 15 +- +-typedef int qp_set[QP_SET_SIZE]; +- +-struct rc_params { +- int rc_quant_incr_limit0; +- int rc_quant_incr_limit1; +- int initial_fullness_offset; +- int initial_xmit_delay; +- int first_line_bpg_offset; +- int second_line_bpg_offset; +- int flatness_min_qp; +- int flatness_max_qp; +- int flatness_det_thresh; +- qp_set qp_min; +- qp_set qp_max; +- qp_set ofs; +- int rc_model_size; +- int rc_edge_factor; +- int rc_tgt_offset_hi; +- int rc_tgt_offset_lo; +- int rc_buf_thresh[QP_SET_SIZE - 1]; +-}; +- +-enum colour_mode { +- CM_RGB, /* 444 RGB */ +- CM_444, /* 444 YUV or simple 422 */ +- CM_422, /* native 422 */ +- CM_420 /* native 420 */ +-}; +- +-enum bits_per_comp { +- BPC_8 = 8, +- BPC_10 = 10, +- BPC_12 = 12 +-}; +- +-enum max_min { +- DAL_MM_MIN = 0, +- DAL_MM_MAX = 1 +-}; +- +-struct qp_entry { +- float bpp; +- const qp_set qps; +-}; +- +-typedef struct qp_entry qp_table[]; ++#include "dml/dsc/rc_calc_fpu.h" + + void calc_rc_params(struct rc_params *rc, const struct drm_dsc_config *pps); + u32 calc_dsc_bytes_per_pixel(const struct drm_dsc_config *pps); +diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c +index ef830aded5b1c..1e19dd674e5a2 100644 +--- a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c ++++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c +@@ -22,7 +22,6 @@ + * Authors: AMD + * + */ +-#include "os_types.h" + #include + #include "dscc_types.h" + #include "rc_calc.h" +-- +2.34.1 + diff --git a/queue-5.15/drm-amd-display-update-watermark-values-for-dcn301.patch b/queue-5.15/drm-amd-display-update-watermark-values-for-dcn301.patch new file mode 100644 index 00000000000..d72d09ee62b --- /dev/null +++ b/queue-5.15/drm-amd-display-update-watermark-values-for-dcn301.patch @@ -0,0 +1,73 @@ +From 2963c89373196122728d7ae127f32cd2f6f3fe8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Jan 2022 17:51:53 -0500 +Subject: drm/amd/display: Update watermark values for DCN301 + +From: Agustin Gutierrez + +[ Upstream commit 2d8ae25d233767171942a9fba5fd8f4a620996be ] + +[Why] +There is underflow / visual corruption DCN301, for high +bandwidth MST DSC configurations such as 2x1440p144 or 2x4k60. + +[How] +Use up-to-date watermark values for DCN301. + +Reviewed-by: Zhan Liu +Signed-off-by: Agustin Gutierrez +Signed-off-by: Alex Deucher +Cc: stable@vger.kernel.org +Signed-off-by: Sasha Levin +--- + .../amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c +index 3eee32faa208c..329ce4e84b83c 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c +@@ -582,32 +582,32 @@ static struct wm_table lpddr5_wm_table = { + .wm_inst = WM_A, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, +- .sr_exit_time_us = 7.95, +- .sr_enter_plus_exit_time_us = 9, ++ .sr_exit_time_us = 13.5, ++ .sr_enter_plus_exit_time_us = 16.5, + .valid = true, + }, + { + .wm_inst = WM_B, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, +- .sr_exit_time_us = 9.82, +- .sr_enter_plus_exit_time_us = 11.196, ++ .sr_exit_time_us = 13.5, ++ .sr_enter_plus_exit_time_us = 16.5, + .valid = true, + }, + { + .wm_inst = WM_C, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, +- .sr_exit_time_us = 9.89, +- .sr_enter_plus_exit_time_us = 11.24, ++ .sr_exit_time_us = 13.5, ++ .sr_enter_plus_exit_time_us = 16.5, + .valid = true, + }, + { + .wm_inst = WM_D, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, +- .sr_exit_time_us = 9.748, +- .sr_enter_plus_exit_time_us = 11.102, ++ .sr_exit_time_us = 13.5, ++ .sr_enter_plus_exit_time_us = 16.5, + .valid = true, + }, + } +-- +2.34.1 + diff --git a/queue-5.15/drm-amd-display-use-adjusted-dcn301-watermarks.patch b/queue-5.15/drm-amd-display-use-adjusted-dcn301-watermarks.patch new file mode 100644 index 00000000000..d4ab54a3d42 --- /dev/null +++ b/queue-5.15/drm-amd-display-use-adjusted-dcn301-watermarks.patch @@ -0,0 +1,158 @@ +From 31557378affc12371a122565524ff1e538c6b55e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Sep 2021 22:09:01 -0400 +Subject: drm/amd/display: Use adjusted DCN301 watermarks + +From: Nikola Cornij + +[ Upstream commit 808643ea56a2f96a42873d5e11c399957d6493aa ] + +[why] +If DCN30 watermark calc is used for DCN301, the calculated values are +wrong due to the data structure mismatch between DCN30 and DCN301. +However, using the original DCN301 watermark values causes underflow. + +[how] +- Add DCN21-style watermark calculations +- Adjust DCN301 watermark values to remove the underflow + +Reviewed-by: Zhan Liu +Acked-by: Rodrigo Siqueira +Signed-off-by: Nikola Cornij +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../display/dc/clk_mgr/dcn301/vg_clk_mgr.c | 4 +- + .../amd/display/dc/dcn301/dcn301_resource.c | 96 ++++++++++++++++++- + 2 files changed, 97 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c +index 7046da14bb2a5..3eee32faa208c 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c +@@ -582,8 +582,8 @@ static struct wm_table lpddr5_wm_table = { + .wm_inst = WM_A, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, +- .sr_exit_time_us = 5.32, +- .sr_enter_plus_exit_time_us = 6.38, ++ .sr_exit_time_us = 7.95, ++ .sr_enter_plus_exit_time_us = 9, + .valid = true, + }, + { +diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +index 26ebe00a55f67..dea358b01791c 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +@@ -1622,12 +1622,106 @@ static void dcn301_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *b + dml_init_instance(&dc->dml, &dcn3_01_soc, &dcn3_01_ip, DML_PROJECT_DCN30); + } + ++static void calculate_wm_set_for_vlevel( ++ int vlevel, ++ struct wm_range_table_entry *table_entry, ++ struct dcn_watermarks *wm_set, ++ struct display_mode_lib *dml, ++ display_e2e_pipe_params_st *pipes, ++ int pipe_cnt) ++{ ++ double dram_clock_change_latency_cached = dml->soc.dram_clock_change_latency_us; ++ ++ ASSERT(vlevel < dml->soc.num_states); ++ /* only pipe 0 is read for voltage and dcf/soc clocks */ ++ pipes[0].clks_cfg.voltage = vlevel; ++ pipes[0].clks_cfg.dcfclk_mhz = dml->soc.clock_limits[vlevel].dcfclk_mhz; ++ pipes[0].clks_cfg.socclk_mhz = dml->soc.clock_limits[vlevel].socclk_mhz; ++ ++ dml->soc.dram_clock_change_latency_us = table_entry->pstate_latency_us; ++ dml->soc.sr_exit_time_us = table_entry->sr_exit_time_us; ++ dml->soc.sr_enter_plus_exit_time_us = table_entry->sr_enter_plus_exit_time_us; ++ ++ wm_set->urgent_ns = get_wm_urgent(dml, pipes, pipe_cnt) * 1000; ++ wm_set->cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(dml, pipes, pipe_cnt) * 1000; ++ wm_set->cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(dml, pipes, pipe_cnt) * 1000; ++ wm_set->cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(dml, pipes, pipe_cnt) * 1000; ++ wm_set->pte_meta_urgent_ns = get_wm_memory_trip(dml, pipes, pipe_cnt) * 1000; ++ wm_set->frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(dml, pipes, pipe_cnt) * 1000; ++ wm_set->frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(dml, pipes, pipe_cnt) * 1000; ++ wm_set->urgent_latency_ns = get_urgent_latency(dml, pipes, pipe_cnt) * 1000; ++ dml->soc.dram_clock_change_latency_us = dram_clock_change_latency_cached; ++ ++} ++ ++static void dcn301_calculate_wm_and_dlg( ++ struct dc *dc, struct dc_state *context, ++ display_e2e_pipe_params_st *pipes, ++ int pipe_cnt, ++ int vlevel_req) ++{ ++ int i, pipe_idx; ++ int vlevel, vlevel_max; ++ struct wm_range_table_entry *table_entry; ++ struct clk_bw_params *bw_params = dc->clk_mgr->bw_params; ++ ++ ASSERT(bw_params); ++ ++ vlevel_max = bw_params->clk_table.num_entries - 1; ++ ++ /* WM Set D */ ++ table_entry = &bw_params->wm_table.entries[WM_D]; ++ if (table_entry->wm_type == WM_TYPE_RETRAINING) ++ vlevel = 0; ++ else ++ vlevel = vlevel_max; ++ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.d, ++ &context->bw_ctx.dml, pipes, pipe_cnt); ++ /* WM Set C */ ++ table_entry = &bw_params->wm_table.entries[WM_C]; ++ vlevel = min(max(vlevel_req, 2), vlevel_max); ++ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.c, ++ &context->bw_ctx.dml, pipes, pipe_cnt); ++ /* WM Set B */ ++ table_entry = &bw_params->wm_table.entries[WM_B]; ++ vlevel = min(max(vlevel_req, 1), vlevel_max); ++ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.b, ++ &context->bw_ctx.dml, pipes, pipe_cnt); ++ ++ /* WM Set A */ ++ table_entry = &bw_params->wm_table.entries[WM_A]; ++ vlevel = min(vlevel_req, vlevel_max); ++ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.a, ++ &context->bw_ctx.dml, pipes, pipe_cnt); ++ ++ for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { ++ if (!context->res_ctx.pipe_ctx[i].stream) ++ continue; ++ ++ pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt); ++ pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); ++ ++ if (dc->config.forced_clocks) { ++ pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz; ++ pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; ++ } ++ if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000) ++ pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0; ++ if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) ++ pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0; ++ ++ pipe_idx++; ++ } ++ ++ dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); ++} ++ + static struct resource_funcs dcn301_res_pool_funcs = { + .destroy = dcn301_destroy_resource_pool, + .link_enc_create = dcn301_link_encoder_create, + .panel_cntl_create = dcn301_panel_cntl_create, + .validate_bandwidth = dcn30_validate_bandwidth, +- .calculate_wm_and_dlg = dcn30_calculate_wm_and_dlg, ++ .calculate_wm_and_dlg = dcn301_calculate_wm_and_dlg, + .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, + .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, + .acquire_idle_pipe_for_layer = dcn20_acquire_idle_pipe_for_layer, +-- +2.34.1 + diff --git a/queue-5.15/drm-amd-display-wrap-dcn301_calculate_wm_and_dlg-for.patch b/queue-5.15/drm-amd-display-wrap-dcn301_calculate_wm_and_dlg-for.patch new file mode 100644 index 00000000000..d27ae568d6b --- /dev/null +++ b/queue-5.15/drm-amd-display-wrap-dcn301_calculate_wm_and_dlg-for.patch @@ -0,0 +1,73 @@ +From 3d8f884b53616eb732e390e4caf21783958c5503 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Jan 2022 01:23:36 +0100 +Subject: drm/amd/display: Wrap dcn301_calculate_wm_and_dlg for FPU. + +From: Bas Nieuwenhuizen + +[ Upstream commit 25f1488bdbba63415239ff301fe61a8546140d9f ] + +Mirrors the logic for dcn30. Cue lots of WARNs and some +kernel panics without this fix. + +Cc: stable@vger.kernel.org +Signed-off-by: Bas Nieuwenhuizen +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/dcn301/dcn301_resource.c | 11 +++++++++++ + .../gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c | 2 +- + .../gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h | 2 +- + 3 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +index d17994bb318f7..34b01cc8f548b 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +@@ -1387,6 +1387,17 @@ static void set_wm_ranges( + pp_smu->nv_funcs.set_wm_ranges(&pp_smu->nv_funcs.pp_smu, &ranges); + } + ++static void dcn301_calculate_wm_and_dlg( ++ struct dc *dc, struct dc_state *context, ++ display_e2e_pipe_params_st *pipes, ++ int pipe_cnt, ++ int vlevel) ++{ ++ DC_FP_START(); ++ dcn301_calculate_wm_and_dlg_fp(dc, context, pipes, pipe_cnt, vlevel); ++ DC_FP_END(); ++} ++ + static struct resource_funcs dcn301_res_pool_funcs = { + .destroy = dcn301_destroy_resource_pool, + .link_enc_create = dcn301_link_encoder_create, +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c +index 94c32832a0e7b..0a7a338649731 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c +@@ -327,7 +327,7 @@ void dcn301_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info) + dcn3_01_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10; + } + +-void dcn301_calculate_wm_and_dlg(struct dc *dc, ++void dcn301_calculate_wm_and_dlg_fp(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h +index fc7065d178422..774b0fdfc80be 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h +@@ -34,7 +34,7 @@ void dcn301_fpu_set_wm_ranges(int i, + + void dcn301_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info); + +-void dcn301_calculate_wm_and_dlg(struct dc *dc, ++void dcn301_calculate_wm_and_dlg_fp(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, +-- +2.34.1 + diff --git a/queue-5.15/drm-amdgpu-display-only-set-vblank_disable_immediate.patch b/queue-5.15/drm-amdgpu-display-only-set-vblank_disable_immediate.patch new file mode 100644 index 00000000000..edf58caf403 --- /dev/null +++ b/queue-5.15/drm-amdgpu-display-only-set-vblank_disable_immediate.patch @@ -0,0 +1,66 @@ +From 457bc16c2cc5839102e056c5a98c957ff97ddea0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Nov 2021 09:32:33 -0500 +Subject: drm/amdgpu/display: Only set vblank_disable_immediate when PSR is not + enabled + +From: Nicholas Kazlauskas + +[ Upstream commit 70897848730470cc477d5d89e6222c0f6a9ac173 ] + +[Why] +PSR currently relies on the kernel's delayed vblank on/off mechanism +as an implicit bufferring mechanism to prevent excessive entry/exit. + +Without this delay the user experience is impacted since it can take +a few frames to enter/exit. + +[How] +Only allow vblank disable immediate for DC when psr is not supported. + +Leave a TODO indicating that this support should be extended in the +future to delay independent of the vblank interrupt. + +Fixes: 92020e81ddbeac ("drm/amdgpu/display: set vblank_disable_immediate for DC") + +Acked-by: Alex Deucher +Reviewed-by: Harry Wentland +Signed-off-by: Nicholas Kazlauskas +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 5ae9b8133d6da..76967adc51606 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -1279,9 +1279,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) + adev_to_drm(adev)->mode_config.cursor_width = adev->dm.dc->caps.max_cursor_size; + adev_to_drm(adev)->mode_config.cursor_height = adev->dm.dc->caps.max_cursor_size; + +- /* Disable vblank IRQs aggressively for power-saving */ +- adev_to_drm(adev)->vblank_disable_immediate = true; +- + if (drm_vblank_init(adev_to_drm(adev), adev->dm.display_indexes_num)) { + DRM_ERROR( + "amdgpu: failed to initialize sw for display support.\n"); +@@ -3866,6 +3863,14 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) + + } + ++ /* ++ * Disable vblank IRQs aggressively for power-saving. ++ * ++ * TODO: Fix vblank control helpers to delay PSR entry to allow this when PSR ++ * is also supported. ++ */ ++ adev_to_drm(adev)->vblank_disable_immediate = !psr_feature_enabled; ++ + /* Software is initialized. Now we can register interrupt handlers. */ + switch (adev->asic_type) { + #if defined(CONFIG_DRM_AMD_DC_SI) +-- +2.34.1 + diff --git a/queue-5.15/drm-amdgpu-filter-out-radeon-pci-device-ids.patch b/queue-5.15/drm-amdgpu-filter-out-radeon-pci-device-ids.patch new file mode 100644 index 00000000000..fe0c76ac12f --- /dev/null +++ b/queue-5.15/drm-amdgpu-filter-out-radeon-pci-device-ids.patch @@ -0,0 +1,692 @@ +From 3cc47c197755ac38101f0e1b38bf5f2adc31600e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Aug 2021 17:17:10 -0400 +Subject: drm/amdgpu: filter out radeon PCI device IDs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit bdbeb0dde4258586bb2f481b12da1e83aa4766f3 ] + +Once we claim all 0x1002 PCI display class devices, we will +need to filter out devices owned by radeon. + +v2: rename radeon id array to make it more clear that +the devices are not supported by amdgpu. + add r128, mach64 pci ids as well + +Acked-by: Christian König (v1) +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 638 +++++++++++++++++++++++- + 1 file changed, 637 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index a8465e3195a67..82bb3e80219cd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -891,6 +891,636 @@ MODULE_PARM_DESC(smu_pptable_id, + "specify pptable id to be used (-1 = auto(default) value, 0 = use pptable from vbios, > 0 = soft pptable id)"); + module_param_named(smu_pptable_id, amdgpu_smu_pptable_id, int, 0444); + ++/* These devices are not supported by amdgpu. ++ * They are supported by the mach64, r128, radeon drivers ++ */ ++static const u16 amdgpu_unsupported_pciidlist[] = { ++ /* mach64 */ ++ 0x4354, ++ 0x4358, ++ 0x4554, ++ 0x4742, ++ 0x4744, ++ 0x4749, ++ 0x474C, ++ 0x474D, ++ 0x474E, ++ 0x474F, ++ 0x4750, ++ 0x4751, ++ 0x4752, ++ 0x4753, ++ 0x4754, ++ 0x4755, ++ 0x4756, ++ 0x4757, ++ 0x4758, ++ 0x4759, ++ 0x475A, ++ 0x4C42, ++ 0x4C44, ++ 0x4C47, ++ 0x4C49, ++ 0x4C4D, ++ 0x4C4E, ++ 0x4C50, ++ 0x4C51, ++ 0x4C52, ++ 0x4C53, ++ 0x5654, ++ 0x5655, ++ 0x5656, ++ /* r128 */ ++ 0x4c45, ++ 0x4c46, ++ 0x4d46, ++ 0x4d4c, ++ 0x5041, ++ 0x5042, ++ 0x5043, ++ 0x5044, ++ 0x5045, ++ 0x5046, ++ 0x5047, ++ 0x5048, ++ 0x5049, ++ 0x504A, ++ 0x504B, ++ 0x504C, ++ 0x504D, ++ 0x504E, ++ 0x504F, ++ 0x5050, ++ 0x5051, ++ 0x5052, ++ 0x5053, ++ 0x5054, ++ 0x5055, ++ 0x5056, ++ 0x5057, ++ 0x5058, ++ 0x5245, ++ 0x5246, ++ 0x5247, ++ 0x524b, ++ 0x524c, ++ 0x534d, ++ 0x5446, ++ 0x544C, ++ 0x5452, ++ /* radeon */ ++ 0x3150, ++ 0x3151, ++ 0x3152, ++ 0x3154, ++ 0x3155, ++ 0x3E50, ++ 0x3E54, ++ 0x4136, ++ 0x4137, ++ 0x4144, ++ 0x4145, ++ 0x4146, ++ 0x4147, ++ 0x4148, ++ 0x4149, ++ 0x414A, ++ 0x414B, ++ 0x4150, ++ 0x4151, ++ 0x4152, ++ 0x4153, ++ 0x4154, ++ 0x4155, ++ 0x4156, ++ 0x4237, ++ 0x4242, ++ 0x4336, ++ 0x4337, ++ 0x4437, ++ 0x4966, ++ 0x4967, ++ 0x4A48, ++ 0x4A49, ++ 0x4A4A, ++ 0x4A4B, ++ 0x4A4C, ++ 0x4A4D, ++ 0x4A4E, ++ 0x4A4F, ++ 0x4A50, ++ 0x4A54, ++ 0x4B48, ++ 0x4B49, ++ 0x4B4A, ++ 0x4B4B, ++ 0x4B4C, ++ 0x4C57, ++ 0x4C58, ++ 0x4C59, ++ 0x4C5A, ++ 0x4C64, ++ 0x4C66, ++ 0x4C67, ++ 0x4E44, ++ 0x4E45, ++ 0x4E46, ++ 0x4E47, ++ 0x4E48, ++ 0x4E49, ++ 0x4E4A, ++ 0x4E4B, ++ 0x4E50, ++ 0x4E51, ++ 0x4E52, ++ 0x4E53, ++ 0x4E54, ++ 0x4E56, ++ 0x5144, ++ 0x5145, ++ 0x5146, ++ 0x5147, ++ 0x5148, ++ 0x514C, ++ 0x514D, ++ 0x5157, ++ 0x5158, ++ 0x5159, ++ 0x515A, ++ 0x515E, ++ 0x5460, ++ 0x5462, ++ 0x5464, ++ 0x5548, ++ 0x5549, ++ 0x554A, ++ 0x554B, ++ 0x554C, ++ 0x554D, ++ 0x554E, ++ 0x554F, ++ 0x5550, ++ 0x5551, ++ 0x5552, ++ 0x5554, ++ 0x564A, ++ 0x564B, ++ 0x564F, ++ 0x5652, ++ 0x5653, ++ 0x5657, ++ 0x5834, ++ 0x5835, ++ 0x5954, ++ 0x5955, ++ 0x5974, ++ 0x5975, ++ 0x5960, ++ 0x5961, ++ 0x5962, ++ 0x5964, ++ 0x5965, ++ 0x5969, ++ 0x5a41, ++ 0x5a42, ++ 0x5a61, ++ 0x5a62, ++ 0x5b60, ++ 0x5b62, ++ 0x5b63, ++ 0x5b64, ++ 0x5b65, ++ 0x5c61, ++ 0x5c63, ++ 0x5d48, ++ 0x5d49, ++ 0x5d4a, ++ 0x5d4c, ++ 0x5d4d, ++ 0x5d4e, ++ 0x5d4f, ++ 0x5d50, ++ 0x5d52, ++ 0x5d57, ++ 0x5e48, ++ 0x5e4a, ++ 0x5e4b, ++ 0x5e4c, ++ 0x5e4d, ++ 0x5e4f, ++ 0x6700, ++ 0x6701, ++ 0x6702, ++ 0x6703, ++ 0x6704, ++ 0x6705, ++ 0x6706, ++ 0x6707, ++ 0x6708, ++ 0x6709, ++ 0x6718, ++ 0x6719, ++ 0x671c, ++ 0x671d, ++ 0x671f, ++ 0x6720, ++ 0x6721, ++ 0x6722, ++ 0x6723, ++ 0x6724, ++ 0x6725, ++ 0x6726, ++ 0x6727, ++ 0x6728, ++ 0x6729, ++ 0x6738, ++ 0x6739, ++ 0x673e, ++ 0x6740, ++ 0x6741, ++ 0x6742, ++ 0x6743, ++ 0x6744, ++ 0x6745, ++ 0x6746, ++ 0x6747, ++ 0x6748, ++ 0x6749, ++ 0x674A, ++ 0x6750, ++ 0x6751, ++ 0x6758, ++ 0x6759, ++ 0x675B, ++ 0x675D, ++ 0x675F, ++ 0x6760, ++ 0x6761, ++ 0x6762, ++ 0x6763, ++ 0x6764, ++ 0x6765, ++ 0x6766, ++ 0x6767, ++ 0x6768, ++ 0x6770, ++ 0x6771, ++ 0x6772, ++ 0x6778, ++ 0x6779, ++ 0x677B, ++ 0x6840, ++ 0x6841, ++ 0x6842, ++ 0x6843, ++ 0x6849, ++ 0x684C, ++ 0x6850, ++ 0x6858, ++ 0x6859, ++ 0x6880, ++ 0x6888, ++ 0x6889, ++ 0x688A, ++ 0x688C, ++ 0x688D, ++ 0x6898, ++ 0x6899, ++ 0x689b, ++ 0x689c, ++ 0x689d, ++ 0x689e, ++ 0x68a0, ++ 0x68a1, ++ 0x68a8, ++ 0x68a9, ++ 0x68b0, ++ 0x68b8, ++ 0x68b9, ++ 0x68ba, ++ 0x68be, ++ 0x68bf, ++ 0x68c0, ++ 0x68c1, ++ 0x68c7, ++ 0x68c8, ++ 0x68c9, ++ 0x68d8, ++ 0x68d9, ++ 0x68da, ++ 0x68de, ++ 0x68e0, ++ 0x68e1, ++ 0x68e4, ++ 0x68e5, ++ 0x68e8, ++ 0x68e9, ++ 0x68f1, ++ 0x68f2, ++ 0x68f8, ++ 0x68f9, ++ 0x68fa, ++ 0x68fe, ++ 0x7100, ++ 0x7101, ++ 0x7102, ++ 0x7103, ++ 0x7104, ++ 0x7105, ++ 0x7106, ++ 0x7108, ++ 0x7109, ++ 0x710A, ++ 0x710B, ++ 0x710C, ++ 0x710E, ++ 0x710F, ++ 0x7140, ++ 0x7141, ++ 0x7142, ++ 0x7143, ++ 0x7144, ++ 0x7145, ++ 0x7146, ++ 0x7147, ++ 0x7149, ++ 0x714A, ++ 0x714B, ++ 0x714C, ++ 0x714D, ++ 0x714E, ++ 0x714F, ++ 0x7151, ++ 0x7152, ++ 0x7153, ++ 0x715E, ++ 0x715F, ++ 0x7180, ++ 0x7181, ++ 0x7183, ++ 0x7186, ++ 0x7187, ++ 0x7188, ++ 0x718A, ++ 0x718B, ++ 0x718C, ++ 0x718D, ++ 0x718F, ++ 0x7193, ++ 0x7196, ++ 0x719B, ++ 0x719F, ++ 0x71C0, ++ 0x71C1, ++ 0x71C2, ++ 0x71C3, ++ 0x71C4, ++ 0x71C5, ++ 0x71C6, ++ 0x71C7, ++ 0x71CD, ++ 0x71CE, ++ 0x71D2, ++ 0x71D4, ++ 0x71D5, ++ 0x71D6, ++ 0x71DA, ++ 0x71DE, ++ 0x7200, ++ 0x7210, ++ 0x7211, ++ 0x7240, ++ 0x7243, ++ 0x7244, ++ 0x7245, ++ 0x7246, ++ 0x7247, ++ 0x7248, ++ 0x7249, ++ 0x724A, ++ 0x724B, ++ 0x724C, ++ 0x724D, ++ 0x724E, ++ 0x724F, ++ 0x7280, ++ 0x7281, ++ 0x7283, ++ 0x7284, ++ 0x7287, ++ 0x7288, ++ 0x7289, ++ 0x728B, ++ 0x728C, ++ 0x7290, ++ 0x7291, ++ 0x7293, ++ 0x7297, ++ 0x7834, ++ 0x7835, ++ 0x791e, ++ 0x791f, ++ 0x793f, ++ 0x7941, ++ 0x7942, ++ 0x796c, ++ 0x796d, ++ 0x796e, ++ 0x796f, ++ 0x9400, ++ 0x9401, ++ 0x9402, ++ 0x9403, ++ 0x9405, ++ 0x940A, ++ 0x940B, ++ 0x940F, ++ 0x94A0, ++ 0x94A1, ++ 0x94A3, ++ 0x94B1, ++ 0x94B3, ++ 0x94B4, ++ 0x94B5, ++ 0x94B9, ++ 0x9440, ++ 0x9441, ++ 0x9442, ++ 0x9443, ++ 0x9444, ++ 0x9446, ++ 0x944A, ++ 0x944B, ++ 0x944C, ++ 0x944E, ++ 0x9450, ++ 0x9452, ++ 0x9456, ++ 0x945A, ++ 0x945B, ++ 0x945E, ++ 0x9460, ++ 0x9462, ++ 0x946A, ++ 0x946B, ++ 0x947A, ++ 0x947B, ++ 0x9480, ++ 0x9487, ++ 0x9488, ++ 0x9489, ++ 0x948A, ++ 0x948F, ++ 0x9490, ++ 0x9491, ++ 0x9495, ++ 0x9498, ++ 0x949C, ++ 0x949E, ++ 0x949F, ++ 0x94C0, ++ 0x94C1, ++ 0x94C3, ++ 0x94C4, ++ 0x94C5, ++ 0x94C6, ++ 0x94C7, ++ 0x94C8, ++ 0x94C9, ++ 0x94CB, ++ 0x94CC, ++ 0x94CD, ++ 0x9500, ++ 0x9501, ++ 0x9504, ++ 0x9505, ++ 0x9506, ++ 0x9507, ++ 0x9508, ++ 0x9509, ++ 0x950F, ++ 0x9511, ++ 0x9515, ++ 0x9517, ++ 0x9519, ++ 0x9540, ++ 0x9541, ++ 0x9542, ++ 0x954E, ++ 0x954F, ++ 0x9552, ++ 0x9553, ++ 0x9555, ++ 0x9557, ++ 0x955f, ++ 0x9580, ++ 0x9581, ++ 0x9583, ++ 0x9586, ++ 0x9587, ++ 0x9588, ++ 0x9589, ++ 0x958A, ++ 0x958B, ++ 0x958C, ++ 0x958D, ++ 0x958E, ++ 0x958F, ++ 0x9590, ++ 0x9591, ++ 0x9593, ++ 0x9595, ++ 0x9596, ++ 0x9597, ++ 0x9598, ++ 0x9599, ++ 0x959B, ++ 0x95C0, ++ 0x95C2, ++ 0x95C4, ++ 0x95C5, ++ 0x95C6, ++ 0x95C7, ++ 0x95C9, ++ 0x95CC, ++ 0x95CD, ++ 0x95CE, ++ 0x95CF, ++ 0x9610, ++ 0x9611, ++ 0x9612, ++ 0x9613, ++ 0x9614, ++ 0x9615, ++ 0x9616, ++ 0x9640, ++ 0x9641, ++ 0x9642, ++ 0x9643, ++ 0x9644, ++ 0x9645, ++ 0x9647, ++ 0x9648, ++ 0x9649, ++ 0x964a, ++ 0x964b, ++ 0x964c, ++ 0x964e, ++ 0x964f, ++ 0x9710, ++ 0x9711, ++ 0x9712, ++ 0x9713, ++ 0x9714, ++ 0x9715, ++ 0x9802, ++ 0x9803, ++ 0x9804, ++ 0x9805, ++ 0x9806, ++ 0x9807, ++ 0x9808, ++ 0x9809, ++ 0x980A, ++ 0x9900, ++ 0x9901, ++ 0x9903, ++ 0x9904, ++ 0x9905, ++ 0x9906, ++ 0x9907, ++ 0x9908, ++ 0x9909, ++ 0x990A, ++ 0x990B, ++ 0x990C, ++ 0x990D, ++ 0x990E, ++ 0x990F, ++ 0x9910, ++ 0x9913, ++ 0x9917, ++ 0x9918, ++ 0x9919, ++ 0x9990, ++ 0x9991, ++ 0x9992, ++ 0x9993, ++ 0x9994, ++ 0x9995, ++ 0x9996, ++ 0x9997, ++ 0x9998, ++ 0x9999, ++ 0x999A, ++ 0x999B, ++ 0x999C, ++ 0x999D, ++ 0x99A0, ++ 0x99A2, ++ 0x99A4, ++}; ++ + static const struct pci_device_id pciidlist[] = { + #ifdef CONFIG_DRM_AMDGPU_SI + {0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI}, +@@ -1273,7 +1903,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, + struct drm_device *ddev; + struct amdgpu_device *adev; + unsigned long flags = ent->driver_data; +- int ret, retry = 0; ++ int ret, retry = 0, i; + bool supports_atomic = false; + bool is_fw_fb; + resource_size_t base, size; +@@ -1281,6 +1911,12 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, + if (amdgpu_aspm == -1 && !pcie_aspm_enabled(pdev)) + amdgpu_aspm = 0; + ++ /* skip devices which are owned by radeon */ ++ for (i = 0; i < ARRAY_SIZE(amdgpu_unsupported_pciidlist); i++) { ++ if (amdgpu_unsupported_pciidlist[i] == pdev->device) ++ return -ENODEV; ++ } ++ + if (amdgpu_virtual_display || + amdgpu_device_asic_has_dc_support(flags & AMD_ASIC_MASK)) + supports_atomic = true; +-- +2.34.1 + diff --git a/queue-5.15/drm-amdgpu-filter-out-radeon-secondary-ids-as-well.patch b/queue-5.15/drm-amdgpu-filter-out-radeon-secondary-ids-as-well.patch new file mode 100644 index 00000000000..e967428adfb --- /dev/null +++ b/queue-5.15/drm-amdgpu-filter-out-radeon-secondary-ids-as-well.patch @@ -0,0 +1,122 @@ +From 09a0a406a4aad431624510f2d0f6403385e6d157 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Jan 2022 12:17:07 -0500 +Subject: drm/amdgpu: filter out radeon secondary ids as well +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit 9e5a14bce2402e84251a10269df0235cd7ce9234 ] + +Older radeon boards (r2xx-r5xx) had secondary PCI functions +which we solely there for supporting multi-head on OSs with +special requirements. Add them to the unsupported list +as well so we don't attempt to bind to them. The driver +would fail to bind to them anyway, but this does so +in a cleaner way that should not confuse the user. + +Cc: stable@vger.kernel.org +Acked-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 81 +++++++++++++++++++++++++ + 1 file changed, 81 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index 82bb3e80219cd..5a7fef324c820 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -1519,6 +1519,87 @@ static const u16 amdgpu_unsupported_pciidlist[] = { + 0x99A0, + 0x99A2, + 0x99A4, ++ /* radeon secondary ids */ ++ 0x3171, ++ 0x3e70, ++ 0x4164, ++ 0x4165, ++ 0x4166, ++ 0x4168, ++ 0x4170, ++ 0x4171, ++ 0x4172, ++ 0x4173, ++ 0x496e, ++ 0x4a69, ++ 0x4a6a, ++ 0x4a6b, ++ 0x4a70, ++ 0x4a74, ++ 0x4b69, ++ 0x4b6b, ++ 0x4b6c, ++ 0x4c6e, ++ 0x4e64, ++ 0x4e65, ++ 0x4e66, ++ 0x4e67, ++ 0x4e68, ++ 0x4e69, ++ 0x4e6a, ++ 0x4e71, ++ 0x4f73, ++ 0x5569, ++ 0x556b, ++ 0x556d, ++ 0x556f, ++ 0x5571, ++ 0x5854, ++ 0x5874, ++ 0x5940, ++ 0x5941, ++ 0x5b72, ++ 0x5b73, ++ 0x5b74, ++ 0x5b75, ++ 0x5d44, ++ 0x5d45, ++ 0x5d6d, ++ 0x5d6f, ++ 0x5d72, ++ 0x5d77, ++ 0x5e6b, ++ 0x5e6d, ++ 0x7120, ++ 0x7124, ++ 0x7129, ++ 0x712e, ++ 0x712f, ++ 0x7162, ++ 0x7163, ++ 0x7166, ++ 0x7167, ++ 0x7172, ++ 0x7173, ++ 0x71a0, ++ 0x71a1, ++ 0x71a3, ++ 0x71a7, ++ 0x71bb, ++ 0x71e0, ++ 0x71e1, ++ 0x71e2, ++ 0x71e6, ++ 0x71e7, ++ 0x71f2, ++ 0x7269, ++ 0x726b, ++ 0x726e, ++ 0x72a0, ++ 0x72a8, ++ 0x72b1, ++ 0x72b3, ++ 0x793f, + }; + + static const struct pci_device_id pciidlist[] = { +-- +2.34.1 + diff --git a/queue-5.15/drm-amdgpu-use-spin_lock_irqsave-to-avoid-deadlock-b.patch b/queue-5.15/drm-amdgpu-use-spin_lock_irqsave-to-avoid-deadlock-b.patch new file mode 100644 index 00000000000..c1abb334e71 --- /dev/null +++ b/queue-5.15/drm-amdgpu-use-spin_lock_irqsave-to-avoid-deadlock-b.patch @@ -0,0 +1,59 @@ +From 1078a53ddb07788f4791140faa1b7371c58ef3f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Jan 2022 16:31:20 +0800 +Subject: drm/amdgpu: use spin_lock_irqsave to avoid deadlock by local + interrupt + +From: Guchun Chen + +[ Upstream commit 2096b74b1da5ca418827b54ac4904493bd9de89c ] + +This is observed in SRIOV case with virtual KMS as display. + +_raw_spin_lock_irqsave+0x37/0x40 +drm_handle_vblank+0x69/0x350 [drm] +? try_to_wake_up+0x432/0x5c0 +? amdgpu_vkms_prepare_fb+0x1c0/0x1c0 [amdgpu] +drm_crtc_handle_vblank+0x17/0x20 [drm] +amdgpu_vkms_vblank_simulate+0x4d/0x80 [amdgpu] +__hrtimer_run_queues+0xfb/0x230 +hrtimer_interrupt+0x109/0x220 +__sysvec_apic_timer_interrupt+0x64/0xe0 +asm_call_irq_on_stack+0x12/0x20 + +Fixes: 84ec374bd580 ("drm/amdgpu: create amdgpu_vkms (v4)") +Signed-off-by: Guchun Chen +Acked-by: Alex Deucher +Tested-by: Kelly Zytaruk +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +index ac9a8cd21c4b6..7d58bf410be05 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +@@ -142,15 +142,16 @@ static void amdgpu_vkms_crtc_atomic_disable(struct drm_crtc *crtc, + static void amdgpu_vkms_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *state) + { ++ unsigned long flags; + if (crtc->state->event) { +- spin_lock(&crtc->dev->event_lock); ++ spin_lock_irqsave(&crtc->dev->event_lock, flags); + + if (drm_crtc_vblank_get(crtc) != 0) + drm_crtc_send_vblank_event(crtc, crtc->state->event); + else + drm_crtc_arm_vblank_event(crtc, crtc->state->event); + +- spin_unlock(&crtc->dev->event_lock); ++ spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + + crtc->state->event = NULL; + } +-- +2.34.1 + diff --git a/queue-5.15/drm-amdkfd-check-for-null-pointer-after-calling-kmem.patch b/queue-5.15/drm-amdkfd-check-for-null-pointer-after-calling-kmem.patch new file mode 100644 index 00000000000..a69b48d9ce7 --- /dev/null +++ b/queue-5.15/drm-amdkfd-check-for-null-pointer-after-calling-kmem.patch @@ -0,0 +1,41 @@ +From f6be691e2820235a10cb309a022d963871b53215 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Jan 2022 17:09:43 +0800 +Subject: drm/amdkfd: Check for null pointer after calling kmemdup + +From: Jiasheng Jiang + +[ Upstream commit abfaf0eee97925905e742aa3b0b72e04a918fa9e ] + +As the possible failure of the allocation, kmemdup() may return NULL +pointer. +Therefore, it should be better to check the 'props2' in order to prevent +the dereference of NULL pointer. + +Fixes: 3a87177eb141 ("drm/amdkfd: Add topology support for dGPUs") +Signed-off-by: Jiasheng Jiang +Reviewed-by: Felix Kuehling +Signed-off-by: Felix Kuehling +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +index cfedfb1e8596c..c33d689f29e8e 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +@@ -1060,6 +1060,9 @@ static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink, + return -ENODEV; + /* same everything but the other direction */ + props2 = kmemdup(props, sizeof(*props2), GFP_KERNEL); ++ if (!props2) ++ return -ENOMEM; ++ + props2->node_from = id_to; + props2->node_to = id_from; + props2->kobj = NULL; +-- +2.34.1 + diff --git a/queue-5.15/drm-atomic-check-new_crtc_state-active-to-determine-.patch b/queue-5.15/drm-atomic-check-new_crtc_state-active-to-determine-.patch new file mode 100644 index 00000000000..a607ec14e99 --- /dev/null +++ b/queue-5.15/drm-atomic-check-new_crtc_state-active-to-determine-.patch @@ -0,0 +1,58 @@ +From 419f0f15ebedba23c94188b6b7e75c4e93b26f14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Dec 2021 12:06:26 +0800 +Subject: drm/atomic: Check new_crtc_state->active to determine if CRTC needs + disable in self refresh mode + +From: Liu Ying + +[ Upstream commit 69e630016ef4e4a1745310c446f204dc6243e907 ] + +Actual hardware state of CRTC is controlled by the member 'active' in +struct drm_crtc_state instead of the member 'enable', according to the +kernel doc of the member 'enable'. In fact, the drm client modeset +and atomic helpers are using the member 'active' to do the control. + +Referencing the member 'enable' of new_crtc_state, the function +crtc_needs_disable() may fail to reflect if CRTC needs disable in +self refresh mode, e.g., when the framebuffer emulation will be blanked +through the client modeset helper with the next commit, the member +'enable' of new_crtc_state is still true while the member 'active' is +false, hence the relevant potential encoder and bridges won't be disabled. + +So, let's check new_crtc_state->active to determine if CRTC needs disable +in self refresh mode instead of new_crtc_state->enable. + +Fixes: 1452c25b0e60 ("drm: Add helpers to kick off self refresh mode in drivers") +Cc: Sean Paul +Cc: Rob Clark +Cc: Maarten Lankhorst +Cc: Maxime Ripard +Cc: Thomas Zimmermann +Cc: David Airlie +Cc: Daniel Vetter +Reviewed-by: Alex Deucher +Signed-off-by: Liu Ying +Signed-off-by: Alex Deucher +Link: https://patchwork.freedesktop.org/patch/msgid/20211230040626.646807-1-victor.liu@nxp.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_atomic_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index 2c0c6ec928200..ff2bc9a118011 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -1001,7 +1001,7 @@ crtc_needs_disable(struct drm_crtc_state *old_state, + * it's in self refresh mode and needs to be fully disabled. + */ + return old_state->active || +- (old_state->self_refresh_active && !new_state->enable) || ++ (old_state->self_refresh_active && !new_state->active) || + new_state->self_refresh_active; + } + +-- +2.34.1 + diff --git a/queue-5.15/drm-i915-disable-drrs-on-ivb-hsw-port-a.patch b/queue-5.15/drm-i915-disable-drrs-on-ivb-hsw-port-a.patch new file mode 100644 index 00000000000..d8632997650 --- /dev/null +++ b/queue-5.15/drm-i915-disable-drrs-on-ivb-hsw-port-a.patch @@ -0,0 +1,64 @@ +From 3f197b5b7dbef6c9fe4d1a1be2f817da2d346c7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Jan 2022 12:37:50 +0200 +Subject: drm/i915: Disable DRRS on IVB/HSW port != A +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit ee59792c97176f12c1da31f29fc4c2aab187f06e ] + +Currently we allow DRRS on IVB PCH ports, but we're missing a +few programming steps meaning it is guaranteed to not work. +And on HSW DRRS is not supported on anything but port A ever +as only transcoder EDP has the M2/N2 registers (though I'm +not sure if HSW ever has eDP on any other port). + +Starting from BDW all transcoders have the dynamically +reprogrammable M/N registers so DRRS could work on any +port. + +Stop initializing DRRS on ports where it cannot possibly work. + +Cc: stable@vger.kernel.org +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20220128103757.22461-11-ville.syrjala@linux.intel.com +Reviewed-by: Jani Nikula +(cherry picked from commit f0d4ce59f4d48622044933054a0e0cefa91ba15e) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/intel_drrs.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c +index be9b6d4482f04..3c7d6bf579484 100644 +--- a/drivers/gpu/drm/i915/display/intel_drrs.c ++++ b/drivers/gpu/drm/i915/display/intel_drrs.c +@@ -445,6 +445,7 @@ intel_dp_drrs_init(struct intel_connector *connector, + struct drm_display_mode *fixed_mode) + { + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct intel_encoder *encoder = connector->encoder; + struct drm_display_mode *downclock_mode = NULL; + + INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work); +@@ -456,6 +457,13 @@ intel_dp_drrs_init(struct intel_connector *connector, + return NULL; + } + ++ if ((DISPLAY_VER(dev_priv) < 8 && !HAS_GMCH(dev_priv)) && ++ encoder->port != PORT_A) { ++ drm_dbg_kms(&dev_priv->drm, ++ "DRRS only supported on eDP port A\n"); ++ return NULL; ++ } ++ + if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) { + drm_dbg_kms(&dev_priv->drm, "VBT doesn't support DRRS\n"); + return NULL; +-- +2.34.1 + diff --git a/queue-5.15/drm-i915-display-move-drrs-code-its-own-file.patch b/queue-5.15/drm-i915-display-move-drrs-code-its-own-file.patch new file mode 100644 index 00000000000..13fc669cc89 --- /dev/null +++ b/queue-5.15/drm-i915-display-move-drrs-code-its-own-file.patch @@ -0,0 +1,1158 @@ +From 466336274bae07f6eace5ba05208328057bf9541 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Aug 2021 10:42:52 -0700 +Subject: drm/i915/display: Move DRRS code its own file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: José Roberto de Souza + +[ Upstream commit a1b63119ee839c8ff622407aab25c9723943638a ] + +intel_dp.c is a 5k lines monster, so moving DRRS out of it to reduce +some lines from it. + +Reviewed-by: Rodrigo Vivi +Cc: Jani Nikula +Cc: Rodrigo Vivi +Signed-off-by: José Roberto de Souza +Link: https://patchwork.freedesktop.org/patch/msgid/20210827174253.51122-2-jose.souza@intel.com +Signed-off-by: Sasha Levin +--- + Documentation/gpu/i915.rst | 14 +- + drivers/gpu/drm/i915/Makefile | 1 + + drivers/gpu/drm/i915/display/intel_ddi.c | 1 + + .../drm/i915/display/intel_display_debugfs.c | 1 + + drivers/gpu/drm/i915/display/intel_dp.c | 467 +---------------- + drivers/gpu/drm/i915/display/intel_dp.h | 11 - + drivers/gpu/drm/i915/display/intel_drrs.c | 477 ++++++++++++++++++ + drivers/gpu/drm/i915/display/intel_drrs.h | 32 ++ + .../gpu/drm/i915/display/intel_frontbuffer.c | 1 + + 9 files changed, 521 insertions(+), 484 deletions(-) + create mode 100644 drivers/gpu/drm/i915/display/intel_drrs.c + create mode 100644 drivers/gpu/drm/i915/display/intel_drrs.h + +diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst +index 204ebdaadb45a..03021dfa0dd81 100644 +--- a/Documentation/gpu/i915.rst ++++ b/Documentation/gpu/i915.rst +@@ -183,25 +183,25 @@ Frame Buffer Compression (FBC) + Display Refresh Rate Switching (DRRS) + ------------------------------------- + +-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c ++.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c + :doc: Display Refresh Rate Switching (DRRS) + +-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c ++.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c + :functions: intel_dp_set_drrs_state + +-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c ++.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c + :functions: intel_edp_drrs_enable + +-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c ++.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c + :functions: intel_edp_drrs_disable + +-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c ++.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c + :functions: intel_edp_drrs_invalidate + +-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c ++.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c + :functions: intel_edp_drrs_flush + +-.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp.c ++.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c + :functions: intel_dp_drrs_init + + DPIO +diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile +index a4154fe14f8c0..26cf754229451 100644 +--- a/drivers/gpu/drm/i915/Makefile ++++ b/drivers/gpu/drm/i915/Makefile +@@ -212,6 +212,7 @@ i915-y += \ + display/intel_dpll.o \ + display/intel_dpll_mgr.o \ + display/intel_dpt.o \ ++ display/intel_drrs.o \ + display/intel_dsb.o \ + display/intel_fb.o \ + display/intel_fbc.o \ +diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c +index 82e5064b4ce7b..f61901e26409e 100644 +--- a/drivers/gpu/drm/i915/display/intel_ddi.c ++++ b/drivers/gpu/drm/i915/display/intel_ddi.c +@@ -40,6 +40,7 @@ + #include "intel_dp_link_training.h" + #include "intel_dp_mst.h" + #include "intel_dpio_phy.h" ++#include "intel_drrs.h" + #include "intel_dsi.h" + #include "intel_fdi.h" + #include "intel_fifo_underrun.h" +diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c +index 8fdacb252bb19..b136a0fc0963b 100644 +--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c ++++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c +@@ -13,6 +13,7 @@ + #include "intel_display_types.h" + #include "intel_dmc.h" + #include "intel_dp.h" ++#include "intel_drrs.h" + #include "intel_fbc.h" + #include "intel_hdcp.h" + #include "intel_hdmi.h" +diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c +index d55363f1fa102..dbff4b6aa22bf 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp.c ++++ b/drivers/gpu/drm/i915/display/intel_dp.c +@@ -56,6 +56,7 @@ + #include "intel_dp_mst.h" + #include "intel_dpio_phy.h" + #include "intel_dpll.h" ++#include "intel_drrs.h" + #include "intel_fifo_underrun.h" + #include "intel_hdcp.h" + #include "intel_hdmi.h" +@@ -1610,46 +1611,6 @@ intel_dp_compute_hdr_metadata_infoframe_sdp(struct intel_dp *intel_dp, + intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA); + } + +-static void +-intel_dp_drrs_compute_config(struct intel_dp *intel_dp, +- struct intel_crtc_state *pipe_config, +- int output_bpp, bool constant_n) +-{ +- struct intel_connector *intel_connector = intel_dp->attached_connector; +- struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); +- int pixel_clock; +- +- if (pipe_config->vrr.enable) +- return; +- +- /* +- * DRRS and PSR can't be enable together, so giving preference to PSR +- * as it allows more power-savings by complete shutting down display, +- * so to guarantee this, intel_dp_drrs_compute_config() must be called +- * after intel_psr_compute_config(). +- */ +- if (pipe_config->has_psr) +- return; +- +- if (!intel_connector->panel.downclock_mode || +- dev_priv->drrs.type != SEAMLESS_DRRS_SUPPORT) +- return; +- +- pipe_config->has_drrs = true; +- +- pixel_clock = intel_connector->panel.downclock_mode->clock; +- if (pipe_config->splitter.enable) +- pixel_clock /= pipe_config->splitter.link_count; +- +- intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock, +- pipe_config->port_clock, &pipe_config->dp_m2_n2, +- constant_n, pipe_config->fec_enable); +- +- /* FIXME: abstract this better */ +- if (pipe_config->splitter.enable) +- pipe_config->dp_m2_n2.gmch_m *= pipe_config->splitter.link_count; +-} +- + int + intel_dp_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, +@@ -4737,432 +4698,6 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect + drm_connector_attach_vrr_capable_property(connector); + } + +-/** +- * intel_dp_set_drrs_state - program registers for RR switch to take effect +- * @dev_priv: i915 device +- * @crtc_state: a pointer to the active intel_crtc_state +- * @refresh_rate: RR to be programmed +- * +- * This function gets called when refresh rate (RR) has to be changed from +- * one frequency to another. Switches can be between high and low RR +- * supported by the panel or to any other RR based on media playback (in +- * this case, RR value needs to be passed from user space). +- * +- * The caller of this function needs to take a lock on dev_priv->drrs. +- */ +-static void intel_dp_set_drrs_state(struct drm_i915_private *dev_priv, +- const struct intel_crtc_state *crtc_state, +- int refresh_rate) +-{ +- struct intel_dp *intel_dp = dev_priv->drrs.dp; +- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); +- enum drrs_refresh_rate_type index = DRRS_HIGH_RR; +- +- if (refresh_rate <= 0) { +- drm_dbg_kms(&dev_priv->drm, +- "Refresh rate should be positive non-zero.\n"); +- return; +- } +- +- if (intel_dp == NULL) { +- drm_dbg_kms(&dev_priv->drm, "DRRS not supported.\n"); +- return; +- } +- +- if (!crtc) { +- drm_dbg_kms(&dev_priv->drm, +- "DRRS: intel_crtc not initialized\n"); +- return; +- } +- +- if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) { +- drm_dbg_kms(&dev_priv->drm, "Only Seamless DRRS supported.\n"); +- return; +- } +- +- if (drm_mode_vrefresh(intel_dp->attached_connector->panel.downclock_mode) == +- refresh_rate) +- index = DRRS_LOW_RR; +- +- if (index == dev_priv->drrs.refresh_rate_type) { +- drm_dbg_kms(&dev_priv->drm, +- "DRRS requested for previously set RR...ignoring\n"); +- return; +- } +- +- if (!crtc_state->hw.active) { +- drm_dbg_kms(&dev_priv->drm, +- "eDP encoder disabled. CRTC not Active\n"); +- return; +- } +- +- if (DISPLAY_VER(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv)) { +- switch (index) { +- case DRRS_HIGH_RR: +- intel_dp_set_m_n(crtc_state, M1_N1); +- break; +- case DRRS_LOW_RR: +- intel_dp_set_m_n(crtc_state, M2_N2); +- break; +- case DRRS_MAX_RR: +- default: +- drm_err(&dev_priv->drm, +- "Unsupported refreshrate type\n"); +- } +- } else if (DISPLAY_VER(dev_priv) > 6) { +- i915_reg_t reg = PIPECONF(crtc_state->cpu_transcoder); +- u32 val; +- +- val = intel_de_read(dev_priv, reg); +- if (index > DRRS_HIGH_RR) { +- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) +- val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV; +- else +- val |= PIPECONF_EDP_RR_MODE_SWITCH; +- } else { +- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) +- val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV; +- else +- val &= ~PIPECONF_EDP_RR_MODE_SWITCH; +- } +- intel_de_write(dev_priv, reg, val); +- } +- +- dev_priv->drrs.refresh_rate_type = index; +- +- drm_dbg_kms(&dev_priv->drm, "eDP Refresh Rate set to : %dHz\n", +- refresh_rate); +-} +- +-static void +-intel_edp_drrs_enable_locked(struct intel_dp *intel_dp) +-{ +- struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); +- +- dev_priv->drrs.busy_frontbuffer_bits = 0; +- dev_priv->drrs.dp = intel_dp; +-} +- +-/** +- * intel_edp_drrs_enable - init drrs struct if supported +- * @intel_dp: DP struct +- * @crtc_state: A pointer to the active crtc state. +- * +- * Initializes frontbuffer_bits and drrs.dp +- */ +-void intel_edp_drrs_enable(struct intel_dp *intel_dp, +- const struct intel_crtc_state *crtc_state) +-{ +- struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); +- +- if (!crtc_state->has_drrs) +- return; +- +- drm_dbg_kms(&dev_priv->drm, "Enabling DRRS\n"); +- +- mutex_lock(&dev_priv->drrs.mutex); +- +- if (dev_priv->drrs.dp) { +- drm_warn(&dev_priv->drm, "DRRS already enabled\n"); +- goto unlock; +- } +- +- intel_edp_drrs_enable_locked(intel_dp); +- +-unlock: +- mutex_unlock(&dev_priv->drrs.mutex); +-} +- +-static void +-intel_edp_drrs_disable_locked(struct intel_dp *intel_dp, +- const struct intel_crtc_state *crtc_state) +-{ +- struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); +- +- if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) { +- int refresh; +- +- refresh = drm_mode_vrefresh(intel_dp->attached_connector->panel.fixed_mode); +- intel_dp_set_drrs_state(dev_priv, crtc_state, refresh); +- } +- +- dev_priv->drrs.dp = NULL; +-} +- +-/** +- * intel_edp_drrs_disable - Disable DRRS +- * @intel_dp: DP struct +- * @old_crtc_state: Pointer to old crtc_state. +- * +- */ +-void intel_edp_drrs_disable(struct intel_dp *intel_dp, +- const struct intel_crtc_state *old_crtc_state) +-{ +- struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); +- +- if (!old_crtc_state->has_drrs) +- return; +- +- mutex_lock(&dev_priv->drrs.mutex); +- if (!dev_priv->drrs.dp) { +- mutex_unlock(&dev_priv->drrs.mutex); +- return; +- } +- +- intel_edp_drrs_disable_locked(intel_dp, old_crtc_state); +- mutex_unlock(&dev_priv->drrs.mutex); +- +- cancel_delayed_work_sync(&dev_priv->drrs.work); +-} +- +-/** +- * intel_edp_drrs_update - Update DRRS state +- * @intel_dp: Intel DP +- * @crtc_state: new CRTC state +- * +- * This function will update DRRS states, disabling or enabling DRRS when +- * executing fastsets. For full modeset, intel_edp_drrs_disable() and +- * intel_edp_drrs_enable() should be called instead. +- */ +-void +-intel_edp_drrs_update(struct intel_dp *intel_dp, +- const struct intel_crtc_state *crtc_state) +-{ +- struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); +- +- if (dev_priv->drrs.type != SEAMLESS_DRRS_SUPPORT) +- return; +- +- mutex_lock(&dev_priv->drrs.mutex); +- +- /* New state matches current one? */ +- if (crtc_state->has_drrs == !!dev_priv->drrs.dp) +- goto unlock; +- +- if (crtc_state->has_drrs) +- intel_edp_drrs_enable_locked(intel_dp); +- else +- intel_edp_drrs_disable_locked(intel_dp, crtc_state); +- +-unlock: +- mutex_unlock(&dev_priv->drrs.mutex); +-} +- +-static void intel_edp_drrs_downclock_work(struct work_struct *work) +-{ +- struct drm_i915_private *dev_priv = +- container_of(work, typeof(*dev_priv), drrs.work.work); +- struct intel_dp *intel_dp; +- +- mutex_lock(&dev_priv->drrs.mutex); +- +- intel_dp = dev_priv->drrs.dp; +- +- if (!intel_dp) +- goto unlock; +- +- /* +- * The delayed work can race with an invalidate hence we need to +- * recheck. +- */ +- +- if (dev_priv->drrs.busy_frontbuffer_bits) +- goto unlock; +- +- if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR) { +- struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc; +- +- intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config, +- drm_mode_vrefresh(intel_dp->attached_connector->panel.downclock_mode)); +- } +- +-unlock: +- mutex_unlock(&dev_priv->drrs.mutex); +-} +- +-/** +- * intel_edp_drrs_invalidate - Disable Idleness DRRS +- * @dev_priv: i915 device +- * @frontbuffer_bits: frontbuffer plane tracking bits +- * +- * This function gets called everytime rendering on the given planes start. +- * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR). +- * +- * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits. +- */ +-void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv, +- unsigned int frontbuffer_bits) +-{ +- struct intel_dp *intel_dp; +- struct drm_crtc *crtc; +- enum pipe pipe; +- +- if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED) +- return; +- +- cancel_delayed_work(&dev_priv->drrs.work); +- +- mutex_lock(&dev_priv->drrs.mutex); +- +- intel_dp = dev_priv->drrs.dp; +- if (!intel_dp) { +- mutex_unlock(&dev_priv->drrs.mutex); +- return; +- } +- +- crtc = dp_to_dig_port(intel_dp)->base.base.crtc; +- pipe = to_intel_crtc(crtc)->pipe; +- +- frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); +- dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits; +- +- /* invalidate means busy screen hence upclock */ +- if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) +- intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config, +- drm_mode_vrefresh(intel_dp->attached_connector->panel.fixed_mode)); +- +- mutex_unlock(&dev_priv->drrs.mutex); +-} +- +-/** +- * intel_edp_drrs_flush - Restart Idleness DRRS +- * @dev_priv: i915 device +- * @frontbuffer_bits: frontbuffer plane tracking bits +- * +- * This function gets called every time rendering on the given planes has +- * completed or flip on a crtc is completed. So DRRS should be upclocked +- * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again, +- * if no other planes are dirty. +- * +- * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits. +- */ +-void intel_edp_drrs_flush(struct drm_i915_private *dev_priv, +- unsigned int frontbuffer_bits) +-{ +- struct intel_dp *intel_dp; +- struct drm_crtc *crtc; +- enum pipe pipe; +- +- if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED) +- return; +- +- cancel_delayed_work(&dev_priv->drrs.work); +- +- mutex_lock(&dev_priv->drrs.mutex); +- +- intel_dp = dev_priv->drrs.dp; +- if (!intel_dp) { +- mutex_unlock(&dev_priv->drrs.mutex); +- return; +- } +- +- crtc = dp_to_dig_port(intel_dp)->base.base.crtc; +- pipe = to_intel_crtc(crtc)->pipe; +- +- frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); +- dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; +- +- /* flush means busy screen hence upclock */ +- if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) +- intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config, +- drm_mode_vrefresh(intel_dp->attached_connector->panel.fixed_mode)); +- +- /* +- * flush also means no more activity hence schedule downclock, if all +- * other fbs are quiescent too +- */ +- if (!dev_priv->drrs.busy_frontbuffer_bits) +- schedule_delayed_work(&dev_priv->drrs.work, +- msecs_to_jiffies(1000)); +- mutex_unlock(&dev_priv->drrs.mutex); +-} +- +-/** +- * DOC: Display Refresh Rate Switching (DRRS) +- * +- * Display Refresh Rate Switching (DRRS) is a power conservation feature +- * which enables swtching between low and high refresh rates, +- * dynamically, based on the usage scenario. This feature is applicable +- * for internal panels. +- * +- * Indication that the panel supports DRRS is given by the panel EDID, which +- * would list multiple refresh rates for one resolution. +- * +- * DRRS is of 2 types - static and seamless. +- * Static DRRS involves changing refresh rate (RR) by doing a full modeset +- * (may appear as a blink on screen) and is used in dock-undock scenario. +- * Seamless DRRS involves changing RR without any visual effect to the user +- * and can be used during normal system usage. This is done by programming +- * certain registers. +- * +- * Support for static/seamless DRRS may be indicated in the VBT based on +- * inputs from the panel spec. +- * +- * DRRS saves power by switching to low RR based on usage scenarios. +- * +- * The implementation is based on frontbuffer tracking implementation. When +- * there is a disturbance on the screen triggered by user activity or a periodic +- * system activity, DRRS is disabled (RR is changed to high RR). When there is +- * no movement on screen, after a timeout of 1 second, a switch to low RR is +- * made. +- * +- * For integration with frontbuffer tracking code, intel_edp_drrs_invalidate() +- * and intel_edp_drrs_flush() are called. +- * +- * DRRS can be further extended to support other internal panels and also +- * the scenario of video playback wherein RR is set based on the rate +- * requested by userspace. +- */ +- +-/** +- * intel_dp_drrs_init - Init basic DRRS work and mutex. +- * @connector: eDP connector +- * @fixed_mode: preferred mode of panel +- * +- * This function is called only once at driver load to initialize basic +- * DRRS stuff. +- * +- * Returns: +- * Downclock mode if panel supports it, else return NULL. +- * DRRS support is determined by the presence of downclock mode (apart +- * from VBT setting). +- */ +-static struct drm_display_mode * +-intel_dp_drrs_init(struct intel_connector *connector, +- struct drm_display_mode *fixed_mode) +-{ +- struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +- struct drm_display_mode *downclock_mode = NULL; +- +- INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work); +- mutex_init(&dev_priv->drrs.mutex); +- +- if (DISPLAY_VER(dev_priv) <= 6) { +- drm_dbg_kms(&dev_priv->drm, +- "DRRS supported for Gen7 and above\n"); +- return NULL; +- } +- +- if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) { +- drm_dbg_kms(&dev_priv->drm, "VBT doesn't support DRRS\n"); +- return NULL; +- } +- +- downclock_mode = intel_panel_edid_downclock_mode(connector, fixed_mode); +- if (!downclock_mode) { +- drm_dbg_kms(&dev_priv->drm, +- "Downclock mode is not found. DRRS not supported\n"); +- return NULL; +- } +- +- dev_priv->drrs.type = dev_priv->vbt.drrs_type; +- +- dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR; +- drm_dbg_kms(&dev_priv->drm, +- "seamless DRRS supported for eDP panel.\n"); +- return downclock_mode; +-} +- + static bool intel_edp_init_connector(struct intel_dp *intel_dp, + struct intel_connector *intel_connector) + { +diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h +index 2121aaa9b8db0..3dd6ebc2f6b14 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp.h ++++ b/drivers/gpu/drm/i915/display/intel_dp.h +@@ -70,17 +70,6 @@ int intel_dp_max_link_rate(struct intel_dp *intel_dp); + int intel_dp_max_lane_count(struct intel_dp *intel_dp); + int intel_dp_rate_select(struct intel_dp *intel_dp, int rate); + +-void intel_edp_drrs_enable(struct intel_dp *intel_dp, +- const struct intel_crtc_state *crtc_state); +-void intel_edp_drrs_disable(struct intel_dp *intel_dp, +- const struct intel_crtc_state *crtc_state); +-void intel_edp_drrs_update(struct intel_dp *intel_dp, +- const struct intel_crtc_state *crtc_state); +-void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv, +- unsigned int frontbuffer_bits); +-void intel_edp_drrs_flush(struct drm_i915_private *dev_priv, +- unsigned int frontbuffer_bits); +- + void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, + u8 *link_bw, u8 *rate_select); + bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp); +diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c +new file mode 100644 +index 0000000000000..be9b6d4482f04 +--- /dev/null ++++ b/drivers/gpu/drm/i915/display/intel_drrs.c +@@ -0,0 +1,477 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * Copyright © 2021 Intel Corporation ++ */ ++ ++#include "i915_drv.h" ++#include "intel_atomic.h" ++#include "intel_de.h" ++#include "intel_display_types.h" ++#include "intel_drrs.h" ++#include "intel_panel.h" ++ ++/** ++ * DOC: Display Refresh Rate Switching (DRRS) ++ * ++ * Display Refresh Rate Switching (DRRS) is a power conservation feature ++ * which enables swtching between low and high refresh rates, ++ * dynamically, based on the usage scenario. This feature is applicable ++ * for internal panels. ++ * ++ * Indication that the panel supports DRRS is given by the panel EDID, which ++ * would list multiple refresh rates for one resolution. ++ * ++ * DRRS is of 2 types - static and seamless. ++ * Static DRRS involves changing refresh rate (RR) by doing a full modeset ++ * (may appear as a blink on screen) and is used in dock-undock scenario. ++ * Seamless DRRS involves changing RR without any visual effect to the user ++ * and can be used during normal system usage. This is done by programming ++ * certain registers. ++ * ++ * Support for static/seamless DRRS may be indicated in the VBT based on ++ * inputs from the panel spec. ++ * ++ * DRRS saves power by switching to low RR based on usage scenarios. ++ * ++ * The implementation is based on frontbuffer tracking implementation. When ++ * there is a disturbance on the screen triggered by user activity or a periodic ++ * system activity, DRRS is disabled (RR is changed to high RR). When there is ++ * no movement on screen, after a timeout of 1 second, a switch to low RR is ++ * made. ++ * ++ * For integration with frontbuffer tracking code, intel_edp_drrs_invalidate() ++ * and intel_edp_drrs_flush() are called. ++ * ++ * DRRS can be further extended to support other internal panels and also ++ * the scenario of video playback wherein RR is set based on the rate ++ * requested by userspace. ++ */ ++ ++void ++intel_dp_drrs_compute_config(struct intel_dp *intel_dp, ++ struct intel_crtc_state *pipe_config, ++ int output_bpp, bool constant_n) ++{ ++ struct intel_connector *intel_connector = intel_dp->attached_connector; ++ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); ++ int pixel_clock; ++ ++ if (pipe_config->vrr.enable) ++ return; ++ ++ /* ++ * DRRS and PSR can't be enable together, so giving preference to PSR ++ * as it allows more power-savings by complete shutting down display, ++ * so to guarantee this, intel_dp_drrs_compute_config() must be called ++ * after intel_psr_compute_config(). ++ */ ++ if (pipe_config->has_psr) ++ return; ++ ++ if (!intel_connector->panel.downclock_mode || ++ dev_priv->drrs.type != SEAMLESS_DRRS_SUPPORT) ++ return; ++ ++ pipe_config->has_drrs = true; ++ ++ pixel_clock = intel_connector->panel.downclock_mode->clock; ++ if (pipe_config->splitter.enable) ++ pixel_clock /= pipe_config->splitter.link_count; ++ ++ intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock, ++ pipe_config->port_clock, &pipe_config->dp_m2_n2, ++ constant_n, pipe_config->fec_enable); ++ ++ /* FIXME: abstract this better */ ++ if (pipe_config->splitter.enable) ++ pipe_config->dp_m2_n2.gmch_m *= pipe_config->splitter.link_count; ++} ++ ++/** ++ * intel_dp_set_drrs_state - program registers for RR switch to take effect ++ * @dev_priv: i915 device ++ * @crtc_state: a pointer to the active intel_crtc_state ++ * @refresh_rate: RR to be programmed ++ * ++ * This function gets called when refresh rate (RR) has to be changed from ++ * one frequency to another. Switches can be between high and low RR ++ * supported by the panel or to any other RR based on media playback (in ++ * this case, RR value needs to be passed from user space). ++ * ++ * The caller of this function needs to take a lock on dev_priv->drrs. ++ */ ++static void intel_dp_set_drrs_state(struct drm_i915_private *dev_priv, ++ const struct intel_crtc_state *crtc_state, ++ int refresh_rate) ++{ ++ struct intel_dp *intel_dp = dev_priv->drrs.dp; ++ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); ++ enum drrs_refresh_rate_type index = DRRS_HIGH_RR; ++ ++ if (refresh_rate <= 0) { ++ drm_dbg_kms(&dev_priv->drm, ++ "Refresh rate should be positive non-zero.\n"); ++ return; ++ } ++ ++ if (intel_dp == NULL) { ++ drm_dbg_kms(&dev_priv->drm, "DRRS not supported.\n"); ++ return; ++ } ++ ++ if (!crtc) { ++ drm_dbg_kms(&dev_priv->drm, ++ "DRRS: intel_crtc not initialized\n"); ++ return; ++ } ++ ++ if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) { ++ drm_dbg_kms(&dev_priv->drm, "Only Seamless DRRS supported.\n"); ++ return; ++ } ++ ++ if (drm_mode_vrefresh(intel_dp->attached_connector->panel.downclock_mode) == ++ refresh_rate) ++ index = DRRS_LOW_RR; ++ ++ if (index == dev_priv->drrs.refresh_rate_type) { ++ drm_dbg_kms(&dev_priv->drm, ++ "DRRS requested for previously set RR...ignoring\n"); ++ return; ++ } ++ ++ if (!crtc_state->hw.active) { ++ drm_dbg_kms(&dev_priv->drm, ++ "eDP encoder disabled. CRTC not Active\n"); ++ return; ++ } ++ ++ if (DISPLAY_VER(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv)) { ++ switch (index) { ++ case DRRS_HIGH_RR: ++ intel_dp_set_m_n(crtc_state, M1_N1); ++ break; ++ case DRRS_LOW_RR: ++ intel_dp_set_m_n(crtc_state, M2_N2); ++ break; ++ case DRRS_MAX_RR: ++ default: ++ drm_err(&dev_priv->drm, ++ "Unsupported refreshrate type\n"); ++ } ++ } else if (DISPLAY_VER(dev_priv) > 6) { ++ i915_reg_t reg = PIPECONF(crtc_state->cpu_transcoder); ++ u32 val; ++ ++ val = intel_de_read(dev_priv, reg); ++ if (index > DRRS_HIGH_RR) { ++ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) ++ val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV; ++ else ++ val |= PIPECONF_EDP_RR_MODE_SWITCH; ++ } else { ++ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) ++ val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV; ++ else ++ val &= ~PIPECONF_EDP_RR_MODE_SWITCH; ++ } ++ intel_de_write(dev_priv, reg, val); ++ } ++ ++ dev_priv->drrs.refresh_rate_type = index; ++ ++ drm_dbg_kms(&dev_priv->drm, "eDP Refresh Rate set to : %dHz\n", ++ refresh_rate); ++} ++ ++static void ++intel_edp_drrs_enable_locked(struct intel_dp *intel_dp) ++{ ++ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); ++ ++ dev_priv->drrs.busy_frontbuffer_bits = 0; ++ dev_priv->drrs.dp = intel_dp; ++} ++ ++/** ++ * intel_edp_drrs_enable - init drrs struct if supported ++ * @intel_dp: DP struct ++ * @crtc_state: A pointer to the active crtc state. ++ * ++ * Initializes frontbuffer_bits and drrs.dp ++ */ ++void intel_edp_drrs_enable(struct intel_dp *intel_dp, ++ const struct intel_crtc_state *crtc_state) ++{ ++ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); ++ ++ if (!crtc_state->has_drrs) ++ return; ++ ++ drm_dbg_kms(&dev_priv->drm, "Enabling DRRS\n"); ++ ++ mutex_lock(&dev_priv->drrs.mutex); ++ ++ if (dev_priv->drrs.dp) { ++ drm_warn(&dev_priv->drm, "DRRS already enabled\n"); ++ goto unlock; ++ } ++ ++ intel_edp_drrs_enable_locked(intel_dp); ++ ++unlock: ++ mutex_unlock(&dev_priv->drrs.mutex); ++} ++ ++static void ++intel_edp_drrs_disable_locked(struct intel_dp *intel_dp, ++ const struct intel_crtc_state *crtc_state) ++{ ++ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); ++ ++ if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) { ++ int refresh; ++ ++ refresh = drm_mode_vrefresh(intel_dp->attached_connector->panel.fixed_mode); ++ intel_dp_set_drrs_state(dev_priv, crtc_state, refresh); ++ } ++ ++ dev_priv->drrs.dp = NULL; ++} ++ ++/** ++ * intel_edp_drrs_disable - Disable DRRS ++ * @intel_dp: DP struct ++ * @old_crtc_state: Pointer to old crtc_state. ++ * ++ */ ++void intel_edp_drrs_disable(struct intel_dp *intel_dp, ++ const struct intel_crtc_state *old_crtc_state) ++{ ++ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); ++ ++ if (!old_crtc_state->has_drrs) ++ return; ++ ++ mutex_lock(&dev_priv->drrs.mutex); ++ if (!dev_priv->drrs.dp) { ++ mutex_unlock(&dev_priv->drrs.mutex); ++ return; ++ } ++ ++ intel_edp_drrs_disable_locked(intel_dp, old_crtc_state); ++ mutex_unlock(&dev_priv->drrs.mutex); ++ ++ cancel_delayed_work_sync(&dev_priv->drrs.work); ++} ++ ++/** ++ * intel_edp_drrs_update - Update DRRS state ++ * @intel_dp: Intel DP ++ * @crtc_state: new CRTC state ++ * ++ * This function will update DRRS states, disabling or enabling DRRS when ++ * executing fastsets. For full modeset, intel_edp_drrs_disable() and ++ * intel_edp_drrs_enable() should be called instead. ++ */ ++void ++intel_edp_drrs_update(struct intel_dp *intel_dp, ++ const struct intel_crtc_state *crtc_state) ++{ ++ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); ++ ++ if (dev_priv->drrs.type != SEAMLESS_DRRS_SUPPORT) ++ return; ++ ++ mutex_lock(&dev_priv->drrs.mutex); ++ ++ /* New state matches current one? */ ++ if (crtc_state->has_drrs == !!dev_priv->drrs.dp) ++ goto unlock; ++ ++ if (crtc_state->has_drrs) ++ intel_edp_drrs_enable_locked(intel_dp); ++ else ++ intel_edp_drrs_disable_locked(intel_dp, crtc_state); ++ ++unlock: ++ mutex_unlock(&dev_priv->drrs.mutex); ++} ++ ++static void intel_edp_drrs_downclock_work(struct work_struct *work) ++{ ++ struct drm_i915_private *dev_priv = ++ container_of(work, typeof(*dev_priv), drrs.work.work); ++ struct intel_dp *intel_dp; ++ ++ mutex_lock(&dev_priv->drrs.mutex); ++ ++ intel_dp = dev_priv->drrs.dp; ++ ++ if (!intel_dp) ++ goto unlock; ++ ++ /* ++ * The delayed work can race with an invalidate hence we need to ++ * recheck. ++ */ ++ ++ if (dev_priv->drrs.busy_frontbuffer_bits) ++ goto unlock; ++ ++ if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR) { ++ struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc; ++ ++ intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config, ++ drm_mode_vrefresh(intel_dp->attached_connector->panel.downclock_mode)); ++ } ++ ++unlock: ++ mutex_unlock(&dev_priv->drrs.mutex); ++} ++ ++/** ++ * intel_edp_drrs_invalidate - Disable Idleness DRRS ++ * @dev_priv: i915 device ++ * @frontbuffer_bits: frontbuffer plane tracking bits ++ * ++ * This function gets called everytime rendering on the given planes start. ++ * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR). ++ * ++ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits. ++ */ ++void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv, ++ unsigned int frontbuffer_bits) ++{ ++ struct intel_dp *intel_dp; ++ struct drm_crtc *crtc; ++ enum pipe pipe; ++ ++ if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED) ++ return; ++ ++ cancel_delayed_work(&dev_priv->drrs.work); ++ ++ mutex_lock(&dev_priv->drrs.mutex); ++ ++ intel_dp = dev_priv->drrs.dp; ++ if (!intel_dp) { ++ mutex_unlock(&dev_priv->drrs.mutex); ++ return; ++ } ++ ++ crtc = dp_to_dig_port(intel_dp)->base.base.crtc; ++ pipe = to_intel_crtc(crtc)->pipe; ++ ++ frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); ++ dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits; ++ ++ /* invalidate means busy screen hence upclock */ ++ if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) ++ intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config, ++ drm_mode_vrefresh(intel_dp->attached_connector->panel.fixed_mode)); ++ ++ mutex_unlock(&dev_priv->drrs.mutex); ++} ++ ++/** ++ * intel_edp_drrs_flush - Restart Idleness DRRS ++ * @dev_priv: i915 device ++ * @frontbuffer_bits: frontbuffer plane tracking bits ++ * ++ * This function gets called every time rendering on the given planes has ++ * completed or flip on a crtc is completed. So DRRS should be upclocked ++ * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again, ++ * if no other planes are dirty. ++ * ++ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits. ++ */ ++void intel_edp_drrs_flush(struct drm_i915_private *dev_priv, ++ unsigned int frontbuffer_bits) ++{ ++ struct intel_dp *intel_dp; ++ struct drm_crtc *crtc; ++ enum pipe pipe; ++ ++ if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED) ++ return; ++ ++ cancel_delayed_work(&dev_priv->drrs.work); ++ ++ mutex_lock(&dev_priv->drrs.mutex); ++ ++ intel_dp = dev_priv->drrs.dp; ++ if (!intel_dp) { ++ mutex_unlock(&dev_priv->drrs.mutex); ++ return; ++ } ++ ++ crtc = dp_to_dig_port(intel_dp)->base.base.crtc; ++ pipe = to_intel_crtc(crtc)->pipe; ++ ++ frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); ++ dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; ++ ++ /* flush means busy screen hence upclock */ ++ if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) ++ intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config, ++ drm_mode_vrefresh(intel_dp->attached_connector->panel.fixed_mode)); ++ ++ /* ++ * flush also means no more activity hence schedule downclock, if all ++ * other fbs are quiescent too ++ */ ++ if (!dev_priv->drrs.busy_frontbuffer_bits) ++ schedule_delayed_work(&dev_priv->drrs.work, ++ msecs_to_jiffies(1000)); ++ mutex_unlock(&dev_priv->drrs.mutex); ++} ++ ++/** ++ * intel_dp_drrs_init - Init basic DRRS work and mutex. ++ * @connector: eDP connector ++ * @fixed_mode: preferred mode of panel ++ * ++ * This function is called only once at driver load to initialize basic ++ * DRRS stuff. ++ * ++ * Returns: ++ * Downclock mode if panel supports it, else return NULL. ++ * DRRS support is determined by the presence of downclock mode (apart ++ * from VBT setting). ++ */ ++struct drm_display_mode * ++intel_dp_drrs_init(struct intel_connector *connector, ++ struct drm_display_mode *fixed_mode) ++{ ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ struct drm_display_mode *downclock_mode = NULL; ++ ++ INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work); ++ mutex_init(&dev_priv->drrs.mutex); ++ ++ if (DISPLAY_VER(dev_priv) <= 6) { ++ drm_dbg_kms(&dev_priv->drm, ++ "DRRS supported for Gen7 and above\n"); ++ return NULL; ++ } ++ ++ if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) { ++ drm_dbg_kms(&dev_priv->drm, "VBT doesn't support DRRS\n"); ++ return NULL; ++ } ++ ++ downclock_mode = intel_panel_edid_downclock_mode(connector, fixed_mode); ++ if (!downclock_mode) { ++ drm_dbg_kms(&dev_priv->drm, ++ "Downclock mode is not found. DRRS not supported\n"); ++ return NULL; ++ } ++ ++ dev_priv->drrs.type = dev_priv->vbt.drrs_type; ++ ++ dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR; ++ drm_dbg_kms(&dev_priv->drm, ++ "seamless DRRS supported for eDP panel.\n"); ++ return downclock_mode; ++} +diff --git a/drivers/gpu/drm/i915/display/intel_drrs.h b/drivers/gpu/drm/i915/display/intel_drrs.h +new file mode 100644 +index 0000000000000..ffa175b4cf4f4 +--- /dev/null ++++ b/drivers/gpu/drm/i915/display/intel_drrs.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * Copyright © 2021 Intel Corporation ++ */ ++ ++#ifndef __INTEL_DRRS_H__ ++#define __INTEL_DRRS_H__ ++ ++#include ++ ++struct drm_i915_private; ++struct intel_crtc_state; ++struct intel_connector; ++struct intel_dp; ++ ++void intel_edp_drrs_enable(struct intel_dp *intel_dp, ++ const struct intel_crtc_state *crtc_state); ++void intel_edp_drrs_disable(struct intel_dp *intel_dp, ++ const struct intel_crtc_state *crtc_state); ++void intel_edp_drrs_update(struct intel_dp *intel_dp, ++ const struct intel_crtc_state *crtc_state); ++void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv, ++ unsigned int frontbuffer_bits); ++void intel_edp_drrs_flush(struct drm_i915_private *dev_priv, ++ unsigned int frontbuffer_bits); ++void intel_dp_drrs_compute_config(struct intel_dp *intel_dp, ++ struct intel_crtc_state *pipe_config, ++ int output_bpp, bool constant_n); ++struct drm_display_mode *intel_dp_drrs_init(struct intel_connector *connector, ++ struct drm_display_mode *fixed_mode); ++ ++#endif /* __INTEL_DRRS_H__ */ +diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c +index 8e75debcce1a9..e4834d84ce5e3 100644 +--- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c ++++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c +@@ -62,6 +62,7 @@ + #include "intel_display_types.h" + #include "intel_fbc.h" + #include "intel_frontbuffer.h" ++#include "intel_drrs.h" + #include "intel_psr.h" + + /** +-- +2.34.1 + diff --git a/queue-5.15/drm-i915-display-split-out-dpt-out-of-intel_display..patch b/queue-5.15/drm-i915-display-split-out-dpt-out-of-intel_display..patch new file mode 100644 index 00000000000..8252847d530 --- /dev/null +++ b/queue-5.15/drm-i915-display-split-out-dpt-out-of-intel_display..patch @@ -0,0 +1,544 @@ +From f71f4dd25f9469a9ada437ad871e59d0bf4bc790 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Aug 2021 15:25:31 +0300 +Subject: drm/i915/display: split out dpt out of intel_display.c + +From: Jani Nikula + +[ Upstream commit dc6d6158a6e8b11a11544a541583296d9323050f ] + +Let's try to reduce the size of intel_display.c, not increase it. + +Reviewed-by: Rodrigo Vivi +Signed-off-by: Jani Nikula +Link: https://patchwork.freedesktop.org/patch/msgid/934a2a0db05e835f6843befef6082e2034f23b3a.1629721467.git.jani.nikula@intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/Makefile | 1 + + drivers/gpu/drm/i915/display/intel_display.c | 220 +----------------- + drivers/gpu/drm/i915/display/intel_dpt.c | 229 +++++++++++++++++++ + drivers/gpu/drm/i915/display/intel_dpt.h | 19 ++ + 4 files changed, 250 insertions(+), 219 deletions(-) + create mode 100644 drivers/gpu/drm/i915/display/intel_dpt.c + create mode 100644 drivers/gpu/drm/i915/display/intel_dpt.h + +diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile +index 335ba9f43d8f7..a4154fe14f8c0 100644 +--- a/drivers/gpu/drm/i915/Makefile ++++ b/drivers/gpu/drm/i915/Makefile +@@ -211,6 +211,7 @@ i915-y += \ + display/intel_dpio_phy.o \ + display/intel_dpll.o \ + display/intel_dpll_mgr.o \ ++ display/intel_dpt.o \ + display/intel_dsb.o \ + display/intel_fb.o \ + display/intel_fbc.o \ +diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c +index 17f44ffea5866..625ce6975eeba 100644 +--- a/drivers/gpu/drm/i915/display/intel_display.c ++++ b/drivers/gpu/drm/i915/display/intel_display.c +@@ -84,6 +84,7 @@ + #include "intel_display_types.h" + #include "intel_dmc.h" + #include "intel_dp_link_training.h" ++#include "intel_dpt.h" + #include "intel_fbc.h" + #include "intel_fdi.h" + #include "intel_fbdev.h" +@@ -126,182 +127,6 @@ static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state); + static void intel_modeset_setup_hw_state(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx); + +-struct i915_dpt { +- struct i915_address_space vm; +- +- struct drm_i915_gem_object *obj; +- struct i915_vma *vma; +- void __iomem *iomem; +-}; +- +-#define i915_is_dpt(vm) ((vm)->is_dpt) +- +-static inline struct i915_dpt * +-i915_vm_to_dpt(struct i915_address_space *vm) +-{ +- BUILD_BUG_ON(offsetof(struct i915_dpt, vm)); +- GEM_BUG_ON(!i915_is_dpt(vm)); +- return container_of(vm, struct i915_dpt, vm); +-} +- +-#define dpt_total_entries(dpt) ((dpt)->vm.total >> PAGE_SHIFT) +- +-static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte) +-{ +- writeq(pte, addr); +-} +- +-static void dpt_insert_page(struct i915_address_space *vm, +- dma_addr_t addr, +- u64 offset, +- enum i915_cache_level level, +- u32 flags) +-{ +- struct i915_dpt *dpt = i915_vm_to_dpt(vm); +- gen8_pte_t __iomem *base = dpt->iomem; +- +- gen8_set_pte(base + offset / I915_GTT_PAGE_SIZE, +- vm->pte_encode(addr, level, flags)); +-} +- +-static void dpt_insert_entries(struct i915_address_space *vm, +- struct i915_vma *vma, +- enum i915_cache_level level, +- u32 flags) +-{ +- struct i915_dpt *dpt = i915_vm_to_dpt(vm); +- gen8_pte_t __iomem *base = dpt->iomem; +- const gen8_pte_t pte_encode = vm->pte_encode(0, level, flags); +- struct sgt_iter sgt_iter; +- dma_addr_t addr; +- int i; +- +- /* +- * Note that we ignore PTE_READ_ONLY here. The caller must be careful +- * not to allow the user to override access to a read only page. +- */ +- +- i = vma->node.start / I915_GTT_PAGE_SIZE; +- for_each_sgt_daddr(addr, sgt_iter, vma->pages) +- gen8_set_pte(&base[i++], pte_encode | addr); +-} +- +-static void dpt_clear_range(struct i915_address_space *vm, +- u64 start, u64 length) +-{ +-} +- +-static void dpt_bind_vma(struct i915_address_space *vm, +- struct i915_vm_pt_stash *stash, +- struct i915_vma *vma, +- enum i915_cache_level cache_level, +- u32 flags) +-{ +- struct drm_i915_gem_object *obj = vma->obj; +- u32 pte_flags; +- +- /* Applicable to VLV (gen8+ do not support RO in the GGTT) */ +- pte_flags = 0; +- if (vma->vm->has_read_only && i915_gem_object_is_readonly(obj)) +- pte_flags |= PTE_READ_ONLY; +- if (i915_gem_object_is_lmem(obj)) +- pte_flags |= PTE_LM; +- +- vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags); +- +- vma->page_sizes.gtt = I915_GTT_PAGE_SIZE; +- +- /* +- * Without aliasing PPGTT there's no difference between +- * GLOBAL/LOCAL_BIND, it's all the same ptes. Hence unconditionally +- * upgrade to both bound if we bind either to avoid double-binding. +- */ +- atomic_or(I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND, &vma->flags); +-} +- +-static void dpt_unbind_vma(struct i915_address_space *vm, struct i915_vma *vma) +-{ +- vm->clear_range(vm, vma->node.start, vma->size); +-} +- +-static void dpt_cleanup(struct i915_address_space *vm) +-{ +- struct i915_dpt *dpt = i915_vm_to_dpt(vm); +- +- i915_gem_object_put(dpt->obj); +-} +- +-static struct i915_address_space * +-intel_dpt_create(struct intel_framebuffer *fb) +-{ +- struct drm_gem_object *obj = &intel_fb_obj(&fb->base)->base; +- struct drm_i915_private *i915 = to_i915(obj->dev); +- struct drm_i915_gem_object *dpt_obj; +- struct i915_address_space *vm; +- struct i915_dpt *dpt; +- size_t size; +- int ret; +- +- if (intel_fb_needs_pot_stride_remap(fb)) +- size = intel_remapped_info_size(&fb->remapped_view.gtt.remapped); +- else +- size = DIV_ROUND_UP_ULL(obj->size, I915_GTT_PAGE_SIZE); +- +- size = round_up(size * sizeof(gen8_pte_t), I915_GTT_PAGE_SIZE); +- +- if (HAS_LMEM(i915)) +- dpt_obj = i915_gem_object_create_lmem(i915, size, 0); +- else +- dpt_obj = i915_gem_object_create_stolen(i915, size); +- if (IS_ERR(dpt_obj)) +- return ERR_CAST(dpt_obj); +- +- ret = i915_gem_object_set_cache_level(dpt_obj, I915_CACHE_NONE); +- if (ret) { +- i915_gem_object_put(dpt_obj); +- return ERR_PTR(ret); +- } +- +- dpt = kzalloc(sizeof(*dpt), GFP_KERNEL); +- if (!dpt) { +- i915_gem_object_put(dpt_obj); +- return ERR_PTR(-ENOMEM); +- } +- +- vm = &dpt->vm; +- +- vm->gt = &i915->gt; +- vm->i915 = i915; +- vm->dma = i915->drm.dev; +- vm->total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE; +- vm->is_dpt = true; +- +- i915_address_space_init(vm, VM_CLASS_DPT); +- +- vm->insert_page = dpt_insert_page; +- vm->clear_range = dpt_clear_range; +- vm->insert_entries = dpt_insert_entries; +- vm->cleanup = dpt_cleanup; +- +- vm->vma_ops.bind_vma = dpt_bind_vma; +- vm->vma_ops.unbind_vma = dpt_unbind_vma; +- vm->vma_ops.set_pages = ggtt_set_pages; +- vm->vma_ops.clear_pages = clear_pages; +- +- vm->pte_encode = gen8_ggtt_pte_encode; +- +- dpt->obj = dpt_obj; +- +- return &dpt->vm; +-} +- +-static void intel_dpt_destroy(struct i915_address_space *vm) +-{ +- struct i915_dpt *dpt = i915_vm_to_dpt(vm); +- +- i915_vm_close(&dpt->vm); +-} +- + /* returns HPLL frequency in kHz */ + int vlv_get_hpll_vco(struct drm_i915_private *dev_priv) + { +@@ -1879,49 +1704,6 @@ static void intel_plane_disable_noatomic(struct intel_crtc *crtc, + intel_wait_for_vblank(dev_priv, crtc->pipe); + } + +-static struct i915_vma *intel_dpt_pin(struct i915_address_space *vm) +-{ +- struct drm_i915_private *i915 = vm->i915; +- struct i915_dpt *dpt = i915_vm_to_dpt(vm); +- intel_wakeref_t wakeref; +- struct i915_vma *vma; +- void __iomem *iomem; +- +- wakeref = intel_runtime_pm_get(&i915->runtime_pm); +- atomic_inc(&i915->gpu_error.pending_fb_pin); +- +- vma = i915_gem_object_ggtt_pin(dpt->obj, NULL, 0, 4096, +- HAS_LMEM(i915) ? 0 : PIN_MAPPABLE); +- if (IS_ERR(vma)) +- goto err; +- +- iomem = i915_vma_pin_iomap(vma); +- i915_vma_unpin(vma); +- if (IS_ERR(iomem)) { +- vma = iomem; +- goto err; +- } +- +- dpt->vma = vma; +- dpt->iomem = iomem; +- +- i915_vma_get(vma); +- +-err: +- atomic_dec(&i915->gpu_error.pending_fb_pin); +- intel_runtime_pm_put(&i915->runtime_pm, wakeref); +- +- return vma; +-} +- +-static void intel_dpt_unpin(struct i915_address_space *vm) +-{ +- struct i915_dpt *dpt = i915_vm_to_dpt(vm); +- +- i915_vma_unpin_iomap(dpt->vma); +- i915_vma_put(dpt->vma); +-} +- + static bool + intel_reuse_initial_plane_obj(struct drm_i915_private *i915, + const struct intel_initial_plane_config *plane_config, +diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c +new file mode 100644 +index 0000000000000..22acd945a9e47 +--- /dev/null ++++ b/drivers/gpu/drm/i915/display/intel_dpt.c +@@ -0,0 +1,229 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * Copyright © 2021 Intel Corporation ++ */ ++ ++#include "i915_drv.h" ++#include "intel_display_types.h" ++#include "intel_dpt.h" ++#include "intel_fb.h" ++#include "gt/gen8_ppgtt.h" ++ ++struct i915_dpt { ++ struct i915_address_space vm; ++ ++ struct drm_i915_gem_object *obj; ++ struct i915_vma *vma; ++ void __iomem *iomem; ++}; ++ ++#define i915_is_dpt(vm) ((vm)->is_dpt) ++ ++static inline struct i915_dpt * ++i915_vm_to_dpt(struct i915_address_space *vm) ++{ ++ BUILD_BUG_ON(offsetof(struct i915_dpt, vm)); ++ GEM_BUG_ON(!i915_is_dpt(vm)); ++ return container_of(vm, struct i915_dpt, vm); ++} ++ ++#define dpt_total_entries(dpt) ((dpt)->vm.total >> PAGE_SHIFT) ++ ++static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte) ++{ ++ writeq(pte, addr); ++} ++ ++static void dpt_insert_page(struct i915_address_space *vm, ++ dma_addr_t addr, ++ u64 offset, ++ enum i915_cache_level level, ++ u32 flags) ++{ ++ struct i915_dpt *dpt = i915_vm_to_dpt(vm); ++ gen8_pte_t __iomem *base = dpt->iomem; ++ ++ gen8_set_pte(base + offset / I915_GTT_PAGE_SIZE, ++ vm->pte_encode(addr, level, flags)); ++} ++ ++static void dpt_insert_entries(struct i915_address_space *vm, ++ struct i915_vma *vma, ++ enum i915_cache_level level, ++ u32 flags) ++{ ++ struct i915_dpt *dpt = i915_vm_to_dpt(vm); ++ gen8_pte_t __iomem *base = dpt->iomem; ++ const gen8_pte_t pte_encode = vm->pte_encode(0, level, flags); ++ struct sgt_iter sgt_iter; ++ dma_addr_t addr; ++ int i; ++ ++ /* ++ * Note that we ignore PTE_READ_ONLY here. The caller must be careful ++ * not to allow the user to override access to a read only page. ++ */ ++ ++ i = vma->node.start / I915_GTT_PAGE_SIZE; ++ for_each_sgt_daddr(addr, sgt_iter, vma->pages) ++ gen8_set_pte(&base[i++], pte_encode | addr); ++} ++ ++static void dpt_clear_range(struct i915_address_space *vm, ++ u64 start, u64 length) ++{ ++} ++ ++static void dpt_bind_vma(struct i915_address_space *vm, ++ struct i915_vm_pt_stash *stash, ++ struct i915_vma *vma, ++ enum i915_cache_level cache_level, ++ u32 flags) ++{ ++ struct drm_i915_gem_object *obj = vma->obj; ++ u32 pte_flags; ++ ++ /* Applicable to VLV (gen8+ do not support RO in the GGTT) */ ++ pte_flags = 0; ++ if (vma->vm->has_read_only && i915_gem_object_is_readonly(obj)) ++ pte_flags |= PTE_READ_ONLY; ++ if (i915_gem_object_is_lmem(obj)) ++ pte_flags |= PTE_LM; ++ ++ vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags); ++ ++ vma->page_sizes.gtt = I915_GTT_PAGE_SIZE; ++ ++ /* ++ * Without aliasing PPGTT there's no difference between ++ * GLOBAL/LOCAL_BIND, it's all the same ptes. Hence unconditionally ++ * upgrade to both bound if we bind either to avoid double-binding. ++ */ ++ atomic_or(I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND, &vma->flags); ++} ++ ++static void dpt_unbind_vma(struct i915_address_space *vm, struct i915_vma *vma) ++{ ++ vm->clear_range(vm, vma->node.start, vma->size); ++} ++ ++static void dpt_cleanup(struct i915_address_space *vm) ++{ ++ struct i915_dpt *dpt = i915_vm_to_dpt(vm); ++ ++ i915_gem_object_put(dpt->obj); ++} ++ ++struct i915_vma *intel_dpt_pin(struct i915_address_space *vm) ++{ ++ struct drm_i915_private *i915 = vm->i915; ++ struct i915_dpt *dpt = i915_vm_to_dpt(vm); ++ intel_wakeref_t wakeref; ++ struct i915_vma *vma; ++ void __iomem *iomem; ++ ++ wakeref = intel_runtime_pm_get(&i915->runtime_pm); ++ atomic_inc(&i915->gpu_error.pending_fb_pin); ++ ++ vma = i915_gem_object_ggtt_pin(dpt->obj, NULL, 0, 4096, ++ HAS_LMEM(i915) ? 0 : PIN_MAPPABLE); ++ if (IS_ERR(vma)) ++ goto err; ++ ++ iomem = i915_vma_pin_iomap(vma); ++ i915_vma_unpin(vma); ++ if (IS_ERR(iomem)) { ++ vma = iomem; ++ goto err; ++ } ++ ++ dpt->vma = vma; ++ dpt->iomem = iomem; ++ ++ i915_vma_get(vma); ++ ++err: ++ atomic_dec(&i915->gpu_error.pending_fb_pin); ++ intel_runtime_pm_put(&i915->runtime_pm, wakeref); ++ ++ return vma; ++} ++ ++void intel_dpt_unpin(struct i915_address_space *vm) ++{ ++ struct i915_dpt *dpt = i915_vm_to_dpt(vm); ++ ++ i915_vma_unpin_iomap(dpt->vma); ++ i915_vma_put(dpt->vma); ++} ++ ++struct i915_address_space * ++intel_dpt_create(struct intel_framebuffer *fb) ++{ ++ struct drm_gem_object *obj = &intel_fb_obj(&fb->base)->base; ++ struct drm_i915_private *i915 = to_i915(obj->dev); ++ struct drm_i915_gem_object *dpt_obj; ++ struct i915_address_space *vm; ++ struct i915_dpt *dpt; ++ size_t size; ++ int ret; ++ ++ if (intel_fb_needs_pot_stride_remap(fb)) ++ size = intel_remapped_info_size(&fb->remapped_view.gtt.remapped); ++ else ++ size = DIV_ROUND_UP_ULL(obj->size, I915_GTT_PAGE_SIZE); ++ ++ size = round_up(size * sizeof(gen8_pte_t), I915_GTT_PAGE_SIZE); ++ ++ if (HAS_LMEM(i915)) ++ dpt_obj = i915_gem_object_create_lmem(i915, size, 0); ++ else ++ dpt_obj = i915_gem_object_create_stolen(i915, size); ++ if (IS_ERR(dpt_obj)) ++ return ERR_CAST(dpt_obj); ++ ++ ret = i915_gem_object_set_cache_level(dpt_obj, I915_CACHE_NONE); ++ if (ret) { ++ i915_gem_object_put(dpt_obj); ++ return ERR_PTR(ret); ++ } ++ ++ dpt = kzalloc(sizeof(*dpt), GFP_KERNEL); ++ if (!dpt) { ++ i915_gem_object_put(dpt_obj); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ vm = &dpt->vm; ++ ++ vm->gt = &i915->gt; ++ vm->i915 = i915; ++ vm->dma = i915->drm.dev; ++ vm->total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE; ++ vm->is_dpt = true; ++ ++ i915_address_space_init(vm, VM_CLASS_DPT); ++ ++ vm->insert_page = dpt_insert_page; ++ vm->clear_range = dpt_clear_range; ++ vm->insert_entries = dpt_insert_entries; ++ vm->cleanup = dpt_cleanup; ++ ++ vm->vma_ops.bind_vma = dpt_bind_vma; ++ vm->vma_ops.unbind_vma = dpt_unbind_vma; ++ vm->vma_ops.set_pages = ggtt_set_pages; ++ vm->vma_ops.clear_pages = clear_pages; ++ ++ vm->pte_encode = gen8_ggtt_pte_encode; ++ ++ dpt->obj = dpt_obj; ++ ++ return &dpt->vm; ++} ++ ++void intel_dpt_destroy(struct i915_address_space *vm) ++{ ++ struct i915_dpt *dpt = i915_vm_to_dpt(vm); ++ ++ i915_vm_close(&dpt->vm); ++} +diff --git a/drivers/gpu/drm/i915/display/intel_dpt.h b/drivers/gpu/drm/i915/display/intel_dpt.h +new file mode 100644 +index 0000000000000..45142b8f849f6 +--- /dev/null ++++ b/drivers/gpu/drm/i915/display/intel_dpt.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * Copyright © 2021 Intel Corporation ++ */ ++ ++#ifndef __INTEL_DPT_H__ ++#define __INTEL_DPT_H__ ++ ++struct i915_address_space; ++struct i915_vma; ++struct intel_framebuffer; ++ ++void intel_dpt_destroy(struct i915_address_space *vm); ++struct i915_vma *intel_dpt_pin(struct i915_address_space *vm); ++void intel_dpt_unpin(struct i915_address_space *vm); ++struct i915_address_space * ++intel_dpt_create(struct intel_framebuffer *fb); ++ ++#endif /* __INTEL_DPT_H__ */ +-- +2.34.1 + diff --git a/queue-5.15/drm-i915-don-t-call-free_mmap_offset-when-purging.patch b/queue-5.15/drm-i915-don-t-call-free_mmap_offset-when-purging.patch new file mode 100644 index 00000000000..dc87f7b0865 --- /dev/null +++ b/queue-5.15/drm-i915-don-t-call-free_mmap_offset-when-purging.patch @@ -0,0 +1,80 @@ +From 6df27b9017b57b841b65e9935baafae2e60aa06e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Jan 2022 17:49:07 +0000 +Subject: drm/i915: don't call free_mmap_offset when purging +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Matthew Auld + +[ Upstream commit 4c2602ba8d74c35d550ed3d518809c697de08d88 ] + +The TTM backend is in theory the only user here(also purge should only +be called once we have dropped the pages), where it is setup at object +creation and is only removed once the object is destroyed. Also +resetting the node here might be iffy since the ttm fault handler +uses the stored fake offset to determine the page offset within the pages +array. + +This also blows up in the dontneed-before-mmap test, since the +expectation is that the vma_node will live on, until the object is +destroyed: + +<2> [749.062902] kernel BUG at drivers/gpu/drm/i915/gem/i915_gem_ttm.c:943! +<4> [749.062923] invalid opcode: 0000 [#1] PREEMPT SMP NOPTI +<4> [749.062928] CPU: 0 PID: 1643 Comm: gem_madvise Tainted: G U W 5.16.0-rc8-CI-CI_DRM_11046+ #1 +<4> [749.062933] Hardware name: Gigabyte Technology Co., Ltd. GB-Z390 Garuda/GB-Z390 Garuda-CF, BIOS IG1c 11/19/2019 +<4> [749.062937] RIP: 0010:i915_ttm_mmap_offset.cold.35+0x5b/0x5d [i915] +<4> [749.063044] Code: 00 48 c7 c2 a0 23 4e a0 48 c7 c7 26 df 4a a0 e8 95 1d d0 e0 bf 01 00 00 00 e8 8b ec cf e0 31 f6 bf 09 00 00 00 e8 5f 30 c0 e0 <0f> 0b 48 c7 c1 24 4b 56 a0 ba 5b 03 00 00 48 c7 c6 c0 23 4e a0 48 +<4> [749.063052] RSP: 0018:ffffc90002ab7d38 EFLAGS: 00010246 +<4> [749.063056] RAX: 0000000000000240 RBX: ffff88811f2e61c0 RCX: 0000000000000006 +<4> [749.063060] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000009 +<4> [749.063063] RBP: ffffc90002ab7e58 R08: 0000000000000001 R09: 0000000000000001 +<4> [749.063067] R10: 000000000123d0f8 R11: ffffc90002ab7b20 R12: ffff888112a1a000 +<4> [749.063071] R13: 0000000000000004 R14: ffff88811f2e61c0 R15: ffff888112a1a000 +<4> [749.063074] FS: 00007f6e5fcad500(0000) GS:ffff8884ad600000(0000) knlGS:0000000000000000 +<4> [749.063078] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +<4> [749.063081] CR2: 00007efd264e39f0 CR3: 0000000115fd6005 CR4: 00000000003706f0 +<4> [749.063085] Call Trace: +<4> [749.063087] +<4> [749.063089] __assign_mmap_offset+0x41/0x300 [i915] +<4> [749.063171] __assign_mmap_offset_handle+0x159/0x270 [i915] +<4> [749.063248] ? i915_gem_dumb_mmap_offset+0x70/0x70 [i915] +<4> [749.063325] drm_ioctl_kernel+0xae/0x140 +<4> [749.063330] drm_ioctl+0x201/0x3d0 +<4> [749.063333] ? i915_gem_dumb_mmap_offset+0x70/0x70 [i915] +<4> [749.063409] ? do_user_addr_fault+0x200/0x670 +<4> [749.063415] __x64_sys_ioctl+0x6d/0xa0 +<4> [749.063419] do_syscall_64+0x3a/0xb0 +<4> [749.063423] entry_SYSCALL_64_after_hwframe+0x44/0xae +<4> [749.063428] RIP: 0033:0x7f6e5f100317 + +Testcase: igt/gem_madvise/dontneed-before-mmap +Fixes: cf3e3e86d779 ("drm/i915: Use ttm mmap handling for ttm bo's.") +Signed-off-by: Matthew Auld +Cc: Thomas Hellström +Reviewed-by: Thomas Hellström +Link: https://patchwork.freedesktop.org/patch/msgid/20220106174910.280616-1-matthew.auld@intel.com +(cherry picked from commit 658a0c632625e1db51837ff754fe18a6a7f2ccf8) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/gem/i915_gem_pages.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c +index 8d6c38a622016..9053cea3395a6 100644 +--- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c ++++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c +@@ -162,7 +162,6 @@ int i915_gem_object_pin_pages_unlocked(struct drm_i915_gem_object *obj) + /* Immediately discard the backing storage */ + void i915_gem_object_truncate(struct drm_i915_gem_object *obj) + { +- drm_gem_free_mmap_offset(&obj->base); + if (obj->ops->truncate) + obj->ops->truncate(obj); + } +-- +2.34.1 + diff --git a/queue-5.15/drm-i915-workaround-broken-bios-dbuf-configuration-o.patch b/queue-5.15/drm-i915-workaround-broken-bios-dbuf-configuration-o.patch new file mode 100644 index 00000000000..33168779fbb --- /dev/null +++ b/queue-5.15/drm-i915-workaround-broken-bios-dbuf-configuration-o.patch @@ -0,0 +1,151 @@ +From f37369add07a90e7fa0b7df826e27f7bae06c6ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 4 Feb 2022 16:18:18 +0200 +Subject: drm/i915: Workaround broken BIOS DBUF configuration on TGL/RKL +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit 4e6f55120c7eccf6f9323bb681632e23cbcb3f3c ] + +On TGL/RKL the BIOS likes to use some kind of bogus DBUF layout +that doesn't match what the spec recommends. With a single active +pipe that is not going to be a problem, but with multiple pipes +active skl_commit_modeset_enables() goes into an infinite loop +since it can't figure out any order in which it can commit the +pipes without causing DBUF overlaps between the planes. + +We'd need some kind of extra DBUF defrag stage in between to +make the transition possible. But that is clearly way too complex +a solution, so in the name of simplicity let's just sanitize the +DBUF state by simply turning off all planes when we detect a +pipe encroaching on its neighbours' DBUF slices. We only have +to disable the primary planes as all other planes should have +already been disabled (if they somehow were enabled) by +earlier sanitization steps. + +And for good measure let's also sanitize in case the DBUF +allocations of the pipes already seem to overlap each other. + +Cc: # v5.14+ +Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/4762 +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20220204141818.1900-3-ville.syrjala@linux.intel.com +Reviewed-by: Stanislav Lisovskiy +(cherry picked from commit 15512021eb3975a8c2366e3883337e252bb0eee5) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/intel_display.c | 1 + + drivers/gpu/drm/i915/intel_pm.c | 68 ++++++++++++++++++++ + drivers/gpu/drm/i915/intel_pm.h | 1 + + 3 files changed, 70 insertions(+) + +diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c +index 625ce6975eeba..dd9cfb193432c 100644 +--- a/drivers/gpu/drm/i915/display/intel_display.c ++++ b/drivers/gpu/drm/i915/display/intel_display.c +@@ -13217,6 +13217,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev, + vlv_wm_sanitize(dev_priv); + } else if (DISPLAY_VER(dev_priv) >= 9) { + skl_wm_get_hw_state(dev_priv); ++ skl_wm_sanitize(dev_priv); + } else if (HAS_PCH_SPLIT(dev_priv)) { + ilk_wm_get_hw_state(dev_priv); + } +diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c +index 9c5e4758947b6..c7c8a556e401a 100644 +--- a/drivers/gpu/drm/i915/intel_pm.c ++++ b/drivers/gpu/drm/i915/intel_pm.c +@@ -6681,6 +6681,74 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) + dbuf_state->enabled_slices = dev_priv->dbuf.enabled_slices; + } + ++static bool skl_dbuf_is_misconfigured(struct drm_i915_private *i915) ++{ ++ const struct intel_dbuf_state *dbuf_state = ++ to_intel_dbuf_state(i915->dbuf.obj.state); ++ struct skl_ddb_entry entries[I915_MAX_PIPES] = {}; ++ struct intel_crtc *crtc; ++ ++ for_each_intel_crtc(&i915->drm, crtc) { ++ const struct intel_crtc_state *crtc_state = ++ to_intel_crtc_state(crtc->base.state); ++ ++ entries[crtc->pipe] = crtc_state->wm.skl.ddb; ++ } ++ ++ for_each_intel_crtc(&i915->drm, crtc) { ++ const struct intel_crtc_state *crtc_state = ++ to_intel_crtc_state(crtc->base.state); ++ u8 slices; ++ ++ slices = skl_compute_dbuf_slices(crtc, dbuf_state->active_pipes, ++ dbuf_state->joined_mbus); ++ if (dbuf_state->slices[crtc->pipe] & ~slices) ++ return true; ++ ++ if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.ddb, entries, ++ I915_MAX_PIPES, crtc->pipe)) ++ return true; ++ } ++ ++ return false; ++} ++ ++void skl_wm_sanitize(struct drm_i915_private *i915) ++{ ++ struct intel_crtc *crtc; ++ ++ /* ++ * On TGL/RKL (at least) the BIOS likes to assign the planes ++ * to the wrong DBUF slices. This will cause an infinite loop ++ * in skl_commit_modeset_enables() as it can't find a way to ++ * transition between the old bogus DBUF layout to the new ++ * proper DBUF layout without DBUF allocation overlaps between ++ * the planes (which cannot be allowed or else the hardware ++ * may hang). If we detect a bogus DBUF layout just turn off ++ * all the planes so that skl_commit_modeset_enables() can ++ * simply ignore them. ++ */ ++ if (!skl_dbuf_is_misconfigured(i915)) ++ return; ++ ++ drm_dbg_kms(&i915->drm, "BIOS has misprogrammed the DBUF, disabling all planes\n"); ++ ++ for_each_intel_crtc(&i915->drm, crtc) { ++ struct intel_plane *plane = to_intel_plane(crtc->base.primary); ++ const struct intel_plane_state *plane_state = ++ to_intel_plane_state(plane->base.state); ++ struct intel_crtc_state *crtc_state = ++ to_intel_crtc_state(crtc->base.state); ++ ++ if (plane_state->uapi.visible) ++ intel_plane_disable_noatomic(crtc, plane); ++ ++ drm_WARN_ON(&i915->drm, crtc_state->active_planes != 0); ++ ++ memset(&crtc_state->wm.skl.ddb, 0, sizeof(crtc_state->wm.skl.ddb)); ++ } ++} ++ + static void ilk_pipe_wm_get_hw_state(struct intel_crtc *crtc) + { + struct drm_device *dev = crtc->base.dev; +diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h +index 91f23b7f0af2e..79d89fe22d8c8 100644 +--- a/drivers/gpu/drm/i915/intel_pm.h ++++ b/drivers/gpu/drm/i915/intel_pm.h +@@ -48,6 +48,7 @@ void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc, + struct skl_pipe_wm *out); + void g4x_wm_sanitize(struct drm_i915_private *dev_priv); + void vlv_wm_sanitize(struct drm_i915_private *dev_priv); ++void skl_wm_sanitize(struct drm_i915_private *dev_priv); + bool intel_can_enable_sagv(struct drm_i915_private *dev_priv, + const struct intel_bw_state *bw_state); + void intel_sagv_pre_plane_update(struct intel_atomic_state *state); +-- +2.34.1 + diff --git a/queue-5.15/drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-ex.patch b/queue-5.15/drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-ex.patch new file mode 100644 index 00000000000..32489dfce12 --- /dev/null +++ b/queue-5.15/drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-ex.patch @@ -0,0 +1,268 @@ +From 460c08e7fbc77dbfe90b71ecd174041ef795413f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 31 Jan 2022 09:55:20 +0100 +Subject: drm/mediatek: mtk_dsi: Avoid EPROBE_DEFER loop with external bridge +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: AngeloGioacchino Del Regno + +[ Upstream commit 647474b8d980256b26b1cd112d7333a4dbd4260a ] + +DRM bridge drivers are now attaching their DSI device at probe time, +which requires us to register our DSI host in order to let the bridge +to probe: this recently started producing an endless -EPROBE_DEFER +loop on some machines that are using external bridges, like the +parade-ps8640, found on the ACER Chromebook R13. + +Now that the DSI hosts/devices probe sequence is documented, we can +do adjustments to the mtk_dsi driver as to both fix now and make sure +to avoid this situation in the future: for this, following what is +documented in drm_bridge.c, move the mtk_dsi component_add() to the +mtk_dsi_ops.attach callback and delete it in the detach callback; +keeping in mind that we are registering a drm_bridge for our DSI, +which is only used/attached if the DSI Host is bound, it wouldn't +make sense to keep adding our bridge at probe time (as it would +be useless to have it if mtk_dsi_ops.attach() fails!), so also move +that one to the dsi host attach function (and remove it in detach). + +Cc: # 5.15.x +Signed-off-by: AngeloGioacchino Del Regno +Reviewed-by: Andrzej Hajda +Reviewed-by: Jagan Teki +Tested-by: Nícolas F. R. A. Prado +Signed-off-by: Chun-Kuang Hu +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_dsi.c | 167 +++++++++++++++-------------- + 1 file changed, 84 insertions(+), 83 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index 5d90d2eb00193..bced4c7d668e3 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -786,18 +786,101 @@ void mtk_dsi_ddp_stop(struct device *dev) + mtk_dsi_poweroff(dsi); + } + ++static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi) ++{ ++ int ret; ++ ++ ret = drm_simple_encoder_init(drm, &dsi->encoder, ++ DRM_MODE_ENCODER_DSI); ++ if (ret) { ++ DRM_ERROR("Failed to encoder init to drm\n"); ++ return ret; ++ } ++ ++ dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev); ++ ++ ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, ++ DRM_BRIDGE_ATTACH_NO_CONNECTOR); ++ if (ret) ++ goto err_cleanup_encoder; ++ ++ dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder); ++ if (IS_ERR(dsi->connector)) { ++ DRM_ERROR("Unable to create bridge connector\n"); ++ ret = PTR_ERR(dsi->connector); ++ goto err_cleanup_encoder; ++ } ++ drm_connector_attach_encoder(dsi->connector, &dsi->encoder); ++ ++ return 0; ++ ++err_cleanup_encoder: ++ drm_encoder_cleanup(&dsi->encoder); ++ return ret; ++} ++ ++static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) ++{ ++ int ret; ++ struct drm_device *drm = data; ++ struct mtk_dsi *dsi = dev_get_drvdata(dev); ++ ++ ret = mtk_dsi_encoder_init(drm, dsi); ++ if (ret) ++ return ret; ++ ++ return device_reset_optional(dev); ++} ++ ++static void mtk_dsi_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct mtk_dsi *dsi = dev_get_drvdata(dev); ++ ++ drm_encoder_cleanup(&dsi->encoder); ++} ++ ++static const struct component_ops mtk_dsi_component_ops = { ++ .bind = mtk_dsi_bind, ++ .unbind = mtk_dsi_unbind, ++}; ++ + static int mtk_dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) + { + struct mtk_dsi *dsi = host_to_dsi(host); ++ struct device *dev = host->dev; ++ int ret; + + dsi->lanes = device->lanes; + dsi->format = device->format; + dsi->mode_flags = device->mode_flags; ++ dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); ++ if (IS_ERR(dsi->next_bridge)) ++ return PTR_ERR(dsi->next_bridge); ++ ++ drm_bridge_add(&dsi->bridge); ++ ++ ret = component_add(host->dev, &mtk_dsi_component_ops); ++ if (ret) { ++ DRM_ERROR("failed to add dsi_host component: %d\n", ret); ++ drm_bridge_remove(&dsi->bridge); ++ return ret; ++ } + + return 0; + } + ++static int mtk_dsi_host_detach(struct mipi_dsi_host *host, ++ struct mipi_dsi_device *device) ++{ ++ struct mtk_dsi *dsi = host_to_dsi(host); ++ ++ component_del(host->dev, &mtk_dsi_component_ops); ++ drm_bridge_remove(&dsi->bridge); ++ return 0; ++} ++ + static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi) + { + int ret; +@@ -938,73 +1021,14 @@ static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host, + + static const struct mipi_dsi_host_ops mtk_dsi_ops = { + .attach = mtk_dsi_host_attach, ++ .detach = mtk_dsi_host_detach, + .transfer = mtk_dsi_host_transfer, + }; + +-static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi) +-{ +- int ret; +- +- ret = drm_simple_encoder_init(drm, &dsi->encoder, +- DRM_MODE_ENCODER_DSI); +- if (ret) { +- DRM_ERROR("Failed to encoder init to drm\n"); +- return ret; +- } +- +- dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev); +- +- ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, +- DRM_BRIDGE_ATTACH_NO_CONNECTOR); +- if (ret) +- goto err_cleanup_encoder; +- +- dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder); +- if (IS_ERR(dsi->connector)) { +- DRM_ERROR("Unable to create bridge connector\n"); +- ret = PTR_ERR(dsi->connector); +- goto err_cleanup_encoder; +- } +- drm_connector_attach_encoder(dsi->connector, &dsi->encoder); +- +- return 0; +- +-err_cleanup_encoder: +- drm_encoder_cleanup(&dsi->encoder); +- return ret; +-} +- +-static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) +-{ +- int ret; +- struct drm_device *drm = data; +- struct mtk_dsi *dsi = dev_get_drvdata(dev); +- +- ret = mtk_dsi_encoder_init(drm, dsi); +- if (ret) +- return ret; +- +- return device_reset_optional(dev); +-} +- +-static void mtk_dsi_unbind(struct device *dev, struct device *master, +- void *data) +-{ +- struct mtk_dsi *dsi = dev_get_drvdata(dev); +- +- drm_encoder_cleanup(&dsi->encoder); +-} +- +-static const struct component_ops mtk_dsi_component_ops = { +- .bind = mtk_dsi_bind, +- .unbind = mtk_dsi_unbind, +-}; +- + static int mtk_dsi_probe(struct platform_device *pdev) + { + struct mtk_dsi *dsi; + struct device *dev = &pdev->dev; +- struct drm_panel *panel; + struct resource *regs; + int irq_num; + int ret; +@@ -1021,19 +1045,6 @@ static int mtk_dsi_probe(struct platform_device *pdev) + return ret; + } + +- ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, +- &panel, &dsi->next_bridge); +- if (ret) +- goto err_unregister_host; +- +- if (panel) { +- dsi->next_bridge = devm_drm_panel_bridge_add(dev, panel); +- if (IS_ERR(dsi->next_bridge)) { +- ret = PTR_ERR(dsi->next_bridge); +- goto err_unregister_host; +- } +- } +- + dsi->driver_data = of_device_get_match_data(dev); + + dsi->engine_clk = devm_clk_get(dev, "engine"); +@@ -1098,14 +1109,6 @@ static int mtk_dsi_probe(struct platform_device *pdev) + dsi->bridge.of_node = dev->of_node; + dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; + +- drm_bridge_add(&dsi->bridge); +- +- ret = component_add(&pdev->dev, &mtk_dsi_component_ops); +- if (ret) { +- dev_err(&pdev->dev, "failed to add component: %d\n", ret); +- goto err_unregister_host; +- } +- + return 0; + + err_unregister_host: +@@ -1118,8 +1121,6 @@ static int mtk_dsi_remove(struct platform_device *pdev) + struct mtk_dsi *dsi = platform_get_drvdata(pdev); + + mtk_output_dsi_disable(dsi); +- drm_bridge_remove(&dsi->bridge); +- component_del(&pdev->dev, &mtk_dsi_component_ops); + mipi_dsi_host_unregister(&dsi->host); + + return 0; +-- +2.34.1 + diff --git a/queue-5.15/drm-mediatek-mtk_dsi-reset-the-dsi0-hardware.patch b/queue-5.15/drm-mediatek-mtk_dsi-reset-the-dsi0-hardware.patch new file mode 100644 index 00000000000..930b0122b57 --- /dev/null +++ b/queue-5.15/drm-mediatek-mtk_dsi-reset-the-dsi0-hardware.patch @@ -0,0 +1,55 @@ +From 0b673f13350208b4d5a98cb41ab106975cbfaa4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Sep 2021 10:31:50 +0200 +Subject: drm/mediatek: mtk_dsi: Reset the dsi0 hardware + +From: Enric Balletbo i Serra + +[ Upstream commit 605c83753d97946aab176735020a33ebfb0b4615 ] + +Reset dsi0 HW to default when power on. This prevents to have different +settingis between the bootloader and the kernel. + +As not all Mediatek boards have the reset consumer configured in their +board description, also is not needed on all of them, the reset is optional, +so the change is compatible with all boards. + +Cc: Jitao Shi +Suggested-by: Chun-Kuang Hu +Signed-off-by: Enric Balletbo i Serra +Acked-by: Chun-Kuang Hu +Reviewed-by: Matthias Brugger +Link: https://lore.kernel.org/r/20210930103105.v4.7.Idbb4727ddf00ba2fe796b630906baff10d994d89@changeid +Signed-off-by: Matthias Brugger +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_dsi.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index 93b40c245f007..5d90d2eb00193 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include