Linux 6.3 release

This commit is contained in:
ferrreo 2023-04-24 12:43:21 +01:00
parent 4077afb918
commit 7b88f21dac
21 changed files with 23564 additions and 1376 deletions

View File

@ -2,6 +2,6 @@
. ./scripts/source.sh . ./scripts/source.sh
. ../scripts/patch.sh . ../scripts/patch.sh
. ../scripts/config.sh # . ../scripts/config.sh
. ../scripts/build.sh # . ../scripts/build.sh
. ../scripts/output.sh # . ../scripts/output.sh

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
From 40a2f9f3e7e56936385c5a97957cd43fbb85fd32 Mon Sep 17 00:00:00 2001 From 0365d5da967f712e2210bc34b0bd3c17aa752ad3 Mon Sep 17 00:00:00 2001
From: Peter Jung <admin@ptr1337.dev> From: Peter Jung <admin@ptr1337.dev>
Date: Sun, 9 Apr 2023 21:35:07 +0200 Date: Mon, 17 Apr 2023 18:43:10 +0200
Subject: [PATCH] EEVDF Subject: [PATCH] EEVDF
Signed-off-by: Peter Jung <admin@ptr1337.dev> Signed-off-by: Peter Jung <admin@ptr1337.dev>
@ -13,11 +13,11 @@ Signed-off-by: Peter Jung <admin@ptr1337.dev>
init/init_task.c | 3 +- init/init_task.c | 3 +-
kernel/sched/core.c | 67 +- kernel/sched/core.c | 67 +-
kernel/sched/debug.c | 50 +- kernel/sched/debug.c | 50 +-
kernel/sched/fair.c | 1171 ++++++++++------------- kernel/sched/fair.c | 1230 +++++++++++------------
kernel/sched/features.h | 28 +- kernel/sched/features.h | 28 +-
kernel/sched/sched.h | 23 +- kernel/sched/sched.h | 23 +-
tools/include/uapi/linux/sched.h | 4 +- tools/include/uapi/linux/sched.h | 4 +-
12 files changed, 697 insertions(+), 717 deletions(-) 12 files changed, 756 insertions(+), 717 deletions(-)
diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
index f67c0829350b..a39dfda3d032 100644 index f67c0829350b..a39dfda3d032 100644
@ -476,7 +476,7 @@ index 8d64fba16cfe..e0d10ac21016 100644
P(dl.runtime); P(dl.runtime);
P(dl.deadline); P(dl.deadline);
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 115be8a965f2..76bd212ee5bd 100644 index 0f92281fbed9..917f0cc106b6 100644
--- a/kernel/sched/fair.c --- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c +++ b/kernel/sched/fair.c
@@ -47,6 +47,7 @@ @@ -47,6 +47,7 @@
@ -608,7 +608,7 @@ index 115be8a965f2..76bd212ee5bd 100644
const struct sched_class fair_sched_class; const struct sched_class fair_sched_class;
@@ -619,35 +569,203 @@ static inline bool entity_before(const struct sched_entity *a, @@ -619,35 +569,229 @@ static inline bool entity_before(const struct sched_entity *a,
return (s64)(a->vruntime - b->vruntime) < 0; return (s64)(a->vruntime - b->vruntime) < 0;
} }
@ -624,34 +624,60 @@ index 115be8a965f2..76bd212ee5bd 100644
+/* +/*
+ * Compute virtual time from the per-task service numbers: + * Compute virtual time from the per-task service numbers:
+ * + *
+ * Fair schedulers conserve lag: \Sum lag_i = 0 + * Fair schedulers conserve lag:
+ * + *
+ * lag_i = S - s_i = w_i * (V - v_i) + * \Sum lag_i = 0
+ * + *
+ * \Sum lag_i = 0 -> \Sum w_i * (V - v_i) = V * \Sum w_i - \Sum w_i * v_i = 0 + * Where lag_i is given by:
+ * + *
+ * From which we solve V: + * lag_i = S - s_i = w_i * (V - v_i)
+ * + *
+ * \Sum v_i * w_i + * Where S is the ideal service time and V is it's virtual time counterpart.
+ * V = -------------- + * Therefore:
+ * \Sum w_i + *
+ * \Sum lag_i = 0
+ * \Sum w_i * (V - v_i) = 0
+ * \Sum w_i * V - w_i * v_i = 0
+ *
+ * From which we can solve an expression for V in v_i (which we have in
+ * se->vruntime):
+ *
+ * \Sum v_i * w_i \Sum v_i * w_i
+ * V = -------------- = --------------
+ * \Sum w_i W
+ *
+ * Specifically, this is the weighted average of all entity virtual runtimes.
+ *
+ * [[ NOTE: this is only equal to the ideal scheduler under the condition
+ * that join/leave operations happen at lag_i = 0, otherwise the
+ * virtual time has non-continguous motion equivalent to:
+ *
+ * V +-= lag_i / W
+ *
+ * Also see the comment in place_entity() that deals with this. ]]
+ * + *
+ * However, since v_i is u64, and the multiplcation could easily overflow + * However, since v_i is u64, and the multiplcation could easily overflow
+ * transform it into a relative form that uses smaller quantities: + * transform it into a relative form that uses smaller quantities:
+ * + *
+ * Substitute: v_i == (v_i - v) + v + * Substitute: v_i == (v_i - v0) + v0
+ * + *
+ * \Sum ((v_i - v) + v) * w_i \Sum (v_i - v) * w_i + * \Sum ((v_i - v0) + v0) * w_i \Sum (v_i - v0) * w_i
+ * V = -------------------------- = -------------------- + v + * V = ---------------------------- = --------------------- + v0
+ * \Sum w_i \Sum w_i + * W W
+ * + *
+ * min_vruntime = v + * Which we track using:
+ * avg_vruntime = \Sum (v_i - v) * w_i + *
+ * cfs_rq->load = \Sum w_i + * v0 := cfs_rq->min_vruntime
+ * \Sum (v_i - v0) * w_i := cfs_rq->avg_vruntime
+ * \Sum w_i := cfs_rq->avg_load
+ * + *
+ * Since min_vruntime is a monotonic increasing variable that closely tracks + * Since min_vruntime is a monotonic increasing variable that closely tracks
+ * the per-task service, these deltas: (v_i - v), will be in the order of the + * the per-task service, these deltas: (v_i - v), will be in the order of the
+ * maximal (virtual) lag induced in the system due to quantisation. + * maximal (virtual) lag induced in the system due to quantisation.
+ *
+ * Also, we use scale_load_down() to reduce the size.
+ *
+ * As measured, the max (key * weight) value was ~44 bits for a kernel build.
+ */ + */
+static void +static void
+avg_vruntime_add(struct cfs_rq *cfs_rq, struct sched_entity *se) +avg_vruntime_add(struct cfs_rq *cfs_rq, struct sched_entity *se)
@ -829,7 +855,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
static inline bool __entity_less(struct rb_node *a, const struct rb_node *b) static inline bool __entity_less(struct rb_node *a, const struct rb_node *b)
@@ -655,17 +773,51 @@ static inline bool __entity_less(struct rb_node *a, const struct rb_node *b) @@ -655,17 +799,51 @@ static inline bool __entity_less(struct rb_node *a, const struct rb_node *b)
return entity_before(__node_2_se(a), __node_2_se(b)); return entity_before(__node_2_se(a), __node_2_se(b));
} }
@ -883,7 +909,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq) struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq)
@@ -678,14 +830,81 @@ struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq) @@ -678,14 +856,81 @@ struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq)
return __node_2_se(left); return __node_2_se(left);
} }
@ -929,7 +955,8 @@ index 115be8a965f2..76bd212ee5bd 100644
+ node = node->rb_left; + node = node->rb_left;
+ continue; + continue;
+ } + }
+
- return __node_2_se(next);
+ /* + /*
+ * If this entity has an earlier deadline than the previous + * If this entity has an earlier deadline than the previous
+ * best, take this one. If it also has the earliest deadline + * best, take this one. If it also has the earliest deadline
@ -964,13 +991,12 @@ index 115be8a965f2..76bd212ee5bd 100644
+ return left; + return left;
+ } + }
+ } + }
+
- return __node_2_se(next);
+ return best; + return best;
} }
#ifdef CONFIG_SCHED_DEBUG #ifdef CONFIG_SCHED_DEBUG
@@ -707,104 +926,43 @@ int sched_update_scaling(void) @@ -707,104 +952,43 @@ int sched_update_scaling(void)
{ {
unsigned int factor = get_update_sysctl_factor(); unsigned int factor = get_update_sysctl_factor();
@ -997,12 +1023,12 @@ index 115be8a965f2..76bd212ee5bd 100644
{ {
- if (unlikely(se->load.weight != NICE_0_LOAD)) - if (unlikely(se->load.weight != NICE_0_LOAD))
- delta = __calc_delta(delta, NICE_0_LOAD, &se->load); - delta = __calc_delta(delta, NICE_0_LOAD, &se->load);
-
- return delta;
-}
+ u32 weight = sched_prio_to_weight[prio]; + u32 weight = sched_prio_to_weight[prio];
+ u64 base = sysctl_sched_base_slice; + u64 base = sysctl_sched_base_slice;
- return delta;
-}
-
-/* -/*
- * The idea is to set a period in which each task runs once. - * The idea is to set a period in which each task runs once.
- * - *
@ -1096,7 +1122,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
#include "pelt.h" #include "pelt.h"
@@ -939,6 +1097,7 @@ static void update_curr(struct cfs_rq *cfs_rq) @@ -939,6 +1123,7 @@ static void update_curr(struct cfs_rq *cfs_rq)
schedstat_add(cfs_rq->exec_clock, delta_exec); schedstat_add(cfs_rq->exec_clock, delta_exec);
curr->vruntime += calc_delta_fair(delta_exec, curr); curr->vruntime += calc_delta_fair(delta_exec, curr);
@ -1104,7 +1130,7 @@ index 115be8a965f2..76bd212ee5bd 100644
update_min_vruntime(cfs_rq); update_min_vruntime(cfs_rq);
if (entity_is_task(curr)) { if (entity_is_task(curr)) {
@@ -3336,16 +3495,28 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { } @@ -3336,16 +3521,28 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
unsigned long weight) unsigned long weight)
{ {
@ -1133,7 +1159,7 @@ index 115be8a965f2..76bd212ee5bd 100644
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
do { do {
u32 divider = get_pelt_divider(&se->avg); u32 divider = get_pelt_divider(&se->avg);
@@ -3355,9 +3526,11 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, @@ -3355,9 +3552,11 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
#endif #endif
enqueue_load_avg(cfs_rq, se); enqueue_load_avg(cfs_rq, se);
@ -1147,7 +1173,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
void reweight_task(struct task_struct *p, int prio) void reweight_task(struct task_struct *p, int prio)
@@ -4653,158 +4826,135 @@ static inline void update_misfit_status(struct task_struct *p, struct rq *rq) {} @@ -4653,158 +4852,168 @@ static inline void update_misfit_status(struct task_struct *p, struct rq *rq) {}
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
@ -1211,20 +1237,53 @@ index 115be8a965f2..76bd212ee5bd 100644
+ * If we want to place a task and preserve lag, we have to + * If we want to place a task and preserve lag, we have to
+ * consider the effect of the new entity on the weighted + * consider the effect of the new entity on the weighted
+ * average and compensate for this, otherwise lag can quickly + * average and compensate for this, otherwise lag can quickly
+ * evaporate: + * evaporate.
+ * + *
+ * l_i = V - v_i <=> v_i = V - l_i + * Lag is defined as:
+ * + *
+ * V = v_avg = W*v_avg / W + * lag_i = S - s_i = w_i * (V - v_i)
+ * + *
+ * V' = (W*v_avg + w_i*v_i) / (W + w_i) + * To avoid the 'w_i' term all over the place, we only track
+ * = (W*v_avg + w_i(v_avg - l_i)) / (W + w_i) + * the virtual lag:
+ * = v_avg + w_i*l_i/(W + w_i)
+ * + *
+ * l_i' = V' - v_i = v_avg + w_i*l_i/(W + w_i) - (v_avg - l) + * vl_i = V - v_i <=> v_i = V - vl_i
+ * = l_i - w_i*l_i/(W + w_i)
+ * + *
+ * l_i = (W + w_i) * l_i' / W + * And we take V to be the weighted average of all v:
+ *
+ * V = (\Sum w_j*v_j) / W
+ *
+ * Where W is: \Sum w_j
+ *
+ * Then, the weighted average after adding an entity with lag
+ * vl_i is given by:
+ *
+ * V' = (\Sum w_j*v_j + w_i*v_i) / (W + w_i)
+ * = (W*V + w_i*(V - vl_i)) / (W + w_i)
+ * = (W*V + w_i*V - w_i*vl_i) / (W + w_i)
+ * = (V*(W + w_i) - w_i*l) / (W + w_i)
+ * = V - w_i*vl_i / (W + w_i)
+ *
+ * And the actual lag after adding an entity with vl_i is:
+ *
+ * vl'_i = V' - v_i
+ * = V - w_i*vl_i / (W + w_i) - (V - vl_i)
+ * = vl_i - w_i*vl_i / (W + w_i)
+ *
+ * Which is strictly less than vl_i. So in order to preserve lag
+ * we should inflate the lag before placement such that the
+ * effective lag after placement comes out right.
+ *
+ * As such, invert the above relation for vl'_i to get the vl_i
+ * we need to use such that the lag after placement is the lag
+ * we computed before dequeue.
+ *
+ * vl'_i = vl_i - w_i*vl_i / (W + w_i)
+ * = ((W + w_i)*vl_i - w_i*vl_i) / (W + w_i)
+ *
+ * (W + w_i)*vl'_i = (W + w_i)*vl_i - w_i*vl_i
+ * = W*vl_i
+ *
+ * vl_i = (W + w_i)*vl'_i / W
+ */ + */
+ load = cfs_rq->avg_load; + load = cfs_rq->avg_load;
+ if (curr && curr->on_rq) + if (curr && curr->on_rq)
@ -1403,7 +1462,7 @@ index 115be8a965f2..76bd212ee5bd 100644
/* /*
* When enqueuing a sched_entity, we must: * When enqueuing a sched_entity, we must:
* - Update loads to have both entity and cfs_rq synced with now. * - Update loads to have both entity and cfs_rq synced with now.
@@ -4816,18 +4966,28 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) @@ -4816,18 +5025,28 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
*/ */
update_load_avg(cfs_rq, se, UPDATE_TG | DO_ATTACH); update_load_avg(cfs_rq, se, UPDATE_TG | DO_ATTACH);
se_update_runnable(se); se_update_runnable(se);
@ -1435,7 +1494,7 @@ index 115be8a965f2..76bd212ee5bd 100644
if (!curr) if (!curr)
__enqueue_entity(cfs_rq, se); __enqueue_entity(cfs_rq, se);
se->on_rq = 1; se->on_rq = 1;
@@ -4839,17 +4999,6 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) @@ -4839,17 +5058,6 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
} }
} }
@ -1453,7 +1512,7 @@ index 115be8a965f2..76bd212ee5bd 100644
static void __clear_buddies_next(struct sched_entity *se) static void __clear_buddies_next(struct sched_entity *se)
{ {
for_each_sched_entity(se) { for_each_sched_entity(se) {
@@ -4861,27 +5010,10 @@ static void __clear_buddies_next(struct sched_entity *se) @@ -4861,27 +5069,10 @@ static void __clear_buddies_next(struct sched_entity *se)
} }
} }
@ -1481,7 +1540,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq); static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq);
@@ -4915,20 +5047,12 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) @@ -4915,20 +5106,12 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
clear_buddies(cfs_rq, se); clear_buddies(cfs_rq, se);
@ -1503,7 +1562,7 @@ index 115be8a965f2..76bd212ee5bd 100644
/* return excess runtime on last dequeue */ /* return excess runtime on last dequeue */
return_cfs_rq_runtime(cfs_rq); return_cfs_rq_runtime(cfs_rq);
@@ -4953,44 +5077,14 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) @@ -4953,44 +5136,14 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
static void static void
check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{ {
@ -1549,7 +1608,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
static void static void
@@ -5031,9 +5125,6 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) @@ -5031,9 +5184,6 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
se->prev_sum_exec_runtime = se->sum_exec_runtime; se->prev_sum_exec_runtime = se->sum_exec_runtime;
} }
@ -1559,30 +1618,27 @@ index 115be8a965f2..76bd212ee5bd 100644
/* /*
* Pick the next process, keeping these things in mind, in this order: * Pick the next process, keeping these things in mind, in this order:
* 1) keep things fair between processes/task groups * 1) keep things fair between processes/task groups
@@ -5044,50 +5135,14 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se); @@ -5044,50 +5194,14 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se);
static struct sched_entity * static struct sched_entity *
pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr) pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{ {
- struct sched_entity *left = __pick_first_entity(cfs_rq); - struct sched_entity *left = __pick_first_entity(cfs_rq);
- struct sched_entity *se; - struct sched_entity *se;
- -
/* - /*
- * If curr is set we have to see if its left of the leftmost entity - * If curr is set we have to see if its left of the leftmost entity
- * still in the tree, provided there was anything in the tree at all. - * still in the tree, provided there was anything in the tree at all.
+ * Enabling NEXT_BUDDY will affect latency but not fairness. - */
*/
- if (!left || (curr && entity_before(curr, left))) - if (!left || (curr && entity_before(curr, left)))
- left = curr; - left = curr;
- -
- se = left; /* ideally we run the leftmost entity */ - se = left; /* ideally we run the leftmost entity */
+ if (sched_feat(NEXT_BUDDY) && -
+ cfs_rq->next && entity_eligible(cfs_rq, cfs_rq->next)) /*
+ return cfs_rq->next;
- /*
- * Avoid running the skip buddy, if running something else can - * Avoid running the skip buddy, if running something else can
- * be done without getting too unfair. - * be done without getting too unfair.
- */ + * Enabling NEXT_BUDDY will affect latency but not fairness.
*/
- if (cfs_rq->skip && cfs_rq->skip == se) { - if (cfs_rq->skip && cfs_rq->skip == se) {
- struct sched_entity *second; - struct sched_entity *second;
- -
@ -1597,7 +1653,10 @@ index 115be8a965f2..76bd212ee5bd 100644
- if (second && wakeup_preempt_entity(second, left) < 1) - if (second && wakeup_preempt_entity(second, left) < 1)
- se = second; - se = second;
- } - }
- + if (sched_feat(NEXT_BUDDY) &&
+ cfs_rq->next && entity_eligible(cfs_rq, cfs_rq->next))
+ return cfs_rq->next;
- if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1) { - if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1) {
- /* - /*
- * Someone really wants this to run. If it's not unfair, run it. - * Someone really wants this to run. If it's not unfair, run it.
@ -1615,7 +1674,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq); static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq);
@@ -5104,8 +5159,6 @@ static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev) @@ -5104,8 +5218,6 @@ static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
/* throttle cfs_rqs exceeding runtime */ /* throttle cfs_rqs exceeding runtime */
check_cfs_rq_runtime(cfs_rq); check_cfs_rq_runtime(cfs_rq);
@ -1624,7 +1683,7 @@ index 115be8a965f2..76bd212ee5bd 100644
if (prev->on_rq) { if (prev->on_rq) {
update_stats_wait_start_fair(cfs_rq, prev); update_stats_wait_start_fair(cfs_rq, prev);
/* Put 'current' back into the tree. */ /* Put 'current' back into the tree. */
@@ -6149,13 +6202,12 @@ static inline void unthrottle_offline_cfs_rqs(struct rq *rq) {} @@ -6149,13 +6261,12 @@ static inline void unthrottle_offline_cfs_rqs(struct rq *rq) {}
static void hrtick_start_fair(struct rq *rq, struct task_struct *p) static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
{ {
struct sched_entity *se = &p->se; struct sched_entity *se = &p->se;
@ -1639,7 +1698,7 @@ index 115be8a965f2..76bd212ee5bd 100644
s64 delta = slice - ran; s64 delta = slice - ran;
if (delta < 0) { if (delta < 0) {
@@ -6179,8 +6231,7 @@ static void hrtick_update(struct rq *rq) @@ -6179,8 +6290,7 @@ static void hrtick_update(struct rq *rq)
if (!hrtick_enabled_fair(rq) || curr->sched_class != &fair_sched_class) if (!hrtick_enabled_fair(rq) || curr->sched_class != &fair_sched_class)
return; return;
@ -1649,7 +1708,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
#else /* !CONFIG_SCHED_HRTICK */ #else /* !CONFIG_SCHED_HRTICK */
static inline void static inline void
@@ -6221,17 +6272,6 @@ static int sched_idle_rq(struct rq *rq) @@ -6221,17 +6331,6 @@ static int sched_idle_rq(struct rq *rq)
rq->nr_running); rq->nr_running);
} }
@ -1667,7 +1726,7 @@ index 115be8a965f2..76bd212ee5bd 100644
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static int sched_idle_cpu(int cpu) static int sched_idle_cpu(int cpu)
{ {
@@ -6333,18 +6373,6 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) @@ -6333,18 +6432,6 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
static void set_next_buddy(struct sched_entity *se); static void set_next_buddy(struct sched_entity *se);
@ -1686,7 +1745,7 @@ index 115be8a965f2..76bd212ee5bd 100644
/* /*
* The dequeue_task method is called before nr_running is * The dequeue_task method is called before nr_running is
* decreased. We remove the task from the rbtree and * decreased. We remove the task from the rbtree and
@@ -6417,7 +6445,6 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) @@ -6417,7 +6504,6 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
dequeue_throttle: dequeue_throttle:
util_est_update(&rq->cfs, p, task_sleep); util_est_update(&rq->cfs, p, task_sleep);
@ -1694,7 +1753,7 @@ index 115be8a965f2..76bd212ee5bd 100644
hrtick_update(rq); hrtick_update(rq);
} }
@@ -6551,23 +6578,6 @@ static int wake_wide(struct task_struct *p) @@ -6551,23 +6637,6 @@ static int wake_wide(struct task_struct *p)
return 1; return 1;
} }
@ -1718,7 +1777,7 @@ index 115be8a965f2..76bd212ee5bd 100644
/* /*
* The purpose of wake_affine() is to quickly determine on which CPU we can run * The purpose of wake_affine() is to quickly determine on which CPU we can run
* soonest. For the purpose of speed we only consider the waking and previous * soonest. For the purpose of speed we only consider the waking and previous
@@ -6604,11 +6614,6 @@ wake_affine_idle(int this_cpu, int prev_cpu, int sync) @@ -6604,11 +6673,6 @@ wake_affine_idle(int this_cpu, int prev_cpu, int sync)
if (available_idle_cpu(prev_cpu)) if (available_idle_cpu(prev_cpu))
return prev_cpu; return prev_cpu;
@ -1730,7 +1789,7 @@ index 115be8a965f2..76bd212ee5bd 100644
return nr_cpumask_bits; return nr_cpumask_bits;
} }
@@ -6983,20 +6988,6 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, bool @@ -6983,20 +7047,6 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, bool
/* overloaded LLC is unlikely to have idle cpu/core */ /* overloaded LLC is unlikely to have idle cpu/core */
if (nr == 1) if (nr == 1)
return -1; return -1;
@ -1751,7 +1810,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
} }
@@ -7729,18 +7720,6 @@ static void migrate_task_rq_fair(struct task_struct *p, int new_cpu) @@ -7729,18 +7779,6 @@ static void migrate_task_rq_fair(struct task_struct *p, int new_cpu)
{ {
struct sched_entity *se = &p->se; struct sched_entity *se = &p->se;
@ -1770,7 +1829,7 @@ index 115be8a965f2..76bd212ee5bd 100644
if (!task_on_rq_migrating(p)) { if (!task_on_rq_migrating(p)) {
remove_entity_load_avg(se); remove_entity_load_avg(se);
@@ -7778,66 +7757,6 @@ balance_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) @@ -7778,66 +7816,6 @@ balance_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
@ -1837,7 +1896,7 @@ index 115be8a965f2..76bd212ee5bd 100644
static void set_next_buddy(struct sched_entity *se) static void set_next_buddy(struct sched_entity *se)
{ {
for_each_sched_entity(se) { for_each_sched_entity(se) {
@@ -7849,12 +7768,6 @@ static void set_next_buddy(struct sched_entity *se) @@ -7849,12 +7827,6 @@ static void set_next_buddy(struct sched_entity *se)
} }
} }
@ -1850,7 +1909,7 @@ index 115be8a965f2..76bd212ee5bd 100644
/* /*
* Preempt the current task with a newly woken task if needed: * Preempt the current task with a newly woken task if needed:
*/ */
@@ -7863,7 +7776,6 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ @@ -7863,7 +7835,6 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
struct task_struct *curr = rq->curr; struct task_struct *curr = rq->curr;
struct sched_entity *se = &curr->se, *pse = &p->se; struct sched_entity *se = &curr->se, *pse = &p->se;
struct cfs_rq *cfs_rq = task_cfs_rq(curr); struct cfs_rq *cfs_rq = task_cfs_rq(curr);
@ -1858,7 +1917,7 @@ index 115be8a965f2..76bd212ee5bd 100644
int next_buddy_marked = 0; int next_buddy_marked = 0;
int cse_is_idle, pse_is_idle; int cse_is_idle, pse_is_idle;
@@ -7879,7 +7791,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ @@ -7879,7 +7850,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
if (unlikely(throttled_hierarchy(cfs_rq_of(pse)))) if (unlikely(throttled_hierarchy(cfs_rq_of(pse))))
return; return;
@ -1867,7 +1926,7 @@ index 115be8a965f2..76bd212ee5bd 100644
set_next_buddy(pse); set_next_buddy(pse);
next_buddy_marked = 1; next_buddy_marked = 1;
} }
@@ -7924,35 +7836,19 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ @@ -7924,35 +7895,19 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
if (cse_is_idle != pse_is_idle) if (cse_is_idle != pse_is_idle)
return; return;
@ -1910,7 +1969,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
@@ -8153,8 +8049,6 @@ static void put_prev_task_fair(struct rq *rq, struct task_struct *prev) @@ -8153,8 +8108,6 @@ static void put_prev_task_fair(struct rq *rq, struct task_struct *prev)
/* /*
* sched_yield() is very simple * sched_yield() is very simple
@ -1919,7 +1978,7 @@ index 115be8a965f2..76bd212ee5bd 100644
*/ */
static void yield_task_fair(struct rq *rq) static void yield_task_fair(struct rq *rq)
{ {
@@ -8170,21 +8064,19 @@ static void yield_task_fair(struct rq *rq) @@ -8170,21 +8123,19 @@ static void yield_task_fair(struct rq *rq)
clear_buddies(cfs_rq, se); clear_buddies(cfs_rq, se);
@ -1953,7 +2012,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
static bool yield_to_task_fair(struct rq *rq, struct task_struct *p) static bool yield_to_task_fair(struct rq *rq, struct task_struct *p)
@@ -8427,8 +8319,7 @@ static int task_hot(struct task_struct *p, struct lb_env *env) @@ -8427,8 +8378,7 @@ static int task_hot(struct task_struct *p, struct lb_env *env)
* Buddy candidates are cache hot: * Buddy candidates are cache hot:
*/ */
if (sched_feat(CACHE_HOT_BUDDY) && env->dst_rq->nr_running && if (sched_feat(CACHE_HOT_BUDDY) && env->dst_rq->nr_running &&
@ -1963,7 +2022,7 @@ index 115be8a965f2..76bd212ee5bd 100644
return 1; return 1;
if (sysctl_sched_migration_cost == -1) if (sysctl_sched_migration_cost == -1)
@@ -11932,8 +11823,8 @@ static void rq_offline_fair(struct rq *rq) @@ -11942,8 +11892,8 @@ static void rq_offline_fair(struct rq *rq)
static inline bool static inline bool
__entity_slice_used(struct sched_entity *se, int min_nr_tasks) __entity_slice_used(struct sched_entity *se, int min_nr_tasks)
{ {
@ -1973,7 +2032,7 @@ index 115be8a965f2..76bd212ee5bd 100644
return (rtime * min_nr_tasks > slice); return (rtime * min_nr_tasks > slice);
} }
@@ -12077,8 +11968,8 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued) @@ -12087,8 +12037,8 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
*/ */
static void task_fork_fair(struct task_struct *p) static void task_fork_fair(struct task_struct *p)
{ {
@ -1983,7 +2042,7 @@ index 115be8a965f2..76bd212ee5bd 100644
struct rq *rq = this_rq(); struct rq *rq = this_rq();
struct rq_flags rf; struct rq_flags rf;
@@ -12087,22 +11978,9 @@ static void task_fork_fair(struct task_struct *p) @@ -12097,22 +12047,9 @@ static void task_fork_fair(struct task_struct *p)
cfs_rq = task_cfs_rq(current); cfs_rq = task_cfs_rq(current);
curr = cfs_rq->curr; curr = cfs_rq->curr;
@ -2008,7 +2067,7 @@ index 115be8a965f2..76bd212ee5bd 100644
rq_unlock(rq, &rf); rq_unlock(rq, &rf);
} }
@@ -12131,34 +12009,6 @@ prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio) @@ -12141,34 +12078,6 @@ prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio)
check_preempt_curr(rq, p, 0); check_preempt_curr(rq, p, 0);
} }
@ -2043,7 +2102,7 @@ index 115be8a965f2..76bd212ee5bd 100644
#ifdef CONFIG_FAIR_GROUP_SCHED #ifdef CONFIG_FAIR_GROUP_SCHED
/* /*
* Propagate the changes of the sched_entity across the tg tree to make it * Propagate the changes of the sched_entity across the tg tree to make it
@@ -12229,16 +12079,6 @@ static void attach_entity_cfs_rq(struct sched_entity *se) @@ -12239,16 +12148,6 @@ static void attach_entity_cfs_rq(struct sched_entity *se)
static void detach_task_cfs_rq(struct task_struct *p) static void detach_task_cfs_rq(struct task_struct *p)
{ {
struct sched_entity *se = &p->se; struct sched_entity *se = &p->se;
@ -2060,7 +2119,7 @@ index 115be8a965f2..76bd212ee5bd 100644
detach_entity_cfs_rq(se); detach_entity_cfs_rq(se);
} }
@@ -12246,12 +12086,8 @@ static void detach_task_cfs_rq(struct task_struct *p) @@ -12256,12 +12155,8 @@ static void detach_task_cfs_rq(struct task_struct *p)
static void attach_task_cfs_rq(struct task_struct *p) static void attach_task_cfs_rq(struct task_struct *p)
{ {
struct sched_entity *se = &p->se; struct sched_entity *se = &p->se;
@ -2073,7 +2132,7 @@ index 115be8a965f2..76bd212ee5bd 100644
} }
static void switched_from_fair(struct rq *rq, struct task_struct *p) static void switched_from_fair(struct rq *rq, struct task_struct *p)
@@ -12362,6 +12198,7 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) @@ -12372,6 +12267,7 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
goto err; goto err;
tg->shares = NICE_0_LOAD; tg->shares = NICE_0_LOAD;
@ -2081,7 +2140,7 @@ index 115be8a965f2..76bd212ee5bd 100644
init_cfs_bandwidth(tg_cfs_bandwidth(tg)); init_cfs_bandwidth(tg_cfs_bandwidth(tg));
@@ -12460,6 +12297,9 @@ void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq, @@ -12470,6 +12366,9 @@ void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
} }
se->my_q = cfs_rq; se->my_q = cfs_rq;
@ -2091,7 +2150,7 @@ index 115be8a965f2..76bd212ee5bd 100644
/* guarantee group entities always have weight */ /* guarantee group entities always have weight */
update_load_set(&se->load, NICE_0_LOAD); update_load_set(&se->load, NICE_0_LOAD);
se->parent = parent; se->parent = parent;
@@ -12590,6 +12430,29 @@ int sched_group_set_idle(struct task_group *tg, long idle) @@ -12600,6 +12499,29 @@ int sched_group_set_idle(struct task_group *tg, long idle)
return 0; return 0;
} }
@ -2121,7 +2180,7 @@ index 115be8a965f2..76bd212ee5bd 100644
#else /* CONFIG_FAIR_GROUP_SCHED */ #else /* CONFIG_FAIR_GROUP_SCHED */
void free_fair_sched_group(struct task_group *tg) { } void free_fair_sched_group(struct task_group *tg) { }
@@ -12616,7 +12479,7 @@ static unsigned int get_rr_interval_fair(struct rq *rq, struct task_struct *task @@ -12626,7 +12548,7 @@ static unsigned int get_rr_interval_fair(struct rq *rq, struct task_struct *task
* idle runqueue: * idle runqueue:
*/ */
if (rq->cfs.load.weight) if (rq->cfs.load.weight)

View File

@ -1,424 +0,0 @@
From d1d05832308e210422f7c52d052b026deb9fabf1 Mon Sep 17 00:00:00 2001
From: Peter Jung <admin@ptr1337.dev>
Date: Thu, 6 Apr 2023 19:12:01 +0200
Subject: [PATCH] bore
Signed-off-by: Peter Jung <admin@ptr1337.dev>
---
include/linux/sched.h | 6 ++
init/Kconfig | 20 ++++++
kernel/sched/core.c | 30 ++++++++
kernel/sched/debug.c | 3 +
kernel/sched/fair.c | 149 +++++++++++++++++++++++++++++++++++++++-
kernel/sched/features.h | 8 +++
6 files changed, 213 insertions(+), 3 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 63d242164b1a..39a046d6cf90 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -555,6 +555,12 @@ struct sched_entity {
u64 sum_exec_runtime;
u64 vruntime;
u64 prev_sum_exec_runtime;
+#ifdef CONFIG_SCHED_BORE
+ u64 prev_burst_time;
+ u64 burst_time;
+ u64 max_burst_time;
+ u8 penalty_score;
+#endif // CONFIG_SCHED_BORE
u64 nr_migrations;
diff --git a/init/Kconfig b/init/Kconfig
index 1fb5f313d18f..6595e5ed2416 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1285,6 +1285,26 @@ config CHECKPOINT_RESTORE
If unsure, say N here.
+config SCHED_BORE
+ bool "Burst-Oriented Response Enhancer"
+ default y
+ help
+ In Desktop and Mobile computing, one might prefer interactive
+ tasks to keep responsive no matter what they run in the background.
+
+ Enabling this kernel feature modifies the scheduler to discriminate
+ tasks by their burst time (runtime since it last went sleeping or
+ yielding state) and prioritize those that run less bursty.
+ Such tasks usually include window compositor, widgets backend,
+ terminal emulator, video playback, games and so on.
+ With a little impact to scheduling fairness, it may improve
+ responsiveness especially under heavy background workload.
+
+ You can turn it off by setting the sysctl kernel.sched_bore = 0.
+ Enabling this feature implies NO_GENTLE_FAIR_SLEEPERS by default.
+
+ If unsure say Y here.
+
config SCHED_AUTOGROUP
bool "Automatic process group scheduling"
select CGROUPS
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 0d18c3969f90..34db768f6ba8 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4418,6 +4418,22 @@ int wake_up_state(struct task_struct *p, unsigned int state)
return try_to_wake_up(p, state, 0);
}
+#ifdef CONFIG_SCHED_BORE
+static inline void adjust_prev_burst(struct task_struct *p)
+{
+ u32 cnt = 0;
+ u64 sum = 0, avg = 0;
+ struct task_struct *sib;
+ list_for_each_entry(sib, &p->sibling, sibling) {
+ cnt++;
+ sum += sib->se.max_burst_time >> 8;
+ }
+ if (cnt) avg = div_u64(sum, cnt) << 8;
+ if (p->se.prev_burst_time < avg) p->se.prev_burst_time = avg;
+ p->se.max_burst_time = p->se.prev_burst_time;
+}
+#endif // CONFIG_SCHED_BORE
+
/*
* Perform scheduler related setup for a newly forked process p.
* p is forked by current.
@@ -4434,6 +4450,9 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
p->se.prev_sum_exec_runtime = 0;
p->se.nr_migrations = 0;
p->se.vruntime = 0;
+#ifdef CONFIG_SCHED_BORE
+ p->se.burst_time = 0;
+#endif // CONFIG_SCHED_BORE
INIT_LIST_HEAD(&p->se.group_node);
#ifdef CONFIG_FAIR_GROUP_SCHED
@@ -4659,6 +4678,9 @@ late_initcall(sched_core_sysctl_init);
int sched_fork(unsigned long clone_flags, struct task_struct *p)
{
__sched_fork(clone_flags, p);
+#ifdef CONFIG_SCHED_BORE
+ adjust_prev_burst(p);
+#endif // CONFIG_SCHED_BORE
/*
* We mark the process as NEW here. This guarantees that
* nobody will actually run it, and a signal or other external
@@ -9126,6 +9148,10 @@ void __init init_idle(struct task_struct *idle, int cpu)
idle->__state = TASK_RUNNING;
idle->se.exec_start = sched_clock();
+#ifdef CONFIG_SCHED_BORE
+ idle->se.prev_burst_time = 0;
+ idle->se.max_burst_time = 0;
+#endif //CONFIG_SCHED_BORE
/*
* PF_KTHREAD should already be set at this point; regardless, make it
* look like a proper per-CPU kthread.
@@ -9793,6 +9819,10 @@ void __init sched_init(void)
BUG_ON(&dl_sched_class != &stop_sched_class + 1);
#endif
+#ifdef CONFIG_SCHED_BORE
+ printk(KERN_INFO "BORE (Burst-Oriented Response Enhancer) CPU Scheduler modification 2.1.1 by Masahito Suzuki");
+#endif // CONFIG_SCHED_BORE
+
wait_bit_init();
#ifdef CONFIG_FAIR_GROUP_SCHED
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 1637b65ba07a..752c43a9ff13 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -547,6 +547,9 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
SPLIT_NS(schedstat_val_or_zero(p->stats.sum_sleep_runtime)),
SPLIT_NS(schedstat_val_or_zero(p->stats.sum_block_runtime)));
+#ifdef CONFIG_SCHED_BORE
+ SEQ_printf(m, " %2d", p->se.penalty_score);
+#endif
#ifdef CONFIG_NUMA_BALANCING
SEQ_printf(m, " %d %d", task_node(p), task_numa_group_id(p));
#endif
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 6986ea31c984..ee461e4586ca 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -19,6 +19,9 @@
*
* Adaptive scheduling granularity, math enhancements by Peter Zijlstra
* Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
+ *
+ * Burst-Oriented Response Enhancer (BORE) CPU Scheduler
+ * Copyright (C) 2021-2023 Masahito Suzuki <firelzrd@gmail.com>
*/
#include <linux/energy_model.h>
#include <linux/mmap_lock.h>
@@ -126,6 +129,16 @@ static unsigned int normalized_sysctl_sched_wakeup_granularity = 1000000UL;
const_debug unsigned int sysctl_sched_migration_cost = 500000UL;
+#ifdef CONFIG_SCHED_BORE
+unsigned int __read_mostly sched_bore = 3;
+unsigned int __read_mostly sched_burst_penalty_offset = 12;
+unsigned int __read_mostly sched_burst_penalty_scale = 1292;
+unsigned int __read_mostly sched_burst_smoothness = 1;
+static int three = 3;
+static int sixty_four = 64;
+static int maxval_12_bits = 4095;
+#endif // CONFIG_SCHED_BORE
+
int sched_thermal_decay_shift;
static int __init setup_sched_thermal_decay_shift(char *str)
{
@@ -185,6 +198,44 @@ static unsigned int sysctl_numa_balancing_promote_rate_limit = 65536;
#ifdef CONFIG_SYSCTL
static struct ctl_table sched_fair_sysctls[] = {
+#ifdef CONFIG_SCHED_BORE
+ {
+ .procname = "sched_bore",
+ .data = &sched_bore,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = &three,
+ },
+ {
+ .procname = "sched_burst_penalty_offset",
+ .data = &sched_burst_penalty_offset,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = &sixty_four,
+ },
+ {
+ .procname = "sched_burst_penalty_scale",
+ .data = &sched_burst_penalty_scale,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = &maxval_12_bits,
+ },
+ {
+ .procname = "sched_burst_smoothness",
+ .data = &sched_burst_smoothness,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = &three,
+ },
+#endif // CONFIG_SCHED_BORE
{
.procname = "sched_child_runs_first",
.data = &sysctl_sched_child_runs_first,
@@ -891,6 +942,47 @@ static void update_tg_load_avg(struct cfs_rq *cfs_rq)
}
#endif /* CONFIG_SMP */
+#ifdef CONFIG_SCHED_BORE
+static inline u32 __calc_bits10(u64 burst_time) {
+ u32 bits = fls64(burst_time);
+ u32 fdigs = likely(bits) ? bits - 1 : 0;
+ return (bits << 10) | (burst_time << (64 - fdigs) >> 54);
+}
+
+static inline u32 __calc_burst_score(u32 bits10, u32 offset) {
+ u32 val10 = max((s32)0, (s32)bits10 - (s32)(offset << 10));
+ return min((u32)39, val10 * sched_burst_penalty_scale >> 20);
+}
+
+static void update_burst_score(struct sched_entity *se) {
+ u32 bits10 = __calc_bits10(se->max_burst_time);
+ se->penalty_score = __calc_burst_score(bits10, sched_burst_penalty_offset);
+}
+
+static inline u64 penalty_scale(u64 delta, struct sched_entity *se) {
+ return mul_u64_u32_shr(delta, sched_prio_to_wmult[se->penalty_score], 22);
+}
+
+static inline u64 preempt_scale(
+ u64 delta, struct sched_entity *curr, struct sched_entity *se) {
+
+ u32 score = max(0, (s32)se->penalty_score - (s32)curr->penalty_score) >> 1;
+ return mul_u64_u32_shr(delta, sched_prio_to_wmult[min(39, 20 + score)], 22);
+}
+
+static inline u64 binary_smooth(u64 old, u64 new, unsigned int smoothness) {
+ return (new + old * ((1 << smoothness) - 1)) >> smoothness;
+}
+
+static void reset_burst(struct sched_entity *se) {
+ se->prev_burst_time = binary_smooth(
+ se->prev_burst_time, se->burst_time, sched_burst_smoothness);
+ se->burst_time = 0;
+
+ se->max_burst_time = se->prev_burst_time;
+}
+#endif // CONFIG_SCHED_BORE
+
/*
* Update the current task's runtime statistics.
*/
@@ -920,6 +1012,14 @@ static void update_curr(struct cfs_rq *cfs_rq)
curr->sum_exec_runtime += delta_exec;
schedstat_add(cfs_rq->exec_clock, delta_exec);
+#ifdef CONFIG_SCHED_BORE
+ curr->burst_time += delta_exec;
+ curr->max_burst_time = max(curr->max_burst_time, curr->burst_time);
+ update_burst_score(curr);
+ if (sched_bore & 1)
+ curr->vruntime += penalty_scale(calc_delta_fair(delta_exec, curr), curr);
+ else
+#endif // CONFIG_SCHED_BORE
curr->vruntime += calc_delta_fair(delta_exec, curr);
update_min_vruntime(cfs_rq);
@@ -5013,8 +5113,14 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
se->prev_sum_exec_runtime = se->sum_exec_runtime;
}
+#ifdef CONFIG_SCHED_BORE
+static int
+wakeup_preempt_entity_bscale(struct sched_entity *curr,
+ struct sched_entity *se, bool do_scale);
+#else // CONFIG_SCHED_BORE
static int
wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se);
+#endif // CONFIG_SCHED_BORE
/*
* Pick the next process, keeping these things in mind, in this order:
@@ -5053,16 +5159,34 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
second = curr;
}
+#ifdef CONFIG_SCHED_BORE
+ if (second && wakeup_preempt_entity_bscale(
+ second, left, sched_bore & 2) < 1)
+#else // CONFIG_SCHED_BORE
if (second && wakeup_preempt_entity(second, left) < 1)
+#endif // CONFIG_SCHED_BORE
se = second;
}
- if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1) {
+#ifdef CONFIG_SCHED_BORE
+ if (cfs_rq->next && wakeup_preempt_entity_bscale(
+ cfs_rq->next, left, sched_bore & 2) < 1)
+#else // CONFIG_SCHED_BORE
+ if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1)
+#endif // CONFIG_SCHED_BORE
+ {
/*
* Someone really wants this to run. If it's not unfair, run it.
*/
se = cfs_rq->next;
- } else if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1) {
+ }
+#ifdef CONFIG_SCHED_BORE
+ else if (cfs_rq->last && wakeup_preempt_entity_bscale(
+ cfs_rq->last, left, sched_bore & 2) < 1)
+#else // CONFIG_SCHED_BORE
+ else if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1)
+#endif // CONFIG_SCHED_BORE
+ {
/*
* Prefer last buddy, try to return the CPU to a preempted task.
*/
@@ -6331,6 +6455,9 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
util_est_dequeue(&rq->cfs, p);
for_each_sched_entity(se) {
+#ifdef CONFIG_SCHED_BORE
+ if (task_sleep) reset_burst(se);
+#endif // CONFIG_SCHED_BORE
cfs_rq = cfs_rq_of(se);
dequeue_entity(cfs_rq, se, flags);
@@ -7746,7 +7873,12 @@ static unsigned long wakeup_gran(struct sched_entity *se)
*
*/
static int
+#ifdef CONFIG_SCHED_BORE
+wakeup_preempt_entity_bscale(struct sched_entity *curr,
+ struct sched_entity *se, bool do_scale)
+#else // CONFIG_SCHED_BORE
wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)
+#endif // CONFIG_SCHED_BORE
{
s64 gran, vdiff = curr->vruntime - se->vruntime;
@@ -7754,6 +7886,9 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)
return -1;
gran = wakeup_gran(se);
+#ifdef CONFIG_SCHED_BORE
+ if (do_scale) gran = preempt_scale(gran, curr, se);
+#endif // CONFIG_SCHED_BORE
if (vdiff > gran)
return 1;
@@ -7858,7 +7993,12 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
return;
update_curr(cfs_rq_of(se));
- if (wakeup_preempt_entity(se, pse) == 1) {
+#ifdef CONFIG_SCHED_BORE
+ if (wakeup_preempt_entity_bscale(se, pse, sched_bore & 2) == 1)
+#else // CONFIG_SCHED_BORE
+ if (wakeup_preempt_entity(se, pse) == 1)
+#endif // CONFIG_SCHED_BORE
+ {
/*
* Bias pick_next to pick the sched entity that is
* triggering this preemption.
@@ -8094,6 +8234,9 @@ static void yield_task_fair(struct rq *rq)
struct task_struct *curr = rq->curr;
struct cfs_rq *cfs_rq = task_cfs_rq(curr);
struct sched_entity *se = &curr->se;
+#ifdef CONFIG_SCHED_BORE
+ reset_burst(se);
+#endif // CONFIG_SCHED_BORE
/*
* Are we the only task in the tree?
diff --git a/kernel/sched/features.h b/kernel/sched/features.h
index ee7f23c76bd3..3115bde98211 100644
--- a/kernel/sched/features.h
+++ b/kernel/sched/features.h
@@ -4,7 +4,11 @@
* them to run sooner, but does not allow tons of sleepers to
* rip the spread apart.
*/
+#ifdef CONFIG_SCHED_BORE
+SCHED_FEAT(GENTLE_FAIR_SLEEPERS, false)
+#else // CONFIG_SCHED_BORE
SCHED_FEAT(GENTLE_FAIR_SLEEPERS, true)
+#endif // CONFIG_SCHED_BORE
/*
* Place new tasks ahead so that they do not starve already running
@@ -17,7 +21,11 @@ SCHED_FEAT(START_DEBIT, true)
* wakeup-preemption), since its likely going to consume data we
* touched, increases cache locality.
*/
+#ifdef CONFIG_SCHED_BORE
+SCHED_FEAT(NEXT_BUDDY, true)
+#else // CONFIG_SCHED_BORE
SCHED_FEAT(NEXT_BUDDY, false)
+#endif // CONFIG_SCHED_BORE
/*
* Prefer to schedule the task that ran last (when we did
--
2.40.0

View File

@ -0,0 +1,101 @@
From 67964b7a12cbfbc30d41534803dc6aa0c89d6383 Mon Sep 17 00:00:00 2001
From: Tsuchiya Yuto <kitakar@gmail.com>
Date: Sun, 18 Oct 2020 16:42:44 +0900
Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI
table
On some Surface 3, the DMI table gets corrupted for unknown reasons
and breaks existing DMI matching used for device-specific quirks.
This commit adds the (broken) DMI data into dmi_system_id tables used
for quirks so that each driver can enable quirks even on the affected
systems.
On affected systems, DMI data will look like this:
$ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\
chassis_vendor,product_name,sys_vendor}
/sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc.
/sys/devices/virtual/dmi/id/board_name:OEMB
/sys/devices/virtual/dmi/id/board_vendor:OEMB
/sys/devices/virtual/dmi/id/chassis_vendor:OEMB
/sys/devices/virtual/dmi/id/product_name:OEMB
/sys/devices/virtual/dmi/id/sys_vendor:OEMB
Expected:
$ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\
chassis_vendor,product_name,sys_vendor}
/sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc.
/sys/devices/virtual/dmi/id/board_name:Surface 3
/sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation
/sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation
/sys/devices/virtual/dmi/id/product_name:Surface 3
/sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation
Signed-off-by: Tsuchiya Yuto <kitakar@gmail.com>
Patchset: surface3-oemb
---
drivers/platform/surface/surface3-wmi.c | 7 +++++++
sound/soc/codecs/rt5645.c | 9 +++++++++
sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++
3 files changed, 24 insertions(+)
diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c
index ca4602bcc7dea..490b9731068ae 100644
--- a/drivers/platform/surface/surface3-wmi.c
+++ b/drivers/platform/surface/surface3-wmi.c
@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
},
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"),
+ },
+ },
#endif
{ }
};
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 620ecbfa4a7a8..b07d06d2971a8 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3717,6 +3717,15 @@ static const struct dmi_system_id dmi_platform_data[] = {
},
.driver_data = (void *)&intel_braswell_platform_data,
},
+ {
+ .ident = "Microsoft Surface 3",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"),
+ },
+ .driver_data = (void *)&intel_braswell_platform_data,
+ },
{
/*
* Match for the GPDwin which unfortunately uses somewhat
diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
index 6beb00858c33f..d82d77387a0a6 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
},
},
+ {
+ .callback = cht_surface_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"),
+ },
+ },
{ }
};
--
2.40.0

View File

@ -0,0 +1,400 @@
From efd716f5123331754ebfc53bccfef07e17fb328b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Tue, 3 Nov 2020 13:28:04 +0100
Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface
devices
The most recent firmware of the 88W8897 card reports a hardcoded LTR
value to the system during initialization, probably as an (unsuccessful)
attempt of the developers to fix firmware crashes. This LTR value
prevents most of the Microsoft Surface devices from entering deep
powersaving states (either platform C-State 10 or S0ix state), because
the exit latency of that state would be higher than what the card can
tolerate.
Turns out the card works just the same (including the firmware crashes)
no matter if that hardcoded LTR value is reported or not, so it's kind
of useless and only prevents us from saving power.
To get rid of those hardcoded LTR reports, it's possible to reset the
PCI bridge device after initializing the cards firmware. I'm not exactly
sure why that works, maybe the power management subsystem of the PCH
resets its stored LTR values when doing a function level reset of the
bridge device. Doing the reset once after starting the wifi firmware
works very well, probably because the firmware only reports that LTR
value a single time during firmware startup.
Patchset: mwifiex
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++
.../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------
.../wireless/marvell/mwifiex/pcie_quirks.h | 1 +
3 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 9a698a16a8f38..14687342bc81c 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -1762,9 +1762,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
+ struct pci_dev *pdev = card->dev;
+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev);
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask;
+ /* Trigger a function level reset of the PCI bridge device, this makes
+ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value
+ * that prevents the system from entering package C10 and S0ix powersaving
+ * states.
+ * We need to do it here because it must happen after firmware
+ * initialization and this function is called after that is done.
+ */
+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE)
+ pci_reset_function(parent_pdev);
+
/* Write the RX ring read pointer in to reg->rx_rdptr */
if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr |
tx_wrap)) {
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
index dd6d21f1dbfd7..f46b06f8d6435 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"),
},
- .driver_data = (void *)QUIRK_FW_RST_D3COLD,
+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD |
+ QUIRK_DO_FLR_ON_BRIDGE),
},
{
.ident = "Surface Pro 5",
@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"),
},
- .driver_data = (void *)QUIRK_FW_RST_D3COLD,
+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD |
+ QUIRK_DO_FLR_ON_BRIDGE),
},
{
.ident = "Surface Pro 5 (LTE)",
@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"),
},
- .driver_data = (void *)QUIRK_FW_RST_D3COLD,
+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD |
+ QUIRK_DO_FLR_ON_BRIDGE),
},
{
.ident = "Surface Pro 6",
@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"),
},
- .driver_data = (void *)QUIRK_FW_RST_D3COLD,
+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD |
+ QUIRK_DO_FLR_ON_BRIDGE),
},
{
.ident = "Surface Book 1",
@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"),
},
- .driver_data = (void *)QUIRK_FW_RST_D3COLD,
+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD |
+ QUIRK_DO_FLR_ON_BRIDGE),
},
{
.ident = "Surface Book 2",
@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"),
},
- .driver_data = (void *)QUIRK_FW_RST_D3COLD,
+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD |
+ QUIRK_DO_FLR_ON_BRIDGE),
},
{
.ident = "Surface Laptop 1",
@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"),
},
- .driver_data = (void *)QUIRK_FW_RST_D3COLD,
+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD |
+ QUIRK_DO_FLR_ON_BRIDGE),
},
{
.ident = "Surface Laptop 2",
@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"),
},
- .driver_data = (void *)QUIRK_FW_RST_D3COLD,
+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD |
+ QUIRK_DO_FLR_ON_BRIDGE),
},
{}
};
@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card)
dev_info(&pdev->dev, "no quirks enabled\n");
if (card->quirks & QUIRK_FW_RST_D3COLD)
dev_info(&pdev->dev, "quirk reset_d3cold enabled\n");
+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE)
+ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n");
}
static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
index d6ff964aec5bf..5d30ae39d65ec 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
@@ -4,6 +4,7 @@
#include "pcie.h"
#define QUIRK_FW_RST_D3COLD BIT(0)
+#define QUIRK_DO_FLR_ON_BRIDGE BIT(1)
void mwifiex_initialize_quirks(struct pcie_service_card *card);
int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev);
--
2.40.0
From 2de203271a35cc09eff860df2f35c5ca5e6ae52c Mon Sep 17 00:00:00 2001
From: Tsuchiya Yuto <kitakar@gmail.com>
Date: Sun, 4 Oct 2020 00:11:49 +0900
Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+
Currently, mwifiex fw will crash after suspend on recent kernel series.
On Windows, it seems that the root port of wifi will never enter D3 state
(stay on D0 state). And on Linux, disabling the D3 state for the
bridge fixes fw crashing after suspend.
This commit disables the D3 state of root port on driver initialization
and fixes fw crashing after suspend.
Signed-off-by: Tsuchiya Yuto <kitakar@gmail.com>
Patchset: mwifiex
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++
.../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------
.../wireless/marvell/mwifiex/pcie_quirks.h | 1 +
3 files changed, 27 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 14687342bc81c..5e1a341f63dff 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -368,6 +368,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct pcie_service_card *card;
+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev);
int ret;
pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
@@ -409,6 +410,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
return -1;
}
+ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing
+ * after suspend
+ */
+ if (card->quirks & QUIRK_NO_BRIDGE_D3)
+ parent_pdev->bridge_d3 = false;
+
return 0;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
index f46b06f8d6435..99b024ecbadea 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"),
},
.driver_data = (void *)(QUIRK_FW_RST_D3COLD |
- QUIRK_DO_FLR_ON_BRIDGE),
+ QUIRK_DO_FLR_ON_BRIDGE |
+ QUIRK_NO_BRIDGE_D3),
},
{
.ident = "Surface Pro 5",
@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"),
},
.driver_data = (void *)(QUIRK_FW_RST_D3COLD |
- QUIRK_DO_FLR_ON_BRIDGE),
+ QUIRK_DO_FLR_ON_BRIDGE |
+ QUIRK_NO_BRIDGE_D3),
},
{
.ident = "Surface Pro 5 (LTE)",
@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"),
},
.driver_data = (void *)(QUIRK_FW_RST_D3COLD |
- QUIRK_DO_FLR_ON_BRIDGE),
+ QUIRK_DO_FLR_ON_BRIDGE |
+ QUIRK_NO_BRIDGE_D3),
},
{
.ident = "Surface Pro 6",
@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"),
},
.driver_data = (void *)(QUIRK_FW_RST_D3COLD |
- QUIRK_DO_FLR_ON_BRIDGE),
+ QUIRK_DO_FLR_ON_BRIDGE |
+ QUIRK_NO_BRIDGE_D3),
},
{
.ident = "Surface Book 1",
@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"),
},
.driver_data = (void *)(QUIRK_FW_RST_D3COLD |
- QUIRK_DO_FLR_ON_BRIDGE),
+ QUIRK_DO_FLR_ON_BRIDGE |
+ QUIRK_NO_BRIDGE_D3),
},
{
.ident = "Surface Book 2",
@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"),
},
.driver_data = (void *)(QUIRK_FW_RST_D3COLD |
- QUIRK_DO_FLR_ON_BRIDGE),
+ QUIRK_DO_FLR_ON_BRIDGE |
+ QUIRK_NO_BRIDGE_D3),
},
{
.ident = "Surface Laptop 1",
@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"),
},
.driver_data = (void *)(QUIRK_FW_RST_D3COLD |
- QUIRK_DO_FLR_ON_BRIDGE),
+ QUIRK_DO_FLR_ON_BRIDGE |
+ QUIRK_NO_BRIDGE_D3),
},
{
.ident = "Surface Laptop 2",
@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"),
},
.driver_data = (void *)(QUIRK_FW_RST_D3COLD |
- QUIRK_DO_FLR_ON_BRIDGE),
+ QUIRK_DO_FLR_ON_BRIDGE |
+ QUIRK_NO_BRIDGE_D3),
},
{}
};
@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card)
dev_info(&pdev->dev, "quirk reset_d3cold enabled\n");
if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE)
dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n");
+ if (card->quirks & QUIRK_NO_BRIDGE_D3)
+ dev_info(&pdev->dev,
+ "quirk no_brigde_d3 enabled\n");
}
static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
index 5d30ae39d65ec..c14eb56eb9118 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
@@ -5,6 +5,7 @@
#define QUIRK_FW_RST_D3COLD BIT(0)
#define QUIRK_DO_FLR_ON_BRIDGE BIT(1)
+#define QUIRK_NO_BRIDGE_D3 BIT(2)
void mwifiex_initialize_quirks(struct pcie_service_card *card);
int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev);
--
2.40.0
From 16c7b19c13e1edab7f236baa59f8f685a4d719b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Thu, 25 Mar 2021 11:33:02 +0100
Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell
88W8897
The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version)
is used in a lot of Microsoft Surface devices, and all those devices
suffer from very low 2.4GHz wifi connection speeds while bluetooth is
enabled. The reason for that is that the default passive scanning
interval for Bluetooth Low Energy devices is quite high in Linux
(interval of 60 msec and scan window of 30 msec, see hci_core.c), and
the Marvell chip is known for its bad bt+wifi coexisting performance.
So decrease that passive scan interval and make the scan window shorter
on this particular device to allow for spending more time transmitting
wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and
the new scan window is 6.25 msec (0xa * 0,625 msec).
This change has a very large impact on the 2.4GHz wifi speeds and gets
it up to performance comparable with the Windows driver, which seems to
apply a similar quirk.
The interval and window length were tested and found to work very well
with a lot of Bluetooth Low Energy devices, including the Surface Pen, a
Bluetooth Speaker and two modern Bluetooth headphones. All devices were
discovered immediately after turning them on. Even lower values were
also tested, but they introduced longer delays until devices get
discovered.
Patchset: mwifiex
---
drivers/bluetooth/btusb.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 5c536151ef836..4de564dd1c604 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25)
#define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26)
#define BTUSB_ACTIONS_SEMI BIT(27)
+#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28)
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@@ -468,6 +469,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL },
{ USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
{ USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL },
+ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL },
/* Intel Bluetooth devices */
{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED },
@@ -4033,6 +4035,19 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_MARVELL)
hdev->set_bdaddr = btusb_set_bdaddr_marvell;
+ /* The Marvell 88W8897 combined wifi and bluetooth card is known for
+ * very bad bt+wifi coexisting performance.
+ *
+ * Decrease the passive BT Low Energy scan interval a bit
+ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter
+ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly
+ * higher wifi throughput while passively scanning for BT LE devices.
+ */
+ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) {
+ hdev->le_scan_interval = 0x0190;
+ hdev->le_scan_window = 0x000a;
+ }
+
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) &&
(id->driver_info & BTUSB_MEDIATEK)) {
hdev->setup = btusb_mtk_setup;
--
2.40.0

View File

@ -0,0 +1,121 @@
From b33823bea207cfd93a97f5af82c1e9fbdc9cbd2b Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 27 Feb 2021 00:45:52 +0100
Subject: [PATCH] ath10k: Add module parameters to override board files
Some Surface devices, specifically the Surface Go and AMD version of the
Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better
with a different board file, as it seems that the firmeware included
upstream is buggy.
As it is generally not a good idea to randomly overwrite files, let
alone doing so via packages, we add module parameters to override those
file names in the driver. This allows us to package/deploy the override
via a modprobe.d config.
Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Patchset: ath10k
---
drivers/net/wireless/ath/ath10k/core.c | 58 ++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 5eb131ab916fd..67f074a126d1f 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -38,6 +38,9 @@ static bool fw_diag_log;
/* frame mode values are mapped as per enum ath10k_hw_txrx_mode */
unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI;
+static char *override_board = "";
+static char *override_board2 = "";
+
unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) |
BIT(ATH10K_FW_CRASH_DUMP_CE_DATA);
@@ -50,6 +53,9 @@ module_param(fw_diag_log, bool, 0644);
module_param_named(frame_mode, ath10k_frame_mode, uint, 0644);
module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444);
+module_param(override_board, charp, 0644);
+module_param(override_board2, charp, 0644);
+
MODULE_PARM_DESC(debug_mask, "Debugging mask");
MODULE_PARM_DESC(uart_print, "Uart target debugging");
MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
@@ -59,6 +65,9 @@ MODULE_PARM_DESC(frame_mode,
MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file");
MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging");
+MODULE_PARM_DESC(override_board, "Override for board.bin file");
+MODULE_PARM_DESC(override_board2, "Override for board-2.bin file");
+
static const struct ath10k_hw_params ath10k_hw_params_list[] = {
{
.id = QCA988X_HW_2_0_VERSION,
@@ -911,6 +920,42 @@ static int ath10k_init_configure_target(struct ath10k *ar)
return 0;
}
+static const char *ath10k_override_board_fw_file(struct ath10k *ar,
+ const char *file)
+{
+ if (strcmp(file, "board.bin") == 0) {
+ if (strcmp(override_board, "") == 0)
+ return file;
+
+ if (strcmp(override_board, "none") == 0) {
+ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n");
+ return NULL;
+ }
+
+ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n",
+ override_board);
+
+ return override_board;
+ }
+
+ if (strcmp(file, "board-2.bin") == 0) {
+ if (strcmp(override_board2, "") == 0)
+ return file;
+
+ if (strcmp(override_board2, "none") == 0) {
+ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n");
+ return NULL;
+ }
+
+ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n",
+ override_board2);
+
+ return override_board2;
+ }
+
+ return file;
+}
+
static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
const char *dir,
const char *file)
@@ -925,6 +970,19 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
if (dir == NULL)
dir = ".";
+ /* HACK: Override board.bin and board-2.bin files if specified.
+ *
+ * Some Surface devices perform better with a different board
+ * configuration. To this end, one would need to replace the board.bin
+ * file with the modified config and remove the board-2.bin file.
+ * Unfortunately, that's not a solution that we can easily package. So
+ * we add module options to perform these overrides here.
+ */
+
+ file = ath10k_override_board_fw_file(ar, file);
+ if (!file)
+ return ERR_PTR(-ENOENT);
+
snprintf(filename, sizeof(filename), "%s/%s", dir, file);
ret = firmware_request_nowarn(&fw, filename, ar->dev);
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n",
--
2.40.0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,335 @@
From 210d383e29aee631650f951351fae9712da009ef Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 25 Jul 2020 17:19:53 +0200
Subject: [PATCH] i2c: acpi: Implement RawBytes read access
Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C
device via a generic serial bus operation region and RawBytes read
access. On the Surface Book 1, this access is required to turn on (and
off) the discrete GPU.
Multiple things are to note here:
a) The RawBytes access is device/driver dependent. The ACPI
specification states:
> Raw accesses assume that the writer has knowledge of the bus that
> the access is made over and the device that is being accessed. The
> protocol may only ensure that the buffer is transmitted to the
> appropriate driver, but the driver must be able to interpret the
> buffer to communicate to a register.
Thus this implementation may likely not work on other devices
accessing I2C via the RawBytes accessor type.
b) The MSHW0030 I2C device is an HID-over-I2C device which seems to
serve multiple functions:
1. It is the main access point for the legacy-type Surface Aggregator
Module (also referred to as SAM-over-HID, as opposed to the newer
SAM-over-SSH/UART). It has currently not been determined on how
support for the legacy SAM should be implemented. Likely via a
custom HID driver.
2. It seems to serve as the HID device for the Integrated Sensor Hub.
This might complicate matters with regards to implementing a
SAM-over-HID driver required by legacy SAM.
In light of this, the simplest approach has been chosen for now.
However, it may make more sense regarding breakage and compatibility to
either provide functionality for replacing or enhancing the default
operation region handler via some additional API functions, or even to
completely blacklist MSHW0030 from the I2C core and provide a custom
driver for it.
Replacing/enhancing the default operation region handler would, however,
either require some sort of secondary driver and access point for it,
from which the new API functions would be called and the new handler
(part) would be installed, or hard-coding them via some sort of
quirk-like interface into the I2C core.
Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Patchset: surface-sam-over-hid
---
drivers/i2c/i2c-core-acpi.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index 4dd777cc0c89f..b2338618163ad 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -639,6 +639,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
return (ret == 1) ? 0 : -EIO;
}
+static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client,
+ u8 *data, u8 data_len)
+{
+ struct i2c_msg msgs[1];
+ int ret = AE_OK;
+
+ msgs[0].addr = client->addr;
+ msgs[0].flags = client->flags;
+ msgs[0].len = data_len + 1;
+ msgs[0].buf = data;
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+
+ if (ret < 0) {
+ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret);
+ return ret;
+ }
+
+ /* 1 transfer must have completed successfully */
+ return (ret == 1) ? 0 : -EIO;
+}
+
static acpi_status
i2c_acpi_space_handler(u32 function, acpi_physical_address command,
u32 bits, u64 *value64,
@@ -740,6 +762,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command,
}
break;
+ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES:
+ if (action == ACPI_READ) {
+ dev_warn(&adapter->dev,
+ "protocol 0x%02x not supported for client 0x%02x\n",
+ accessor_type, client->addr);
+ ret = AE_BAD_PARAMETER;
+ goto err;
+ } else {
+ status = acpi_gsb_i2c_write_raw_bytes(client,
+ gsb->data, info->access_length);
+ }
+ break;
+
default:
dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n",
accessor_type, client->addr);
--
2.40.0
From 40308d86e91a5396416b378ba73dd96d3f5d5dfa Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 13 Feb 2021 16:41:18 +0100
Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch
Add driver exposing the discrete GPU power-switch of the Microsoft
Surface Book 1 to user-space.
On the Surface Book 1, the dGPU power is controlled via the Surface
System Aggregator Module (SAM). The specific SAM-over-HID command for
this is exposed via ACPI. This module provides a simple driver exposing
the ACPI call via a sysfs parameter to user-space, so that users can
easily power-on/-off the dGPU.
Patchset: surface-sam-over-hid
---
drivers/platform/surface/Kconfig | 7 +
drivers/platform/surface/Makefile | 1 +
.../surface/surfacebook1_dgpu_switch.c | 162 ++++++++++++++++++
3 files changed, 170 insertions(+)
create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c
diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
index b629e82af97c0..68656e8f309ed 100644
--- a/drivers/platform/surface/Kconfig
+++ b/drivers/platform/surface/Kconfig
@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH
Select M or Y here, if you want to provide tablet-mode switch input
events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio.
+config SURFACE_BOOK1_DGPU_SWITCH
+ tristate "Surface Book 1 dGPU Switch Driver"
+ depends on SYSFS
+ help
+ This driver provides a sysfs switch to set the power-state of the
+ discrete GPU found on the Microsoft Surface Book 1.
+
config SURFACE_DTX
tristate "Surface DTX (Detachment System) Driver"
depends on SURFACE_AGGREGATOR
diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile
index 53344330939bf..7efcd0cdb5329 100644
--- a/drivers/platform/surface/Makefile
+++ b/drivers/platform/surface/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o
obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o
obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o
obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o
+obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o
obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o
obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o
obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o
diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c
new file mode 100644
index 0000000000000..8b816ed8f35c6
--- /dev/null
+++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+
+
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
+
+static const guid_t dgpu_sw_guid = GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4,
+ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35);
+
+#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI"
+#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON"
+#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF"
+
+
+static int sb1_dgpu_sw_dsmcall(void)
+{
+ union acpi_object *ret;
+ acpi_handle handle;
+ acpi_status status;
+
+ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle);
+ if (status)
+ return -EINVAL;
+
+ ret = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER);
+ if (!ret)
+ return -EINVAL;
+
+ ACPI_FREE(ret);
+ return 0;
+}
+
+static int sb1_dgpu_sw_hgon(void)
+{
+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
+ acpi_status status;
+
+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf);
+ if (status) {
+ pr_err("failed to run HGON: %d\n", status);
+ return -EINVAL;
+ }
+
+ if (buf.pointer)
+ ACPI_FREE(buf.pointer);
+
+ pr_info("turned-on dGPU via HGON\n");
+ return 0;
+}
+
+static int sb1_dgpu_sw_hgof(void)
+{
+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
+ acpi_status status;
+
+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf);
+ if (status) {
+ pr_err("failed to run HGOF: %d\n", status);
+ return -EINVAL;
+ }
+
+ if (buf.pointer)
+ ACPI_FREE(buf.pointer);
+
+ pr_info("turned-off dGPU via HGOF\n");
+ return 0;
+}
+
+
+static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ int status, value;
+
+ status = kstrtoint(buf, 0, &value);
+ if (status < 0)
+ return status;
+
+ if (value != 1)
+ return -EINVAL;
+
+ status = sb1_dgpu_sw_dsmcall();
+
+ return status < 0 ? status : len;
+}
+
+static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ bool power;
+ int status;
+
+ status = kstrtobool(buf, &power);
+ if (status < 0)
+ return status;
+
+ if (power)
+ status = sb1_dgpu_sw_hgon();
+ else
+ status = sb1_dgpu_sw_hgof();
+
+ return status < 0 ? status : len;
+}
+
+static DEVICE_ATTR_WO(dgpu_dsmcall);
+static DEVICE_ATTR_WO(dgpu_power);
+
+static struct attribute *sb1_dgpu_sw_attrs[] = {
+ &dev_attr_dgpu_dsmcall.attr,
+ &dev_attr_dgpu_power.attr,
+ NULL,
+};
+
+static const struct attribute_group sb1_dgpu_sw_attr_group = {
+ .attrs = sb1_dgpu_sw_attrs,
+};
+
+
+static int sb1_dgpu_sw_probe(struct platform_device *pdev)
+{
+ return sysfs_create_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group);
+}
+
+static int sb1_dgpu_sw_remove(struct platform_device *pdev)
+{
+ sysfs_remove_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group);
+ return 0;
+}
+
+/*
+ * The dGPU power seems to be actually handled by MSHW0040. However, that is
+ * also the power-/volume-button device with a mainline driver. So let's use
+ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device.
+ */
+static const struct acpi_device_id sb1_dgpu_sw_match[] = {
+ { "MSHW0041", },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match);
+
+static struct platform_driver sb1_dgpu_sw = {
+ .probe = sb1_dgpu_sw_probe,
+ .remove = sb1_dgpu_sw_remove,
+ .driver = {
+ .name = "surfacebook1_dgpu_switch",
+ .acpi_match_table = sb1_dgpu_sw_match,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+};
+module_platform_driver(sb1_dgpu_sw);
+
+MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
+MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1");
+MODULE_LICENSE("GPL");
--
2.40.0

View File

@ -0,0 +1,149 @@
From 95137da18e3280468a9ae8c8c08665c23d6331d3 Mon Sep 17 00:00:00 2001
From: Sachi King <nakato@nakato.io>
Date: Tue, 5 Oct 2021 00:05:09 +1100
Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices
The power button on the AMD variant of the Surface Laptop uses the
same MSHW0040 device ID as the 5th and later generation of Surface
devices, however they report 0 for their OEM platform revision. As the
_DSM does not exist on the devices requiring special casing, check for
the existance of the _DSM to determine if soc_button_array should be
loaded.
Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices")
Co-developed-by: Maximilian Luz <luzmaximilian@gmail.com>
Signed-off-by: Sachi King <nakato@nakato.io>
Patchset: surface-button
---
drivers/input/misc/soc_button_array.c | 33 +++++++--------------------
1 file changed, 8 insertions(+), 25 deletions(-)
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index 09489380afda7..0f02411a60f1c 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -507,8 +507,8 @@ static const struct soc_device_data soc_device_MSHW0028 = {
* Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
* devices use MSHW0040 for power and volume buttons, however the way they
* have to be addressed differs. Make sure that we only load this drivers
- * for the correct devices by checking the OEM Platform Revision provided by
- * the _DSM method.
+ * for the correct devices by checking if the OEM Platform Revision DSM call
+ * exists.
*/
#define MSHW0040_DSM_REVISION 0x01
#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
@@ -519,31 +519,14 @@ static const guid_t MSHW0040_DSM_UUID =
static int soc_device_check_MSHW0040(struct device *dev)
{
acpi_handle handle = ACPI_HANDLE(dev);
- union acpi_object *result;
- u64 oem_platform_rev = 0; // valid revisions are nonzero
-
- // get OEM platform revision
- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
- MSHW0040_DSM_REVISION,
- MSHW0040_DSM_GET_OMPR, NULL,
- ACPI_TYPE_INTEGER);
-
- if (result) {
- oem_platform_rev = result->integer.value;
- ACPI_FREE(result);
- }
-
- /*
- * If the revision is zero here, the _DSM evaluation has failed. This
- * indicates that we have a Pro 4 or Book 1 and this driver should not
- * be used.
- */
- if (oem_platform_rev == 0)
- return -ENODEV;
+ bool exists;
- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
+ // check if OEM platform revision DSM call exists
+ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID,
+ MSHW0040_DSM_REVISION,
+ BIT(MSHW0040_DSM_GET_OMPR));
- return 0;
+ return exists ? 0 : -ENODEV;
}
/*
--
2.40.0
From 30283e8c20af0d8bdf9f7d7075ca85d34b4c8870 Mon Sep 17 00:00:00 2001
From: Sachi King <nakato@nakato.io>
Date: Tue, 5 Oct 2021 00:22:57 +1100
Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd
variant
The AMD variant of the Surface Laptop report 0 for their OEM platform
revision. The Surface devices that require the surfacepro3_button
driver do not have the _DSM that gets the OEM platform revision. If the
method does not exist, load surfacepro3_button.
Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check")
Co-developed-by: Maximilian Luz <luzmaximilian@gmail.com>
Signed-off-by: Sachi King <nakato@nakato.io>
Patchset: surface-button
---
drivers/platform/surface/surfacepro3_button.c | 30 ++++---------------
1 file changed, 6 insertions(+), 24 deletions(-)
diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c
index 2755601f979cd..4240c98ca2265 100644
--- a/drivers/platform/surface/surfacepro3_button.c
+++ b/drivers/platform/surface/surfacepro3_button.c
@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev)
/*
* Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device
* ID (MSHW0040) for the power/volume buttons. Make sure this is the right
- * device by checking for the _DSM method and OEM Platform Revision.
+ * device by checking for the _DSM method and OEM Platform Revision DSM
+ * function.
*
* Returns true if the driver should bind to this device, i.e. the device is
* either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1.
@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev)
static bool surface_button_check_MSHW0040(struct acpi_device *dev)
{
acpi_handle handle = dev->handle;
- union acpi_object *result;
- u64 oem_platform_rev = 0; // valid revisions are nonzero
-
- // get OEM platform revision
- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
- MSHW0040_DSM_REVISION,
- MSHW0040_DSM_GET_OMPR,
- NULL, ACPI_TYPE_INTEGER);
-
- /*
- * If evaluating the _DSM fails, the method is not present. This means
- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we
- * should use this driver. We use revision 0 indicating it is
- * unavailable.
- */
-
- if (result) {
- oem_platform_rev = result->integer.value;
- ACPI_FREE(result);
- }
-
- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev);
- return oem_platform_rev == 0;
+ // make sure that OEM platform revision DSM call does not exist
+ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID,
+ MSHW0040_DSM_REVISION,
+ BIT(MSHW0040_DSM_GET_OMPR));
}
--
2.40.0

