Update Linux kernel release to v7.2.8-2 for base and BORE kernels

Signed-off-by: Krzysztof Wilczyński <kwilczynski@omarchy.org>
This commit is contained in:
Krzysztof Wilczyński committed 2026-10-06 16:10:37 +09:00
1 parent 69c8193e2a
commit 8d103ac6e3
524 files changed
+147294 -88760

No files matched your search

@@ -1,5 +1,4 @@
diff --git a/kernel/fork.c b/kernel/fork.c
index f0e2e131a9a5..7b611da9a27a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -127,6 +127,12 @@
@@ -15,7 +14,7 @@ index f0e2e131a9a5..7b611da9a27a 100644
/*
* Minimum number of threads to boot the kernel
*/
@@ -2093,6 +2099,11 @@ __latent_entropy struct task_struct *copy_process(
@@ -2092,6 +2098,11 @@ __latent_entropy struct task_struct *copy_process(
return ERR_PTR(-EPERM);
}
@@ -27,7 +26,7 @@ index f0e2e131a9a5..7b611da9a27a 100644
/*
* Force any signals received before this point to be delivered
* before the fork happens. Collect up signals sent to multiple
@@ -3163,6 +3174,10 @@ static int check_unshare_flags(unsigned long unshare_flags)
@@ -3165,6 +3176,10 @@ static int check_unshare_flags(unsigned long unshare_flags)
if (!current_is_single_threaded())
return -EINVAL;
}
@@ -38,7 +37,7 @@ index f0e2e131a9a5..7b611da9a27a 100644
return 0;
}
@@ -3398,6 +3413,15 @@ static const struct ctl_table fork_sysctl_table[] = {
@@ -3400,6 +3415,15 @@ static const struct ctl_table fork_sysctl_table[] = {
.mode = 0644,
.proc_handler = sysctl_max_threads,
},
@@ -177,7 +177,7 @@ diff --git a/kernel/fork.c b/kernel/fork.c
#include <trace/events/sched.h>
#define CREATE_TRACE_POINTS
@@ -2441,6 +2445,11 @@ __latent_entropy struct task_struct *copy_process(
@@ -2443,6 +2447,11 @@ __latent_entropy struct task_struct *copy_process(
p->start_time = ktime_get_ns();
p->start_boottime = ktime_get_boottime_ns();
@@ -189,7 +189,7 @@ diff --git a/kernel/fork.c b/kernel/fork.c
/*
* Make it visible to the rest of the system, but dont wake it up yet.
* Need tasklist lock for parent etc handling!
@@ -2526,7 +2535,11 @@ __latent_entropy struct task_struct *copy_process(
@@ -2528,7 +2537,11 @@ __latent_entropy struct task_struct *copy_process(
p->real_parent->signal->is_child_subreaper;
if (clone_flags & CLONE_AUTOREAP)
p->signal->autoreap = 1;
@@ -749,7 +749,7 @@ diff --git a/kernel/sched/core.c b/kernel/sched/core.c
struct load_weight lw;
if (task_has_idle_policy(p)) {
@@ -8975,6 +8983,10 @@ void __init sched_init(void)
@@ -8989,6 +8997,10 @@ void __init sched_init(void)
BUG_ON(!sched_class_above(&ext_sched_class, &idle_sched_class));
#endif
@@ -934,7 +934,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
void __init sched_init_granularity(void)
{
@@ -1083,7 +1108,11 @@ struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq)
@@ -1093,7 +1118,11 @@ struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq)
*/
static inline void set_protect_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
@@ -946,7 +946,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
u64 vprot = se->deadline;
if (sched_feat(RUN_TO_PARITY))
@@ -1160,8 +1189,17 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq, bool protect)
@@ -1170,8 +1199,17 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq, bool protect)
if (curr && (!curr->on_rq || !entity_eligible(cfs_rq, curr)))
curr = NULL;
@@ -966,7 +966,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
/* Pick the leftmost entity if it's eligible */
if (se && entity_eligible(cfs_rq, se)) {
@@ -1217,6 +1255,7 @@ struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq)
@@ -1227,6 +1265,7 @@ struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq)
/**************************************************************
* Scheduling class statistics methods:
*/
@@ -974,7 +974,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
int sched_update_scaling(void)
{
unsigned int factor = get_update_sysctl_factor();
@@ -1228,6 +1267,7 @@ int sched_update_scaling(void)
@@ -1238,6 +1277,7 @@ int sched_update_scaling(void)
return 0;
}
@@ -982,7 +982,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se);
@@ -1971,6 +2011,38 @@ static void account_llc_dequeue(struct rq *rq, struct task_struct *p) {}
@@ -1979,6 +2019,38 @@ static void account_llc_dequeue(struct rq *rq, struct task_struct *p) {}
#endif /* CONFIG_SCHED_CACHE */
@@ -1021,7 +1021,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
/*
* Used by other classes to account runtime.
*/
@@ -2006,6 +2078,11 @@ static void update_curr(struct cfs_rq *cfs_rq)
@@ -2014,6 +2086,11 @@ static void update_curr(struct cfs_rq *cfs_rq)
resched = update_deadline(cfs_rq, curr);
if (entity_is_task(curr)) {
@@ -1033,7 +1033,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
/*
* If the fair_server is active, we need to account for the
* fair_server time whether or not the task is running on
@@ -4663,8 +4740,8 @@ rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
@@ -4671,8 +4748,8 @@ rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
se->vprot = div64_long(se->vprot * old_weight, weight);
}
@@ -1044,7 +1044,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
{
bool curr = cfs_rq->curr == se;
bool rel_vprot = false;
@@ -5967,13 +6044,12 @@ void __setparam_fair(struct task_struct *p, const struct sched_attr *attr)
@@ -5976,13 +6053,12 @@ void __setparam_fair(struct task_struct *p, const struct sched_attr *attr)
static void
place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
{
@@ -1059,7 +1059,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
/*
* Due to how V is constructed as the weighted average of entities,
@@ -6085,7 +6161,18 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
@@ -6094,7 +6170,18 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
se->rel_deadline = 0;
return;
}
@@ -1079,7 +1079,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
/*
* When joining the competition; the existing tasks will be,
* on average, halfway through their slice, as such start tasks
@@ -6094,6 +6181,9 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
@@ -6103,6 +6190,9 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
if (sched_feat(PLACE_DEADLINE_INITIAL) && (flags & ENQUEUE_INITIAL))
vslice /= 2;
@@ -1089,7 +1089,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
/*
* EEVDF: vd_i = ve_i + r_i/w_i
*/
@@ -6104,7 +6194,7 @@ static void check_enqueue_throttle(struct cfs_rq *cfs_rq);
@@ -6113,7 +6203,7 @@ static void check_enqueue_throttle(struct cfs_rq *cfs_rq);
static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq);
static void
@@ -1098,7 +1098,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
static void
enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
@@ -7767,7 +7857,7 @@ static int choose_idle_cpu(int cpu, struct task_struct *p)
@@ -7776,7 +7866,7 @@ static int choose_idle_cpu(int cpu, struct task_struct *p)
}
static void
@@ -1107,7 +1107,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
{
struct cfs_rq *cfs_rq = cfs_rq_of(se);
@@ -7785,7 +7875,13 @@ requeue_delayed_entity(struct sched_entity *se)
@@ -7794,7 +7884,13 @@ requeue_delayed_entity(struct sched_entity *se)
cfs_rq->nr_queued--;
if (se != cfs_rq->curr)
__dequeue_entity(cfs_rq, se);
@@ -1122,7 +1122,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
if (se != cfs_rq->curr)
__enqueue_entity(cfs_rq, se);
cfs_rq->nr_queued++;
@@ -7824,7 +7920,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
@@ -7833,7 +7929,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
util_est_enqueue(&rq->cfs, p);
if (flags & ENQUEUE_DELAYED) {
@@ -1131,7 +1131,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
return;
}
@@ -7842,7 +7938,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
@@ -7851,7 +7947,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
for_each_sched_entity(se) {
if (se->on_rq) {
if (se->sched_delayed)
@@ -1140,7 +1140,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
break;
}
cfs_rq = cfs_rq_of(se);
@@ -8045,6 +8141,15 @@ static bool dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
@@ -8054,6 +8150,15 @@ static bool dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
if (!p->se.sched_delayed)
util_est_dequeue(&rq->cfs, p);
@@ -1156,7 +1156,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
if (dequeue_entities(rq, &p->se, flags) < 0)
return false;
@@ -9850,6 +9955,18 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f
@@ -9860,6 +9965,18 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f
goto pick;
}
@@ -1175,7 +1175,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
/*
* Ignore wakee preemption on WF_FORK as it is less likely that
* there is shared data as exec often follow fork. Do not
@@ -10020,16 +10137,25 @@ static void yield_task_fair(struct rq *rq)
@@ -10030,16 +10147,25 @@ static void yield_task_fair(struct rq *rq)
/*
* Are we the only task in the tree?
*/
@@ -1201,7 +1201,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
/*
* Tell update_rq_clock() that we've just updated,
* so we don't do microscopic update in schedule()
@@ -15010,6 +15136,9 @@ static void switched_to_fair(struct rq *rq, struct task_struct *p)
@@ -15022,6 +15148,9 @@ static void switched_to_fair(struct rq *rq, struct task_struct *p)
WARN_ON_ONCE(p->se.sched_delayed);
attach_task_cfs_rq(p);
+33 -214
View File
@@ -22,19 +22,6 @@ diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable
typedef struct page *pgtable_t;
extern pteval_t __supported_pte_mask;
diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h
--- a/arch/x86/include/asm/pkeys.h
+++ b/arch/x86/include/asm/pkeys.h
@@ -88,6 +88,9 @@ int mm_pkey_alloc(struct mm_struct *mm)
u16 all_pkeys_mask = ((1U << arch_max_pkey()) - 1);
int ret;
+ if (!arch_pkeys_enabled())
+ return -1;
+
/*
* Are we out of pkeys? We must handle this specially
* because ffz() behavior is undefined if there are no
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -168,35 +155,7 @@ diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -62,18 +62,18 @@ enum cpa_warn {
static const int cpa_warn_level = CPA_PROTECT;
/*
- * Serialize cpa() (for !DEBUG_PAGEALLOC which uses large identity mappings)
- * using cpa_lock. So that we don't allow any other cpu, with stale large tlb
- * entries change the page attribute in parallel to some other cpu
- * splitting a large page entry along with changing the attribute.
+ * Serialize cpa() using cpa_lock so that we don't allow any other cpu, with
+ * stale large tlb entries, to change the page attribute in parallel to some
+ * other cpu splitting a large page entry along with changing the attribute.
*/
static DEFINE_SPINLOCK(cpa_lock);
-#define CPA_FLUSHTLB 1
-#define CPA_ARRAY 2
-#define CPA_PAGES_ARRAY 4
-#define CPA_NO_CHECK_ALIAS 8 /* Do not search for aliases */
-#define CPA_COLLAPSE 16 /* try to collapse large pages */
+#define CPA_FLUSHTLB 0x01
+#define CPA_ARRAY 0x02
+#define CPA_PAGES_ARRAY 0x04
+#define CPA_NO_CHECK_ALIAS 0x08 /* Do not search for aliases */
+#define CPA_COLLAPSE 0x10 /* try to collapse large pages */
+#define CPA_DEBUG_PAGEALLOC 0x20
static inline pgprot_t cachemode2pgprot(enum page_cache_mode pcm)
{
@@ -86,9 +86,8 @@ static unsigned long direct_pages_count[PG_LEVEL_NUM];
@@ -88,9 +88,8 @@ static unsigned long direct_pages_count[PG_LEVEL_NUM];
void update_page_count(int level, unsigned long pages)
{
/* Protect against CPA */
@@ -207,16 +166,37 @@ diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
}
static void split_page_count(int level)
@@ -418,6 +417,8 @@ static void cpa_collapse_large_pages(struct cpa_data *cpa)
@@ -420,7 +419,7 @@ static void __cpa_collapse_large_pages(struct cpa_data *cpa)
int collapsed = 0;
int i;
- spin_lock(&cpa_lock);
+ guard(spinlock)(&cpa_lock);
+
if (cpa->flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) {
for (i = 0; i < cpa->numpages; i++)
collapsed += collapse_large_pages(__cpa_addr(cpa, i),
@@ -888,24 +889,23 @@ static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte)
@@ -435,10 +434,8 @@ static void __cpa_collapse_large_pages(struct cpa_data *cpa)
collapsed += collapse_large_pages(addr, &pgtables);
}
- if (!collapsed) {
- spin_unlock(&cpa_lock);
+ if (!collapsed)
return;
- }
flush_tlb_all();
@@ -454,8 +451,6 @@ static void __cpa_collapse_large_pages(struct cpa_data *cpa)
else
pagetable_free(ptdesc);
}
-
- spin_unlock(&cpa_lock);
}
static void cpa_collapse_large_pages(struct cpa_data *cpa)
@@ -916,24 +911,23 @@ static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte)
{
/* change init_mm */
set_pte_atomic(kpte, pte);
@@ -246,7 +226,7 @@ diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
}
static pgprot_t pgprot_clear_protnone_bits(pgprot_t prot)
@@ -1075,16 +1075,11 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address,
@@ -1103,16 +1097,11 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address,
static int should_split_large_page(pte_t *kpte, unsigned long address,
struct cpa_data *cpa)
{
@@ -265,7 +245,7 @@ diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
}
static void split_set_pte(struct cpa_data *cpa, pte_t *pte, unsigned long pfn,
@@ -1135,16 +1130,14 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,
@@ -1162,16 +1151,14 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,
bool nx, rw;
pte_t *tmp;
@@ -284,7 +264,7 @@ diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
paravirt_alloc_pte(&init_mm, page_to_pfn(base));
@@ -1177,7 +1170,6 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,
@@ -1204,7 +1191,6 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,
break;
default:
@@ -292,7 +272,7 @@ diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
return 1;
}
@@ -1225,7 +1217,6 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,
@@ -1252,7 +1238,6 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,
* just split large page entry.
*/
flush_tlb_all();
@@ -300,21 +280,7 @@ diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
return 0;
}
@@ -1235,11 +1226,9 @@ static int split_large_page(struct cpa_data *cpa, pte_t *kpte,
{
struct ptdesc *ptdesc;
- if (!debug_pagealloc_enabled())
- spin_unlock(&cpa_lock);
+ spin_unlock(&cpa_lock);
ptdesc = pagetable_alloc(GFP_KERNEL, 0);
- if (!debug_pagealloc_enabled())
- spin_lock(&cpa_lock);
+ spin_lock(&cpa_lock);
if (!ptdesc)
return -ENOMEM;
@@ -1298,11 +1287,11 @@ static int collapse_pmd_page(pmd_t *pmd, unsigned long addr,
@@ -1327,11 +1312,11 @@ static int collapse_pmd_page(pmd_t *pmd, unsigned long addr,
list_add(&page_ptdesc(pmd_page(old_pmd))->pt_list, pgtables);
if (IS_ENABLED(CONFIG_X86_32)) {
@@ -329,7 +295,7 @@ diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
p4d_t *p4d = p4d_offset(pgd, addr);
pud_t *pud = pud_offset(p4d, addr);
pmd_t *pmd = pmd_offset(pud, addr);
@@ -1376,7 +1365,7 @@ static int collapse_pud_page(pud_t *pud, unsigned long addr,
@@ -1405,7 +1390,7 @@ static int collapse_pud_page(pud_t *pud, unsigned long addr,
*/
static int collapse_large_pages(unsigned long addr, struct list_head *pgtables)
{
@@ -338,7 +304,7 @@ diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
pgd_t *pgd;
p4d_t *p4d;
pud_t *pud;
@@ -1384,26 +1373,24 @@ static int collapse_large_pages(unsigned long addr, struct list_head *pgtables)
@@ -1413,26 +1398,24 @@ static int collapse_large_pages(unsigned long addr, struct list_head *pgtables)
addr &= PMD_MASK;
@@ -370,153 +336,6 @@ diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
return collapsed;
}
@@ -2004,6 +1991,7 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int primary)
{
unsigned long numpages = cpa->numpages;
unsigned long rempages = numpages;
+ bool lock = true;
int ret = 0;
/*
@@ -2013,6 +2001,29 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int primary)
!cpa->force_split)
return ret;
+ /*
+ * DEBUG_PAGEALLOC is special; it is called from any context the
+ * page-allocator is, which violates the normal cpa_lock locking
+ * rules.
+ *
+ * However, since it is part of the page-allocator, things are still
+ * properly serialized by the page-allocator locking and the fact that
+ * when a page is owned by the page-allocator, it isn't owned by
+ * anybody else. That is, you *SHOULD NOT* be calling cpa() on memory
+ * that isn't allocated.
+ *
+ * Additionally, DEBUG_PAGEALLOC ensures (per probe_page_size_mask())
+ * that the kernel mapping is 4k pages, therefore there are no large
+ * pages to split/collapse.
+ *
+ * Furthermore, the page-allocator strictly manages pages that
+ * *exist*, avoiding pgd_lock.
+ *
+ * Therefore, it is safe to not take cpa_lock.
+ */
+ if (debug_pagealloc_enabled() && (cpa->flags & CPA_DEBUG_PAGEALLOC))
+ lock = false;
+
while (rempages) {
/*
* Store the remaining nr of pages for the large page
@@ -2023,11 +2034,12 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int primary)
if (cpa->flags & (CPA_ARRAY | CPA_PAGES_ARRAY))
cpa->numpages = 1;
- if (!debug_pagealloc_enabled())
- spin_lock(&cpa_lock);
- ret = __change_page_attr(cpa, primary);
- if (!debug_pagealloc_enabled())
- spin_unlock(&cpa_lock);
+ if (lock) {
+ guard(spinlock)(&cpa_lock);
+ ret = __change_page_attr(cpa, primary);
+ } else {
+ ret = __change_page_attr(cpa, primary);
+ }
if (ret)
goto out;
@@ -2606,7 +2618,7 @@ int set_pages_rw(struct page *page, int numpages)
return set_memory_rw(addr, numpages);
}
-static int __set_pages_p(struct page *page, int numpages)
+static int __set_pages_p(struct page *page, int numpages, unsigned int cpa_flags)
{
unsigned long tempaddr = (unsigned long) page_address(page);
struct cpa_data cpa = { .vaddr = &tempaddr,
@@ -2614,7 +2626,7 @@ static int __set_pages_p(struct page *page, int numpages)
.numpages = numpages,
.mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW),
.mask_clr = __pgprot(0),
- .flags = CPA_NO_CHECK_ALIAS };
+ .flags = CPA_NO_CHECK_ALIAS | cpa_flags };
/*
* No alias checking needed for setting present flag. otherwise,
@@ -2625,7 +2637,7 @@ static int __set_pages_p(struct page *page, int numpages)
return __change_page_attr_set_clr(&cpa, 1);
}
-static int __set_pages_np(struct page *page, int numpages)
+static int __set_pages_np(struct page *page, int numpages, unsigned int cpa_flags)
{
unsigned long tempaddr = (unsigned long) page_address(page);
struct cpa_data cpa = { .vaddr = &tempaddr,
@@ -2633,7 +2645,7 @@ static int __set_pages_np(struct page *page, int numpages)
.numpages = numpages,
.mask_set = __pgprot(0),
.mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY),
- .flags = CPA_NO_CHECK_ALIAS };
+ .flags = CPA_NO_CHECK_ALIAS | cpa_flags };
/*
* No alias checking needed for setting not present flag. otherwise,
@@ -2646,20 +2658,20 @@ static int __set_pages_np(struct page *page, int numpages)
int set_direct_map_invalid_noflush(struct page *page)
{
- return __set_pages_np(page, 1);
+ return __set_pages_np(page, 1, 0);
}
int set_direct_map_default_noflush(struct page *page)
{
- return __set_pages_p(page, 1);
+ return __set_pages_p(page, 1, 0);
}
int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid)
{
if (valid)
- return __set_pages_p(page, nr);
+ return __set_pages_p(page, nr, 0);
- return __set_pages_np(page, nr);
+ return __set_pages_np(page, nr, 0);
}
#ifdef CONFIG_DEBUG_PAGEALLOC
@@ -2678,15 +2690,23 @@ void __kernel_map_pages(struct page *page, int numpages, int enable)
* and hence no memory allocations during large page split.
*/
if (enable)
- __set_pages_p(page, numpages);
+ __set_pages_p(page, numpages, CPA_DEBUG_PAGEALLOC);
else
- __set_pages_np(page, numpages);
+ __set_pages_np(page, numpages, CPA_DEBUG_PAGEALLOC);
/*
- * We should perform an IPI and flush all tlbs,
- * but that can deadlock->flush only current cpu.
- * Preemption needs to be disabled around __flush_tlb_all() due to
- * CR3 reload in __native_flush_tlb().
+ * We should perform an IPI and flush all tlbs, but that can
+ * deadlock, settle for a local flush.
+ *
+ * Not doing a global TLB flush means that remote CPUs will retain
+ * stale TLB entries. In case of P->NP (on free) this means the remote
+ * CPUs will not take the faults, making the debug scheme less
+ * reliable. On the NP->P (on alloc) this means the remote CPUs can
+ * take a spurious fault. However spurious_kernel_fault() will observe
+ * *_present() and fix it up.
+ *
+ * Preemption needs to be disabled around __flush_tlb_all() due to CR3
+ * reload in __native_flush_tlb().
*/
preempt_disable();
__flush_tlb_all();
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
Binary file not shown.
@@ -1,7 +1,7 @@
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -13464,12 +13464,15 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
@@ -13476,12 +13476,15 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
* still unbalanced. ld_moved simply stays zero, so it is
* correctly treated as an imbalance.
*/
@@ -1,23 +0,0 @@
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3751,11 +3751,17 @@ static inline void ttwu_do_wakeup(struct task_struct *p)
void update_rq_avg_idle(struct rq *rq)
{
- u64 delta = rq_clock(rq) - rq->idle_stamp;
- u64 max = 2*rq->max_idle_balance_cost;
+ u64 idle_stamp = rq->idle_stamp;
+ u64 delta, max;
+
+ if (!idle_stamp)
+ return;
+
+ delta = rq_clock(rq) - idle_stamp;
update_avg(&rq->avg_idle, delta);
+ max = 2 * rq->max_idle_balance_cost;
if (rq->avg_idle > max)
rq->avg_idle = max;
rq->idle_stamp = 0;
@@ -212,7 +212,7 @@ diff --git a/include/linux/vtime.h b/include/linux/vtime.h
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5099,7 +5099,7 @@ static inline void prepare_task(struct task_struct *next)
@@ -5106,7 +5106,7 @@ static inline void prepare_task(struct task_struct *next)
WRITE_ONCE(next->on_cpu, 1);
}
@@ -221,7 +221,7 @@ diff --git a/kernel/sched/core.c b/kernel/sched/core.c
{
/*
* This must be the very last reference to @prev from this CPU. After
@@ -5143,7 +5143,7 @@ static void zap_balance_callbacks(struct rq *rq)
@@ -5150,7 +5150,7 @@ static void zap_balance_callbacks(struct rq *rq)
rq->balance_callback = found ? &balance_push_callback : NULL;
}
@@ -230,7 +230,7 @@ diff --git a/kernel/sched/core.c b/kernel/sched/core.c
{
void (*func)(struct rq *rq);
struct balance_callback *next;
@@ -5178,7 +5178,7 @@ struct balance_callback balance_push_callback = {
@@ -5185,7 +5185,7 @@ struct balance_callback balance_push_callback = {
.func = balance_push,
};
@@ -239,7 +239,7 @@ diff --git a/kernel/sched/core.c b/kernel/sched/core.c
__splice_balance_callbacks(struct rq *rq, bool split)
{
struct balance_callback *head = rq->balance_callback;
@@ -5252,7 +5252,7 @@ prepare_lock_switch(struct rq *rq, struct task_struct *next, struct rq_flags *rf
@@ -5259,7 +5259,7 @@ prepare_lock_switch(struct rq *rq, struct task_struct *next, struct rq_flags *rf
__acquire(__rq_lockp(this_rq()));
}
@@ -248,7 +248,7 @@ diff --git a/kernel/sched/core.c b/kernel/sched/core.c
__releases(__rq_lockp(rq))
{
/*
@@ -5286,7 +5286,7 @@ static inline void kmap_local_sched_out(void)
@@ -5293,7 +5293,7 @@ static inline void kmap_local_sched_out(void)
#endif
}
@@ -257,7 +257,7 @@ diff --git a/kernel/sched/core.c b/kernel/sched/core.c
{
#ifdef CONFIG_KMAP_LOCAL
if (unlikely(current->kmap_ctrl.idx))
@@ -5340,7 +5340,7 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
@@ -5347,7 +5347,7 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
* past. 'prev == current' is still correct but we need to recalculate this_rq
* because prev may have moved to another CPU.
*/
@@ -1,21 +1,7 @@
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -3026,8 +3026,8 @@ static struct task_struct *pick_next_pushable_dl_task(struct rq *rq)
next_node = rb_first_cached(&rq->dl.pushable_dl_tasks_root);
while (next_node) {
i = __node_2_pdl(next_node);
- /* make sure task isn't on_cpu (possible with proxy-exec) */
- if (!task_on_cpu(rq, i)) {
+ /* skip tasks that cannot be migrated */
+ if (!task_on_cpu(rq, i) && !is_migration_disabled(i)) {
p = i;
break;
}
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -10691,17 +10691,40 @@ static enum llc_mig can_migrate_llc(int src_cpu, int dst_cpu,
@@ -10701,17 +10701,40 @@ static enum llc_mig can_migrate_llc(int src_cpu, int dst_cpu,
return mig_llc;
}
@@ -58,7 +44,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
mm = p->mm;
if (!mm)
return mig_unrestricted;
@@ -10758,6 +10781,14 @@ alb_break_llc(struct lb_env *env)
@@ -10768,6 +10791,14 @@ alb_break_llc(struct lb_env *env)
unsigned long util = 0;
struct task_struct *cur;
@@ -73,7 +59,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
if (env->src_rq->nr_running <= 1)
return true;
@@ -10765,7 +10796,8 @@ alb_break_llc(struct lb_env *env)
@@ -10775,7 +10806,8 @@ alb_break_llc(struct lb_env *env)
if (cur && cur->sched_class == &fair_sched_class)
util = task_util(cur);
@@ -83,7 +69,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
util, false) == mig_forbid)
return true;
}
@@ -10805,8 +10837,7 @@ static bool migrate_degrades_llc(struct task_struct *p, struct lb_env *env)
@@ -10815,8 +10847,7 @@ static bool migrate_degrades_llc(struct task_struct *p, struct lb_env *env)
READ_ONCE(p->preferred_llc) != llc_id(env->dst_cpu))
return true;
@@ -93,7 +79,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
return false;
return true;
@@ -11869,6 +11900,15 @@ static inline bool llc_balance(struct lb_env *env, struct sg_lb_stats *sgs,
@@ -11879,6 +11910,15 @@ static inline bool llc_balance(struct lb_env *env, struct sg_lb_stats *sgs,
if (env->sd->flags & SD_SHARE_LLC)
return false;
@@ -109,17 +95,3 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
/*
* Skip cache aware tagging if nr_balanced_failed is sufficiently high.
* Threshold of cache_nice_tries is set to 1 higher than nr_balance_failed
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1871,8 +1871,8 @@ static struct task_struct *pick_next_pushable_task(struct rq *rq)
return NULL;
plist_for_each_entry(i, head, pushable_tasks) {
- /* make sure task isn't on_cpu (possible with proxy-exec) */
- if (!task_on_cpu(rq, i)) {
+ /* skip tasks that cannot be migrated */
+ if (!task_on_cpu(rq, i) && !is_migration_disabled(i)) {
p = i;
break;
}
@@ -1,24 +0,0 @@
diff --git a/arch/x86/kernel/itmt.c b/arch/x86/kernel/itmt.c
--- a/arch/x86/kernel/itmt.c
+++ b/arch/x86/kernel/itmt.c
@@ -110,18 +110,14 @@ int sched_set_itmt_support(void)
arch_debugfs_dir,
&sysctl_sched_itmt_enabled,
&dfs_sched_itmt_fops);
- if (IS_ERR_OR_NULL(dfs_sched_itmt)) {
+ if (IS_ERR(dfs_sched_itmt))
dfs_sched_itmt = NULL;
- return -ENOMEM;
- }
dfs_sched_core_prio = debugfs_create_file("sched_core_priority", 0644,
arch_debugfs_dir, NULL,
&sched_core_priority_fops);
- if (IS_ERR_OR_NULL(dfs_sched_core_prio)) {
+ if (IS_ERR(dfs_sched_core_prio))
dfs_sched_core_prio = NULL;
- return -ENOMEM;
- }
sched_itmt_capable = true;
@@ -14,22 +14,22 @@ diff --git a/include/linux/sched/sd_flags.h b/include/linux/sched/sd_flags.h
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -12028,10 +12028,25 @@ static inline void update_sg_lb_stats(struct lb_env *env,
@@ -12038,12 +12038,25 @@ static inline void update_sg_lb_stats(struct lb_env *env,
continue;
if (sd_flags & SD_ASYM_CPUCAPACITY) {
- /* Check for a misfit task on the cpu */
- if (sgs->group_misfit_task_load < rq->misfit_task_load) {
- sgs->group_misfit_task_load = rq->misfit_task_load;
- *sg_overloaded = 1;
-
+ if (rq->misfit_task_load) {
+ /*
+ * Always mark the root domain overloaded so big
+ * CPUs can pick up misfit tasks via newly idle
+ * balance.
+ */
+ if (balancing_at_rd)
+ *sg_overloaded = 1;
if (balancing_at_rd)
*sg_overloaded = 1;
+
+ /*
+ * Only account misfit load if @dst_cpu can
@@ -44,43 +44,7 @@ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
}
} else if (env->idle && sched_reduced_capacity(rq, env->sd)) {
/* Check for a task running on a CPU with reduced capacity */
@@ -12110,6 +12125,17 @@ static bool update_sd_pick_busiest(struct lb_env *env,
sds->local_stat.group_type != group_has_spare))
return false;
+ /*
+ * Candidate sg has no more than one task per CPU and has higher
+ * per-CPU capacity. Migrating tasks to less capable CPUs may harm
+ * throughput. Maximize throughput, power/energy consequences are not
+ * considered.
+ */
+ if ((env->sd->flags & SD_ASYM_CPUCAPACITY) &&
+ (sgs->group_type <= group_fully_busy) &&
+ (capacity_greater(sg->sgc->min_capacity, capacity_of(env->dst_cpu))))
+ return false;
+
if (sgs->group_type > busiest->group_type)
return true;
@@ -12216,17 +12242,6 @@ static bool update_sd_pick_busiest(struct lb_env *env,
break;
}
- /*
- * Candidate sg has no more than one task per CPU and has higher
- * per-CPU capacity. Migrating tasks to less capable CPUs may harm
- * throughput. Maximize throughput, power/energy consequences are not
- * considered.
- */
- if ((env->sd->flags & SD_ASYM_CPUCAPACITY) &&
- (sgs->group_type <= group_fully_busy) &&
- (capacity_greater(sg->sgc->min_capacity, capacity_of(env->dst_cpu))))
- return false;
-
return true;
}
@@ -13144,9 +13159,24 @@ static struct rq *sched_balance_find_src_rq(struct lb_env *env,
@@ -13156,9 +13169,24 @@ static struct rq *sched_balance_find_src_rq(struct lb_env *env,
* average load.
*/
if (env->sd->flags & SD_ASYM_CPUCAPACITY &&
@@ -1,7 +1,7 @@
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -14050,29 +14050,62 @@ static inline int on_null_domain(struct rq *rq)
@@ -14060,29 +14060,62 @@ static inline int on_null_domain(struct rq *rq)
*/
static inline int find_new_ilb(void)
{
@@ -1,61 +0,0 @@
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -53,6 +53,7 @@
#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/moduleparam.h>
+#include <linux/pm_qos.h>
#include <linux/sysfs.h>
#include <asm/cpuid/api.h>
#include <asm/cpu_device_id.h>
@@ -2697,6 +2698,9 @@ static void __init cmdline_table_adjust(struct cpuidle_driver *drv)
pr_info("Failed to adjust C-states with data from 'intel_idle.table'\n");
}
+#define INTEL_IDLE_INIT_QOS 20
+static struct pm_qos_request qos_req __initdata;
+
static int __init intel_idle_init(void)
{
const struct x86_cpu_id *id;
@@ -2766,6 +2770,13 @@ static int __init intel_idle_init(void)
if (retval)
pr_warn("failed to initialized sysfs");
+ /*
+ * Some platforms, in particular the Intel S1200BTL motherboard, have a
+ * problem with using package idle states too early, so prevent that
+ * from taking place until the device_initcall() phase is over.
+ */
+ cpu_latency_qos_add_request(&qos_req, INTEL_IDLE_INIT_QOS);
+
retval = cpuidle_register_driver(&intel_idle_driver);
if (retval) {
struct cpuidle_driver *drv = cpuidle_get_driver();
@@ -2790,6 +2801,9 @@ static int __init intel_idle_init(void)
intel_idle_cpuidle_devices_uninit();
cpuidle_unregister_driver(&intel_idle_driver);
init_driver_fail:
+ if (cpu_latency_qos_request_active((&qos_req)))
+ cpu_latency_qos_remove_request(&qos_req);
+
intel_idle_sysfs_uninit();
free_percpu(intel_idle_cpuidle_devices);
return retval;
@@ -2797,6 +2811,15 @@ static int __init intel_idle_init(void)
}
subsys_initcall_sync(intel_idle_init);
+static int __init intel_idle_init_complete(void)
+{
+ if (cpu_latency_qos_request_active((&qos_req)))
+ cpu_latency_qos_remove_request(&qos_req);
+
+ return 0;
+}
+device_initcall_sync(intel_idle_init_complete);
+
/*
* We are not really modular, but we used to support that. Meaning we also
* support "intel_idle.max_cstate=..." at boot and also a read-only export of
Binary file not shown.
File diff suppressed because it is too large. Load diff
@@ -1,480 +0,0 @@
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -782,6 +782,7 @@ static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy,
static void amd_pstate_adjust_perf(struct cpufreq_policy *policy,
unsigned long _min_perf,
unsigned long target_perf,
+ unsigned long _max_perf,
unsigned long capacity)
{
u8 max_perf, min_perf, des_perf, cap_perf;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2225,14 +2225,17 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch);
* @policy: cpufreq policy object of the target CPU.
* @min_perf: Minimum (required) performance level (units of @capacity).
* @target_perf: Target (desired) performance level (units of @capacity).
+ * @max_perf: Maximum (allowed) performance level (units of @capacity).
* @capacity: Capacity of the target CPU.
*
- * Carry out a fast performance level switch of @cpu without sleeping.
+ * Carry out a fast performance level adjustment for the CPU represented by
+ * @policy without sleeping.
*
* The driver's ->adjust_perf() callback invoked by this function must be
- * suitable for being called from within RCU-sched read-side critical sections
- * and it is expected to select a suitable performance level equal to or above
- * @min_perf and preferably equal to or below @target_perf.
+ * suitable for calling from within RCU-sched read-side critical sections and
+ * it is expected to program the processor to select suitable performance
+ * levels between @min_perf and @max_perf inclusive and preferably close to
+ * @target_perf going forward for the CPU represented by @policy.
*
* This function must not be called if policy->fast_switch_enabled is unset.
*
@@ -2244,9 +2247,10 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch);
void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
+ unsigned long max_perf,
unsigned long capacity)
{
- cpufreq_driver->adjust_perf(policy, min_perf, target_perf, capacity);
+ cpufreq_driver->adjust_perf(policy, min_perf, target_perf, max_perf, capacity);
}
/**
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -299,7 +299,6 @@ struct pstate_funcs {
static struct pstate_funcs pstate_funcs __read_mostly;
static bool hwp_active __ro_after_init;
-static int hwp_mode_bdw __ro_after_init;
static bool per_cpu_limits __ro_after_init;
static bool hwp_forced __ro_after_init;
static bool hwp_boost __read_mostly;
@@ -587,21 +586,14 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
hwp_is_hybrid = true;
- cpu->pstate.turbo_freq = rounddown(cpu->pstate.turbo_pstate * scaling,
- perf_ctl_scaling);
- cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling,
- perf_ctl_scaling);
-
freq = perf_ctl_max_phys * perf_ctl_scaling;
cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq);
- freq = cpu->pstate.min_pstate * perf_ctl_scaling;
- cpu->pstate.min_freq = freq;
/*
* Cast the min P-state value retrieved via pstate_funcs.get_min() to
* the effective range of HWP performance levels.
*/
- cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq);
+ cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, cpu->pstate.min_freq);
}
static bool turbo_is_disabled(void)
@@ -979,12 +971,10 @@ static int hybrid_get_cost(struct device *dev, unsigned long freq,
* capacity. Similarly, P-cores start to be populated when E-cores are
* utilized above 60% of the capacity.
*/
- if (hybrid_get_cpu_type(dev->id) == INTEL_CPU_TYPE_ATOM) {
- if (hybrid_has_l3(dev->id)) /* E-core */
- *cost += 1;
- } else { /* P-core */
+ if (hybrid_get_cpu_type(dev->id) == INTEL_CPU_TYPE_CORE) /* P-core */
*cost += 2;
- }
+ else if (hybrid_has_l3(dev->id)) /* E-core */
+ *cost += 1;
return 0;
}
@@ -1185,6 +1175,22 @@ static bool hybrid_clear_max_perf_cpu(void)
return ret;
}
+static void intel_pstate_update_freq_limits(struct cpudata *cpu)
+{
+ int scaling = cpu->pstate.scaling;
+ unsigned int turbo_freq = cpu->pstate.turbo_pstate * scaling;
+ unsigned int max_freq = cpu->pstate.max_pstate * scaling;
+ int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
+
+ if (scaling != perf_ctl_scaling) {
+ turbo_freq = rounddown(turbo_freq, perf_ctl_scaling);
+ max_freq = rounddown(max_freq, perf_ctl_scaling);
+ }
+
+ cpu->pstate.turbo_freq = turbo_freq;
+ cpu->pstate.max_freq = max_freq;
+}
+
static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
{
u64 cap;
@@ -1197,20 +1203,8 @@ static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
static void intel_pstate_get_hwp_cap(struct cpudata *cpu)
{
- int scaling = cpu->pstate.scaling;
-
__intel_pstate_get_hwp_cap(cpu);
-
- cpu->pstate.max_freq = cpu->pstate.max_pstate * scaling;
- cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * scaling;
- if (scaling != cpu->pstate.perf_ctl_scaling) {
- int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
-
- cpu->pstate.max_freq = rounddown(cpu->pstate.max_freq,
- perf_ctl_scaling);
- cpu->pstate.turbo_freq = rounddown(cpu->pstate.turbo_freq,
- perf_ctl_scaling);
- }
+ intel_pstate_update_freq_limits(cpu);
}
static void hybrid_update_capacity(struct cpudata *cpu)
@@ -2299,33 +2293,16 @@ static int hwp_get_cpu_scaling(int cpu)
return intel_pstate_cppc_get_scaling(cpu);
}
-static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
-{
- trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
- cpu->pstate.current_pstate = pstate;
- /*
- * Generally, there is no guarantee that this code will always run on
- * the CPU being updated, so force the register update to run on the
- * right CPU.
- */
- wrmsrq_on_cpu(cpu->cpu, MSR_IA32_PERF_CTL,
- pstate_funcs.get_val(cpu, pstate));
-}
-
-static void intel_pstate_set_min_pstate(struct cpudata *cpu)
-{
- intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
-}
-
static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
{
int perf_ctl_scaling = pstate_funcs.get_scaling();
cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical(cpu->cpu);
cpu->pstate.min_pstate = pstate_funcs.get_min(cpu->cpu);
+ cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
cpu->pstate.perf_ctl_scaling = perf_ctl_scaling;
- if (hwp_active && !hwp_mode_bdw) {
+ if (hwp_active) {
__intel_pstate_get_hwp_cap(cpu);
if (pstate_funcs.get_cpu_scaling) {
@@ -2345,19 +2322,13 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(cpu->cpu);
}
- if (cpu->pstate.scaling == perf_ctl_scaling) {
- cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
- cpu->pstate.max_freq = cpu->pstate.max_pstate * perf_ctl_scaling;
- cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * perf_ctl_scaling;
- }
+ intel_pstate_update_freq_limits(cpu);
if (pstate_funcs.get_aperf_mperf_shift)
cpu->aperf_mperf_shift = pstate_funcs.get_aperf_mperf_shift();
if (pstate_funcs.get_vid)
pstate_funcs.get_vid(cpu);
-
- intel_pstate_set_min_pstate(cpu);
}
/*
@@ -2884,8 +2855,22 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu,
cpu->min_perf_ratio);
}
+static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
+{
+ trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
+ cpu->pstate.current_pstate = pstate;
+ /*
+ * Generally, there is no guarantee that this code will always run on
+ * the CPU being updated, so force the register update to run on the
+ * right CPU.
+ */
+ wrmsrq_on_cpu(cpu->cpu, MSR_IA32_PERF_CTL,
+ pstate_funcs.get_val(cpu, pstate));
+}
+
static int intel_pstate_set_policy(struct cpufreq_policy *policy)
{
+ unsigned int freq = policy->min;
struct cpudata *cpu;
if (!policy->cpuinfo.max_freq)
@@ -2901,7 +2886,23 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
intel_pstate_update_perf_limits(cpu, policy->min, policy->max);
- if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) {
+ if (hwp_active) {
+ /*
+ * The active mode only requires an update util hook if HWP
+ * boost is used and the policy is not "performance".
+ */
+ if (hwp_boost && cpu->policy != CPUFREQ_POLICY_PERFORMANCE) {
+ intel_pstate_set_update_util_hook(policy->cpu);
+ } else {
+ intel_pstate_clear_update_util_hook(policy->cpu);
+ if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) {
+ freq = cpu->max_perf_ratio * cpu->pstate.scaling;
+ if (cpu->pstate.scaling != cpu->pstate.perf_ctl_scaling)
+ freq = rounddown(freq, cpu->pstate.perf_ctl_scaling);
+ }
+ }
+ intel_pstate_hwp_set(policy->cpu);
+ } else if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) {
int pstate = max(cpu->pstate.min_pstate, cpu->max_perf_ratio);
/*
@@ -2910,25 +2911,17 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
*/
intel_pstate_clear_update_util_hook(policy->cpu);
intel_pstate_set_pstate(cpu, pstate);
+ freq = pstate * cpu->pstate.scaling;
} else {
intel_pstate_set_update_util_hook(policy->cpu);
}
-
- if (hwp_active) {
- /*
- * When hwp_boost was active before and dynamically it
- * was turned off, in that case we need to clear the
- * update util hook.
- */
- if (!hwp_boost)
- intel_pstate_clear_update_util_hook(policy->cpu);
- intel_pstate_hwp_set(policy->cpu);
- }
/*
- * policy->cur is never updated with the intel_pstate driver, but it
- * is used as a stale frequency value. So, keep it within limits.
+ * policy->cur is never updated in the intel_pstate driver, but it is
+ * used as a stale frequency value, so set it to reflect the actual
+ * requested P-state in the "performance" policy case and to the min
+ * otherwise.
*/
- policy->cur = policy->min;
+ policy->cur = freq;
mutex_unlock(&intel_pstate_limits_lock);
@@ -2971,6 +2964,11 @@ static int intel_pstate_verify_policy(struct cpufreq_policy_data *policy)
return 0;
}
+static void intel_pstate_set_min_pstate(struct cpudata *cpu)
+{
+ intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
+}
+
static int intel_cpufreq_cpu_offline(struct cpufreq_policy *policy)
{
struct cpudata *cpu = all_cpu_data[policy->cpu];
@@ -3063,6 +3061,7 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy)
static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
{
int ret = __intel_pstate_cpu_init(policy);
+ struct cpudata *cpu;
if (ret)
return ret;
@@ -3073,11 +3072,11 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
*/
policy->policy = CPUFREQ_POLICY_POWERSAVE;
- if (hwp_active) {
- struct cpudata *cpu = all_cpu_data[policy->cpu];
-
+ cpu = all_cpu_data[policy->cpu];
+ if (hwp_active)
cpu->epp_cached = intel_pstate_get_epp(cpu, 0);
- }
+ else
+ intel_pstate_set_min_pstate(cpu);
return 0;
}
@@ -3243,6 +3242,7 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy,
static void intel_cpufreq_adjust_perf(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
+ unsigned long max_perf,
unsigned long capacity)
{
struct cpudata *cpu = all_cpu_data[policy->cpu];
@@ -3273,7 +3273,13 @@ static void intel_cpufreq_adjust_perf(struct cpufreq_policy *policy,
if (min_pstate > cpu->max_perf_ratio)
min_pstate = cpu->max_perf_ratio;
- max_pstate = min(cap_pstate, cpu->max_perf_ratio);
+ max_pstate = cap_pstate;
+ if (max_perf < capacity)
+ max_pstate = DIV_ROUND_UP(cap_pstate * max_perf, capacity);
+
+ if (max_pstate > cpu->max_perf_ratio)
+ max_pstate = cpu->max_perf_ratio;
+
if (max_pstate < min_pstate)
max_pstate = min_pstate;
@@ -3301,8 +3307,6 @@ static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy)
return ret;
policy->cpuinfo.transition_latency = INTEL_CPUFREQ_TRANSITION_LATENCY;
- /* This reflects the intel_pstate_get_cpu_pstates() setting. */
- policy->cur = policy->cpuinfo.min_freq;
req = kzalloc_objs(*req, 2);
if (!req) {
@@ -3323,9 +3327,15 @@ static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy)
WRITE_ONCE(cpu->hwp_req_cached, value);
cpu->epp_cached = intel_pstate_get_epp(cpu, value);
+
+ intel_cpufreq_hwp_update(cpu, cpu->pstate.min_pstate,
+ cpu->pstate.max_pstate,
+ cpu->pstate.min_pstate, false);
} else {
policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY;
+ intel_pstate_set_min_pstate(cpu);
}
+ policy->cur = policy->cpuinfo.min_freq;
freq = DIV_ROUND_UP(cpu->pstate.turbo_freq * global.min_perf_pct, 100);
@@ -3676,14 +3686,14 @@ static inline bool intel_pstate_has_acpi_ppc(void) { return false; }
static inline void intel_pstate_request_control_from_smm(void) {}
#endif /* CONFIG_ACPI */
-#define INTEL_PSTATE_HWP_BROADWELL 0x01
+#define INTEL_PSTATE_HWP_NOT_HYBRID 0x01
#define X86_MATCH_HWP(vfm, hwp_mode) \
X86_MATCH_VFM_FEATURE(vfm, X86_FEATURE_HWP, hwp_mode)
static const struct x86_cpu_id hwp_support_ids[] __initconst = {
- X86_MATCH_HWP(INTEL_BROADWELL_X, INTEL_PSTATE_HWP_BROADWELL),
- X86_MATCH_HWP(INTEL_BROADWELL_D, INTEL_PSTATE_HWP_BROADWELL),
+ X86_MATCH_HWP(INTEL_BROADWELL_X, INTEL_PSTATE_HWP_NOT_HYBRID),
+ X86_MATCH_HWP(INTEL_BROADWELL_D, INTEL_PSTATE_HWP_NOT_HYBRID),
X86_MATCH_HWP(INTEL_ANY, 0),
{}
};
@@ -3808,7 +3818,6 @@ static int __init intel_pstate_init(void)
if (!no_hwp) {
hwp_active = true;
- hwp_mode_bdw = id->driver_data;
intel_pstate.attr = hwp_cpufreq_attrs;
intel_cpufreq.attr = hwp_cpufreq_attrs;
intel_cpufreq.flags |= CPUFREQ_NEED_UPDATE_LIMITS;
@@ -3816,7 +3825,8 @@ static int __init intel_pstate_init(void)
if (!default_driver)
default_driver = &intel_pstate;
- pstate_funcs.get_cpu_scaling = hwp_get_cpu_scaling;
+ if (!id->driver_data)
+ pstate_funcs.get_cpu_scaling = hwp_get_cpu_scaling;
goto hwp_cpu_matched;
}
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -379,6 +379,7 @@ struct cpufreq_driver {
void (*adjust_perf)(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
+ unsigned long max_perf,
unsigned long capacity);
/*
@@ -624,6 +625,7 @@ unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy,
void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
+ unsigned long max_perf,
unsigned long capacity);
bool cpufreq_driver_has_adjust_perf(void);
int cpufreq_driver_target(struct cpufreq_policy *policy,
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -50,6 +50,7 @@ struct sugov_cpu {
unsigned long util;
unsigned long bw_min;
+ unsigned long bw_max;
/* The field below is for single-CPU policies only: */
#ifdef CONFIG_NO_HZ_COMMON
@@ -243,6 +244,7 @@ static void sugov_get_util(struct sugov_cpu *sg_cpu, unsigned long boost)
util = effective_cpu_util(sg_cpu->cpu, util, &min, &max);
util = max(util, boost);
sg_cpu->bw_min = min;
+ sg_cpu->bw_max = max;
sg_cpu->util = sugov_effective_cpu_perf(sg_cpu->cpu, util, min, max);
}
@@ -495,7 +497,7 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time,
sg_cpu->util = prev_util;
cpufreq_driver_adjust_perf(sg_policy->policy, sg_cpu->bw_min,
- sg_cpu->util, max_cap);
+ sg_cpu->util, sg_cpu->bw_max, max_cap);
sg_policy->need_freq_update = false;
sg_policy->last_freq_update_time = time;
diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -792,7 +792,13 @@ fn fast_switch(_policy: &mut Policy, _target_freq: u32) -> u32 {
}
/// Driver's `adjust_perf` callback.
- fn adjust_perf(_policy: &mut Policy, _min_perf: usize, _target_perf: usize, _capacity: usize) {
+ fn adjust_perf(
+ _policy: &mut Policy,
+ _min_perf: usize,
+ _target_perf: usize,
+ _max_perf: usize,
+ _capacity: usize,
+ ) {
build_error!(VTABLE_DEFAULT_ERROR)
}
@@ -1263,12 +1269,13 @@ impl<T: Driver> Registration<T> {
ptr: *mut bindings::cpufreq_policy,
min_perf: c_ulong,
target_perf: c_ulong,
+ max_perf: c_ulong,
capacity: c_ulong,
) {
// SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
// lifetime of `policy`.
let policy = unsafe { Policy::from_raw_mut(ptr) };
- T::adjust_perf(policy, min_perf, target_perf, capacity);
+ T::adjust_perf(policy, min_perf, target_perf, max_perf, capacity);
}
/// Driver's `get_intermediate` callback.
Binary file not shown.
@@ -1,127 +0,0 @@
diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c
--- a/drivers/cpufreq/amd-pstate-ut.c
+++ b/drivers/cpufreq/amd-pstate-ut.c
@@ -560,6 +560,11 @@ static int amd_pstate_ut_check_freq_attrs(u32 index)
static int __init amd_pstate_ut_init(void)
{
u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases);
+ enum amd_pstate_mode mode = amd_pstate_get_status();
+
+ /* don't test if no running amd-pstate driver */
+ if (mode == AMD_PSTATE_UNDEFINED || mode == AMD_PSTATE_DISABLE)
+ return -EOPNOTSUPP;
for (i = 0; i < arr_size; i++) {
int ret;
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -199,7 +199,7 @@ static inline int get_mode_idx_from_str(const char *str, size_t size)
static DEFINE_MUTEX(amd_pstate_driver_lock);
-static u8 msr_get_epp(struct amd_cpudata *cpudata)
+static int msr_get_epp(struct amd_cpudata *cpudata)
{
u64 value;
int ret;
@@ -215,12 +215,12 @@ static u8 msr_get_epp(struct amd_cpudata *cpudata)
DEFINE_STATIC_CALL(amd_pstate_get_epp, msr_get_epp);
-static inline s16 amd_pstate_get_epp(struct amd_cpudata *cpudata)
+static inline int amd_pstate_get_epp(struct amd_cpudata *cpudata)
{
return static_call(amd_pstate_get_epp)(cpudata);
}
-static u8 shmem_get_epp(struct amd_cpudata *cpudata)
+static int shmem_get_epp(struct amd_cpudata *cpudata)
{
u64 epp;
int ret;
@@ -526,9 +526,6 @@ static int shmem_init_perf(struct amd_cpudata *cpudata)
WRITE_ONCE(cpudata->perf, perf);
WRITE_ONCE(cpudata->prefcore_ranking, cppc_perf.highest_perf);
- if (cppc_state == AMD_PSTATE_ACTIVE)
- return 0;
-
ret = cppc_get_auto_sel(cpudata->cpu, &auto_sel);
if (ret) {
pr_warn("failed to get auto_sel, ret: %d\n", ret);
@@ -1174,6 +1171,9 @@ static int amd_pstate_power_supply_notifier(struct notifier_block *nb,
if (cpudata->current_profile != PLATFORM_PROFILE_BALANCED)
return 0;
+ if (!policy)
+ return NOTIFY_OK;
+
epp = amd_pstate_get_balanced_epp(policy);
ret = amd_pstate_set_epp(policy, epp);
@@ -1209,6 +1209,9 @@ static int amd_pstate_profile_set(struct device *dev,
struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpudata->cpu);
int ret;
+ if (!policy)
+ return -ENODEV;
+
switch (profile) {
case PLATFORM_PROFILE_LOW_POWER:
ret = amd_pstate_set_epp(policy, AMD_CPPC_EPP_POWERSAVE);
@@ -1877,6 +1880,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
struct amd_cpudata *cpudata;
union perf_cached perf;
struct device *dev;
+ int default_epp;
int ret;
/*
@@ -1925,6 +1929,13 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
policy->boost_supported = READ_ONCE(cpudata->boost_supported);
+ /* Fetch the firmware programmed default EPP value */
+ default_epp = amd_pstate_get_epp(cpudata);
+ if (default_epp < 0) {
+ ret = default_epp;
+ goto free_cpudata1;
+ }
+
/*
* Set the policy to provide a valid fallback value in case
* the default cpufreq governor is neither powersave nor performance.
@@ -1932,7 +1943,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
if (amd_pstate_acpi_pm_profile_server() ||
amd_pstate_acpi_pm_profile_undefined()) {
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
- cpudata->epp_default_ac = cpudata->epp_default_dc = amd_pstate_get_epp(cpudata);
+ cpudata->epp_default_ac = cpudata->epp_default_dc = default_epp;
cpudata->current_profile = PLATFORM_PROFILE_PERFORMANCE;
} else {
policy->policy = CPUFREQ_POLICY_POWERSAVE;
diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
--- a/drivers/cpufreq/amd-pstate.h
+++ b/drivers/cpufreq/amd-pstate.h
@@ -32,6 +32,7 @@
* @min_limit_perf: Cached value of the performance corresponding to policy->min
* @max_limit_perf: Cached value of the performance corresponding to policy->max
* @bios_min_perf: Cached perf value corresponding to the "Requested CPU Min Frequency" BIOS option
+ * @val: Raw 64-bit value for atomic access via READ_ONCE()/WRITE_ONCE()
*/
union perf_cached {
struct {
@@ -89,7 +90,12 @@ struct amd_aperf_mperf {
* @epp_default_ac: Default EPP value for AC power source
* @epp_default_dc: Default EPP value for DC power source
* @dynamic_epp: Whether dynamic EPP is enabled
+ * @raw_epp: Whether the last EPP write was a raw numeric value rather than a
+ * named preference
* @power_nb: Notifier block for power events
+ * @current_profile: Currently selected platform profile option
+ * @ppdev: Device registered with the platform profile handler
+ * @profile_name: Name under which @ppdev is registered
*
* The amd_cpudata is key private data for each CPU thread in AMD P-State, and
* represents all the attributes and goals that AMD P-State requests at runtime.
@@ -0,0 +1,104 @@
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -453,8 +453,8 @@ int dev_pm_opp_get_opp_count(struct device *dev)
_find_opp_table(dev);
if (IS_ERR(opp_table)) {
- dev_dbg(dev, "%s: OPP table not found (%ld)\n",
- __func__, PTR_ERR(opp_table));
+ dev_dbg(dev, "%s: OPP table not found (%pe)\n",
+ __func__, opp_table);
return PTR_ERR(opp_table);
}
@@ -611,8 +611,8 @@ _find_key(struct device *dev, unsigned long *key, int index, bool available,
_find_opp_table(dev);
if (IS_ERR(opp_table)) {
- dev_err(dev, "%s: OPP table not found (%ld)\n", __func__,
- PTR_ERR(opp_table));
+ dev_err(dev, "%s: OPP table not found (%pe)\n", __func__,
+ opp_table);
return ERR_CAST(opp_table);
}
@@ -722,8 +722,8 @@ struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev,
struct opp_table *opp_table __free(put_opp_table) = _find_opp_table(dev);
if (IS_ERR(opp_table)) {
- dev_err(dev, "%s: OPP table not found (%ld)\n", __func__,
- PTR_ERR(opp_table));
+ dev_err(dev, "%s: OPP table not found (%pe)\n", __func__,
+ opp_table);
return ERR_CAST(opp_table);
}
@@ -1036,8 +1036,8 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
/* Regulator not available for device */
if (IS_ERR(reg)) {
- dev_dbg(dev, "%s: regulator not available: %ld\n", __func__,
- PTR_ERR(reg));
+ dev_dbg(dev, "%s: regulator not available: %pe\n", __func__,
+ reg);
return 0;
}
@@ -1448,8 +1448,8 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
temp_freq = freq;
opp = _find_freq_ceil(opp_table, &temp_freq);
if (IS_ERR(opp)) {
- dev_err(dev, "%s: failed to find OPP for freq %lu (%ld)\n",
- __func__, freq, PTR_ERR(opp));
+ dev_err(dev, "%s: failed to find OPP for freq %lu (%pe)\n",
+ __func__, freq, opp);
return PTR_ERR(opp);
}
@@ -1581,6 +1581,8 @@ static struct opp_table *_update_opp_table_clk(struct device *dev,
struct opp_table *opp_table,
bool getclk)
{
+ int ret;
+
/*
* Return early if we don't need to get clk or we have already done it
* earlier.
@@ -1607,9 +1609,9 @@ static struct opp_table *_update_opp_table_clk(struct device *dev,
opp_table->clk = clk_get_optional(dev, NULL);
if (IS_ERR(opp_table->clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(opp_table->clk), "Couldn't find clock\n");
dev_pm_opp_put_opp_table(opp_table);
- dev_err_probe(dev, PTR_ERR(opp_table->clk), "Couldn't find clock\n");
- return ERR_CAST(opp_table->clk);
+ return ERR_PTR(ret);
}
if (opp_table->clk)
@@ -2869,8 +2871,8 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
struct dev_pm_opp *opp __free(put_opp) = ERR_PTR(-ENODEV), *tmp_opp;
if (IS_ERR(opp_table)) {
- dev_warn(dev, "%s: Device OPP not found (%ld)\n", __func__,
- PTR_ERR(opp_table));
+ dev_warn(dev, "%s: Device OPP not found (%pe)\n", __func__,
+ opp_table);
return PTR_ERR(opp_table);
}
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -1345,8 +1345,8 @@ int of_get_required_opp_performance_state(struct device_node *np, int index)
_find_table_of_opp_np(required_np);
if (IS_ERR(opp_table)) {
- pr_err("%s: Failed to find required OPP table %pOF: %ld\n",
- __func__, np, PTR_ERR(opp_table));
+ pr_err("%s: Failed to find required OPP table %pOF: %pe\n",
+ __func__, np, opp_table);
return PTR_ERR(opp_table);
}
@@ -1,18 +0,0 @@
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -1929,12 +1929,13 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
policy->boost_supported = READ_ONCE(cpudata->boost_supported);
- /* Fetch the firmware programmed default EPP value */
+ /* Cache the firmware programmed EPP */
default_epp = amd_pstate_get_epp(cpudata);
if (default_epp < 0) {
ret = default_epp;
goto free_cpudata1;
}
+ FIELD_MODIFY(AMD_CPPC_EPP_PERF_MASK, &cpudata->cppc_req_cached, default_epp);
/*
* Set the policy to provide a valid fallback value in case
@@ -0,0 +1,54 @@
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -408,9 +408,18 @@ int hibernation_snapshot(int platform_mode)
if (error)
goto Close;
+ error = dpm_prepare(PMSG_FREEZE);
+ if (error)
+ goto Complete;
+
+ /* Preallocate image memory before freezing kernel threads and shutting down devices. */
+ error = hibernate_preallocate_memory();
+ if (error)
+ goto Complete;
+
error = freeze_kernel_threads();
if (error)
- goto Close;
+ goto Cleanup;
if (hibernation_test(TEST_FREEZER)) {
@@ -422,15 +431,6 @@ int hibernation_snapshot(int platform_mode)
goto Thaw;
}
- error = dpm_prepare(PMSG_FREEZE);
- if (error)
- goto Complete;
-
- /* Preallocate image memory before shutting down devices. */
- error = hibernate_preallocate_memory();
- if (error)
- goto Complete;
-
console_suspend_all();
pm_restrict_gfp_mask();
@@ -464,10 +464,12 @@ int hibernation_snapshot(int platform_mode)
platform_end(platform_mode);
return error;
- Complete:
- dpm_complete(PMSG_RECOVER);
Thaw:
thaw_kernel_threads();
+ Cleanup:
+ swsusp_free();
+ Complete:
+ dpm_complete(PMSG_RECOVER);
goto Close;
}
@@ -0,0 +1,61 @@
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2590,8 +2590,8 @@ static void cpufreq_update_pressure(struct cpufreq_policy *policy)
cpu = cpumask_first(policy->related_cpus);
max_freq = arch_scale_freq_ref(cpu);
- if (!max_freq)
- max_freq = policy->cpuinfo.max_freq;
+ if (!max_freq && cpufreq_driver->scale_freq_ref)
+ max_freq = cpufreq_driver->scale_freq_ref(policy);
capped_freq = policy->max;
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -1175,6 +1175,14 @@ static bool hybrid_clear_max_perf_cpu(void)
return ret;
}
+static unsigned int intel_pstate_scale_freq_ref(struct cpufreq_policy *policy)
+{
+ if (READ_ONCE(all_cpu_data[policy->cpu]->capacity_perf))
+ return policy->cpuinfo.max_freq;
+
+ return 0;
+}
+
static void intel_pstate_update_freq_limits(struct cpudata *cpu)
{
int scaling = cpu->pstate.scaling;
@@ -3092,6 +3100,7 @@ static struct cpufreq_driver intel_pstate = {
.offline = intel_pstate_cpu_offline,
.online = intel_pstate_cpu_online,
.update_limits = intel_pstate_update_limits,
+ .scale_freq_ref = intel_pstate_scale_freq_ref,
.name = "intel_pstate",
};
@@ -3415,6 +3424,7 @@ static struct cpufreq_driver intel_cpufreq = {
.suspend = intel_cpufreq_suspend,
.resume = intel_pstate_resume,
.update_limits = intel_pstate_update_limits,
+ .scale_freq_ref = intel_pstate_scale_freq_ref,
.name = "intel_cpufreq",
};
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -420,6 +420,9 @@ struct cpufreq_driver {
/* Will be called after the driver is fully initialized */
void (*ready)(struct cpufreq_policy *policy);
+ /* Return the capacity reference frequency for policy. */
+ unsigned int (*scale_freq_ref)(struct cpufreq_policy *policy);
+
struct freq_attr **attr;
/* platform specific boost support code */
@@ -278,25 +278,7 @@ diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -270,10 +270,15 @@ struct mem_cgroup {
#endif
int kmemcg_id;
- struct memcg_vmstats_percpu __percpu *vmstats_percpu;
-
#ifdef CONFIG_CGROUP_WRITEBACK
struct list_head cgwb_list;
+#endif
+
+ /* Keep the hot per-CPU stats pointer away from memory event counters. */
+ struct memcg_vmstats_percpu __percpu *vmstats_percpu
+ ____cacheline_aligned_in_smp;
+
+#ifdef CONFIG_CGROUP_WRITEBACK
struct wb_domain cgwb_domain;
struct memcg_cgwb_frn cgwb_frn[MEMCG_CGWB_FRN_CNT];
#endif
@@ -947,6 +952,8 @@ unsigned long memcg_page_state_output(struct mem_cgroup *memcg, int item);
@@ -952,6 +952,8 @@ unsigned long memcg_page_state_output(struct mem_cgroup *memcg, int item);
bool memcg_stat_item_valid(int idx);
bool memcg_vm_event_item_valid(enum vm_event_item idx);
unsigned long lruvec_page_state(struct lruvec *lruvec, enum node_stat_item idx);
@@ -305,7 +287,7 @@ diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
unsigned long lruvec_page_state_local(struct lruvec *lruvec,
enum node_stat_item idx);
@@ -1399,6 +1406,12 @@ static inline unsigned long lruvec_page_state(struct lruvec *lruvec,
@@ -1404,6 +1406,12 @@ static inline unsigned long lruvec_page_state(struct lruvec *lruvec,
return node_page_state(lruvec_pgdat(lruvec), idx);
}
@@ -576,66 +558,6 @@ diff --git a/lib/maple_tree.c b/lib/maple_tree.c
return wr_slot_store;
return wr_node_store;
@@ -3793,35 +3825,40 @@ int mas_alloc_cyclic(struct ma_state *mas, unsigned long *startp,
void *entry, unsigned long range_lo, unsigned long range_hi,
unsigned long *next, gfp_t gfp)
{
- unsigned long min = range_lo;
- int ret = 0;
+ int ret;
+ unsigned long min;
+
+ min = range_lo;
+ do {
+ range_lo = max(min, *next);
+ ret = mas_empty_area(mas, range_lo, range_hi, 1);
+ if (ret < 0 && range_lo > min) {
+ mas_reset(mas);
+ ret = mas_empty_area(mas, min, range_hi, 1);
+ if (ret == 0)
+ ret = 1;
+ }
+ if (ret < 0)
+ goto out;
+
+ mas_insert(mas, entry);
+ } while (mas_nomem(mas, gfp));
+
+ if (mas_is_err(mas)) {
+ ret = xa_err(mas->node);
+ goto out;
+ }
- range_lo = max(min, *next);
- ret = mas_empty_area(mas, range_lo, range_hi, 1);
if ((mas->tree->ma_flags & MT_FLAGS_ALLOC_WRAPPED) && ret == 0) {
mas->tree->ma_flags &= ~MT_FLAGS_ALLOC_WRAPPED;
ret = 1;
}
- if (ret < 0 && range_lo > min) {
- mas_reset(mas);
- ret = mas_empty_area(mas, min, range_hi, 1);
- if (ret == 0)
- ret = 1;
- }
- if (ret < 0)
- return ret;
-
- do {
- mas_insert(mas, entry);
- } while (mas_nomem(mas, gfp));
- if (mas_is_err(mas))
- return xa_err(mas->node);
-
*startp = mas->index;
*next = *startp + 1;
if (*next == 0)
mas->tree->ma_flags |= MT_FLAGS_ALLOC_WRAPPED;
+out:
mas_destroy(mas);
return ret;
}
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -898,24 +820,7 @@ diff --git a/mm/swap.c b/mm/swap.c
static void lru_activate(struct lruvec *lruvec, struct folio *folio)
{
long nr_pages = folio_nr_pages(folio);
@@ -1153,7 +1086,16 @@ static void lruvec_reparent_lru(struct lruvec *child_lruvec,
for_each_managed_zone_pgdat(zone, NODE_DATA(nid), zid, MAX_NR_ZONES - 1) {
unsigned long size = mem_cgroup_get_zone_lru_size(child_lruvec, lru, zid);
+ if (!size)
+ continue;
+
+ /*
+ * The folios are accounted to the parent from now on, so the
+ * size has to be moved, not just copied. Leaving it behind
+ * makes the dying child describe folios it no longer owns.
+ */
mem_cgroup_update_lru_size(parent_lruvec, lru, zid, size);
+ mem_cgroup_update_lru_size(child_lruvec, lru, zid, -(long)size);
}
}
@@ -1164,8 +1106,6 @@ void lru_reparent_memcg(struct mem_cgroup *memcg, struct mem_cgroup *parent, int
@@ -1173,8 +1106,6 @@ void lru_reparent_memcg(struct mem_cgroup *memcg, struct mem_cgroup *parent, int
child_lruvec = mem_cgroup_lruvec(memcg, NODE_DATA(nid));
parent_lruvec = mem_cgroup_lruvec(parent, NODE_DATA(nid));
@@ -1129,20 +1034,7 @@ diff --git a/mm/vmscan.c b/mm/vmscan.c
pte_t *pte = pvmw->pte;
unsigned long addr = pvmw->address;
struct vm_area_struct *vma = pvmw->vma;
@@ -4571,7 +4629,12 @@ void lru_gen_reparent_memcg(struct mem_cgroup *memcg, struct mem_cgroup *parent,
for_each_managed_zone_pgdat(zone, NODE_DATA(nid), zid, MAX_NR_ZONES - 1) {
unsigned long size = mem_cgroup_get_zone_lru_size(child_lruvec, lru, zid);
+ if (!size)
+ continue;
+
+ /* Move the accounting, do not duplicate it. */
mem_cgroup_update_lru_size(parent_lruvec, lru, zid, size);
+ mem_cgroup_update_lru_size(child_lruvec, lru, zid, -(long)size);
}
}
}
@@ -4814,7 +4877,8 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
@@ -4819,7 +4877,8 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
struct reclaim_stat stat;
struct lru_gen_mm_walk *walk;
int scanned, reclaimed;
@@ -1152,7 +1044,7 @@ diff --git a/mm/vmscan.c b/mm/vmscan.c
bool skip_retry = false;
struct mem_cgroup *memcg = lruvec_memcg(lruvec);
struct pglist_data *pgdat = lruvec_pgdat(lruvec);
@@ -4826,6 +4890,7 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
@@ -4831,6 +4890,7 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
scanned = isolate_folios(nr_to_scan, lruvec, sc, swappiness,
&list, &isolated, &type, &type_scanned);
@@ -1160,7 +1052,7 @@ diff --git a/mm/vmscan.c b/mm/vmscan.c
/* Scanning may have emptied the oldest gen, flush it */
if (scanned)
@@ -4838,6 +4903,7 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
@@ -4843,6 +4903,7 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
retry:
reclaimed = shrink_folio_list(&list, pgdat, sc, &stat, false, memcg);
sc->nr_reclaimed += reclaimed;
@@ -1168,7 +1060,7 @@ diff --git a/mm/vmscan.c b/mm/vmscan.c
/* Retry pass is only meant for clean folios without new isolation */
if (isolated)
handle_reclaim_writeback(isolated, pgdat, sc, &stat);
@@ -4887,6 +4953,10 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
@@ -4892,6 +4953,10 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
goto retry;
}
@@ -0,0 +1,35 @@
diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
--- a/mm/pgtable-generic.c
+++ b/mm/pgtable-generic.c
@@ -438,12 +438,30 @@ static void kernel_pgtable_work_func(struct work_struct *work)
__pagetable_free(pt);
}
+static void schedule_kernel_pgtable_free(void)
+{
+ schedule_work(&kernel_pgtable_work.work);
+}
+
void pagetable_free_kernel(struct ptdesc *pt)
{
spin_lock(&kernel_pgtable_work.lock);
list_add(&pt->pt_list, &kernel_pgtable_work.list);
spin_unlock(&kernel_pgtable_work.lock);
- schedule_work(&kernel_pgtable_work.work);
+ /*
+ * The workqueue may not exist yet while the system is booting.
+ * kernel_pgtable_drain_early() schedules the work once it does.
+ */
+ if (system_state != SYSTEM_BOOTING)
+ schedule_kernel_pgtable_free();
}
+
+static int __init kernel_pgtable_drain_early(void)
+{
+ /* Free the kernel page tables queued while booting. */
+ schedule_kernel_pgtable_free();
+ return 0;
+}
+core_initcall(kernel_pgtable_drain_early);
#endif
@@ -1,12 +0,0 @@
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -806,7 +806,7 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
pmdval_t val = pmd_val(pmd), oldval = val;
pmd_t pmd_result;
- val &= (_HPAGE_CHG_MASK & ~_PAGE_DIRTY);
+ val &= _HPAGE_CHG_MASK;
val |= check_pgprot(newprot) & ~_HPAGE_CHG_MASK;
val = flip_protnone_guard(oldval, val, PHYSICAL_PMD_PAGE_MASK);
File diff suppressed because it is too large. Load diff
Binary file not shown.
@@ -0,0 +1,92 @@
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -627,7 +627,7 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
ret = mark_block_group_to_copy(fs_info, src_device);
if (ret)
- return ret;
+ goto leave;
down_write(&dev_replace->rwsem);
dev_replace->replace_task = current;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -384,6 +384,7 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
inode_flags &= ~BTRFS_INODE_COMPRESS;
inode_flags |= BTRFS_INODE_NOCOMPRESS;
} else if (fsflags & FS_COMPR_FL) {
+ enum btrfs_compression_type comp_type;
if (IS_SWAPFILE(&inode->vfs_inode))
return -ETXTBSY;
@@ -391,9 +392,23 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
inode_flags |= BTRFS_INODE_COMPRESS;
inode_flags &= ~BTRFS_INODE_NOCOMPRESS;
- comp = btrfs_compress_type2str(fs_info->compress_type);
- if (!comp || comp[0] == 0)
- comp = btrfs_compress_type2str(BTRFS_COMPRESS_ZLIB);
+ /*
+ * Keep the algorithm recorded in the compression property,
+ * otherwise changing an unrelated attribute would reset it to
+ * the mount default, since FS_IOC_SETFLAGS callers write back
+ * the whole flag set they got from FS_IOC_GETFLAGS and that
+ * includes FS_COMPR_FL for any inode carrying the property.
+ *
+ * Inodes with the compress flag set but no property keep using
+ * the mount default, so they behave as before.
+ */
+ if (inode->prop_compress)
+ comp_type = inode->prop_compress;
+ else if (fs_info->compress_type)
+ comp_type = fs_info->compress_type;
+ else
+ comp_type = BTRFS_COMPRESS_ZLIB;
+ comp = btrfs_compress_type2str(comp_type);
} else {
inode_flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
}
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -6417,6 +6417,13 @@ static int process_extent(struct send_ctx *sctx,
if (S_ISLNK(sctx->cur_inode_mode))
return 0;
+ if (unlikely(!S_ISREG(sctx->cur_inode_mode))) {
+ btrfs_crit(sctx->send_root->fs_info,
+ "send: extent for non-regular inode %llu root %llu mode 0%llo",
+ key->objectid, btrfs_root_id(sctx->send_root),
+ sctx->cur_inode_mode & S_IFMT);
+ return -EUCLEAN;
+ }
if (sctx->parent_root && !sctx->cur_inode_new) {
ret = is_extent_unchanged(sctx, path, key);
diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -2710,6 +2710,7 @@ int btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 leng
{
struct btrfs_block_group *block_group;
u64 min_alloc_bytes;
+ int ret = 0;
if (!btrfs_is_zoned(fs_info))
return 0;
@@ -2729,11 +2730,11 @@ int btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 leng
block_group->start + block_group->zone_capacity)
goto out;
- do_zone_finish(block_group, true);
+ ret = do_zone_finish(block_group, true);
out:
btrfs_put_block_group(block_group);
- return 0;
+ return ret;
}
static void btrfs_zone_finish_endio_workfn(struct work_struct *work)
@@ -1,386 +0,0 @@
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -626,7 +626,7 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
ret = mark_block_group_to_copy(fs_info, src_device);
if (ret)
- return ret;
+ goto leave;
down_write(&dev_replace->rwsem);
dev_replace->replace_task = current;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3436,6 +3436,9 @@ int btrfs_finish_one_ordered(struct btrfs_ordered_extent *ordered_extent)
*/
btrfs_remove_ordered_extent(ordered_extent);
+ /* Cleanup any remaining biocs attached to the OE. */
+ btrfs_cleanup_ordered_bioc_list(ordered_extent);
+
/* once for us */
btrfs_put_ordered_extent(ordered_extent);
/* once for the tree */
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -384,6 +384,7 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
inode_flags &= ~BTRFS_INODE_COMPRESS;
inode_flags |= BTRFS_INODE_NOCOMPRESS;
} else if (fsflags & FS_COMPR_FL) {
+ enum btrfs_compression_type comp_type;
if (IS_SWAPFILE(&inode->vfs_inode))
return -ETXTBSY;
@@ -391,9 +392,23 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
inode_flags |= BTRFS_INODE_COMPRESS;
inode_flags &= ~BTRFS_INODE_NOCOMPRESS;
- comp = btrfs_compress_type2str(fs_info->compress_type);
- if (!comp || comp[0] == 0)
- comp = btrfs_compress_type2str(BTRFS_COMPRESS_ZLIB);
+ /*
+ * Keep the algorithm recorded in the compression property,
+ * otherwise changing an unrelated attribute would reset it to
+ * the mount default, since FS_IOC_SETFLAGS callers write back
+ * the whole flag set they got from FS_IOC_GETFLAGS and that
+ * includes FS_COMPR_FL for any inode carrying the property.
+ *
+ * Inodes with the compress flag set but no property keep using
+ * the mount default, so they behave as before.
+ */
+ if (inode->prop_compress)
+ comp_type = inode->prop_compress;
+ else if (fs_info->compress_type)
+ comp_type = fs_info->compress_type;
+ else
+ comp_type = BTRFS_COMPRESS_ZLIB;
+ comp = btrfs_compress_type2str(comp_type);
} else {
inode_flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
}
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -310,8 +310,10 @@ static int update_raid_extent_item(struct btrfs_trans_handle *trans,
ret = btrfs_search_slot(trans, trans->fs_info->stripe_root, key, path,
0, 1);
- if (ret)
- return (ret == 1 ? ret : -EINVAL);
+ if (ret > 0)
+ ret = -ENOENT;
+ if (ret < 0)
+ return ret;
leaf = path->nodes[0];
slot = path->slots[0];
@@ -337,7 +339,6 @@ int btrfs_insert_one_raid_extent(struct btrfs_trans_handle *trans,
stripe_extent = kzalloc(item_size, GFP_NOFS);
if (unlikely(!stripe_extent)) {
btrfs_abort_transaction(trans, -ENOMEM);
- btrfs_end_transaction(trans);
return -ENOMEM;
}
@@ -374,7 +375,7 @@ int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
struct btrfs_ordered_extent *ordered_extent)
{
struct btrfs_io_context *bioc;
- int ret;
+ int ret = 0;
if (!btrfs_fs_incompat(trans->fs_info, RAID_STRIPE_TREE))
return 0;
@@ -382,17 +383,23 @@ int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
list_for_each_entry(bioc, &ordered_extent->bioc_list, rst_ordered_entry) {
ret = btrfs_insert_one_raid_extent(trans, bioc);
if (ret)
- return ret;
+ break;
}
- while (!list_empty(&ordered_extent->bioc_list)) {
- bioc = list_first_entry(&ordered_extent->bioc_list,
+ btrfs_cleanup_ordered_bioc_list(ordered_extent);
+ return ret;
+}
+
+void btrfs_cleanup_ordered_bioc_list(struct btrfs_ordered_extent *ordered)
+{
+ while (!list_empty(&ordered->bioc_list)) {
+ struct btrfs_io_context *bioc;
+
+ bioc = list_first_entry(&ordered->bioc_list,
typeof(*bioc), rst_ordered_entry);
list_del(&bioc->rst_ordered_entry);
btrfs_put_bioc(bioc);
}
-
- return 0;
}
int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
diff --git a/fs/btrfs/raid-stripe-tree.h b/fs/btrfs/raid-stripe-tree.h
--- a/fs/btrfs/raid-stripe-tree.h
+++ b/fs/btrfs/raid-stripe-tree.h
@@ -28,6 +28,7 @@ int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
u32 stripe_index, struct btrfs_io_stripe *stripe);
int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
struct btrfs_ordered_extent *ordered_extent);
+void btrfs_cleanup_ordered_bioc_list(struct btrfs_ordered_extent *ordered);
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
int btrfs_insert_one_raid_extent(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -1023,6 +1023,10 @@ static void scrub_stripe_report_errors(struct scrub_ctx *sctx,
skip:
for_each_set_bit(sector_nr, &extent_bitmap, stripe->nr_sectors) {
+ const u64 sector_logical = stripe->logical +
+ ((u64)sector_nr << fs_info->sectorsize_bits);
+ const u64 sector_physical = physical +
+ ((u64)sector_nr << fs_info->sectorsize_bits);
bool repaired = false;
if (scrub_bitmap_test_bit_is_metadata(stripe, sector_nr)) {
@@ -1051,12 +1055,12 @@ static void scrub_stripe_report_errors(struct scrub_ctx *sctx,
if (dev) {
btrfs_err_rl(fs_info,
"scrub: fixed up error at logical %llu on dev %s physical %llu",
- stripe->logical, btrfs_dev_name(dev),
- physical);
+ sector_logical, btrfs_dev_name(dev),
+ sector_physical);
} else {
btrfs_err_rl(fs_info,
"scrub: fixed up error at logical %llu on mirror %u",
- stripe->logical, stripe->mirror_num);
+ sector_logical, stripe->mirror_num);
}
continue;
}
@@ -1065,30 +1069,30 @@ static void scrub_stripe_report_errors(struct scrub_ctx *sctx,
if (dev) {
btrfs_err_rl(fs_info,
"scrub: unable to fixup (regular) error at logical %llu on dev %s physical %llu",
- stripe->logical, btrfs_dev_name(dev),
- physical);
+ sector_logical, btrfs_dev_name(dev),
+ sector_physical);
} else {
btrfs_err_rl(fs_info,
"scrub: unable to fixup (regular) error at logical %llu on mirror %u",
- stripe->logical, stripe->mirror_num);
+ sector_logical, stripe->mirror_num);
}
if (scrub_bitmap_test_bit_io_error(stripe, sector_nr))
if (__ratelimit(&rs) && dev)
scrub_print_common_warning("i/o error", dev, false,
- stripe->logical, physical);
+ sector_logical, sector_physical);
if (scrub_bitmap_test_bit_csum_error(stripe, sector_nr))
if (__ratelimit(&rs) && dev)
scrub_print_common_warning("checksum error", dev, false,
- stripe->logical, physical);
+ sector_logical, sector_physical);
if (scrub_bitmap_test_bit_meta_error(stripe, sector_nr))
if (__ratelimit(&rs) && dev)
scrub_print_common_warning("header error", dev, false,
- stripe->logical, physical);
+ sector_logical, sector_physical);
if (scrub_bitmap_test_bit_meta_gen_error(stripe, sector_nr))
if (__ratelimit(&rs) && dev)
scrub_print_common_warning("generation error", dev, false,
- stripe->logical, physical);
+ sector_logical, sector_physical);
}
/* Update the device stats. */
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -2065,7 +2065,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
ret = is_inode_existent(sctx, dir, dir_gen, NULL, &parent_root_dir_gen);
if (ret <= 0)
- return 0;
+ return ret;
/*
* If we have a parent root we need to verify that the parent dir was
@@ -6417,6 +6417,13 @@ static int process_extent(struct send_ctx *sctx,
if (S_ISLNK(sctx->cur_inode_mode))
return 0;
+ if (unlikely(!S_ISREG(sctx->cur_inode_mode))) {
+ btrfs_crit(sctx->send_root->fs_info,
+ "send: extent for non-regular inode %llu root %llu mode 0%llo",
+ key->objectid, btrfs_root_id(sctx->send_root),
+ sctx->cur_inode_mode & S_IFMT);
+ return -EUCLEAN;
+ }
if (sctx->parent_root && !sctx->cur_inode_new) {
ret = is_extent_unchanged(sctx, path, key);
diff --git a/fs/btrfs/tests/extent-io-tests.c b/fs/btrfs/tests/extent-io-tests.c
--- a/fs/btrfs/tests/extent-io-tests.c
+++ b/fs/btrfs/tests/extent-io-tests.c
@@ -133,14 +133,14 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
if (IS_ERR(root)) {
test_std_err(TEST_ALLOC_ROOT);
ret = PTR_ERR(root);
- goto out;
+ goto out_root_info;
}
inode = btrfs_new_test_inode();
if (!inode) {
test_std_err(TEST_ALLOC_INODE);
ret = -ENOMEM;
- goto out;
+ goto out_root_info;
}
tmp = &BTRFS_I(inode)->io_tree;
BTRFS_I(inode)->root = root;
@@ -333,6 +333,7 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
process_page_range(inode, 0, total_dirty - 1,
PROCESS_UNLOCK | PROCESS_RELEASE);
iput(inode);
+out_root_info:
btrfs_free_dummy_root(root);
btrfs_free_dummy_fs_info(fs_info);
return ret;
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -458,8 +458,19 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans,
* through btrfs_record_root_in_trans without having to take the
* lock. smp_wmb() makes sure that all the writes above are
* done before we pop in the zero below
+ *
+ * If @force is true, it means the call is from
+ * qgroup_account_snapshot(), which only requires radix tree
+ * tracking.
+ * We should not force reloc root creation here, as the root
+ * may have already been modified, and in that case
+ * root->commit_root has already been dropped.
+ *
+ * Using that commit root will cause the reloc root to refer
+ * to a deleted extent, causing extent tree corruption.
*/
- ret = btrfs_init_reloc_root(trans, root);
+ if (!force)
+ ret = btrfs_init_reloc_root(trans, root);
smp_mb__before_atomic();
clear_bit(BTRFS_ROOT_IN_TRANS_SETUP, &root->state);
}
@@ -2583,6 +2594,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
ret = btrfs_write_and_wait_transaction(trans);
if (unlikely(ret)) {
btrfs_err(fs_info, "error while writing out transaction: %pe", ERR_PTR(ret));
+ /*
+ * Abort before releasing tree_log_mutex, so a log sync waiting
+ * on it sees the fs error and skips writing super_for_commit
+ * for this failed transaction. See btrfs_sync_log().
+ */
+ btrfs_abort_transaction(trans, ret);
mutex_unlock(&fs_info->tree_log_mutex);
goto scrub_continue;
}
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3035,7 +3035,11 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
error_sysfs:
btrfs_sysfs_remove_device(device);
mutex_lock(&fs_info->fs_devices->device_list_mutex);
+ if (seeding_dev)
+ btrfs_assign_next_active_device(device, seed_devices->latest_dev);
mutex_lock(&fs_info->chunk_mutex);
+ if (!list_empty(&device->post_commit_list))
+ list_del_init(&device->post_commit_list);
list_del_rcu(&device->dev_list);
list_del(&device->dev_alloc_list);
fs_info->fs_devices->num_devices--;
diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -2626,16 +2626,13 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
down_read(&dev_replace->rwsem);
map = block_group->physical_map;
for (i = 0; i < map->num_stripes; i++) {
-
ret = call_zone_finish(block_group, &map->stripes[i]);
- if (ret) {
- up_read(&dev_replace->rwsem);
- return ret;
- }
+ if (ret)
+ break;
}
up_read(&dev_replace->rwsem);
- if (!fully_written)
+ if (!ret && !fully_written)
btrfs_dec_block_group_ro(block_group);
spin_lock(&fs_info->zone_active_bgs_lock);
@@ -2648,7 +2645,7 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
clear_and_wake_up_bit(BTRFS_FS_NEED_ZONE_FINISH, &fs_info->flags);
- return 0;
+ return ret;
}
int btrfs_zone_finish(struct btrfs_block_group *block_group)
@@ -2713,6 +2710,7 @@ int btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 leng
{
struct btrfs_block_group *block_group;
u64 min_alloc_bytes;
+ int ret = 0;
if (!btrfs_is_zoned(fs_info))
return 0;
@@ -2732,11 +2730,11 @@ int btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 leng
block_group->start + block_group->zone_capacity)
goto out;
- do_zone_finish(block_group, true);
+ ret = do_zone_finish(block_group, true);
out:
btrfs_put_block_group(block_group);
- return 0;
+ return ret;
}
static void btrfs_zone_finish_endio_workfn(struct work_struct *work)
diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c
--- a/fs/btrfs/zstd.c
+++ b/fs/btrfs/zstd.c
@@ -307,8 +307,17 @@ struct list_head *zstd_get_workspace(struct btrfs_fs_info *fs_info, int level)
DEFINE_WAIT(wait);
prepare_to_wait(&zwsm->wait, &wait, TASK_UNINTERRUPTIBLE);
- schedule();
+ /*
+ * Re-check after being queued: zstd_put_workspace() only wakes
+ * a queue that already has a sleeper, so a workspace returned
+ * since the failed allocation woke nobody.
+ */
+ ws = zstd_find_workspace(fs_info, level);
+ if (!ws)
+ schedule();
finish_wait(&zwsm->wait, &wait);
+ if (ws)
+ return ws;
goto again;
}
@@ -0,0 +1,97 @@
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -3074,6 +3074,18 @@ struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *tran
return ERR_PTR(ret);
}
+ /*
+ * Ensure the corresponding space_info object is created and
+ * assigned to our block group. We want our bg to be added to the rbtree
+ * with its ->space_info set.
+ *
+ * On a zoned filesystem btrfs_add_new_free_space() ends up in
+ * __btrfs_add_free_space_zoned(), which dereferences
+ * block_group->space_info, so it has to be set beforehand.
+ */
+ cache->space_info = space_info;
+ ASSERT(cache->space_info);
+
ret = btrfs_add_new_free_space(cache, chunk_offset, chunk_offset + size, NULL);
btrfs_free_excluded_extents(cache);
if (ret) {
@@ -3081,14 +3093,6 @@ struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *tran
return ERR_PTR(ret);
}
- /*
- * Ensure the corresponding space_info object is created and
- * assigned to our block group. We want our bg to be added to the rbtree
- * with its ->space_info set.
- */
- cache->space_info = space_info;
- ASSERT(cache->space_info);
-
ret = btrfs_add_block_group_cache(cache);
if (ret) {
btrfs_remove_free_space_cache(cache);
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -1909,6 +1909,16 @@ static int check_inode_ref(struct extent_buffer *leaf,
return -EUCLEAN;
}
+ if (unlikely(btrfs_is_fstree(btrfs_header_owner(leaf)) &&
+ (key->offset < BTRFS_FIRST_FREE_OBJECTID ||
+ key->offset > BTRFS_LAST_FREE_OBJECTID))) {
+ inode_ref_err(leaf, slot,
+ "invalid offset for ref key, have %llu expect [%llu, %lld]",
+ key->offset, BTRFS_FIRST_FREE_OBJECTID,
+ BTRFS_LAST_FREE_OBJECTID);
+ return -EUCLEAN;
+ }
+
ptr = btrfs_item_ptr_offset(leaf, slot);
end = ptr + btrfs_item_size(leaf, slot);
while (ptr < end) {
@@ -1952,12 +1962,14 @@ static int check_inode_extref(struct extent_buffer *leaf,
{
unsigned long ptr = btrfs_item_ptr_offset(leaf, slot);
unsigned long end = ptr + btrfs_item_size(leaf, slot);
+ const bool is_fstree = btrfs_is_fstree(btrfs_header_owner(leaf));
if (unlikely(!check_prev_ino(leaf, key, slot, prev_key)))
return -EUCLEAN;
while (ptr < end) {
struct btrfs_inode_extref *extref = (struct btrfs_inode_extref *)ptr;
+ u64 parent;
u16 namelen;
if (unlikely(ptr + sizeof(*extref) > end)) {
@@ -1967,7 +1979,24 @@ static int check_inode_extref(struct extent_buffer *leaf,
return -EUCLEAN;
}
+ parent = btrfs_inode_extref_parent(leaf, extref);
+ if (unlikely(is_fstree && (parent < BTRFS_FIRST_FREE_OBJECTID ||
+ parent > BTRFS_LAST_FREE_OBJECTID))) {
+ inode_ref_err(leaf, slot,
+ "invalid parent for extref key, have %llu expect [%llu, %lld]",
+ parent, BTRFS_FIRST_FREE_OBJECTID,
+ BTRFS_LAST_FREE_OBJECTID);
+ return -EUCLEAN;
+ }
+
namelen = btrfs_inode_extref_name_len(leaf, extref);
+ if (unlikely(namelen == 0 || namelen > BTRFS_NAME_LEN)) {
+ inode_ref_err(leaf, slot,
+ "invalid inode extref name length, has %u expect [1, %u]",
+ namelen, BTRFS_NAME_LEN);
+ return -EUCLEAN;
+ }
+
if (unlikely(ptr + sizeof(*extref) + namelen > end)) {
inode_ref_err(leaf, slot,
"inode extref overflow, ptr %lu end %lu namelen %u",
@@ -0,0 +1,77 @@
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -2306,7 +2306,7 @@ static int check_free_space_extent(struct extent_buffer *leaf, struct btrfs_key
if (unlikely(btrfs_item_size(leaf, slot) != 0)) {
generic_err(leaf, slot,
- "invalid item size for free space info, has %u expect 0",
+ "invalid item size for free space extent, has %u expect 0",
btrfs_item_size(leaf, slot));
return -EUCLEAN;
}
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -740,6 +740,36 @@ const u8 *btrfs_sb_fsid_ptr(const struct btrfs_super_block *sb)
return has_metadata_uuid ? sb->metadata_uuid : sb->fsid;
}
+static bool should_rename_device(const struct btrfs_device *dev)
+{
+ bool ret;
+ const char *old_name;
+
+ rcu_read_lock();
+ old_name = rcu_dereference(dev->name);
+ /*
+ * For systems booted without an initramfs, the rootfs has the device
+ * name "/dev/root".
+ *
+ * Although using btrfs without an initramfs is not recommended (if a
+ * new device is added to the rootfs, the system can no longer boot, as
+ * there is no way to register all devices), there is still a minority
+ * of users doing this.
+ *
+ * And after the system is up, a later device scan on the real block
+ * device file will never get this device's name updated, as the
+ * device->devt is still the same.
+ *
+ * Here we add one and only one exception for "/dev/root", to allow the
+ * device name to be updated even if the new path points to the same
+ * block device.
+ */
+ ret = (strcmp(old_name, "/dev/root") == 0);
+ rcu_read_unlock();
+
+ return ret;
+}
+
/*
* Add new device to list of registered devices
*
@@ -860,7 +890,8 @@ static noinline struct btrfs_device *device_list_add(const char *path,
MAJOR(path_devt), MINOR(path_devt),
current->comm, task_pid_nr(current));
- } else if (!device->name || device->devt != path_devt) {
+ } else if (!device->name || device->devt != path_devt ||
+ should_rename_device(device)) {
const char *old_name;
/*
diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -2688,6 +2688,11 @@ bool btrfs_can_activate_zone(struct btrfs_fs_devices *fs_devices, u64 flags)
switch (flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
case 0: /* single */
+ case BTRFS_BLOCK_GROUP_RAID0:
+ case BTRFS_BLOCK_GROUP_RAID1:
+ case BTRFS_BLOCK_GROUP_RAID1C3:
+ case BTRFS_BLOCK_GROUP_RAID1C4:
+ case BTRFS_BLOCK_GROUP_RAID10:
ret = (atomic_read(&zinfo->active_zones_left) >= (1 + reserved));
break;
case BTRFS_BLOCK_GROUP_DUP:
@@ -1,7 +1,7 @@
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -2280,6 +2280,9 @@ int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
@@ -2289,6 +2289,9 @@ int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
*/
if ((is_truncate || !is_wb) &&
S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {
@@ -28,7 +28,7 @@ diff --git a/fs/fuse/file.c b/fs/fuse/file.c
if (inode->i_size < pos + iov_iter_count(ii))
set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
@@ -2908,6 +2912,11 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
@@ -2909,6 +2913,11 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
/* we could have extended the file */
if (!(mode & FALLOC_FL_KEEP_SIZE)) {
@@ -1,7 +1,7 @@
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -216,10 +216,13 @@ EXPORT_SYMBOL_GPL(fuse_req_hash);
@@ -213,10 +213,13 @@ EXPORT_SYMBOL_GPL(fuse_req_hash);
/*
* A new request is available, wake fiq->waitq
*/
@@ -17,7 +17,7 @@ diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
spin_unlock(&fiq->lock);
}
@@ -236,7 +239,7 @@ void fuse_dev_queue_forget(struct fuse_iqueue *fiq,
@@ -233,7 +236,7 @@ void fuse_dev_queue_forget(struct fuse_iqueue *fiq,
if (fiq->connected) {
fiq->forget_list_tail->next = forget;
fiq->forget_list_tail = forget;
@@ -26,7 +26,7 @@ diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
} else {
kfree(forget);
spin_unlock(&fiq->lock);
@@ -258,7 +261,7 @@ void fuse_dev_queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
@@ -255,7 +258,7 @@ void fuse_dev_queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
list_del_init(&req->intr_entry);
spin_unlock(&fiq->lock);
} else {
@@ -35,7 +35,7 @@ diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
}
} else {
spin_unlock(&fiq->lock);
@@ -288,11 +291,13 @@ EXPORT_SYMBOL_GPL(fuse_request_assign_unique);
@@ -285,11 +288,13 @@ EXPORT_SYMBOL_GPL(fuse_request_assign_unique);
static void fuse_dev_queue_req(struct fuse_iqueue *fiq, struct fuse_req *req)
{
@@ -50,7 +50,7 @@ diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
} else {
spin_unlock(&fiq->lock);
req->out.h.error = -ENOTCONN;
@@ -755,6 +760,11 @@ static void __fuse_request_send(struct fuse_req *req)
@@ -752,6 +757,11 @@ static void __fuse_request_send(struct fuse_req *req)
/* acquire extra reference, since request is still needed after
fuse_request_end() */
__fuse_get_request(req);
@@ -62,7 +62,7 @@ diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
fuse_send_one(fiq, req);
request_wait_answer(req);
@@ -1809,7 +1819,7 @@ void fuse_chan_resend(struct fuse_chan *fch)
@@ -1806,7 +1816,7 @@ void fuse_chan_resend(struct fuse_chan *fch)
}
/* iq and pq requests are both oldest to newest */
list_splice(&to_queue, &fiq->pending);
@@ -94,7 +94,7 @@ diff --git a/fs/fuse/fuse_dev_i.h b/fs/fuse/fuse_dev_i.h
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1417,6 +1417,7 @@ static void process_init_reply(struct fuse_args *args, int error)
@@ -1420,6 +1420,7 @@ static void process_init_reply(struct fuse_args *args, int error)
fm->sb->s_bdi->ra_pages =
min(fm->sb->s_bdi->ra_pages, ra_pages);
@@ -1,7 +1,7 @@
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -409,7 +409,8 @@ void fuse_chan_max_background_set(struct fuse_chan *fch, unsigned int val)
@@ -406,7 +406,8 @@ void fuse_chan_max_background_set(struct fuse_chan *fch, unsigned int val)
fch->max_background = val;
fch->blocked = fch->num_background >= fch->max_background;
if (!fch->blocked)
@@ -0,0 +1,119 @@
diff --git a/fs/internal.h b/fs/internal.h
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -204,6 +204,7 @@ int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
int flag);
int chown_common(const struct path *path, uid_t user, gid_t group);
extern int vfs_open(const struct path *, struct file *);
+int vfs_open_consume(struct path *, struct file *);
/*
* inode.c
diff --git a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4652,6 +4652,7 @@ static const char *open_last_lookups(struct nameidata *nd,
static int do_open(struct nameidata *nd,
struct file *file, const struct open_flags *op)
{
+ struct vfsmount *mnt;
struct mnt_idmap *idmap;
int open_flag = op->open_flag;
bool do_truncate;
@@ -4693,11 +4694,17 @@ static int do_open(struct nameidata *nd,
error = mnt_want_write(nd->path.mnt);
if (error)
return error;
+ /*
+ * A dedicated reference is needed because after the call to
+ * vfs_open_consume() we no longer own the reference in nd->path.mnt
+ * while we need to undo write acess below.
+ */
+ mnt = mntget(nd->path.mnt);
do_truncate = true;
}
error = may_open(idmap, &nd->path, acc_mode, open_flag);
if (!error && !(file->f_mode & FMODE_OPENED))
- error = vfs_open(&nd->path, file);
+ error = vfs_open_consume(&nd->path, file);
if (!error)
error = security_file_post_open(file, op->acc_mode);
if (!error && do_truncate)
@@ -4706,8 +4713,10 @@ static int do_open(struct nameidata *nd,
WARN_ON(1);
error = -EINVAL;
}
- if (do_truncate)
- mnt_drop_write(nd->path.mnt);
+ if (do_truncate) {
+ mnt_drop_write(mnt);
+ mntput(mnt);
+ }
return error;
}
diff --git a/fs/open.c b/fs/open.c
--- a/fs/open.c
+++ b/fs/open.c
@@ -882,6 +882,11 @@ static inline int file_get_write_access(struct file *f)
return error;
}
+/*
+ * Populate struct file
+ *
+ * NOTE: it assumes f_path is populated and consumes the caller's reference.
+ */
static int do_dentry_open(struct file *f,
int (*open)(struct inode *, struct file *))
{
@@ -889,7 +894,6 @@ static int do_dentry_open(struct file *f,
struct inode *inode = f->f_path.dentry->d_inode;
int error;
- path_get(&f->f_path);
f->f_inode = inode;
f->f_mapping = inode->i_mapping;
f->f_wb_err = filemap_sample_wb_err(f->f_mapping);
@@ -1006,6 +1010,7 @@ int finish_open(struct file *file, struct dentry *dentry,
BUG_ON(file->f_mode & FMODE_OPENED); /* once it's opened, it's opened */
file->__f_path.dentry = dentry;
+ path_get(&file->f_path);
return do_dentry_open(file, open);
}
EXPORT_SYMBOL(finish_open);
@@ -1049,6 +1054,7 @@ int vfs_open(const struct path *path, struct file *file)
int ret;
file->__f_path = *path;
+ path_get(&file->f_path);
ret = do_dentry_open(file, NULL);
if (!ret) {
/*
@@ -1061,6 +1067,25 @@ int vfs_open(const struct path *path, struct file *file)
return ret;
}
+/**
+ * vfs_open_consume - open the file at the given path and consume the reference
+ * @path: path to open
+ * @file: newly allocated file with f_flag initialized
+ */
+int vfs_open_consume(struct path *path, struct file *file)
+{
+ int ret;
+
+ file->__f_path = *path;
+ path->mnt = NULL;
+ path->dentry = NULL;
+ ret = do_dentry_open(file, NULL);
+ if (!ret) {
+ fsnotify_open(file);
+ }
+ return ret;
+}
+
struct file *dentry_open(const struct path *path, int flags,
const struct cred *cred)
{
@@ -1,12 +0,0 @@
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1343,7 +1343,7 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
if (ttm_tt_is_populated(tt)) {
ret = ttm_tt_swapout(bdev, tt, swapout_walk->gfp_flags);
- if (!ret) {
+ if (ret > 0) {
spin_lock(&bdev->lru_lock);
ttm_resource_del_bulk_move_unevictable(bo->resource, bo);
ttm_resource_move_to_lru_tail(bo->resource);
@@ -1,5 +1,4 @@
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index c21e0c0ef0b1..e62788328bfd 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1780,6 +1780,7 @@ struct intel_psr {
@@ -11,10 +10,9 @@ index c21e0c0ef0b1..e62788328bfd 100644
u8 io_wake_lines;
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index beaa1d62613d..644ab9b1bee9 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -2475,6 +2475,7 @@ void intel_psr_disable(struct intel_dp *intel_dp,
@@ -2481,6 +2481,7 @@ void intel_psr_disable(struct intel_dp *intel_dp,
mutex_unlock(&intel_dp->psr.lock);
cancel_work_sync(&intel_dp->psr.work);
cancel_delayed_work_sync(&intel_dp->psr.dc3co_work);
@@ -22,7 +20,7 @@ index beaa1d62613d..644ab9b1bee9 100644
}
/**
@@ -2506,6 +2507,7 @@ void intel_psr_pause(struct intel_dp *intel_dp)
@@ -2512,6 +2513,7 @@ void intel_psr_pause(struct intel_dp *intel_dp)
cancel_work_sync(&psr->work);
cancel_delayed_work_sync(&psr->dc3co_work);
@@ -30,48 +28,48 @@ index beaa1d62613d..644ab9b1bee9 100644
}
/**
@@ -3539,6 +3541,17 @@ static void intel_psr_handle_irq(struct intel_dp *intel_dp)
@@ -3545,6 +3547,17 @@ static void intel_psr_handle_irq(struct intel_dp *intel_dp)
drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
}
+#define PANEL_REPLAY_REENABLE_DELAY_MS 50
+
+static bool panel_replay_alpm_cursor_lag_workaround_enabled(struct intel_dp *intel_dp)
+static bool panel_replay_exit_on_flush_enabled(struct intel_dp *intel_dp)
+{
+ return intel_dp_is_edp(intel_dp) &&
+ intel_dp->psr.panel_replay_enabled &&
+ intel_dp->psr.sel_update_enabled &&
+ intel_has_dpcd_quirk(intel_dp,
+ QUIRK_PANEL_REPLAY_ALPM_CURSOR_LAG);
+ QUIRK_PANEL_REPLAY_EXIT_ON_FLUSH);
+}
+
static void intel_psr_work(struct work_struct *work)
{
struct intel_dp *intel_dp =
@@ -3557,6 +3570,11 @@ static void intel_psr_work(struct work_struct *work)
@@ -3563,6 +3576,11 @@ static void intel_psr_work(struct work_struct *work)
if (intel_dp->psr.pause_counter)
goto unlock;
+ /* The dedicated delayed work owns re-entry while the workaround is armed. */
+ if (panel_replay_alpm_cursor_lag_workaround_enabled(intel_dp) &&
+ /* The dedicated delayed work owns re-entry while the quirk is armed. */
+ if (panel_replay_exit_on_flush_enabled(intel_dp) &&
+ delayed_work_pending(&intel_dp->psr.panel_replay_reenable_work))
+ goto unlock;
+
/*
* We have to make sure PSR is ready for re-enable
* otherwise it keeps disabled until next full enable/disable cycle.
@@ -3566,6 +3584,10 @@ static void intel_psr_work(struct work_struct *work)
@@ -3572,6 +3590,10 @@ static void intel_psr_work(struct work_struct *work)
if (!__psr_wait_for_idle_locked(intel_dp))
goto unlock;
+ if (panel_replay_alpm_cursor_lag_workaround_enabled(intel_dp) &&
+ if (panel_replay_exit_on_flush_enabled(intel_dp) &&
+ delayed_work_pending(&intel_dp->psr.panel_replay_reenable_work))
+ goto unlock;
+
/*
* The delayed work can race with an invalidate hence we need to
* recheck. Since psr_flush first clears this and then reschedules we
@@ -3579,6 +3601,33 @@ static void intel_psr_work(struct work_struct *work)
@@ -3585,6 +3607,33 @@ static void intel_psr_work(struct work_struct *work)
mutex_unlock(&intel_dp->psr.lock);
}
@@ -84,7 +82,7 @@ index beaa1d62613d..644ab9b1bee9 100644
+ mutex_lock(&intel_dp->psr.lock);
+
+ if (!intel_dp->psr.enabled ||
+ !panel_replay_alpm_cursor_lag_workaround_enabled(intel_dp) ||
+ !panel_replay_exit_on_flush_enabled(intel_dp) ||
+ intel_dp->psr.pause_counter ||
+ READ_ONCE(intel_dp->psr.irq_aux_error))
+ goto unlock;
@@ -105,25 +103,25 @@ index beaa1d62613d..644ab9b1bee9 100644
static void intel_psr_configure_full_frame_update(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
@@ -3650,8 +3699,11 @@ void intel_psr_invalidate(struct intel_display *display,
@@ -3656,8 +3705,11 @@ void intel_psr_invalidate(struct intel_display *display,
INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe);
intel_dp->psr.busy_frontbuffer_bits |= pipe_frontbuffer_bits;
- if (pipe_frontbuffer_bits)
+ if (pipe_frontbuffer_bits) {
+ if (panel_replay_alpm_cursor_lag_workaround_enabled(intel_dp))
+ if (panel_replay_exit_on_flush_enabled(intel_dp))
+ cancel_delayed_work(&intel_dp->psr.panel_replay_reenable_work);
_psr_invalidate_handle(intel_dp);
+ }
mutex_unlock(&intel_dp->psr.lock);
}
@@ -3767,6 +3819,15 @@ void intel_psr_flush(struct intel_display *display,
@@ -3773,6 +3825,15 @@ void intel_psr_flush(struct intel_display *display,
if (intel_dp->psr.pause_counter)
goto unlock;
+ if (pipe_frontbuffer_bits &&
+ panel_replay_alpm_cursor_lag_workaround_enabled(intel_dp)) {
+ panel_replay_exit_on_flush_enabled(intel_dp)) {
+ intel_psr_exit(intel_dp);
+ mod_delayed_work(display->wq.unordered,
+ &intel_dp->psr.panel_replay_reenable_work,
@@ -134,7 +132,7 @@ index beaa1d62613d..644ab9b1bee9 100644
if (origin == ORIGIN_FLIP ||
(origin == ORIGIN_CURSOR_UPDATE &&
!intel_dp->psr.psr2_sel_fetch_enabled)) {
@@ -3830,6 +3891,8 @@ void intel_psr_init(struct intel_dp *intel_dp)
@@ -3836,6 +3897,8 @@ void intel_psr_init(struct intel_dp *intel_dp)
INIT_WORK(&intel_dp->psr.work, intel_psr_work);
INIT_DELAYED_WORK(&intel_dp->psr.dc3co_work, tgl_dc3co_disable_work);
@@ -144,53 +142,31 @@ index beaa1d62613d..644ab9b1bee9 100644
}
diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c
index 33245f44c0d5..dc6576016400 100644
--- a/drivers/gpu/drm/i915/display/intel_quirks.c
+++ b/drivers/gpu/drm/i915/display/intel_quirks.c
@@ -86,12 +86,13 @@ static void quirk_edp_limit_rate_hbr2(struct intel_display *display)
drm_info(display->drm, "Applying eDP Limit rate to HBR2 quirk\n");
}
-static void quirk_disable_edp_panel_replay(struct intel_dp *intel_dp)
+static void quirk_panel_replay_alpm_cursor_lag(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
- intel_set_dpcd_quirk(intel_dp, QUIRK_DISABLE_EDP_PANEL_REPLAY);
- drm_info(display->drm, "Applying disable Panel Replay quirk\n");
+ intel_set_dpcd_quirk(intel_dp, QUIRK_PANEL_REPLAY_ALPM_CURSOR_LAG);
+ drm_info(display->drm,
+ "Applying Panel Replay ALPM cursor lag workaround\n");
@@ -94,6 +94,14 @@ static void quirk_disable_edp_panel_replay(struct intel_dp *intel_dp)
drm_info(display->drm, "Applying disable Panel Replay quirk\n");
}
+static void quirk_panel_replay_exit_on_flush(struct intel_dp *intel_dp)
+{
+ struct intel_display *display = to_intel_display(intel_dp);
+
+ intel_set_dpcd_quirk(intel_dp, QUIRK_PANEL_REPLAY_EXIT_ON_FLUSH);
+ drm_info(display->drm, "Applying Panel Replay exit on flush quirk\n");
+}
+
static void quirk_disable_psr2(struct intel_display *display)
@@ -276,7 +277,7 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = {
.subsystem_vendor = 0x1028,
.subsystem_device = 0x0db9,
.sink_oui = SINK_OUI(0x00, 0x22, 0xb9),
- .hook = quirk_disable_edp_panel_replay,
+ .hook = quirk_panel_replay_alpm_cursor_lag,
},
/* Dell XPS 16 DA16260 */
{
@@ -284,7 +285,7 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = {
.subsystem_vendor = 0x1028,
.subsystem_device = 0x0dba,
.sink_oui = SINK_OUI(0x00, 0x22, 0xb9),
- .hook = quirk_disable_edp_panel_replay,
+ .hook = quirk_panel_replay_alpm_cursor_lag,
},
};
{
intel_set_quirk(display, QUIRK_DISABLE_PSR2);
diff --git a/drivers/gpu/drm/i915/display/intel_quirks.h b/drivers/gpu/drm/i915/display/intel_quirks.h
index 970a4fe52faf..50ef333b87a9 100644
--- a/drivers/gpu/drm/i915/display/intel_quirks.h
+++ b/drivers/gpu/drm/i915/display/intel_quirks.h
@@ -23,6 +23,7 @@ enum intel_quirk_id {
QUIRK_EDP_LIMIT_RATE_HBR2,
QUIRK_DISABLE_EDP_PANEL_REPLAY,
QUIRK_DISABLE_PSR2,
+ QUIRK_PANEL_REPLAY_ALPM_CURSOR_LAG,
+ QUIRK_PANEL_REPLAY_EXIT_ON_FLUSH,
};
void intel_init_quirks(struct intel_display *display);
@@ -0,0 +1,12 @@
diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c
--- a/drivers/gpu/drm/i915/display/intel_quirks.c
+++ b/drivers/gpu/drm/i915/display/intel_quirks.c
@@ -284,7 +284,7 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = {
.subsystem_vendor = 0x1028,
.subsystem_device = 0x0db9,
.sink_oui = SINK_OUI(0x00, 0x22, 0xb9),
- .hook = quirk_disable_edp_panel_replay,
+ .hook = quirk_panel_replay_exit_on_flush,
},
/* Dell XPS 16 DA16260 */
{
@@ -0,0 +1,12 @@
diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c
--- a/drivers/gpu/drm/i915/display/intel_quirks.c
+++ b/drivers/gpu/drm/i915/display/intel_quirks.c
@@ -292,7 +292,7 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = {
.subsystem_vendor = 0x1028,
.subsystem_device = 0x0dba,
.sink_oui = SINK_OUI(0x00, 0x22, 0xb9),
- .hook = quirk_disable_edp_panel_replay,
+ .hook = quirk_panel_replay_exit_on_flush,
},
};
@@ -0,0 +1,28 @@
diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c
--- a/drivers/gpu/drm/i915/display/intel_quirks.c
+++ b/drivers/gpu/drm/i915/display/intel_quirks.c
@@ -267,6 +267,9 @@ static struct intel_quirk intel_quirks[] = {
/* Xiaomi Book Pro 14 2026 */
{ 0xb081, 0x1d72, 0x2424, quirk_disable_psr2 },
+
+ /* Dell XPS 13 DX13260 */
+ { DEVICE_ID_ANY, 0x1028, 0x0e54, quirk_disable_psr2 },
};
static const struct intel_dpcd_quirk intel_dpcd_quirks[] = {
@@ -294,6 +297,14 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = {
.sink_oui = SINK_OUI(0x00, 0x22, 0xb9),
.hook = quirk_panel_replay_exit_on_flush,
},
+ /* Dell XPS 13 DX13260 */
+ {
+ .device = DEVICE_ID_ANY,
+ .subsystem_vendor = 0x1028,
+ .subsystem_device = 0x0e54,
+ .sink_oui = SINK_OUI(0x00, 0x22, 0xb9),
+ .hook = quirk_disable_edp_panel_replay,
+ },
};
void intel_init_quirks(struct intel_display *display)
@@ -0,0 +1,19 @@
diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c
--- a/drivers/gpu/drm/i915/display/intel_quirks.c
+++ b/drivers/gpu/drm/i915/display/intel_quirks.c
@@ -305,6 +305,15 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = {
.sink_oui = SINK_OUI(0x00, 0x22, 0xb9),
.hook = quirk_disable_edp_panel_replay,
},
+ /* Dell XPS 13 DX13260 (Wildcat Lake), sink "Bamboo" */
+ {
+ .device = DEVICE_ID_ANY,
+ .subsystem_vendor = 0x1028,
+ .subsystem_device = 0x0e53,
+ .sink_oui = SINK_OUI(0x00, 0x22, 0xb9),
+ .sink_device_id = SINK_DEVICE_ID(0x42, 0x61, 0x6d, 0x62, 0x6f, 0x6f),
+ .hook = quirk_panel_replay_exit_on_flush,
+ },
};
void intel_init_quirks(struct intel_display *display)
+2 -2
View File
@@ -55,7 +55,7 @@ diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/dis
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
@@ -1937,10 +1937,10 @@ static int intel_plane_min_height(struct intel_plane *plane,
@@ -1932,10 +1932,10 @@ static int intel_plane_min_height(struct intel_plane *plane,
return 1;
}
@@ -70,7 +70,7 @@ diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/dr
{
if (plane->max_width)
return plane->max_width(fb, color_plane, rotation);
@@ -1948,10 +1948,10 @@ static int intel_plane_max_width(struct intel_plane *plane,
@@ -1943,10 +1943,10 @@ static int intel_plane_max_width(struct intel_plane *plane,
return INT_MAX;
}
Binary file not shown.
@@ -0,0 +1,95 @@
diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
--- a/drivers/gpu/drm/i915/display/intel_cursor.c
+++ b/drivers/gpu/drm/i915/display/intel_cursor.c
@@ -536,7 +536,8 @@ static void i9xx_cursor_disable_sel_fetch_arm(struct intel_dsb *dsb,
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
- if (!crtc_state->enable_psr2_sel_fetch)
+ if (!crtc_state->enable_psr2_sel_fetch &&
+ !crtc_state->clear_psr2_sel_fetch)
return;
intel_de_write_dsb(display, dsb, SEL_FETCH_CUR_CTL(pipe), 0);
@@ -569,8 +570,10 @@ static void i9xx_cursor_update_sel_fetch_arm(struct intel_dsb *dsb,
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
- if (!crtc_state->enable_psr2_sel_fetch)
+ if (!crtc_state->enable_psr2_sel_fetch) {
+ i9xx_cursor_disable_sel_fetch_arm(dsb, plane, crtc_state);
return;
+ }
if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) {
if (crtc_state->enable_psr2_su_region_et) {
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1177,6 +1177,8 @@ struct intel_crtc_state {
bool has_sel_update;
bool enable_psr2_sel_fetch;
bool enable_psr2_su_region_et;
+ /* Drop the stale selective fetch enable bits as selective fetch is turned off */
+ bool clear_psr2_sel_fetch;
bool req_psr2_sdp_prior_scanline;
bool has_panel_replay;
bool link_off_after_as_sdp_when_pr_active;
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -2941,6 +2941,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct intel_display *display = to_intel_display(state);
+ const struct intel_crtc_state *old_crtc_state =
+ intel_atomic_get_old_crtc_state(state, crtc);
struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
struct intel_plane_state *new_plane_state, *old_plane_state;
struct intel_plane *plane;
@@ -2953,6 +2955,19 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
bool full_update = false, su_area_changed;
int i, ret;
+ /*
+ * Selective fetch is not always usable, for instance it is dropped
+ * while pipe CRC is active. The planes keep their selective fetch
+ * enable bit set in hardware over that, and a plane disabled while
+ * selective fetch is off never gets the bit cleared. Once selective
+ * fetch comes back the hardware would resume fetching for a plane that
+ * is no longer enabled and keep its DDB range reserved, so have the
+ * plane update drop the bit for every plane of the pipe as selective
+ * fetch is turned off.
+ */
+ crtc_state->clear_psr2_sel_fetch = old_crtc_state->enable_psr2_sel_fetch &&
+ !crtc_state->enable_psr2_sel_fetch;
+
if (!crtc_state->enable_psr2_sel_fetch)
return 0;
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
@@ -885,7 +885,8 @@ static void icl_plane_disable_sel_fetch_arm(struct intel_dsb *dsb,
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
- if (!crtc_state->enable_psr2_sel_fetch)
+ if (!crtc_state->enable_psr2_sel_fetch &&
+ !crtc_state->clear_psr2_sel_fetch)
return;
intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id), 0);
@@ -1634,10 +1635,8 @@ static void icl_plane_update_sel_fetch_arm(struct intel_dsb *dsb,
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
- if (!crtc_state->enable_psr2_sel_fetch)
- return;
-
- if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0)
+ if (crtc_state->enable_psr2_sel_fetch &&
+ drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0)
intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id),
SEL_FETCH_PLANE_CTL_ENABLE);
else
@@ -0,0 +1,22 @@
diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c
--- a/drivers/gpu/drm/i915/display/intel_dsb.c
+++ b/drivers/gpu/drm/i915/display/intel_dsb.c
@@ -902,9 +902,17 @@ void intel_dsb_wait_for_delayed_vblank(struct intel_atomic_state *state,
* the hardware itself guarantees that we're SCL lines
* away from the delayed vblank, and we won't be inside
* the vmin safe window so this extra wait does nothing.
+ *
+ * Experimentally, DSB may observe a slightly stale
+ * PIPEDSL value. When the actual scanline has just reached
+ * safe_window_start, WAIT_DSL_OUT may complete immediately
+ * due to the stale value.
+ *
+ * Shift the start back by one scanline to ensure the wait
+ * window is entered reliably.
*/
intel_dsb_wait_scanline_out(state, dsb,
- intel_vrr_safe_window_start(crtc_state),
+ intel_vrr_safe_window_start(crtc_state) - 1,
intel_vrr_vmin_safe_window_end(crtc_state));
/*
* When the push is sent during vblank it will trigger
@@ -0,0 +1,42 @@
diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c
--- a/drivers/gpu/drm/i915/display/intel_display_params.c
+++ b/drivers/gpu/drm/i915/display/intel_display_params.c
@@ -120,6 +120,10 @@ intel_display_param_named_unsafe(enable_psr, int, 0400,
"(0=disabled, 1=enable up to PSR1, 2=enable up to PSR2) "
"Default: -1 (use per-chip default)");
+intel_display_param_named_unsafe(enable_dc_balance, bool, 0400,
+ "Enable VRR DC balance (0=disabled, 1=enabled). "
+ "Default: 0 (disabled)");
+
intel_display_param_named_unsafe(enable_panel_replay, int, 0400,
"Enable Panel Replay (0=disabled, 1=enabled). Default: -1 (use per-chip default)");
diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h
--- a/drivers/gpu/drm/i915/display/intel_display_params.h
+++ b/drivers/gpu/drm/i915/display/intel_display_params.h
@@ -46,6 +46,7 @@ struct drm_printer;
param(bool, enable_dp_mst, true, 0600) \
param(int, enable_fbc, -1, 0600) \
param(int, enable_psr, -1, 0600) \
+ param(bool, enable_dc_balance, false, 0600) \
param(int, enable_panel_replay, -1, 0600) \
param(bool, psr_safest_params, false, 0400) \
param(bool, enable_psr2_sel_fetch, true, 0400) \
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
@@ -383,10 +383,12 @@ static bool intel_vrr_dc_balance_possible(const struct intel_crtc_state *crtc_st
static void
intel_vrr_dc_balance_compute_config(struct intel_crtc_state *crtc_state)
{
+ struct intel_display *display = to_intel_display(crtc_state);
int guardband_usec, adjustment_usec;
struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
- if (!intel_vrr_dc_balance_possible(crtc_state) || !crtc_state->vrr.enable)
+ if (!intel_vrr_dc_balance_possible(crtc_state) ||
+ !crtc_state->vrr.enable || !display->params.enable_dc_balance)
return;
crtc_state->vrr.dc_balance.vmax = crtc_state->vrr.vmax;
@@ -9,7 +9,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
#include "modules/inc/mod_power.h"
#include "modules/power/power_helpers.h"
@@ -10068,6 +10069,9 @@ static void update_freesync_state_on_stream(
@@ -10088,6 +10089,9 @@ static void update_freesync_state_on_stream(
&vrr_infopacket,
pack_sdp_v1_3);
@@ -19,7 +19,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
new_crtc_state->freesync_vrr_info_changed |=
(memcmp(&new_crtc_state->vrr_infopacket,
&vrr_infopacket,
@@ -10079,6 +10083,36 @@ static void update_freesync_state_on_stream(
@@ -10099,6 +10103,36 @@ static void update_freesync_state_on_stream(
new_stream->vrr_infopacket = vrr_infopacket;
new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
@@ -56,7 +56,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
if (new_crtc_state->freesync_vrr_info_changed)
drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d",
new_crtc_state->base.crtc->base.id,
@@ -10645,9 +10679,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
@@ -10665,9 +10699,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
}
if (acrtc_state->stream) {
@@ -70,7 +70,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
}
}
@@ -12049,6 +12086,14 @@ static void get_freesync_config_for_crtc(
@@ -12069,6 +12106,14 @@ static void get_freesync_config_for_crtc(
}
out:
new_crtc_state->freesync_config = config;
@@ -85,7 +85,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
}
static void reset_freesync_config_for_crtc(
@@ -14011,6 +14056,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
@@ -14031,6 +14076,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
if (!adev->dm.freesync_module || !dc_supports_vrr(sink->ctx->dce_version))
goto update;
@@ -101,7 +101,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
/* Some eDP panels only have the refresh rate range info in DisplayID */
@@ -14036,7 +14090,9 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
@@ -14056,7 +14110,9 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
}
@@ -112,7 +112,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
if (i >= 0) {
amdgpu_dm_connector->vsdb_info = vsdb_info;
@@ -14052,6 +14108,59 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
@@ -14072,6 +14128,59 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
}
}
@@ -172,7 +172,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
}
if (amdgpu_dm_connector->dc_link)
@@ -14093,6 +14202,11 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
@@ -14113,6 +14222,11 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
if (dm_con_state)
dm_con_state->freesync_capable = freesync_capable;
@@ -1,7 +1,7 @@
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -10069,7 +10069,10 @@ static void update_freesync_state_on_stream(
@@ -10089,7 +10089,10 @@ static void update_freesync_state_on_stream(
&vrr_infopacket,
pack_sdp_v1_3);
@@ -0,0 +1,14 @@
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -10090,8 +10090,8 @@ static void update_freesync_state_on_stream(
pack_sdp_v1_3);
/* Per HDMI 2.1, VTEM is valid on TMDS as well as FRL */
- if (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_FRL ||
- (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A &&
+ if (new_stream->signal == SIGNAL_TYPE_HDMI_FRL ||
+ (new_stream->signal == SIGNAL_TYPE_HDMI_TYPE_A &&
aconn && aconn->base.display_info.hdmi.vrr_cap.supported))
mod_build_infopacket_vtem(new_stream, &vrr_params, 0, &vrr_infopacket);
@@ -0,0 +1,12 @@
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -2025,7 +2025,7 @@ static void hdmi_frl_status_polling_work(struct work_struct *work)
if (!dc_is_hdmi_signal(dc_link->connector_signal))
continue;
- if (dc_link->connector_signal != SIGNAL_TYPE_HDMI_FRL)
+ if (dc_link->frl_link_settings.frl_link_rate == 0)
continue;
link_update = dc_link_frl_poll_status_flag(dc_link);
@@ -0,0 +1,12 @@
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c
--- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c
@@ -882,7 +882,7 @@ static void verify_link_capability_non_destructive(struct dc_link *link)
else
link->verified_link_cap = dp_get_max_link_cap(link);
} else if (dc_is_hdmi_signal(link->local_sink->sink_signal)) {
- link->verified_link_cap = link->reported_link_cap;
+ link->frl_verified_link_cap = link->frl_reported_link_cap;
if (is_hdmi_frl_in_use(link)) {
link->local_sink->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
@@ -0,0 +1,26 @@
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c b/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c
--- a/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c
@@ -630,17 +630,17 @@ enum frl_cap_chk_result dml1_frl_cap_chk(struct frl_cap_chk_params *params)
{
struct frl_cap_chk_intermediates inter;
-#if defined (CONFIG_DRM_AMD_DC_FP)
- if (params->compressed)
- return dml1_frl_cap_chk_compressed(params, &inter);
-#endif
-
return dml1_frl_cap_chk_inter(params, &inter);
}
enum frl_cap_chk_result dml1_frl_cap_chk_inter(struct frl_cap_chk_params *params,
struct frl_cap_chk_intermediates *inter)
{
+#if defined (CONFIG_DRM_AMD_DC_FP)
+ if (params->compressed)
+ return dml1_frl_cap_chk_compressed(params, inter);
+#endif
+
return dml1_frl_cap_chk_uncompressed(params, inter);
}
@@ -1,7 +1,7 @@
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7096,6 +7096,11 @@ static void fill_stream_properties_from_drm_display_mode(
@@ -7116,6 +7116,11 @@ static void fill_stream_properties_from_drm_display_mode(
stream->output_color_space = get_output_color_space(timing_out, connector_state);
stream->content_type = get_output_content_type(connector_state);
@@ -13,7 +13,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
}
static void fill_audio_info(struct audio_info *audio_info,
@@ -7616,6 +7621,7 @@ create_stream_for_sink(struct drm_connector *connector,
@@ -7636,6 +7641,7 @@ create_stream_for_sink(struct drm_connector *connector,
struct drm_display_mode mode;
struct drm_display_mode saved_mode;
struct drm_display_mode *freesync_mode = NULL;
@@ -21,7 +21,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
bool native_mode_found = false;
bool recalculate_timing = false;
bool scale = dm_state->scaling != RMX_OFF;
@@ -7707,6 +7713,16 @@ create_stream_for_sink(struct drm_connector *connector,
@@ -7727,6 +7733,16 @@ create_stream_for_sink(struct drm_connector *connector,
}
}
@@ -1,7 +1,7 @@
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7622,6 +7622,7 @@ create_stream_for_sink(struct drm_connector *connector,
@@ -7642,6 +7642,7 @@ create_stream_for_sink(struct drm_connector *connector,
struct drm_display_mode saved_mode;
struct drm_display_mode *freesync_mode = NULL;
struct drm_display_mode *dsc_passthru_mode = NULL;
@@ -9,7 +9,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
bool native_mode_found = false;
bool recalculate_timing = false;
bool scale = dm_state->scaling != RMX_OFF;
@@ -7688,6 +7689,22 @@ create_stream_for_sink(struct drm_connector *connector,
@@ -7708,6 +7709,22 @@ create_stream_for_sink(struct drm_connector *connector,
mode_refresh = drm_mode_vrefresh(&mode);
@@ -32,7 +32,7 @@ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm
if (preferred_mode == NULL) {
/*
* This may not be an error, the use case is when we have no
@@ -7713,16 +7730,6 @@ create_stream_for_sink(struct drm_connector *connector,
@@ -7733,16 +7750,6 @@ create_stream_for_sink(struct drm_connector *connector,
}
}
@@ -1,16 +0,0 @@
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -2366,8 +2366,10 @@ static void bxt_sanitize_cdclk(struct intel_display *display)
* dividers both syncing to an active pipe, or asynchronously
* (PIPE_NONE).
*/
- cdctl &= ~bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
- cdctl |= bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
+ if (DISPLAY_VER(display) < 30) {
+ cdctl &= ~bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
+ cdctl |= bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
+ }
if (cdctl != expected) {
if (DISPLAY_VER(display) < 20) {
Loaded 100 of 524 files, more files were not shown because too many files have changed in this diff. Show more