View File

@ -0,0 +1,574 @@
From 3d290bb729d71c5952ccb275803d451e2bb6557a Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 18 Feb 2023 01:02:49 +0100
Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3
Type-Cover
The touchpad on the Type-Cover of the Surface Go 3 is sometimes not
being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this
issue.
More specifically, the device in question is a fairly standard modern
touchpad with pointer and touchpad input modes. During setup, the device
needs to be switched from pointer- to touchpad-mode (which is done in
hid-multitouch) to fully utilize it as intended. Unfortunately, however,
this seems to occasionally fail silently, leaving the device in
pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this.
Link: https://github.com/linux-surface/linux-surface/issues/1059
Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Patchset: surface-typecover
---
drivers/usb/core/quirks.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 934b3d997702e..2c6604c6e8e12 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -220,6 +220,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Microsoft Surface Dock Ethernet (RTL8153 GigE) */
{ USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM },
+ /* Microsoft Surface Go 3 Type-Cover */
+ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT },
+
/* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */
{ USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME },
--
2.40.0
From de05852c9a1295c7e8f415b6c12059fd9519b901 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Thu, 5 Nov 2020 13:09:45 +0100
Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when
suspending
The Type Cover for Microsoft Surface devices supports a special usb
control request to disable or enable the built-in keyboard backlight.
On Windows, this request happens when putting the device into suspend or
resuming it, without it the backlight of the Type Cover will remain
enabled for some time even though the computer is suspended, which looks
weird to the user.
So add support for this special usb control request to hid-multitouch,
which is the driver that's handling the Type Cover.
The reason we have to use a pm_notifier for this instead of the usual
suspend/resume methods is that those won't get called in case the usb
device is already autosuspended.
Also, if the device is autosuspended, we have to briefly autoresume it
in order to send the request. Doing that should be fine, the usb-core
driver does something similar during suspend inside choose_wakeup().
To make sure we don't send that request to every device but only to
devices which support it, add a new quirk
MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk
is only enabled for the usb id of the Surface Pro 2017 Type Cover, which
is where I confirmed that it's working.
Patchset: surface-typecover
---
drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++-
1 file changed, 98 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index e31be0cb8b850..63fd042aba6ba 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -34,7 +34,10 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/usb.h>
#include <linux/input/mt.h>
#include <linux/jiffies.h>
#include <linux/string.h>
@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels");
MODULE_LICENSE("GPL");
#include "hid-ids.h"
+#include "usbhid/usbhid.h"
/* quirks to control the device */
#define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0)
@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
#define MT_QUIRK_DISABLE_WAKEUP BIT(21)
#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
#define MT_BUTTONTYPE_CLICKPAD 0
+#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086
+
enum latency_mode {
HID_LATENCY_NORMAL = 0,
HID_LATENCY_HIGH = 1,
@@ -169,6 +176,8 @@ struct mt_device {
struct list_head applications;
struct list_head reports;
+
+ struct notifier_block pm_notifier;
};
static void mt_post_parse_default_settings(struct mt_device *td,
@@ -213,6 +222,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_GOOGLE 0x0111
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
#define MT_CLS_SMART_TECH 0x0113
+#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114
#define MT_DEFAULT_MAXCONTACT 10
#define MT_MAX_MAXCONTACT 250
@@ -397,6 +407,16 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_SEPARATE_APP_REPORT,
},
+ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER,
+ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT |
+ MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_IGNORE_DUPLICATES |
+ MT_QUIRK_HOVERING |
+ MT_QUIRK_CONTACT_CNT_ACCURATE |
+ MT_QUIRK_STICKY_FINGERS |
+ MT_QUIRK_WIN8_PTP_BUTTONS,
+ .export_all_inputs = true
+ },
{ }
};
@@ -1728,6 +1748,69 @@ static void mt_expired_timeout(struct timer_list *t)
clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
}
+static void get_type_cover_backlight_field(struct hid_device *hdev,
+ struct hid_field **field)
+{
+ struct hid_report_enum *rep_enum;
+ struct hid_report *rep;
+ struct hid_field *cur_field;
+ int i, j;
+
+ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
+ list_for_each_entry(rep, &rep_enum->report_list, list) {
+ for (i = 0; i < rep->maxfield; i++) {
+ cur_field = rep->field[i];
+
+ for (j = 0; j < cur_field->maxusage; j++) {
+ if (cur_field->usage[j].hid
+ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) {
+ *field = cur_field;
+ return;
+ }
+ }
+ }
+ }
+}
+
+static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
+{
+ struct usb_device *udev = hid_to_usb_dev(hdev);
+ struct hid_field *field = NULL;
+
+ /* Wake up the device in case it's already suspended */
+ pm_runtime_get_sync(&udev->dev);
+
+ get_type_cover_backlight_field(hdev, &field);
+ if (!field) {
+ hid_err(hdev, "couldn't find backlight field\n");
+ goto out;
+ }
+
+ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff;
+ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT);
+
+out:
+ pm_runtime_put_sync(&udev->dev);
+}
+
+static int mt_pm_notifier(struct notifier_block *notifier,
+ unsigned long pm_event,
+ void *unused)
+{
+ struct mt_device *td =
+ container_of(notifier, struct mt_device, pm_notifier);
+ struct hid_device *hdev = td->hdev;
+
+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) {
+ if (pm_event == PM_SUSPEND_PREPARE)
+ update_keyboard_backlight(hdev, 0);
+ else if (pm_event == PM_POST_SUSPEND)
+ update_keyboard_backlight(hdev, 1);
+ }
+
+ return NOTIFY_DONE;
+}
+
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret, i;
@@ -1751,6 +1834,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
hid_set_drvdata(hdev, td);
+ td->pm_notifier.notifier_call = mt_pm_notifier;
+ register_pm_notifier(&td->pm_notifier);
+
INIT_LIST_HEAD(&td->applications);
INIT_LIST_HEAD(&td->reports);
@@ -1789,15 +1875,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
timer_setup(&td->release_timer, mt_expired_timeout, 0);
ret = hid_parse(hdev);
- if (ret != 0)
+ if (ret != 0) {
+ unregister_pm_notifier(&td->pm_notifier);
return ret;
+ }
if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID)
mt_fix_const_fields(hdev, HID_DG_CONTACTID);
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
- if (ret)
+ if (ret) {
+ unregister_pm_notifier(&td->pm_notifier);
return ret;
+ }
ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
if (ret)
@@ -1849,6 +1939,7 @@ static void mt_remove(struct hid_device *hdev)
{
struct mt_device *td = hid_get_drvdata(hdev);
+ unregister_pm_notifier(&td->pm_notifier);
del_timer_sync(&td->release_timer);
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
@@ -2226,6 +2317,11 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR2) },
+ /* Microsoft Surface type cover */
+ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER,
+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
+ USB_VENDOR_ID_MICROSOFT, 0x09c0) },
+
/* Google MT devices */
{ .driver_data = MT_CLS_GOOGLE,
HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
--
2.40.0
From f8bf8b278e663f3c7cfc269a1c5cffd7342a906b Mon Sep 17 00:00:00 2001
From: PJungkamp <p.jungkamp@gmail.com>
Date: Fri, 25 Feb 2022 12:04:25 +0100
Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet
switch
The Surface Pro Type Cover has several non standard HID usages in it's
hid report descriptor.
I noticed that, upon folding the typecover back, a vendor specific range
of 4 32 bit integer hid usages is transmitted.
Only the first byte of the message seems to convey reliable information
about the keyboard state.
0x22 => Normal (keys enabled)
0x33 => Folded back (keys disabled)
0x53 => Rotated left/right side up (keys disabled)
0x13 => Cover closed (keys disabled)
0x43 => Folded back and Tablet upside down (keys disabled)
This list may not be exhaustive.
The tablet mode switch will be disabled for a value of 0x22 and enabled
on any other value.
Patchset: surface-typecover
---
drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------
1 file changed, 122 insertions(+), 26 deletions(-)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 63fd042aba6ba..508a250ff4bf1 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_DISABLE_WAKEUP BIT(21)
#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23)
+#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL");
#define MT_BUTTONTYPE_CLICKPAD 0
#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086
+#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072
+#define MS_TYPE_COVER_APPLICATION 0xff050050
enum latency_mode {
HID_LATENCY_NORMAL = 0,
@@ -409,6 +412,7 @@ static const struct mt_class mt_classes[] = {
},
{ .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER,
.quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT |
+ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH |
MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_IGNORE_DUPLICATES |
MT_QUIRK_HOVERING |
@@ -1390,6 +1394,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->application != HID_CP_CONSUMER_CONTROL &&
field->application != HID_GD_WIRELESS_RADIO_CTLS &&
field->application != HID_GD_SYSTEM_MULTIAXIS &&
+ !(field->application == MS_TYPE_COVER_APPLICATION &&
+ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) &&
!(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
application->quirks & MT_QUIRK_ASUS_CUSTOM_UP))
return -1;
@@ -1417,6 +1424,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 1;
}
+ /*
+ * The Microsoft Surface Pro Typecover has a non-standard HID
+ * tablet mode switch on a vendor specific usage page with vendor
+ * specific usage.
+ */
+ if (field->application == MS_TYPE_COVER_APPLICATION &&
+ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) {
+ usage->type = EV_SW;
+ usage->code = SW_TABLET_MODE;
+ *max = SW_MAX;
+ *bit = hi->input->swbit;
+ return 1;
+ }
+
if (rdata->is_mt_collection)
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
application);
@@ -1438,6 +1460,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
{
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_report_data *rdata;
+ struct input_dev *input;
rdata = mt_find_report_data(td, field->report);
if (rdata && rdata->is_mt_collection) {
@@ -1445,6 +1468,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
return -1;
}
+ /*
+ * We own an input device which acts as a tablet mode switch for
+ * the Surface Pro Typecover.
+ */
+ if (field->application == MS_TYPE_COVER_APPLICATION &&
+ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) {
+ input = hi->input;
+ input_set_capability(input, EV_SW, SW_TABLET_MODE);
+ input_report_switch(input, SW_TABLET_MODE, 0);
+ return -1;
+ }
+
/* let hid-core decide for the others */
return 0;
}
@@ -1454,11 +1490,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
{
struct mt_device *td = hid_get_drvdata(hid);
struct mt_report_data *rdata;
+ struct input_dev *input;
rdata = mt_find_report_data(td, field->report);
if (rdata && rdata->is_mt_collection)
return mt_touch_event(hid, field, usage, value);
+ if (field->application == MS_TYPE_COVER_APPLICATION &&
+ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) {
+ input = field->hidinput->input;
+ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22);
+ input_sync(input);
+ return 1;
+ }
+
return 0;
}
@@ -1611,6 +1657,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app)
app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
+static int get_type_cover_field(struct hid_report_enum *rep_enum,
+ struct hid_field **field, int usage)
+{
+ struct hid_report *rep;
+ struct hid_field *cur_field;
+ int i, j;
+
+ list_for_each_entry(rep, &rep_enum->report_list, list) {
+ for (i = 0; i < rep->maxfield; i++) {
+ cur_field = rep->field[i];
+ if (cur_field->application != MS_TYPE_COVER_APPLICATION)
+ continue;
+ for (j = 0; j < cur_field->maxusage; j++) {
+ if (cur_field->usage[j].hid == usage) {
+ *field = cur_field;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static void request_type_cover_tablet_mode_switch(struct hid_device *hdev)
+{
+ struct hid_field *field;
+
+ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT],
+ &field,
+ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) {
+ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT);
+ } else {
+ hid_err(hdev, "couldn't find tablet mode field\n");
+ }
+}
+
static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
{
struct mt_device *td = hid_get_drvdata(hdev);
@@ -1660,6 +1742,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
/* force BTN_STYLUS to allow tablet matching in udev */
__set_bit(BTN_STYLUS, hi->input->keybit);
break;
+ case MS_TYPE_COVER_APPLICATION:
+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) {
+ suffix = "Tablet Mode Switch";
+ request_type_cover_tablet_mode_switch(hdev);
+ break;
+ }
+ fallthrough;
default:
suffix = "UNKNOWN";
break;
@@ -1748,30 +1837,6 @@ static void mt_expired_timeout(struct timer_list *t)
clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
}
-static void get_type_cover_backlight_field(struct hid_device *hdev,
- struct hid_field **field)
-{
- struct hid_report_enum *rep_enum;
- struct hid_report *rep;
- struct hid_field *cur_field;
- int i, j;
-
- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
- list_for_each_entry(rep, &rep_enum->report_list, list) {
- for (i = 0; i < rep->maxfield; i++) {
- cur_field = rep->field[i];
-
- for (j = 0; j < cur_field->maxusage; j++) {
- if (cur_field->usage[j].hid
- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) {
- *field = cur_field;
- return;
- }
- }
- }
- }
-}
-
static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
{
struct usb_device *udev = hid_to_usb_dev(hdev);
@@ -1780,8 +1845,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
/* Wake up the device in case it's already suspended */
pm_runtime_get_sync(&udev->dev);
- get_type_cover_backlight_field(hdev, &field);
- if (!field) {
+ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT],
+ &field,
+ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) {
hid_err(hdev, "couldn't find backlight field\n");
goto out;
}
@@ -1916,13 +1982,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state)
static int mt_reset_resume(struct hid_device *hdev)
{
+ struct mt_device *td = hid_get_drvdata(hdev);
+
mt_release_contacts(hdev);
mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
+
+ /* Request an update on the typecover folding state on resume
+ * after reset.
+ */
+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH)
+ request_type_cover_tablet_mode_switch(hdev);
+
return 0;
}
static int mt_resume(struct hid_device *hdev)
{
+ struct mt_device *td = hid_get_drvdata(hdev);
+
/* Some Elan legacy devices require SET_IDLE to be set on resume.
* It should be safe to send it to other devices too.
* Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
@@ -1931,6 +2008,10 @@ static int mt_resume(struct hid_device *hdev)
mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
+ /* Request an update on the typecover folding state on resume. */
+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH)
+ request_type_cover_tablet_mode_switch(hdev);
+
return 0;
}
#endif
@@ -1938,6 +2019,21 @@ static int mt_resume(struct hid_device *hdev)
static void mt_remove(struct hid_device *hdev)
{
struct mt_device *td = hid_get_drvdata(hdev);
+ struct hid_field *field;
+ struct input_dev *input;
+
+ /* Reset tablet mode switch on disconnect. */
+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) {
+ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT],
+ &field,
+ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) {
+ input = field->hidinput->input;
+ input_report_switch(input, SW_TABLET_MODE, 0);
+ input_sync(input);
+ } else {
+ hid_err(hdev, "couldn't find tablet mode field\n");
+ }
+ }
unregister_pm_notifier(&td->pm_notifier);
del_timer_sync(&td->release_timer);
--
2.40.0

View File

@ -0,0 +1,97 @@
From d335694ac0657ca040b1f2fa9799a16d862b2923 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sun, 19 Feb 2023 22:12:24 +0100
Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod
Work around buggy EFI firmware: On some Microsoft Surface devices
(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with
EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the
system down, it returns and the system stays on.
It turns out that this only happens after PCI shutdown callbacks ran for
specific devices. Excluding those devices from the shutdown process
makes the ResetSystem call work as expected.
TODO: Maybe we can find a better way or the root cause of this?
Not-Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Patchset: surface-shutdown
---
drivers/pci/pci-driver.c | 3 +++
drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 1 +
3 files changed, 40 insertions(+)
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 7a19f11daca3a..e6b8c9ef7c216 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -507,6 +507,9 @@ static void pci_device_shutdown(struct device *dev)
struct pci_dev *pci_dev = to_pci_dev(dev);
struct pci_driver *drv = pci_dev->driver;
+ if (pci_dev->no_shutdown)
+ return;
+
pm_runtime_resume(dev);
if (drv && drv->shutdown)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 494fa46f57671..106fb2ff855b2 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -6015,3 +6015,39 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2d, dpc_log_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2f, dpc_log_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size);
#endif
+
+static const struct dmi_system_id no_shutdown_dmi_table[] = {
+ /*
+ * Systems on which some devices should not be touched during shutdown.
+ */
+ {
+ .ident = "Microsoft Surface Pro 9",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"),
+ },
+ },
+ {
+ .ident = "Microsoft Surface Laptop 5",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"),
+ },
+ },
+ {}
+};
+
+static void quirk_no_shutdown(struct pci_dev *dev)
+{
+ if (!dmi_check_system(no_shutdown_dmi_table))
+ return;
+
+ dev->no_shutdown = 1;
+ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n",
+ dev->vendor, dev->device);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7e8e8633ad905..a09234cf28796 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -464,6 +464,7 @@ struct pci_dev {
unsigned int no_vf_scan:1; /* Don't scan for VFs after IOV enablement */
unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */
unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */
+ unsigned int no_shutdown:1; /* Do not touch device on shutdown */
pci_dev_flags_t dev_flags;
atomic_t enable_cnt; /* pci_enable_device has been called */
--
2.40.0

View File

@ -0,0 +1,51 @@
From bec43860c192a554c7923f82ddd6403d36aa9c1c Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sun, 12 Mar 2023 01:41:57 +0100
Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9
Add the lid GPE used by the Surface Pro 9.
Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Patchset: surface-gpe
---
drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c
index c219b840d491a..69c4352e8406b 100644
--- a/drivers/platform/surface/surface_gpe.c
+++ b/drivers/platform/surface/surface_gpe.c
@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = {
{},
};
+static const struct property_entry lid_device_props_l52[] = {
+ PROPERTY_ENTRY_U32("gpe", 0x52),
+ {},
+};
+
static const struct property_entry lid_device_props_l57[] = {
PROPERTY_ENTRY_U32("gpe", 0x57),
{},
@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = {
},
.driver_data = (void *)lid_device_props_l4B,
},
+ {
+ /*
+ * We match for SKU here due to product name clash with the ARM
+ * version.
+ */
+ .ident = "Surface Pro 9",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"),
+ },
+ .driver_data = (void *)lid_device_props_l52,
+ },
{
.ident = "Surface Book 1",
.matches = {
--
2.40.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
From 7e996cc2b2f8543e6b82fef715776ad2d6076af7 Mon Sep 17 00:00:00 2001
From: Sachi King <nakato@nakato.io>
Date: Sat, 29 May 2021 17:47:38 +1000
Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7
override
This patch is the work of Thomas Gleixner <tglx@linutronix.de> and is
copied from:
https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/
This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin
setup that is missing in the laptops ACPI table.
This patch was used for validation of the issue, and is not a proper
fix, but is probably a better temporary hack than continuing to probe
the Legacy PIC and run with the PIC in an unknown state.
Patchset: amd-gpio
---
arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 0f762070a5e10..6362dd4522337 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -22,6 +22,7 @@
#include <linux/efi-bgrt.h>
#include <linux/serial_core.h>
#include <linux/pgtable.h>
+#include <linux/dmi.h>
#include <asm/e820/api.h>
#include <asm/irqdomain.h>
@@ -1252,6 +1253,17 @@ static void __init mp_config_acpi_legacy_irqs(void)
}
}
+static const struct dmi_system_id surface_quirk[] __initconst = {
+ {
+ .ident = "Microsoft Surface Laptop 4 (AMD)",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953")
+ },
+ },
+ {}
+};
+
/*
* Parse IOAPIC related entries in MADT
* returns 0 on success, < 0 on error
@@ -1307,6 +1319,11 @@ static int __init acpi_parse_madt_ioapic_entries(void)
acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0,
acpi_gbl_FADT.sci_interrupt);
+ if (dmi_check_system(surface_quirk)) {
+ pr_warn("Surface hack: Override irq 7\n");
+ mp_override_legacy_irq(7, 3, 3, 7);
+ }
+
/* Fill in identity legacy mappings where no override */
mp_config_acpi_legacy_irqs();
--
2.40.0
From c4b8d0e7087cbd85f086d13b24b2cbfd1d2c9e91 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Thu, 3 Jun 2021 14:04:26 +0200
Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override
quirk
The 13" version of the Surface Laptop 4 has the same problem as the 15"
version, but uses a different SKU. Add that SKU to the quirk as well.
Patchset: amd-gpio
---
arch/x86/kernel/acpi/boot.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 6362dd4522337..8a092c2c6fa86 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1255,12 +1255,19 @@ static void __init mp_config_acpi_legacy_irqs(void)
static const struct dmi_system_id surface_quirk[] __initconst = {
{
- .ident = "Microsoft Surface Laptop 4 (AMD)",
+ .ident = "Microsoft Surface Laptop 4 (AMD 15\")",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953")
},
},
+ {
+ .ident = "Microsoft Surface Laptop 4 (AMD 13\")",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959")
+ },
+ },
{}
};
--
2.40.0

View File

@ -0,0 +1,109 @@
From c3f3a7ab79b01b35c9e488fc2d92a66b802d8df8 Mon Sep 17 00:00:00 2001
From: "Bart Groeneveld | GPX Solutions B.V" <bart@gpxbv.nl>
Date: Mon, 5 Dec 2022 16:08:46 +0100
Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms
The specification [1] allows so-called HW-reduced platforms,
which do not implement everything, especially the wakeup related stuff.
In that case, it is still usable as a RTC. This is helpful for [2]
and [3], which is about a device with no other working RTC,
but it does have an HW-reduced TAD, which can be used as a RTC instead.
[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device
[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313
[3]: https://github.com/linux-surface/linux-surface/issues/415
Signed-off-by: Bart Groeneveld | GPX Solutions B.V. <bart@gpxbv.nl>
Patchset: rtc
---
drivers/acpi/acpi_tad.c | 35 ++++++++++++++++++++++++-----------
1 file changed, 24 insertions(+), 11 deletions(-)
diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c
index e9b8e8305e23e..944276934e7ec 100644
--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -432,6 +432,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RO(caps);
+static struct attribute *acpi_tad_attrs[] = {
+ &dev_attr_caps.attr,
+ NULL,
+};
+static const struct attribute_group acpi_tad_attr_group = {
+ .attrs = acpi_tad_attrs,
+};
+
static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -480,15 +488,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RW(ac_status);
-static struct attribute *acpi_tad_attrs[] = {
- &dev_attr_caps.attr,
+static struct attribute *acpi_tad_ac_attrs[] = {
&dev_attr_ac_alarm.attr,
&dev_attr_ac_policy.attr,
&dev_attr_ac_status.attr,
NULL,
};
-static const struct attribute_group acpi_tad_attr_group = {
- .attrs = acpi_tad_attrs,
+static const struct attribute_group acpi_tad_ac_attr_group = {
+ .attrs = acpi_tad_ac_attrs,
};
static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr,
@@ -563,13 +570,18 @@ static int acpi_tad_remove(struct platform_device *pdev)
pm_runtime_get_sync(dev);
+ if (dd->capabilities & ACPI_TAD_AC_WAKE)
+ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group);
+
if (dd->capabilities & ACPI_TAD_DC_WAKE)
sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group);
sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group);
- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER);
- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER);
+ if (dd->capabilities & ACPI_TAD_AC_WAKE) {
+ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER);
+ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER);
+ }
if (dd->capabilities & ACPI_TAD_DC_WAKE) {
acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER);
acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER);
@@ -604,11 +616,6 @@ static int acpi_tad_probe(struct platform_device *pdev)
return -ENODEV;
}
- if (!acpi_has_method(handle, "_PRW")) {
- dev_info(dev, "Missing _PRW\n");
- return -ENODEV;
- }
-
dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
if (!dd)
return -ENOMEM;
@@ -637,6 +644,12 @@ static int acpi_tad_probe(struct platform_device *pdev)
if (ret)
goto fail;
+ if (caps & ACPI_TAD_AC_WAKE) {
+ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group);
+ if (ret)
+ goto fail;
+ }
+
if (caps & ACPI_TAD_DC_WAKE) {
ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group);
if (ret)
--
2.40.0

View File

@ -7,8 +7,8 @@ echo "Pika Kernel - Applying patches"
patch -Np1 < "../patches/0001-cachy-all.patch" patch -Np1 < "../patches/0001-cachy-all.patch"
# orig patch from cachy # orig patch from cachy
patch -Np1 < "../patches/0002-eevdf.patch" patch -Np1 < "../patches/0002-eevdf.patch"
# orig patch from cachy - 0001-bore-eevdf.patch - looks to not exist for 6.3 so switch to eevdf/cfs # Linux-surface
#patch -Np1 < "../patches/0003-bore.patch" patch -Np1 < "../patches/surface/*.patch"
# HDR patch - Currently broken against 6.3 # HDR patch - Currently broken against 6.3
#patch -Np1 < "../patches/0004-hdr.patch" #patch -Np1 < "../patches/0004-hdr.patch"
# Nintendo controller rumble patch # Nintendo controller rumble patch

View File

@ -2,7 +2,7 @@
echo "Pika Kernel - Getting source" echo "Pika Kernel - Getting source"
wget -nv https://git.kernel.org/torvalds/t/linux-6.3-rc6.tar.gz wget -nv https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.3.tar.xz
tar -zxf ./linux-6.3-rc6.tar.gz tar -zxf ./linux-6.3.tar.xz
cd linux-6.3-rc6 cd linux-6.3